| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  | import Singleton from "../Base/Singleton"; | 
					
						
							|  |  |  |  | import { ApiMsgEnum, IModel } from "../Common"; | 
					
						
							|  |  |  |  | import { binaryEncode, binaryDecode } from "../Common/Binary"; | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  | const TIMEOUT = 5000; | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-07 22:24:46 +08:00
										 |  |  |  | interface IItem { | 
					
						
							|  |  |  |  |   cb: Function; | 
					
						
							|  |  |  |  |   ctx: unknown; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-03 20:06:57 +08:00
										 |  |  |  | export interface ICallApiRet<T> { | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |   success: boolean; | 
					
						
							|  |  |  |  |   error?: Error; | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |   res?: T; | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | export default class NetworkManager extends Singleton { | 
					
						
							|  |  |  |  |   static get Instance() { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |     return super.GetInstance<NetworkManager>(); | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |   ws: WebSocket; | 
					
						
							|  |  |  |  |   port = 8888; | 
					
						
							|  |  |  |  |   maps: Map<ApiMsgEnum, Array<IItem>> = new Map(); | 
					
						
							|  |  |  |  |   isConnected = false; | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   connect() { | 
					
						
							|  |  |  |  |     return new Promise((resolve, reject) => { | 
					
						
							| 
									
										
										
										
											2022-12-03 21:28:38 +08:00
										 |  |  |  |       if (this.isConnected) { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |         resolve(true); | 
					
						
							|  |  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2022-12-03 21:28:38 +08:00
										 |  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |       this.ws = new WebSocket(`ws://localhost:${this.port}`); | 
					
						
							| 
									
										
										
										
											2022-12-07 22:24:46 +08:00
										 |  |  |  |       //onmessage接受的数据类型,只有在后端返回字节数组的时候才有效果
 | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |       this.ws.binaryType = "arraybuffer"; | 
					
						
							| 
									
										
										
										
											2022-12-07 22:24:46 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |       this.ws.onopen = () => { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |         this.isConnected = true; | 
					
						
							|  |  |  |  |         resolve(true); | 
					
						
							|  |  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-07 22:24:46 +08:00
										 |  |  |  |       this.ws.onerror = (e) => { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |         this.isConnected = false; | 
					
						
							|  |  |  |  |         console.log(e); | 
					
						
							|  |  |  |  |         reject("ws onerror"); | 
					
						
							|  |  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       this.ws.onclose = () => { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |         this.isConnected = false; | 
					
						
							|  |  |  |  |         reject("ws onclose"); | 
					
						
							|  |  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       this.ws.onmessage = (e) => { | 
					
						
							|  |  |  |  |         try { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |           const json = binaryDecode(e.data); | 
					
						
							|  |  |  |  |           const { name, data } = json; | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |           try { | 
					
						
							| 
									
										
										
										
											2022-12-04 22:10:30 +08:00
										 |  |  |  |             if (this.maps.has(name) && this.maps.get(name).length) { | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |               console.log(json); | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |               this.maps.get(name).forEach(({ cb, ctx }) => cb.call(ctx, data)); | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |             } | 
					
						
							|  |  |  |  |           } catch (error) { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |             console.log("onmessage:", error); | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |           } | 
					
						
							|  |  |  |  |         } catch (error) { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |           console.log("解析失败,不是合法的JSON格式", error); | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |       }; | 
					
						
							|  |  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |   callApi<T extends keyof IModel["api"]>(name: T, data: IModel["api"][T]["req"]): Promise<ICallApiRet<IModel["api"][T]["res"]>> { | 
					
						
							| 
									
										
										
										
											2022-12-03 20:06:57 +08:00
										 |  |  |  |     return new Promise((resolve) => { | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |       try { | 
					
						
							|  |  |  |  |         // 超时处理
 | 
					
						
							|  |  |  |  |         const timer = setTimeout(() => { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |           resolve({ success: false, error: new Error("timeout") }); | 
					
						
							|  |  |  |  |           this.unlistenMsg(name as any, cb, null); | 
					
						
							|  |  |  |  |         }, TIMEOUT); | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 回调处理
 | 
					
						
							| 
									
										
										
										
											2022-12-03 20:06:57 +08:00
										 |  |  |  |         const cb = (res) => { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |           resolve(res); | 
					
						
							|  |  |  |  |           clearTimeout(timer); | 
					
						
							|  |  |  |  |           this.unlistenMsg(name as any, cb, null); | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |         this.listenMsg(name as any, cb, null); | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |         this.sendMsg(name as any, data); | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |       } catch (error) { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |         resolve({ success: false, error: error as Error }); | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-12-03 20:06:57 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |   async sendMsg<T extends keyof IModel["msg"]>(name: T, data: IModel["msg"][T]) { | 
					
						
							|  |  |  |  |     const view = binaryEncode(name, data); | 
					
						
							|  |  |  |  |     let delay = parseInt(new URLSearchParams(location.search).get("delay") || "0") || 0; | 
					
						
							|  |  |  |  |     await new Promise((r) => setTimeout(r, delay)); | 
					
						
							|  |  |  |  |     this.ws.send(view.buffer); | 
					
						
							| 
									
										
										
										
											2022-12-03 20:06:57 +08:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |   listenMsg<T extends keyof IModel["msg"]>(name: T, cb: (args: IModel["msg"][T]) => void, ctx: unknown) { | 
					
						
							| 
									
										
										
										
											2022-12-04 22:10:30 +08:00
										 |  |  |  |     if (this.maps.has(name)) { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |       this.maps.get(name).push({ ctx, cb }); | 
					
						
							| 
									
										
										
										
											2022-12-03 20:06:57 +08:00
										 |  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |       this.maps.set(name, [{ ctx, cb }]); | 
					
						
							| 
									
										
										
										
											2022-12-03 20:06:57 +08:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |   unlistenMsg<T extends keyof IModel["msg"]>(name: T, cb: (args: IModel["msg"][T]) => void, ctx: unknown) { | 
					
						
							| 
									
										
										
										
											2022-12-04 22:10:30 +08:00
										 |  |  |  |     if (this.maps.has(name)) { | 
					
						
							| 
									
										
										
										
											2022-12-08 21:14:02 +08:00
										 |  |  |  |       const items = this.maps.get(name); | 
					
						
							|  |  |  |  |       const index = items.findIndex((i) => cb === i.cb && i.ctx === ctx); | 
					
						
							|  |  |  |  |       index > -1 && items.splice(index, 1); | 
					
						
							| 
									
										
										
										
											2022-12-03 20:06:57 +08:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-12-01 22:26:41 +08:00
										 |  |  |  | } |