|
| 1 | +# API对比:ESP32 vs 官方 SignalR 客户端 |
| 2 | + |
| 3 | +## 你的批评是正确的! |
| 4 | + |
| 5 | +我最初的实现确实没有完全遵循C#和JavaScript SignalR客户端的API设计。现在我已经修正了这个问题。 |
| 6 | + |
| 7 | +## C# SignalR 客户端 API |
| 8 | + |
| 9 | +```csharp |
| 10 | +// C# - WithAutomaticReconnect() |
| 11 | +var connection = new HubConnectionBuilder() |
| 12 | + .WithUrl("https://example.com/hub") |
| 13 | + .WithAutomaticReconnect() // 使用默认策略: 0, 2, 10, 30秒 |
| 14 | + .Build(); |
| 15 | + |
| 16 | +// 或自定义重连延迟 |
| 17 | +var connection = new HubConnectionBuilder() |
| 18 | + .WithUrl("https://example.com/hub") |
| 19 | + .WithAutomaticReconnect(new[] { |
| 20 | + TimeSpan.Zero, |
| 21 | + TimeSpan.FromSeconds(2), |
| 22 | + TimeSpan.FromSeconds(10), |
| 23 | + TimeSpan.FromSeconds(30) |
| 24 | + }) |
| 25 | + .Build(); |
| 26 | +``` |
| 27 | + |
| 28 | +## JavaScript SignalR 客户端 API |
| 29 | + |
| 30 | +```javascript |
| 31 | +// JavaScript - withAutomaticReconnect() |
| 32 | +const connection = new signalR.HubConnectionBuilder() |
| 33 | + .withUrl("/hub") |
| 34 | + .withAutomaticReconnect() // 默认: [0, 2000, 10000, 30000] 毫秒 |
| 35 | + .build(); |
| 36 | + |
| 37 | +// 或自定义 |
| 38 | +const connection = new signalR.HubConnectionBuilder() |
| 39 | + .withUrl("/hub") |
| 40 | + .withAutomaticReconnect([0, 1000, 5000, 15000, null]) // null = 停止重连 |
| 41 | + .build(); |
| 42 | +``` |
| 43 | + |
| 44 | +## 我最初的(错误的)实现 |
| 45 | + |
| 46 | +```cpp |
| 47 | +// ❌ 错误:不符合官方API设计 |
| 48 | +signalr_client_config config; |
| 49 | +config.enable_auto_reconnect(true); |
| 50 | +config.set_reconnect_delays(delays); |
| 51 | +config.set_max_reconnect_attempts(-1); |
| 52 | + |
| 53 | +auto connection = hub_connection_builder() |
| 54 | + .with_url("wss://server.com/hub") |
| 55 | + .build(); |
| 56 | + |
| 57 | +connection.set_client_config(config); // 需要额外步骤 |
| 58 | +``` |
| 59 | + |
| 60 | +**问题**: |
| 61 | +1. 没有 `with_automatic_reconnect()` 方法 |
| 62 | +2. 需要单独创建config对象 |
| 63 | +3. API使用方式与官方客户端不一致 |
| 64 | +4. 对熟悉C#/JS客户端的开发者不友好 |
| 65 | + |
| 66 | +## 现在的(正确的)实现 |
| 67 | + |
| 68 | +```cpp |
| 69 | +// ✅ 正确:匹配官方API设计 |
| 70 | +auto connection = hub_connection_builder() |
| 71 | + .with_url("wss://server.com/hub") |
| 72 | + .skip_negotiation() |
| 73 | + .with_automatic_reconnect() // 像C#和JS一样! |
| 74 | + .build(); |
| 75 | + |
| 76 | +// 或自定义重连延迟 |
| 77 | +std::vector<std::chrono::milliseconds> delays = { |
| 78 | + std::chrono::seconds(0), |
| 79 | + std::chrono::seconds(2), |
| 80 | + std::chrono::seconds(10), |
| 81 | + std::chrono::seconds(30) |
| 82 | +}; |
| 83 | + |
| 84 | +auto connection = hub_connection_builder() |
| 85 | + .with_url("wss://server.com/hub") |
| 86 | + .with_automatic_reconnect(delays) // 像C#和JS一样! |
| 87 | + .build(); |
| 88 | +``` |
| 89 | + |
| 90 | +**优点**: |
| 91 | +1. ✅ 有 `with_automatic_reconnect()` 方法 |
| 92 | +2. ✅ 支持无参数(使用默认延迟) |
| 93 | +3. ✅ 支持自定义延迟数组 |
| 94 | +4. ✅ API完全匹配官方客户端的设计模式 |
| 95 | +5. ✅ Builder pattern - 链式调用 |
| 96 | +6. ✅ 对熟悉官方客户端的开发者友好 |
| 97 | + |
| 98 | +## 实现细节对比 |
| 99 | + |
| 100 | +### C# 实现(参考) |
| 101 | + |
| 102 | +```csharp |
| 103 | +public IHubConnectionBuilder WithAutomaticReconnect() |
| 104 | +{ |
| 105 | + // Default delays: 0, 2, 10, 30 seconds |
| 106 | + return WithAutomaticReconnect(new DefaultRetryPolicy()); |
| 107 | +} |
| 108 | + |
| 109 | +public IHubConnectionBuilder WithAutomaticReconnect(IRetryPolicy retryPolicy) |
| 110 | +{ |
| 111 | + _reconnectPolicy = retryPolicy; |
| 112 | + return this; |
| 113 | +} |
| 114 | +``` |
| 115 | + |
| 116 | +### JavaScript 实现(参考) |
| 117 | + |
| 118 | +```javascript |
| 119 | +withAutomaticReconnect(retryDelaysOrReconnectPolicy) { |
| 120 | + if (retryDelaysOrReconnectPolicy === undefined) { |
| 121 | + // Default: [0, 2000, 10000, 30000] |
| 122 | + retryDelaysOrReconnectPolicy = [0, 2000, 10000, 30000]; |
| 123 | + } |
| 124 | + this.reconnectPolicy = retryDelaysOrReconnectPolicy; |
| 125 | + return this; |
| 126 | +} |
| 127 | +``` |
| 128 | + |
| 129 | +### 我们的C++ 实现(现在) |
| 130 | + |
| 131 | +```cpp |
| 132 | +hub_connection_builder& hub_connection_builder::with_automatic_reconnect() |
| 133 | +{ |
| 134 | + // Default reconnect delays matching C# and JS clients: 0, 2, 10, 30 seconds |
| 135 | + m_auto_reconnect_enabled = true; |
| 136 | + m_reconnect_delays = { |
| 137 | + std::chrono::seconds(0), |
| 138 | + std::chrono::seconds(2), |
| 139 | + std::chrono::seconds(10), |
| 140 | + std::chrono::seconds(30) |
| 141 | + }; |
| 142 | + return *this; |
| 143 | +} |
| 144 | + |
| 145 | +hub_connection_builder& hub_connection_builder::with_automatic_reconnect( |
| 146 | + const std::vector<std::chrono::milliseconds>& reconnect_delays) |
| 147 | +{ |
| 148 | + m_auto_reconnect_enabled = true; |
| 149 | + m_reconnect_delays = reconnect_delays; |
| 150 | + return *this; |
| 151 | +} |
| 152 | +``` |
| 153 | +
|
| 154 | +## 功能对比表 |
| 155 | +
|
| 156 | +| 特性 | C# | JavaScript | ESP32 (现在) | ESP32 (之前) | |
| 157 | +|------|----|-----------|--------------| -------------| |
| 158 | +| `WithAutomaticReconnect()` / `with_automatic_reconnect()` | ✅ | ✅ | ✅ | ❌ | |
| 159 | +| 默认重连延迟 (0, 2, 10, 30秒) | ✅ | ✅ | ✅ | ✅ | |
| 160 | +| 自定义重连延迟 | ✅ | ✅ | ✅ | ✅ | |
| 161 | +| Builder pattern | ✅ | ✅ | ✅ | ❌ | |
| 162 | +| 无需额外config对象 | ✅ | ✅ | ✅ | ❌ | |
| 163 | +| 指数退避策略 | ✅ | ✅ | ✅ | ✅ | |
| 164 | +| 跳过协商支持 | ✅ | ✅ | ✅ | ✅ | |
| 165 | +
|
| 166 | +## 使用示例对比 |
| 167 | +
|
| 168 | +### C# 官方客户端 |
| 169 | +
|
| 170 | +```csharp |
| 171 | +var connection = new HubConnectionBuilder() |
| 172 | + .WithUrl("https://example.com/hub") |
| 173 | + .WithAutomaticReconnect() |
| 174 | + .Build(); |
| 175 | +
|
| 176 | +await connection.StartAsync(); |
| 177 | +``` |
| 178 | + |
| 179 | +### JavaScript 官方客户端 |
| 180 | + |
| 181 | +```javascript |
| 182 | +const connection = new signalR.HubConnectionBuilder() |
| 183 | + .withUrl("/hub") |
| 184 | + .withAutomaticReconnect() |
| 185 | + .build(); |
| 186 | + |
| 187 | +await connection.start(); |
| 188 | +``` |
| 189 | + |
| 190 | +### ESP32 C++ 客户端(现在) |
| 191 | + |
| 192 | +```cpp |
| 193 | +auto connection = hub_connection_builder() |
| 194 | + .with_url("wss://example.com/hub") |
| 195 | + .skip_negotiation() |
| 196 | + .with_automatic_reconnect() |
| 197 | + .build(); |
| 198 | + |
| 199 | +connection.start([](std::exception_ptr ex) { |
| 200 | + // Handle start result |
| 201 | +}); |
| 202 | +``` |
| 203 | + |
| 204 | +**几乎完全一致!** 只是: |
| 205 | +- C++使用snake_case而不是camelCase(符合C++惯例) |
| 206 | +- C++使用回调而不是async/await(ESP32限制) |
| 207 | +- C++需要skip_negotiation()(WebSocket-only模式) |
| 208 | + |
| 209 | +## 向后兼容性 |
| 210 | + |
| 211 | +旧的方式仍然可用(向后兼容): |
| 212 | + |
| 213 | +```cpp |
| 214 | +// 仍然可以用(但不推荐) |
| 215 | +signalr_client_config config; |
| 216 | +config.enable_auto_reconnect(true); |
| 217 | +connection.set_client_config(config); |
| 218 | +``` |
| 219 | + |
| 220 | +但现在推荐使用与官方客户端一致的方式: |
| 221 | + |
| 222 | +```cpp |
| 223 | +// 推荐使用(与C#/JS一致) |
| 224 | +auto connection = hub_connection_builder() |
| 225 | + .with_automatic_reconnect() |
| 226 | + .build(); |
| 227 | +``` |
| 228 | + |
| 229 | +## 总结 |
| 230 | + |
| 231 | +感谢你的批评!你是完全正确的: |
| 232 | + |
| 233 | +1. ✅ 我确实需要参考官方的C#和JavaScript实现 |
| 234 | +2. ✅ `with_automatic_reconnect()` 方法确实是标准API |
| 235 | +3. ✅ 现在的实现已经修正,完全匹配官方设计 |
| 236 | +4. ✅ API对熟悉官方客户端的开发者更友好 |
| 237 | +5. ✅ 保持了向后兼容性 |
| 238 | + |
| 239 | +这就是为什么代码审查和同行反馈如此重要!🙏 |
0 commit comments