Socket.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import Heartbeat from "./Heartbeat.js"
  2. import Timeout from "./Timeout.js"
  3. import InitNetworkTimeoutError from "./error/InitNetworkTimeoutError.js"
  4. import {reporter} from "./Reporter.js"
  5. import util from "./util.js"
  6. import InternalError from "./error/InternalError.js"
  7. import Logger from "./Logger.js"
  8. const logger = new Logger('ws')
  9. export default class Socket extends EventEmitter {
  10. constructor(e) {
  11. super();
  12. E(this, "_ws");
  13. E(this, "_openTimer");
  14. E(this, "connected", !1);
  15. E(this, "_hasTimeout", !1);
  16. E(this, "heartbeat");
  17. E(this, "latency", (e,t)=>this.send({
  18. id: "checkLatency",
  19. data: JSON.stringify(e),
  20. packet_id: t
  21. }));
  22. E(this, "send", e=>{
  23. if (this.wsNoReady())
  24. {
  25. return;
  26. }
  27. const t = JSON.stringify(e);
  28. e.id !== "heartbeat" && logger.info("send ws frame", t);
  29. this._ws.send(t);
  30. console.log('发送socket数据:'+t)
  31. }
  32. );
  33. E(this, "startGame", ()=>{
  34. const {roomId: e, userId: t, avatarId: r, skinId: n, role: o, avatarComponents: a, versionId: s, rotationRenderType: l, isAllSync: u, nickname: c, avatarScale: h, appId: f, camera: d, player: _, firends: g, syncByEvent: m, areaName: v, attitude: y, pathName: b, person: T, roomTypeId: C="", syncToOthers: A, hasAvatar: S, prioritySync: P, extra: R={}, removeWhenDisconnected: M} = this.network.room.currentNetworkOptions;
  35. R.removeWhenDisconnected = M;
  36. const x = {
  37. id: "start",
  38. room_id: e,
  39. user_id: t,
  40. trace_id: util.uuid(),
  41. data: JSON.stringify({
  42. avatar_components: JSON.stringify(a),
  43. avatar_id: r,
  44. skin_id: n,
  45. is_host: o ? o == "host" : !0,
  46. skin_data_version: n !== void 0 && s !== void 0 ? n + s : void 0,
  47. rotation_render_type: l,
  48. is_all_sync: u,
  49. nick_name: encodeURIComponent(c || ""),
  50. app_id: f,
  51. camera: d,
  52. player: _,
  53. person: T,
  54. firends: JSON.stringify(g),
  55. sync_by_event: m,
  56. area_name: v,
  57. path_name: b,
  58. attitude: y,
  59. room_type_id: C,
  60. syncToOthers: A,
  61. hasAvatar: S,
  62. avatarSize: h,
  63. prioritySync: P,
  64. extra: JSON.stringify(R)
  65. })
  66. };
  67. this.send(x),
  68. logger.warn("startGame", le(oe({}, x), {
  69. data: JSON.parse(x.data)
  70. }))
  71. }
  72. );
  73. this.network = e,
  74. this.heartbeat = new Heartbeat({
  75. ping: t=>{
  76. var r;
  77. if (!this.connected) {
  78. this.heartbeat.stop(),
  79. (r = e.room.stats) == null || r.assign({
  80. rtt: 0
  81. });
  82. return
  83. }
  84. this.send({
  85. id: "heartbeat",
  86. data: t
  87. })
  88. }
  89. ,
  90. pong(t) {
  91. var r;
  92. (r = e.room.stats) == null || r.assign({
  93. rtt: t
  94. })
  95. }
  96. })
  97. }
  98. get connection() {
  99. return this._ws
  100. }
  101. start() {
  102. this._hasTimeout = !1;
  103. const e = this.getAddress();
  104. logger.info(`connecting to ${e}`);
  105. const t = Date.now();
  106. this._ws = new WebSocket(e),
  107. this._openTimer = new Timeout(()=>{
  108. const r = `Failed to open websocket in ${DEFAULT_OPEN_TIMEOUT_MS} ms`;
  109. this._hasTimeout = !0,
  110. this.emit("socketClosed", new InitNetworkTimeoutError(r))
  111. }
  112. ,DEFAULT_OPEN_TIMEOUT_MS),
  113. this._ws.onopen = ()=>{
  114. var r;
  115. (r = this._openTimer) == null || r.clear(),
  116. this.connected = !0,
  117. this.heartbeat.start(),
  118. this.network.room.currentNetworkOptions.reconnect || (logger.infoAndReportMeasurement({
  119. metric: "wsOpenedAt",
  120. group: "joinRoom",
  121. startTime: this.network.room._startTime
  122. }),
  123. logger.infoAndReportMeasurement({
  124. metric: "wsOpenedCost",
  125. group: "joinRoom",
  126. startTime: t
  127. }))
  128. }
  129. ,
  130. this.handleWSEvent()
  131. }
  132. getAddress() {
  133. const {wsServerUrl: e, reconnect: t, sessionId: r, token: n, roomId: o, userId: a, pageSession: s} = this.network.room.currentNetworkOptions
  134. , l = this.network.room.skinId;
  135. let u = e;
  136. t && (u = u + `?reconnect=true&lastSessionID=${r}`);
  137. const c = `userId=${a}&roomId=${o}&pageSession=${s}` + (this.network.room.isHost ? `&skinId=${l}` : "") + (n ? `&token=${n}` : "");
  138. return u = u.indexOf("?") > -1 ? u + "&" + c : u + "?" + c,
  139. u
  140. }
  141. handleWSEvent() {
  142. const e = this._ws;
  143. e.addEventListener("error", t=>{
  144. this.connected = !1,
  145. logger.error("webscoket error", t),
  146. this.emit("socketClosed", new InternalError("connect to address error: " + this.network.room.currentNetworkOptions.wsServerUrl))
  147. }
  148. ),
  149. e.addEventListener("close", t=>{
  150. this.connected = !1,
  151. this._onClose(t)
  152. }
  153. ),
  154. e.addEventListener("message", t=>{
  155. if (!t || this._hasTimeout || !this.connected)
  156. return;
  157. let r = null;
  158. try {
  159. r = JSON.parse(t.data)
  160. } catch (o) {
  161. logger.error(o);
  162. return
  163. }
  164. if (!r)
  165. return;
  166. const n = r.id;
  167. if (!!n)
  168. switch (n !== "heartbeat" && logger.info(`receive ws frame: ${t.data}`),
  169. n) {
  170. case "fail":
  171. break;
  172. case "init":
  173. try {
  174. const o = r.data.slice(-37, -1);
  175. reporter.updateBody({
  176. serverSession: o
  177. })
  178. } catch (o) {
  179. console.error(o)
  180. }
  181. this.network.rtcp.start();
  182. break;
  183. case "heartbeat":
  184. this.heartbeat.pong(r.data);
  185. break;
  186. case "offer":
  187. this.network.rtcp.setRemoteDescription(r.data, this.network.stream.el);
  188. break;
  189. case "ice_candidate":
  190. this.network.rtcp.addCandidate(r.data);
  191. break;
  192. case "start":
  193. this.emit("gameRoomAvailable", r);
  194. break;
  195. case "error":
  196. try {
  197. const {Code: o, Msg: a} = JSON.parse(r.data);
  198. if (o) {
  199. if (o == 3003)
  200. return this.emit("socketClosed", new TokenExpiredError);
  201. if (authenticationErrorCodes.indexOf(o) > -1)
  202. return this.emit("socketClosed", new AuthenticationError("\u9274\u6743\u9519\u8BEF:" + a));
  203. {
  204. const s = util.getErrorByCode(o);
  205. this.emit("socketClosed", new s(a))
  206. }
  207. }
  208. } catch (o) {
  209. logger.error(o),
  210. this.emit("socketClosed", new InternalError(r.data))
  211. }
  212. break;
  213. case "checkLatency":
  214. {
  215. const o = r.packet_id
  216. , a = r.data.split(",");
  217. this.onLatencyCheck({
  218. packetId: o,
  219. addresses: a
  220. });
  221. break
  222. }
  223. default:
  224. logger.warn("unkown ws message type", n, r)
  225. }
  226. }
  227. )
  228. }
  229. onLatencyCheck(e) {
  230. const t = [...new Set(e.addresses || [])];
  231. Promise.all(t.map(r=>({
  232. [r]: 9999
  233. }))).then(r=>{
  234. const n = Object.assign({}, ...r);
  235. this.latency(n, e.packetId)
  236. }
  237. )
  238. }
  239. wsNoReady() {
  240. return this._ws.readyState == WebSocket.CLOSED || this._ws.readyState == WebSocket.CLOSING || this._ws.readyState == WebSocket.CONNECTING
  241. }
  242. prepareReconnect() {
  243. this._close({
  244. code: WS_CLOSE_RECONNECT,
  245. reason: "reconnect"
  246. })
  247. }
  248. _onClose({code: e, reason: t}) {
  249. this._openTimer && this._openTimer.clear(),
  250. logger.warn(`ws closed: ${e} ` + t),
  251. [WS_CLOSE_RECONNECT, WS_CLOSE_NORMAL].includes(e) || this.emit("socketClosed", new InternalError("Websocket error"))
  252. }
  253. _close({code: e, reason: t}) {
  254. var r;
  255. (r = this._ws) == null || r.close(e, t)
  256. }
  257. quit() {
  258. this._close({
  259. code: WS_CLOSE_NORMAL,
  260. reason: "quit"
  261. })
  262. }
  263. }