Socket.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. class Socket extends EventEmitter {
  2. constructor(e) {
  3. super();
  4. E(this, "_ws");
  5. E(this, "_openTimer");
  6. E(this, "connected", !1);
  7. E(this, "_hasTimeout", !1);
  8. E(this, "heartbeat");
  9. E(this, "latency", (e,t)=>this.send({
  10. id: "checkLatency",
  11. data: JSON.stringify(e),
  12. packet_id: tconst log$k = new Logger("ws");
  13. class Socket extends EventEmitter {
  14. constructor(e) {
  15. super();
  16. E(this, "_ws");
  17. E(this, "_openTimer");
  18. E(this, "connected", !1);
  19. E(this, "_hasTimeout", !1);
  20. E(this, "heartbeat");
  21. E(this, "latency", (e,t)=>this.send({
  22. id: "checkLatency",
  23. data: JSON.stringify(e),
  24. packet_id: t
  25. }));
  26. E(this, "send", e=>{
  27. if (this.wsNoReady())
  28. return;
  29. const t = JSON.stringify(e);
  30. e.id !== "heartbeat" && log$k.info("send ws frame", t),
  31. this._ws.send(t)
  32. }
  33. );
  34. E(this, "startGame", ()=>{
  35. 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;
  36. R.removeWhenDisconnected = M;
  37. const x = {
  38. id: "start",
  39. room_id: e,
  40. user_id: t,
  41. trace_id: uuid$1(),
  42. data: JSON.stringify({
  43. avatar_components: JSON.stringify(a),
  44. avatar_id: r,
  45. skin_id: n,
  46. is_host: o ? o == "host" : !0,
  47. skin_data_version: n !== void 0 && s !== void 0 ? n + s : void 0,
  48. rotation_render_type: l,
  49. is_all_sync: u,
  50. nick_name: encodeURIComponent(c || ""),
  51. app_id: f,
  52. camera: d,
  53. player: _,
  54. person: T,
  55. firends: JSON.stringify(g),
  56. sync_by_event: m,
  57. area_name: v,
  58. path_name: b,
  59. attitude: y,
  60. room_type_id: C,
  61. syncToOthers: A,
  62. hasAvatar: S,
  63. avatarSize: h,
  64. prioritySync: P,
  65. extra: JSON.stringify(R)
  66. })
  67. };
  68. this.send(x),
  69. log$k.warn("startGame", le(oe({}, x), {
  70. data: JSON.parse(x.data)
  71. }))
  72. }
  73. );
  74. this.network = e,
  75. this.heartbeat = new Heartbeat({
  76. ping: t=>{
  77. var r;
  78. if (!this.connected) {
  79. this.heartbeat.stop(),
  80. (r = e.room.stats) == null || r.assign({
  81. rtt: 0
  82. });
  83. return
  84. }
  85. this.send({
  86. id: "heartbeat",
  87. data: t
  88. })
  89. }
  90. ,
  91. pong(t) {
  92. var r;
  93. (r = e.room.stats) == null || r.assign({
  94. rtt: t
  95. })
  96. }
  97. })
  98. }
  99. get connection() {
  100. return this._ws
  101. }
  102. start() {
  103. this._hasTimeout = !1;
  104. const e = this.getAddress();
  105. log$k.info(`connecting to ${e}`);
  106. const t = Date.now();
  107. this._ws = new WebSocket(e),
  108. this._openTimer = new Timeout(()=>{
  109. const r = `Failed to open websocket in ${DEFAULT_OPEN_TIMEOUT_MS} ms`;
  110. this._hasTimeout = !0,
  111. this.emit("socketClosed", new InitNetworkTimeoutError(r))
  112. }
  113. ,DEFAULT_OPEN_TIMEOUT_MS),
  114. this._ws.onopen = ()=>{
  115. var r;
  116. (r = this._openTimer) == null || r.clear(),
  117. this.connected = !0,
  118. this.heartbeat.start(),
  119. this.network.room.currentNetworkOptions.reconnect || (log$k.infoAndReportMeasurement({
  120. metric: "wsOpenedAt",
  121. group: "joinRoom",
  122. startTime: this.network.room._startTime
  123. }),
  124. log$k.infoAndReportMeasurement({
  125. metric: "wsOpenedCost",
  126. group: "joinRoom",
  127. startTime: t
  128. }))
  129. }
  130. ,
  131. this.handleWSEvent()
  132. }
  133. getAddress() {
  134. const {wsServerUrl: e, reconnect: t, sessionId: r, token: n, roomId: o, userId: a, pageSession: s} = this.network.room.currentNetworkOptions
  135. , l = this.network.room.skinId;
  136. let u = e;
  137. t && (u = u + `?reconnect=true&lastSessionID=${r}`);
  138. const c = `userId=${a}&roomId=${o}&pageSession=${s}` + (this.network.room.isHost ? `&skinId=${l}` : "") + (n ? `&token=${n}` : "");
  139. return u = u.indexOf("?") > -1 ? u + "&" + c : u + "?" + c,
  140. u
  141. }
  142. handleWSEvent() {
  143. const e = this._ws;
  144. e.addEventListener("error", t=>{
  145. this.connected = !1,
  146. log$k.error("webscoket error", t),
  147. this.emit("socketClosed", new InternalError("connect to address error: " + this.network.room.currentNetworkOptions.wsServerUrl))
  148. }
  149. ),
  150. e.addEventListener("close", t=>{
  151. this.connected = !1,
  152. this._onClose(t)
  153. }
  154. ),
  155. e.addEventListener("message", t=>{
  156. if (!t || this._hasTimeout || !this.connected)
  157. return;
  158. let r = null;
  159. try {
  160. r = JSON.parse(t.data)
  161. } catch (o) {
  162. log$k.error(o);
  163. return
  164. }
  165. if (!r)
  166. return;
  167. const n = r.id;
  168. if (!!n)
  169. switch (n !== "heartbeat" && log$k.info(`receive ws frame: ${t.data}`),
  170. n) {
  171. case "fail":
  172. break;
  173. case "init":
  174. try {
  175. const o = r.data.slice(-37, -1);
  176. reporter.updateBody({
  177. serverSession: o
  178. })
  179. } catch (o) {
  180. console.error(o)
  181. }
  182. this.network.rtcp.start();
  183. break;
  184. case "heartbeat":
  185. this.heartbeat.pong(r.data);
  186. break;
  187. case "offer":
  188. this.network.rtcp.setRemoteDescription(r.data, this.network.stream.el);
  189. break;
  190. case "ice_candidate":
  191. this.network.rtcp.addCandidate(r.data);
  192. break;
  193. case "start":
  194. this.emit("gameRoomAvailable", r);
  195. break;
  196. case "error":
  197. try {
  198. const {Code: o, Msg: a} = JSON.parse(r.data);
  199. if (o) {
  200. if (o == 3003)
  201. return this.emit("socketClosed", new TokenExpiredError);
  202. if (authenticationErrorCodes.indexOf(o) > -1)
  203. return this.emit("socketClosed", new AuthenticationError("\u9274\u6743\u9519\u8BEF:" + a));
  204. {
  205. const s = getErrorByCode(o);
  206. this.emit("socketClosed", new s(a))
  207. }
  208. }
  209. } catch (o) {
  210. log$k.error(o),
  211. this.emit("socketClosed", new InternalError(r.data))
  212. }
  213. break;
  214. case "checkLatency":
  215. {
  216. const o = r.packet_id
  217. , a = r.data.split(",");
  218. this.onLatencyCheck({
  219. packetId: o,
  220. addresses: a
  221. });
  222. break
  223. }
  224. default:
  225. log$k.warn("unkown ws message type", n, r)
  226. }
  227. }
  228. )
  229. }
  230. onLatencyCheck(e) {
  231. const t = [...new Set(e.addresses || [])];
  232. Promise.all(t.map(r=>({
  233. [r]: 9999
  234. }))).then(r=>{
  235. const n = Object.assign({}, ...r);
  236. this.latency(n, e.packetId)
  237. }
  238. )
  239. }
  240. wsNoReady() {
  241. return this._ws.readyState == WebSocket.CLOSED || this._ws.readyState == WebSocket.CLOSING || this._ws.readyState == WebSocket.CONNECTING
  242. }
  243. prepareReconnect() {
  244. this._close({
  245. code: WS_CLOSE_RECONNECT,
  246. reason: "reconnect"
  247. })
  248. }
  249. _onClose({code: e, reason: t}) {
  250. this._openTimer && this._openTimer.clear(),
  251. log$k.warn(`ws closed: ${e} ` + t),
  252. [WS_CLOSE_RECONNECT, WS_CLOSE_NORMAL].includes(e) || this.emit("socketClosed", new InternalError("Websocket error"))
  253. }
  254. _close({code: e, reason: t}) {
  255. var r;
  256. (r = this._ws) == null || r.close(e, t)
  257. }
  258. quit() {
  259. this._close({
  260. code: WS_CLOSE_NORMAL,
  261. reason: "quit"
  262. })
  263. }
  264. }
  265. }));
  266. E(this, "send", e=>{
  267. if (this.wsNoReady())
  268. return;
  269. const t = JSON.stringify(e);
  270. e.id !== "heartbeat" && log$k.info("send ws frame", t),
  271. this._ws.send(t)
  272. }
  273. );
  274. E(this, "startGame", ()=>{
  275. 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;
  276. R.removeWhenDisconnected = M;
  277. const x = {
  278. id: "start",
  279. room_id: e,
  280. user_id: t,
  281. trace_id: uuid$1(),
  282. data: JSON.stringify({
  283. avatar_components: JSON.stringify(a),
  284. avatar_id: r,
  285. skin_id: n,
  286. is_host: o ? o == "host" : !0,
  287. skin_data_version: n !== void 0 && s !== void 0 ? n + s : void 0,
  288. rotation_render_type: l,
  289. is_all_sync: u,
  290. nick_name: encodeURIComponent(c || ""),
  291. app_id: f,
  292. camera: d,
  293. player: _,
  294. person: T,
  295. firends: JSON.stringify(g),
  296. sync_by_event: m,
  297. area_name: v,
  298. path_name: b,
  299. attitude: y,
  300. room_type_id: C,
  301. syncToOthers: A,
  302. hasAvatar: S,
  303. avatarSize: h,
  304. prioritySync: P,
  305. extra: JSON.stringify(R)
  306. })
  307. };
  308. this.send(x),
  309. log$k.warn("startGame", le(oe({}, x), {
  310. data: JSON.parse(x.data)
  311. }))
  312. }
  313. );
  314. this.network = e,
  315. this.heartbeat = new Heartbeat({
  316. ping: t=>{
  317. var r;
  318. if (!this.connected) {
  319. this.heartbeat.stop(),
  320. (r = e.room.stats) == null || r.assign({
  321. rtt: 0
  322. });
  323. return
  324. }
  325. this.send({
  326. id: "heartbeat",
  327. data: t
  328. })
  329. }
  330. ,
  331. pong(t) {
  332. var r;
  333. (r = e.room.stats) == null || r.assign({
  334. rtt: t
  335. })
  336. }
  337. })
  338. }
  339. get connection() {
  340. return this._ws
  341. }
  342. start() {
  343. this._hasTimeout = !1;
  344. const e = this.getAddress();
  345. log$k.info(`connecting to ${e}`);
  346. const t = Date.now();
  347. this._ws = new WebSocket(e),
  348. this._openTimer = new Timeout(()=>{
  349. const r = `Failed to open websocket in ${DEFAULT_OPEN_TIMEOUT_MS} ms`;
  350. this._hasTimeout = !0,
  351. this.emit("socketClosed", new InitNetworkTimeoutError(r))
  352. }
  353. ,DEFAULT_OPEN_TIMEOUT_MS),
  354. this._ws.onopen = ()=>{
  355. var r;
  356. (r = this._openTimer) == null || r.clear(),
  357. this.connected = !0,
  358. this.heartbeat.start(),
  359. this.network.room.currentNetworkOptions.reconnect || (log$k.infoAndReportMeasurement({
  360. metric: "wsOpenedAt",
  361. group: "joinRoom",
  362. startTime: this.network.room._startTime
  363. }),
  364. log$k.infoAndReportMeasurement({
  365. metric: "wsOpenedCost",
  366. group: "joinRoom",
  367. startTime: t
  368. }))
  369. }
  370. ,
  371. this.handleWSEvent()
  372. }
  373. getAddress() {
  374. const {wsServerUrl: e, reconnect: t, sessionId: r, token: n, roomId: o, userId: a, pageSession: s} = this.network.room.currentNetworkOptions
  375. , l = this.network.room.skinId;
  376. let u = e;
  377. t && (u = u + `?reconnect=true&lastSessionID=${r}`);
  378. const c = `userId=${a}&roomId=${o}&pageSession=${s}` + (this.network.room.isHost ? `&skinId=${l}` : "") + (n ? `&token=${n}` : "");
  379. return u = u.indexOf("?") > -1 ? u + "&" + c : u + "?" + c,
  380. u
  381. }
  382. handleWSEvent() {
  383. const e = this._ws;
  384. e.addEventListener("error", t=>{
  385. this.connected = !1,
  386. log$k.error("webscoket error", t),
  387. this.emit("socketClosed", new InternalError("connect to address error: " + this.network.room.currentNetworkOptions.wsServerUrl))
  388. }
  389. ),
  390. e.addEventListener("close", t=>{
  391. this.connected = !1,
  392. this._onClose(t)
  393. }
  394. ),
  395. e.addEventListener("message", t=>{
  396. if (!t || this._hasTimeout || !this.connected)
  397. return;
  398. let r = null;
  399. try {
  400. r = JSON.parse(t.data)
  401. } catch (o) {
  402. log$k.error(o);
  403. return
  404. }
  405. if (!r)
  406. return;
  407. const n = r.id;
  408. if (!!n)
  409. switch (n !== "heartbeat" && log$k.info(`receive ws frame: ${t.data}`),
  410. n) {
  411. case "fail":
  412. break;
  413. case "init":
  414. try {
  415. const o = r.data.slice(-37, -1);
  416. reporter.updateBody({
  417. serverSession: o
  418. })
  419. } catch (o) {
  420. console.error(o)
  421. }
  422. this.network.rtcp.start();
  423. break;
  424. case "heartbeat":
  425. this.heartbeat.pong(r.data);
  426. break;
  427. case "offer":
  428. this.network.rtcp.setRemoteDescription(r.data, this.network.stream.el);
  429. break;
  430. case "ice_candidate":
  431. this.network.rtcp.addCandidate(r.data);
  432. break;
  433. case "start":
  434. this.emit("gameRoomAvailable", r);
  435. break;
  436. case "error":
  437. try {
  438. const {Code: o, Msg: a} = JSON.parse(r.data);
  439. if (o) {
  440. if (o == 3003)
  441. return this.emit("socketClosed", new TokenExpiredError);
  442. if (authenticationErrorCodes.indexOf(o) > -1)
  443. return this.emit("socketClosed", new AuthenticationError("\u9274\u6743\u9519\u8BEF:" + a));
  444. {
  445. const s = getErrorByCode(o);
  446. this.emit("socketClosed", new s(a))
  447. }
  448. }
  449. } catch (o) {
  450. log$k.error(o),
  451. this.emit("socketClosed", new InternalError(r.data))
  452. }
  453. break;
  454. case "checkLatency":
  455. {
  456. const o = r.packet_id
  457. , a = r.data.split(",");
  458. this.onLatencyCheck({
  459. packetId: o,
  460. addresses: a
  461. });
  462. break
  463. }
  464. default:
  465. log$k.warn("unkown ws message type", n, r)
  466. }
  467. }
  468. )
  469. }
  470. onLatencyCheck(e) {
  471. const t = [...new Set(e.addresses || [])];
  472. Promise.all(t.map(r=>({
  473. [r]: 9999
  474. }))).then(r=>{
  475. const n = Object.assign({}, ...r);
  476. this.latency(n, e.packetId)
  477. }
  478. )
  479. }
  480. wsNoReady() {
  481. return this._ws.readyState == WebSocket.CLOSED || this._ws.readyState == WebSocket.CLOSING || this._ws.readyState == WebSocket.CONNECTING
  482. }
  483. prepareReconnect() {
  484. this._close({
  485. code: WS_CLOSE_RECONNECT,
  486. reason: "reconnect"
  487. })
  488. }
  489. _onClose({code: e, reason: t}) {
  490. this._openTimer && this._openTimer.clear(),
  491. log$k.warn(`ws closed: ${e} ` + t),
  492. [WS_CLOSE_RECONNECT, WS_CLOSE_NORMAL].includes(e) || this.emit("socketClosed", new InternalError("Websocket error"))
  493. }
  494. _close({code: e, reason: t}) {
  495. var r;
  496. (r = this._ws) == null || r.close(e, t)
  497. }
  498. quit() {
  499. this._close({
  500. code: WS_CLOSE_NORMAL,
  501. reason: "quit"
  502. })
  503. }
  504. }