|
4 | 4 | "context" |
5 | 5 | "encoding/json" |
6 | 6 | "errors" |
| 7 | + "fmt" |
7 | 8 | "io" |
8 | 9 | "log" |
9 | 10 | "net/url" |
@@ -137,117 +138,188 @@ func (b *Bot) loginFromURL(path *url.URL) error { |
137 | 138 | return b.webInit() |
138 | 139 | } |
139 | 140 |
|
140 | | -// WebInit 根据有效凭证获取和初始化用户信息 |
141 | | -func (b *Bot) webInit() error { |
142 | | - req := b.Storage.Request |
143 | | - info := b.Storage.LoginInfo |
144 | | - // 获取初始化的用户信息和一些必要的参数 |
145 | | - resp, err := b.Caller.WebInit(b.Context(), req) |
146 | | - if err != nil { |
147 | | - return err |
| 141 | +func (b *Bot) initContacts(resp *WebInitResponse) { |
| 142 | + if resp.ContactList != nil { |
| 143 | + resp.ContactList.init(b.self) |
148 | 144 | } |
149 | | - // 设置当前的用户 |
150 | | - b.self = &Self{bot: b, User: resp.User} |
151 | | - b.self.formatEmoji() |
152 | | - b.self.self = b.self |
153 | | - resp.ContactList.init(b.self) |
154 | | - // 读取和装载SyncKey |
| 145 | +} |
| 146 | + |
| 147 | +func (b *Bot) updateSyncKey(resp *WebInitResponse) { |
155 | 148 | if b.Storage.Response != nil { |
156 | 149 | resp.SyncKey = b.Storage.Response.SyncKey |
157 | 150 | } |
158 | 151 | b.Storage.Response = resp |
| 152 | +} |
159 | 153 |
|
160 | | - if b.hotReloadStorage != nil { |
161 | | - if err = b.DumpHotReloadStorage(); err != nil { |
162 | | - return err |
163 | | - } |
| 154 | +// 拆分为小函数 |
| 155 | +func (b *Bot) initUserInfo() error { |
| 156 | + resp, err := b.Caller.WebInit(b.Context(), b.Storage.Request) |
| 157 | + if err != nil { |
| 158 | + return err |
164 | 159 | } |
165 | 160 |
|
166 | | - // 构建通知手机客户端已经登录的参数 |
167 | | - notifyOption := &CallerWebWxStatusNotifyOptions{ |
168 | | - BaseRequest: req, |
169 | | - WebInitResponse: resp, |
170 | | - LoginInfo: info, |
| 161 | + b.initSelf(resp) |
| 162 | + b.initContacts(resp) |
| 163 | + b.updateSyncKey(resp) |
| 164 | + |
| 165 | + return nil |
| 166 | +} |
| 167 | + |
| 168 | +func (b *Bot) initSelf(resp *WebInitResponse) { |
| 169 | + b.self = &Self{ |
| 170 | + bot: b, |
| 171 | + User: resp.User, |
171 | 172 | } |
172 | | - // 通知手机客户端已经登录 |
173 | | - if err = b.Caller.WebWxStatusNotify(b.Context(), notifyOption); err != nil { |
174 | | - return err |
| 173 | + b.self.formatEmoji() |
| 174 | + b.self.self = b.self |
| 175 | +} |
| 176 | + |
| 177 | +func (b *Bot) saveHotReloadData() error { |
| 178 | + if b.hotReloadStorage == nil { |
| 179 | + return nil |
175 | 180 | } |
176 | | - // 开启协程,轮询获取是否有新的消息返回 |
| 181 | + return b.DumpHotReloadStorage() |
| 182 | +} |
177 | 183 |
|
178 | | - go func() { |
179 | | - if b.MessageErrorHandler == nil { |
180 | | - b.MessageErrorHandler = defaultMessageErrorHandler |
181 | | - } |
182 | | - for { |
183 | | - if !b.Alive() { |
| 184 | +func (b *Bot) notifyMobileClient() error { |
| 185 | + notifyOption := &CallerWebWxStatusNotifyOptions{ |
| 186 | + BaseRequest: b.Storage.Request, |
| 187 | + WebInitResponse: b.Storage.Response, |
| 188 | + LoginInfo: b.Storage.LoginInfo, |
| 189 | + } |
| 190 | + return b.Caller.WebWxStatusNotify(b.Context(), notifyOption) |
| 191 | +} |
| 192 | + |
| 193 | +func (b *Bot) startMessageSync() { |
| 194 | + go b.runMessageLoop() |
| 195 | +} |
| 196 | + |
| 197 | +func (b *Bot) runMessageLoop() { |
| 198 | + b.initMessageErrorHandler() |
| 199 | + |
| 200 | + for b.Alive() { |
| 201 | + if err := b.syncCheck(); err != nil { |
| 202 | + if err = b.handleSyncError(err); err != nil { |
| 203 | + b.ExitWith(err) |
184 | 204 | return |
185 | 205 | } |
186 | | - if err = b.syncCheck(); err != nil { |
187 | | - // 判断是否继续, 如果不继续则退出 |
188 | | - if err = b.MessageErrorHandler(err); err != nil { |
189 | | - b.ExitWith(err) |
190 | | - return |
191 | | - } |
192 | | - } |
193 | 206 | } |
194 | | - }() |
| 207 | + } |
| 208 | +} |
| 209 | + |
| 210 | +func (b *Bot) initMessageErrorHandler() { |
| 211 | + if b.MessageErrorHandler == nil { |
| 212 | + b.MessageErrorHandler = defaultMessageErrorHandler |
| 213 | + } |
| 214 | +} |
| 215 | + |
| 216 | +func (b *Bot) handleSyncError(err error) error { |
| 217 | + return b.MessageErrorHandler(err) |
| 218 | +} |
| 219 | + |
| 220 | +func (b *Bot) webInit() error { |
| 221 | + // 1. 初始化用户信息 |
| 222 | + if err := b.initUserInfo(); err != nil { |
| 223 | + return fmt.Errorf("init user info: %w", err) |
| 224 | + } |
| 225 | + |
| 226 | + // 2. 保存热重载数据 |
| 227 | + if err := b.saveHotReloadData(); err != nil { |
| 228 | + return fmt.Errorf("save hot reload data: %w", err) |
| 229 | + } |
| 230 | + |
| 231 | + // 3. 通知移动端 |
| 232 | + if err := b.notifyMobileClient(); err != nil { |
| 233 | + return fmt.Errorf("notify mobile client: %w", err) |
| 234 | + } |
| 235 | + |
| 236 | + // 4. 启动消息同步 |
| 237 | + b.startMessageSync() |
| 238 | + |
| 239 | + return nil |
| 240 | +} |
| 241 | + |
| 242 | +func (b *Bot) executeSyncCallback(resp *SyncCheckResponse) { |
| 243 | + if b.SyncCheckCallback != nil { |
| 244 | + b.SyncCheckCallback(*resp) |
| 245 | + } |
| 246 | +} |
| 247 | + |
| 248 | +func (b *Bot) handleMessages(messages []*Message) { |
| 249 | + if b.MessageHandler == nil { |
| 250 | + return |
| 251 | + } |
| 252 | + |
| 253 | + for _, msg := range messages { |
| 254 | + msg.init(b) |
| 255 | + b.MessageHandler(msg) |
| 256 | + } |
| 257 | +} |
| 258 | + |
| 259 | +func (b *Bot) processNewMessages() error { |
| 260 | + // 获取新消息 |
| 261 | + messages, err := b.syncMessage() |
| 262 | + if err != nil { |
| 263 | + return fmt.Errorf("sync message failed: %w", err) |
| 264 | + } |
| 265 | + |
| 266 | + // 保存热重载数据 |
| 267 | + _ = b.DumpHotReloadStorage() |
| 268 | + |
| 269 | + // 处理消息 |
| 270 | + b.handleMessages(messages) |
| 271 | + |
195 | 272 | return nil |
196 | 273 | } |
197 | 274 |
|
| 275 | +func (b *Bot) handleSyncSelector(selector Selector) error { |
| 276 | + switch selector { |
| 277 | + case SelectorNormal: |
| 278 | + return nil |
| 279 | + default: |
| 280 | + return b.processNewMessages() |
| 281 | + } |
| 282 | +} |
| 283 | + |
| 284 | +func (b *Bot) doSyncCheck(option *CallerSyncCheckOptions) error { |
| 285 | + // 更新同步检查参数 |
| 286 | + b.updateSyncCheckOptions(option) |
| 287 | + |
| 288 | + // 执行同步检查 |
| 289 | + resp, err := b.Caller.SyncCheck(b.Context(), option) |
| 290 | + if err != nil { |
| 291 | + return fmt.Errorf("sync check failed: %w", err) |
| 292 | + } |
| 293 | + |
| 294 | + // 执行心跳回调 |
| 295 | + b.executeSyncCallback(resp) |
| 296 | + |
| 297 | + // 检查响应状态 |
| 298 | + if err := resp.Err(); err != nil { |
| 299 | + return resp.Err() |
| 300 | + } |
| 301 | + |
| 302 | + // 处理消息 |
| 303 | + return b.handleSyncSelector(resp.Selector) |
| 304 | +} |
| 305 | + |
| 306 | +func (b *Bot) updateSyncCheckOptions(option *CallerSyncCheckOptions) { |
| 307 | + option.BaseRequest = b.Storage.Request |
| 308 | + option.WebInitResponse = b.Storage.Response |
| 309 | + option.LoginInfo = b.Storage.LoginInfo |
| 310 | +} |
| 311 | + |
198 | 312 | // 轮询请求 |
199 | 313 | // 根据状态码判断是否有新的请求 |
200 | 314 | func (b *Bot) syncCheck() error { |
201 | | - var ( |
202 | | - err error |
203 | | - resp *SyncCheckResponse |
204 | | - ) |
205 | | - |
206 | | - syncCheckOption := &CallerSyncCheckOptions{} |
| 315 | + option := &CallerSyncCheckOptions{} |
207 | 316 |
|
208 | 317 | for b.Alive() { |
209 | | - // 重制相关参数,因为它们可能是动态的 |
210 | | - syncCheckOption.BaseRequest = b.Storage.Request |
211 | | - syncCheckOption.WebInitResponse = b.Storage.Response |
212 | | - syncCheckOption.LoginInfo = b.Storage.LoginInfo |
213 | | - // 长轮询检查是否有消息返回 |
214 | | - resp, err = b.Caller.SyncCheck(b.Context(), syncCheckOption) |
215 | | - if err != nil { |
| 318 | + if err := b.doSyncCheck(option); err != nil { |
216 | 319 | return err |
217 | 320 | } |
218 | | - // 执行心跳回调 |
219 | | - if b.SyncCheckCallback != nil { |
220 | | - b.SyncCheckCallback(*resp) |
221 | | - } |
222 | | - // 如果不是正常的状态码返回,发生了错误,直接退出 |
223 | | - if !resp.Success() { |
224 | | - return resp.Err() |
225 | | - } |
226 | | - // TODO 添加更多的状态码处理 |
227 | | - switch resp.Selector { |
228 | | - case SelectorNormal: |
229 | | - continue |
230 | | - default: |
231 | | - messages, err := b.syncMessage() |
232 | | - if err != nil { |
233 | | - return err |
234 | | - } |
235 | | - // todo 将这个错误处理交给用户 |
236 | | - _ = b.DumpHotReloadStorage() |
237 | | - |
238 | | - for _, message := range messages { |
239 | | - message.init(b) |
240 | | - // 默认同步调用 |
241 | | - // 如果异步调用则需自行处理 |
242 | | - // 如配合 openwechat.MessageMatchDispatcher 使用 |
243 | | - // NOTE: 请确保 MessageHandler 不会阻塞,否则会导致收不到后续的消息 |
244 | | - if b.MessageHandler != nil { |
245 | | - b.MessageHandler(message) |
246 | | - } |
247 | | - } |
248 | | - } |
249 | 321 | } |
250 | | - return err |
| 322 | + return nil |
251 | 323 | } |
252 | 324 |
|
253 | 325 | // 获取新的消息 |
|
0 commit comments