123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- const log$i = new Logger("NetworkController");
- class NetworkController extends EventEmitter {
- constructor(e) {
- super();
- E(this, "socket");
- E(this, "rtcp");
- E(this, "stream");
- E(this, "_state", "connecting");
- E(this, "_networkMonitor");
- E(this, "blockedActions", []);
- E(this, "reconnectCount", 0);
- E(this, "startGame", ()=>new Promise((e,t)=>{
- if (!this.rtcp.connected)
- return t(new InternalError("Game cannot load. Please refresh"));
- if (!this.rtcp.inputReady)
- return t(new InternalError("Game is not ready yet. Please wait"));
- this.socket.on("gameRoomAvailable", r=>{
- this.setState("connected"),
- e(r),
- this.rtcp.heartbeat.start()
- }
- ),
- this.socket.on("socketClosed", r=>{
- t(r)
- }
- ),
- this.socket.startGame()
- }
- ));
- this.room = e,
- this.socket = new Socket(this),
- this.rtcp = new Rtcp(this),
- this.stream = new Stream,
- this._networkMonitor = new NetworkMonitor(()=>{
- log$i.info("network changed, online:", this._networkMonitor.isOnline),
- this._state === "disconnected" && this._networkMonitor.isOnline && (log$i.info("network back to online, try to reconnect"),
- this.reconnect())
- }
- ),
- checkNetworkQuality(this.room.currentNetworkOptions.wsServerUrl),
- this._networkMonitor.start(),
- new VisibilityChangeHandler().subscribe(r=>{
- var n, o;
- r ? ((o = this.room.stats) == null || o.disable(),
- log$i.infoAndReportMeasurement({
- metric: "pageHide",
- startTime: Date.now()
- })) : ((n = this.room.stats) == null || n.enable(),
- log$i.infoAndReportMeasurement({
- metric: "pageShow",
- startTime: Date.now(),
- extra: {
- state: this._state
- }
- }),
- this._state === "disconnected" && this.reconnect())
- }
- )
- }
- addBlockedActions(e) {
- this.blockedActions.push(...e)
- }
- removeBlockedActions(e) {
- if (!e) {
- this.blockedActions = [];
- return
- }
- const t = this.blockedActions.indexOf(e);
- this.blockedActions.splice(t, 1)
- }
- setState(e) {
- this._state !== e && (log$i.info("Set network state to ", e),
- this._state = e)
- }
- async connectAndStart(e) {
- return this.connect(e).then(this.startGame)
- }
- async connect(e=!1) {
- return this.room.updateCurrentNetworkOptions({
- reconnect: e
- }),
- new Promise((t,r)=>{
- this.rtcp.on("rtcConnected", ()=>{
- this.setState("connected"),
- t()
- }
- ),
- this.rtcp.on("rtcDisconnected", ()=>{
- log$i.info("rtc disconnected"),
- this._state === "connecting" ? (this.setState("disconnected"),
- r(new InternalError("rtc connect failed"))) : (this.setState("disconnected"),
- log$i.info("rtc disconnected, start to reconnect"),
- this.reconnect())
- }
- ),
- this.socket.on("socketQuit", ()=>{
- log$i.info("socket quit success"),
- this.setState("closed")
- }
- ),
- this.socket.on("socketClosed", n=>{
- this._state === "connecting" && (this.setState("disconnected"),
- r(n)),
- r(n)
- }
- ),
- this.socket.start()
- }
- )
- }
- reconnect() {
- if (this.room.viewMode === "observer")
- return;
- const e = Date.now();
- if (this.reconnectCount++,
- this.reconnectCount > MAX_RECONNECT_COUNT) {
- log$i.error("reconnect failed, reached max reconnect count", MAX_RECONNECT_COUNT),
- this.reconnectCount = 0,
- this.emit("stateChanged", {
- state: "disconnected"
- });
- return
- }
- return log$i.info("start reconnect, count:", this.reconnectCount),
- this._reconnect().then(()=>{
- log$i.infoAndReportMeasurement({
- startTime: e,
- metric: "reconnect"
- })
- }
- ).catch(t=>{
- if (log$i.infoAndReportMeasurement({
- startTime: e,
- metric: "reconnect",
- error: t
- }),
- t.code === Codes$1.RepeatLogin) {
- this.room.handleRepetLogin();
- return
- }
- const r = 1e3;
- log$i.info("reconnect failed, wait " + r + " ms for next reconnect"),
- setTimeout(()=>{
- this.reconnect()
- }
- , r)
- }
- )
- }
- _reconnect() {
- return this._state === "closed" ? (log$i.warn("connection closed already"),
- Promise.reject()) : this._state === "connecting" ? (log$i.warn("connection is already in connecting state"),
- Promise.reject()) : this._state !== "disconnected" ? Promise.reject() : (this.prepareReconnect(),
- this._state = "connecting",
- this.emit("stateChanged", {
- state: "reconnecting",
- count: this.reconnectCount
- }),
- this.socket.off("gameRoomAvailable"),
- this.socket.off("socketClosed"),
- this.rtcp.off("rtcDisconnected"),
- this.rtcp.off("rtcConnected"),
- this.connectAndStart(!0).then(({session_id: e})=>{
- this.room.updateCurrentNetworkOptions({
- sessionId: e
- }),
- reporter.updateBody({
- serverSession: e
- }),
- log$i.info("reconnect success"),
- this.setState("connected"),
- this.reconnectCount = 0,
- this.emit("stateChanged", {
- state: "reconnected"
- })
- }
- ))
- }
- prepareReconnect() {
- this.rtcp.disconnect(),
- this.socket.prepareReconnect(),
- this.prepareReconnectOptions()
- }
- prepareReconnectOptions() {
- const {camera: e, player: t} = this.room.currentClickingState || {};
- e && t && this.room.updateCurrentNetworkOptions({
- camera: e,
- player: t
- })
- }
- sendRtcData(e) {
- if (this.blockedActions.includes(e.action_type)) {
- log$i.info(`action: ${Actions[e.action_type]} was blocked`);
- return
- }
- this.rtcp.sendData(e)
- }
- sendSocketData(e) {
- log$i.debug("ws send ->", e),
- this.socket.send(e)
- }
- quit() {
- const e = uuid$1()
- , t = {
- action_type: Actions.Exit,
- trace_id: e,
- exit_action: {},
- user_id: this.room.options.userId,
- packet_id: e
- };
- this.setState("closed"),
- this.socket.quit(),
- this.sendRtcData(t)
- }
- }
|