'use strict'
!(function(require, directRequire) {
  'use strict'
  function a(a) {
    switch (a.cmd) {
      case h.RequestCmd.Login:
        return h.ResponseType.Login
      case h.RequestCmd.EventNotifyBegin:
        return h.ResponseType.EventNotifyBegin
      case h.RequestCmd.EventNotifyBlock:
        return h.ResponseType.EventNotifyBlock
      case h.RequestCmd.EventNotifyEnd:
        return h.ResponseType.EventNotifyEnd
      case h.RequestCmd.Heartbeat:
        return h.ResponseType.Heartbeat
      case h.RequestCmd.JoinRoom:
        return h.ResponseType.JoinRoom
      case h.RequestCmd.MessageNotify:
        return h.ResponseType.MessageNotify
      case h.RequestCmd.MessageNotifyParallelly:
        return h.ResponseType.MessageNotifyParallelly
      case h.RequestCmd.QuitRoom:
        return h.ResponseType.QuitRoom
      case h.RequestCmd.SendDebugMessage:
        return h.ResponseType.SendDebugMessage
      case h.RequestCmd.SendDebugMessageParallelly:
        return h.ResponseType.SendDebugMessageParallelly
      case h.RequestCmd.SyncMessage:
        return h.ResponseType.SyncMessage
      default:
        return h.ResponseType.Unknown
    }
  }
  function b(a) {
    return 0 === a ? 100 : 1 === a ? 500 : 2 === a ? 1e3 : 3 === a ? 3e3 : 0
  }
  function c(c, a) {
    return c.seq - a.seq
  }
  var d = Math.max,
    e =
      (this && this.__decorate) ||
      function(a, b, e, f) {
        var g,
          d = arguments.length,
          c =
            3 > d
              ? b
              : null === f
                ? (f = Object.getOwnPropertyDescriptor(b, e))
                : f
        if ('object' == typeof Reflect && 'function' == typeof Reflect.decorate)
          c = Reflect.decorate(a, b, e, f)
        else
          for (var h = a.length - 1; 0 <= h; h--)
            (g = a[h]) &&
              (c = (3 > d ? g(c) : 3 < d ? g(b, e, c) : g(b, e)) || c)
        return 3 < d && c && Object.defineProperty(b, e, c), c
      }
  Object.defineProperty(exports, '__esModule', { value: !0 })
  const f = require('ws'),
    g = require('eventemitter3'),
    h = require('./a148d3a11fd5268109e21fb40c9d527b.js'),
    j = require('./46d7303eb986fa402d60bf5e929aa077.js'),
    i = require('./1c9e324c5ce9b5feb007c03bcb3f41dc.js'),
    k = require('./56a764ae9cb4336bf6babe1c1da0275b.js'),
    { getNewTicket: l } = require('./89ba85d67a88f7636d657c22b5d3e038.js'),
    m = k.default('[messager]'),
    n = j.logInvoke(m),
    o = j.logStack(m),
    p = 10
  exports.sorterForDebugMessage = c
  var q
  ;(function(a) {
    ;(a[(a.Dead = -1)] = 'Dead'),
      (a[(a.Unintialized = 0)] = 'Unintialized'),
      (a[(a.Disconnected = 1)] = 'Disconnected'),
      (a[(a.Logout = 2)] = 'Logout'),
      (a[(a.LoginHanged = 3)] = 'LoginHanged'),
      (a[(a.Waiting = 4)] = 'Waiting'),
      (a[(a.ServerBlocked = 5)] = 'ServerBlocked'),
      (a[(a.ActiveHanged = 6)] = 'ActiveHanged'),
      (a[(a.ActiveIdle = 7)] = 'ActiveIdle')
  })((q = exports.ConnectionStatus || (exports.ConnectionStatus = {})))
  class r extends g.EventEmitter {
    constructor(a) {
      super(),
        (this.status = q.Unintialized),
        (this.inSpeed = 0),
        (this.outSpeed = 0),
        (this.outDebugMessageSpeed = 0),
        (this.inDebugMessageSpeed = 0),
        (this.tempDir = ''),
        (this.autoLoopingTimeout = void 0),
        (this.inCount = 0),
        (this.outCount = 0),
        (this.outDebugMessageCount = 0),
        (this.inDebugMessageCount = 0),
        (this.inBytesCount = 0),
        (this.outBytesCount = 0),
        (this.ws = null),
        (this.loggedIn = !1),
        (this.debugMessagesCollectionTimeout = void 0),
        (this.needSendHeartbeat = !1),
        (this.receivedSeq = 0),
        (this.managedSeq = 0),
        (this.lastSendSeq = 0),
        (this.serverAck = 0),
        (this.managedDebugTimestamp = NaN),
        (this.lastDebugMessageSendTimestamp = Date.now()),
        (this.missedMessageCount = 0),
        (this.sendQueue = []),
        (this.receivedDebugMessages = []),
        (this.debugMessagesToSend = []),
        (this.cachedDebugMessageSendGroups = []),
        (this.lastSendTimestamp = 0),
        (this.lastSyncTimestamp = 0),
        (this.destroyed = !1),
        (this.roomInfo = null),
        (this.resolvers = {}),
        (this.retryCount = 0),
        (this.serverErrorRetryCount = 0),
        (this.serverErrorStamp = void 0),
        (this._restarting = !1),
        (this._retrying = !1),
        (this._askForRetryFn = () => Promise.resolve(!1)),
        (this.dataSendReports = []),
        (this.reportCounter = 0),
        (this.dataSendReportTimer = void 0),
        (this.compressionSavedBytes = 0),
        (this.tempDir = a.tempDir),
        (this.initialRoomInfo = a.initialRoomInfo)
    }
    init() {
      if (
        ((this._restarting = !1),
        (this.missedMessageCount = 0),
        this.status <= q.Dead)
      )
        return m.w('cannot init a dead instance'), !1
      ;(global.ms = this),
        this.setStatus(q.Disconnected),
        this.ws &&
          (this.ws.removeAllListeners(),
          j.tryCatch(() => this.ws.close()),
          (this.ws = null)),
        m.i('websocket instance generated')
      const a = (this.ws = new f(h.RemoteUrl))
      return (
        a.addEventListener('message', this.onWsMessage.bind(this)),
        a.addEventListener('close', this.onWsClose.bind(this)),
        a.addEventListener('error', this.onWsError.bind(this)),
        a.addEventListener('open', this.onWsOpen.bind(this)),
        !0
      )
    }
    getBaseRequestTemplate() {
      return { clientversion: j.clientVersion }
    }
    onWsMessage(b) {
      ;(this.missedMessageCount = 0), ++this.inCount
      let c
      if (!b)
        return (
          m.w('received empty message from ws', b),
          void m.f('<RECEIVED>  <EMPTY>  ' + b)
        )
      if (Buffer.isBuffer(b)) c = b
      else if ('string' == typeof b) c = Buffer.from(b)
      else if (Buffer.isBuffer(b.data)) c = b.data
      else if ('string' == typeof b.data) c = Buffer.from(b.data)
      else
        return (
          m.w('received invalid message from ws', b),
          void m.f('<RECEIVED>  <INVALID>  ' + b)
        )
      this.inBytesCount += c.byteLength || 0
      let d
      if (
        ((d = j.tryCatch(() => i.unwrapProtoToDataFormat(c))),
        j.invalidTryCatchResult(d))
      ) {
        m.e('received response data broken', d.error.stack, b),
          m.f('<RECEIVED>  <BROKEN>  ' + b)
        const a = { type: 'receivedbrokenmessage', message: d.error.message }
        return void this.emit('event', a)
      }
      ;(d && d.data) ||
        (m.w('received data with no inner data', d.data),
        m.f('<RECEIVED>  <EMPTY INNERDATA>  ' + d.data),
        (d.data = {}))
      const e = d.data,
        f = a(d)
      if (e.hasOwnProperty('base_response')) {
        const a = (e.base_response || {}).errcode
        if (a && a !== h.KnownErrorCode.OK)
          return (
            m.e('received error code', a, j.isDev ? j.jsonStringify(e) : e),
            j.isDev &&
              m.f('<RECEIVED>  <ERROR CODE>  ' + j.jsonStringify(d.data)),
            this.resolvers[f] &&
              (m.w('rejecting resolvers[', h.ResponseType[f], ']'),
              this.resolvers[f].reject(e),
              delete this.resolvers[f]),
            void this.onErrorCode(a, d.uuid || '')
          )
      }
      if (
        (m.f(
          '<RECEIVED>  ' + j.jsonStringify({ '(cmd)': f, '(uuid)': d.uuid })
        ),
        this.setStatusByResponse(f),
        this.resolvers[f] &&
          (this.resolvers[f].resolve(e), delete this.resolvers[f]),
        f === h.ResponseType.Login)
      )
        return void this.onReceiveLoginResponse(e)
      if (f === h.ResponseType.Heartbeat)
        return void this.onReceiveHeartbeatResponse()
      if (f === h.ResponseType.JoinRoom)
        return void this.onReceiveJoinRoomResponse(e)
      if (
        f === h.ResponseType.MessageNotify ||
        f === h.ResponseType.MessageNotifyParallelly
      )
        return (
          this.onReceiveDebugMessage(e),
          void (e.send_ack && this.onReceiveServerSendAck(e))
        )
      if (f === h.ResponseType.SendDebugMessageParallelly)
        return (
          this.onReceiveSendDebugMessageParallellyResponse(e),
          void (e.send_ack && this.onReceiveServerSendAck(e))
        )
      if (f === h.ResponseType.EventNotifyBegin)
        return void this.onReceiveBeginEvent()
      if (f === h.ResponseType.EventNotifyBlock)
        return void this.onReceiveBlockEvent()
      if (f === h.ResponseType.EventNotifyEnd)
        return void this.onReceiveEndEvent()
      if (f === h.ResponseType.QuitRoom)
        return void this.onReceiveQuitRoomResponse()
      if (f === h.ResponseType.SyncMessage)
        return (
          this.onReceiveDebugMessage(e),
          void (e.send_ack && this.onReceiveServerSendAck(e))
        )
      this.emit('event', { type: 'receivedinvalidmessage' }),
        m.w('received invalid cmd', d.cmd, 'type', f, h.ResponseType[f])
    }
    onReceiveDebugMessage(a) {
      if (
        ('array' !== j.typeOf(a.debug_message) && (a.debug_message = []),
        1 > a.debug_message.length)
      )
        return
      m.f(
        '(onReceiveDebugMessage) ' + a.debug_message.map(a => a.seq).join(',')
      ),
        (this.inDebugMessageCount += a.debug_message.length)
      const b = [...a.debug_message]
      if (
        (b.push(...this.receivedDebugMessages),
        (this.receivedDebugMessages = []),
        b.sort(c),
        this.receivedSeq + 1 < b[0].seq)
      )
        return (
          m.e(
            'received minimum seq',
            b[0].seq,
            'larger than received seq',
            this.receivedSeq
          ),
          this.receivedDebugMessages.push(...b),
          m.w('current received seqs', this.receivedDebugMessages),
          this.emit('accident'),
          void this.syncDebugMessages(b[0].seq)
        )
      const d = []
      let e = -1
      for (const c of b) {
        if ((++e, c.seq <= this.receivedSeq)) continue
        const a = d[d.length - 1]
        if (a) {
          if (a.seq === c.seq) continue
          if (a.seq + 1 !== c.seq) break
        } else if (this.receivedSeq + 1 !== c.seq) break
        d.push(c)
      }
      const f = b.slice(e + 1)
      if ((this.receivedDebugMessages.push(...f), 1 > d.length))
        return void m.i('nothing new to debug.')
      const g = d[d.length - 1].seq
      ;(this.receivedSeq = g),
        0 < f.length &&
          (m.w(
            'although some debug messages can be emited, there is still something missed for range [',
            this.receivedSeq + 1,
            ',',
            f[0].seq - 1,
            ']'
          ),
          this.syncDebugMessages(f[0].seq),
          this.emit('accident')),
        0 == this.receivedSeq % 20 && this.sendDidReceiveMessageImmediately()
      for (const b of d) this.emit('debugmessage', b)
    }
    sendDidReceiveMessageImmediately() {
      this.needSendHeartbeat = !0
    }
    syncDebugMessages(a = Infinity) {
      this.lastSyncTimestamp = Date.now()
      const b = {
        base_request: this.getBaseRequestTemplate(),
        min_seq: this.receivedSeq,
        serialized_uuid: `sync-${this.receivedSeq}`
      }
      isFinite(a) &&
        a > this.receivedSeq &&
        ((b.max_seq = a),
        (b.serialized_uuid = `sync-${this.receivedSeq}-${a}`)),
        this.send(b, h.RequestType.SyncMessage)
    }
    sendDebugMessage(a, b, c, e) {
      const f = (c && c.len) || 0,
        g = {
          seq: ++this.managedSeq,
          delay: 0,
          category: b,
          data: a,
          _len: f,
          compress_algo: e
        }
      if (b !== h.DebugMessageCategory.Ping) {
        const a = c && 'number' == typeof c.timestamp ? c.timestamp : Date.now()
        ;(g.delay = isNaN(this.managedDebugTimestamp)
          ? 0
          : d(0, a - this.managedDebugTimestamp)),
          (this.managedDebugTimestamp = d(this.managedDebugTimestamp, a))
      }
      this.debugMessagesToSend.push(g), this.startCollectDebugMessages()
    }
    startCollectDebugMessages(a = 17) {
      if (!this.debugMessagesCollectionTimeout) {
        const b = Date.now() - this.lastDebugMessageSendTimestamp
        17 > b && (a = 34),
          (this.debugMessagesCollectionTimeout = setTimeout(() => {
            this.sendDebugMessagesImmediately()
          }, d(0, a - b)))
      }
    }
    packTestSendGroup() {
      const a = this.debugMessagesToSend.slice(0, 10)
      if (1 > a.length) return void m.i('no debug message to pack')
      const b = {
        base_request: this.getBaseRequestTemplate(),
        debug_message: a,
        recv_ack: this.receivedSeq,
        serialized_uuid: `dm-${a[0].seq}-${
          a[a.length - 1].seq
        }-(test)-${Date.now()}`
      }
      let c = 0
      for (const b of a) c += b._len || 0
      const d = {
        lastSentTimestamp: Date.now(),
        sendDebugMessageRequest: b,
        confirmed: !1,
        dataSize: c
      }
      return d
    }
    sendDebugMessagesImmediately() {
      if (
        (clearTimeout(this.debugMessagesCollectionTimeout),
        (this.debugMessagesCollectionTimeout = void 0),
        this.status < q.ActiveIdle)
      )
        return void m.w('status', this.status, 'not ready sending new messages')
      const a = this.debugMessagesToSend
      if (((this.debugMessagesToSend = []), 1 > a.length))
        return void m.i('nothing new to send')
      let b = 0,
        c = 0
      const d = [0],
        e = []
      let f = 0
      for (const g = a.length; f < g; f++)
        (b += a[f]._len || 0),
          (c += a[f]._len || 0),
          64000 < b &&
            (m.w('reached size limit 64K, lens =', b, '@', f),
            d.push(f + 1),
            e.push(b),
            (b = 0))
      ;(2 > d.length || d[d.length - 1] < a.length) &&
        (d.push(a.length), e.push(b))
      const g = Date.now()
      for (let b = 1, f = d.length; b < f; b++) {
        const f = a.slice(d[b - 1], d[b])
        if (1 > f.length) continue
        const i = {
            base_request: this.getBaseRequestTemplate(),
            debug_message: f,
            recv_ack: this.receivedSeq,
            serialized_uuid: `dm-${f[0].seq}-${
              f[f.length - 1].seq
            }-${b}/${d.length - 1}-(${e[b - 1]})-${g}`
          },
          j = {
            lastSentTimestamp: g,
            sendDebugMessageRequest: i,
            confirmed: !1,
            dataSize: c
          }
        this.cachedDebugMessageSendGroups.push(j),
          this.send(i, h.RequestType.SendDebugMessageParallelly)
      }
      this.lastDebugMessageSendTimestamp = g
    }
    checkCachedSendGroups(a = !1) {
      const b = this.cachedDebugMessageSendGroups,
        c = [],
        d = [],
        e = Date.now()
      for (const f of b)
        f.confirmed ||
          (c.push(f), (2e4 <= e - f.lastSentTimestamp || a) && d.push(f))
      if (((this.cachedDebugMessageSendGroups = c), 0 < d.length)) {
        if (
          (m.w(
            'some messages missed, shall resending',
            d.length,
            'send groups'
          ),
          !a && this.status < q.ActiveIdle)
        )
          return void m.w('not ready resending messages')
        m.f(
          '(checkCachedSendGroups) forceResend=' +
            (a + ' >> resends seqs :: ') +
            d
              .map(a => {
                return a.sendDebugMessageRequest.debug_message
                  .map(a => a.seq)
                  .join(', ')
              })
              .join(', ')
        )
        for (const b of d)
          (b.lastSentTimestamp = e),
            this.send(
              b.sendDebugMessageRequest,
              h.RequestType.SendDebugMessageParallelly,
              a
            )
      }
      this.startCollectDebugMessages()
    }
    testSendDebugMessage() {
      let a
      for (const b of this.cachedDebugMessageSendGroups)
        if (!b.confirmed) {
          a = b
          break
        }
      a || (a = this.packTestSendGroup()),
        a
          ? ((a.lastSentTimestamp = Date.now()),
            this.send(
              a.sendDebugMessageRequest,
              h.RequestType.SendDebugMessageParallelly,
              !0
            ))
          : m.w('no test debug message to send')
    }
    onReceiveServerSendAck(a) {
      let b = a.send_ack
      if ('number' !== j.typeOf(b) && ((b = parseInt(b + '', 10)), isNaN(b))) {
        const c = {
          type: 'receivedinvalidmessage',
          message: 'invalid send_ack ' + a.send_ack
        }
        return (
          this.emit('event', c),
          void m.e('received invalid type of send_ack', b)
        )
      }
      if (
        (j
          .expect(b, m)
          .as(a => {
            return a >= this.serverAck && a <= this.lastSendSeq
          })
          .fail(() => {
            const a = {
              type: 'servererror',
              message: 'send_ack invalid ' + b,
              kind: 'error'
            }
            this.emit('event', a)
          }),
        b <= this.serverAck || b > this.lastSendSeq)
      )
        return
      m.f('(onReceiveServerSendAck)  ' + b),
        (this.serverAck = d(b, this.serverAck))
      let c = 0
      for (const b of this.cachedDebugMessageSendGroups) {
        if (b.confirmed) continue
        const a = b.sendDebugMessageRequest.debug_message
        a[a.length - 1].seq <= this.serverAck ? (b.confirmed = !0) : (c += 1)
      }
      this.status === q.ActiveHanged &&
        c < p &&
        (m.i('server confirms some messages, switch back to active idle'),
        this.setStatus(q.ActiveIdle),
        this.checkCachedSendGroups())
    }
    onReceiveSendDebugMessageParallellyResponse(a) {
      const b = parseInt(a.max_ack, 10),
        c = parseInt(a.min_ack, 10)
      if (isNaN(b) || isNaN(c)) {
        m.w('invalid acks', a.min_ack, a.max_ack)
        const b = {
          type: 'receivedinvalidmessage',
          message: 'received invalid acks ' + a.min_ack + ', ' + a.max_ack
        }
        return void this.emit('event', b)
      }
      m.f('(onReceiveSendDebugMessageParallellyResponse) ' + c + ', ' + b)
      let d = 0,
        e = !1
      for (const f of this.cachedDebugMessageSendGroups) {
        if (f.confirmed) continue
        const a = f.sendDebugMessageRequest.debug_message
        if (a[0].seq === c) {
          j
            .expect(a[a.length - 1].seq, m)
            .toBe(b)
            .fail(() => {
              m.e('ack range invalid')
              this.emit('event', {
                type: 'receivedinvalidmessage',
                message: 'received invalid ack ranges ' + c + ', ' + b
              })
            }),
            (f.confirmed = !0)
          const d = {
            cost_time: Date.now() - f.lastSentTimestamp,
            data_size: f.dataSize,
            message_count: f.sendDebugMessageRequest.debug_message.length
          }
          this.dataSendReports.push(d), (e = !0)
          break
        } else d += 1
      }
      if (
        (e || m.w_('min and max ack not found', c, b),
        this.status === q.ActiveHanged && d < p)
      )
        m.i('server confirms some messages, switch back to active idle'),
          this.setStatus(q.ActiveIdle),
          this.checkCachedSendGroups()
      else if (this.status === q.ServerBlocked) {
        m.i(
          'received regular response for debug message, switch back to active idle'
        ),
          this.setStatus(q.ActiveIdle),
          this.checkCachedSendGroups()
        this.emit('event', { type: 'serverblock', blocked: !1, kind: 'event' })
      }
    }
    reportDataSend() {
      const a = this.dataSendReports
      this.emit('datasendreport', a), (this.dataSendReports = [])
    }
    setStatus(a) {
      if (this.status !== a) {
        const b = this.status
        ;(this.status = a), this.emit('statuschange', a, b)
      }
    }
    processSendQueue() {
      if (!(1 > this.sendQueue.length)) {
        const a = [...this.sendQueue]
        this.sendQueue = []
        for (const b of a)
          b.type !== h.RequestType.Unknown &&
            (m.i('process send queue item', b), this.send(b.msg, b.type))
      }
    }
    onErrorCode(a, b) {
      let c = !0
      if (
        (h.KnownErrorCode.hasOwnProperty(a)
          ? (c = this.onKnownErrorCode(a, b))
          : m.e('unknown error', a),
        c)
      ) {
        const c = {
          type: 'receivederrorcode',
          errorCode: a,
          errorMessage: h.KnownErrorCode[a],
          message: 'received error code ' + a + ' on ' + b,
          kind: 'error'
        }
        this.emit('event', c)
      }
    }
    onKnownErrorCode(a, b) {
      let c = !0
      switch (a) {
        case h.KnownErrorCode.OK:
          break
        case h.KnownErrorCode.SYSTEM_BUSY: {
          if (
            (m.e('system busy'),
            this.serverErrorStamp &&
              (b || '').startsWith(this.serverErrorStamp))
          )
            this.serverErrorRetryCount += 1
          else {
            const a = (b || '').match(/^dm-\d+-/i)
            a && a[0] && (this.serverErrorStamp = a[0]),
              (this.serverErrorRetryCount = 0)
          }
          if (3 < this.serverErrorRetryCount) {
            this.emit('event', {
              type: 'servererror',
              message: 'Server Busy',
              kind: 'error'
            }),
              this.destroy()
          } else this.checkCachedSendGroups(!0), this.syncDebugMessages()
          break
        }
        case h.KnownErrorCode.ERR_SYS:
        case h.KnownErrorCode.NOT_EXIST:
        case h.KnownErrorCode.INVALID_ARGS: {
          m.e('internal error', a)
          break
        }
        case h.KnownErrorCode.INVALID_LOGIN_TICKET: {
          m.w('login error'), this.destroy()
          break
        }
        case h.KnownErrorCode.HAS_NO_PERMISSION: {
          m.w('no permission error'), this.destroy()
          break
        }
        case h.KnownErrorCode.ROOM_IN_DEBUGGING: {
          m.w('room already in debugging status'), this.destroy()
          break
        }
        case h.KnownErrorCode.NO_EXIST_ROOM: {
          m.w('could not find room'), this.destroy()
          break
        }
        case h.KnownErrorCode.MD5_NOT_MATCH: {
          m.w('md5 not matching')
          break
        }
        case h.KnownErrorCode.USER_IN_DEBUGGING: {
          m.w('user already in debugging status'), this.destroy()
          break
        }
        case h.KnownErrorCode.SEQ_ERROR: {
          m.w('send seq error')
          break
        }
        case h.KnownErrorCode.SEND_MSG_BUSY: {
          m.w('send msg busy error'), this.onServerSendMessageBusy(), (c = !1)
          break
        }
        case h.KnownErrorCode.SEND_MSG_SEQ_RANGE_ERROR: {
          m.w('send seq range error')
          break
        }
        default: {
          j.expectFail.fail(() => {
            j.assertNever(a), m.e('known error code', a)
          })
          break
        }
      }
      return c
    }
    onServerSendMessageBusy() {
      if (this.status > q.ServerBlocked) {
        this.setStatus(q.ServerBlocked)
        this.emit('event', {
          type: 'serverblock',
          blocked: !0,
          message: 'send message busy',
          kind: 'warn'
        })
      } else m.w('no need to change status to ServerBlocked')
    }
    onWsClose() {
      return this._restarting || this._retrying
        ? void m.i('websocket close while restarting or retrying.')
        : void (this.status >= q.Disconnected
            ? (this.setStatus(q.Disconnected),
              m.e('websocket close'),
              m.f('<CLOSE>'),
              this.retryIfNeeded())
            : m.w(
                'received close event while status',
                this.status,
                '< Disconnected.'
              ))
    }
    onAskForRetry(a) {
      this._askForRetryFn = a
    }
    async retryIfNeeded() {
      if (
        ((this._restarting || this._retrying) && m.i('no need to retry'),
        (this._retrying = !0),
        this.retryCount >= 3)
      )
        if ('function' === j.typeOf(this._askForRetryFn)) {
          let a = !1
          try {
            ;(a = await this._askForRetryFn(this.retryCount + 1)), (a = !!a)
          } catch (b) {
            m.e('calling askForRetryFn with error', b), (a = !1)
          }
          if (!a) return m.i('askForRetryFn: no'), void this.destroy()
          m.i('askForRetryFn: yes')
        } else return void m.w('askForRetryFn broken')
      ++this.retryCount
      const a = b(this.retryCount)
      await j.delayPromise(a), (this._retrying = !1), this.restart()
    }
    onWsError(a) {
      this.setStatus(q.Disconnected)
      const b = a && a.stack ? a.stack : a
      m.e('websocket error', b), m.f('<ERROR>  ' + b)
      const c = {
        type: 'sessionerror',
        kind: 'error',
        message: 'websocket error ' + a.message || a
      }
      this.emit('event', c), this.retryIfNeeded()
    }
    onWsOpen() {
      ;(this.retryCount = 0), this.enableAutoLoop(), this.login()
    }
    enableAutoLoop() {
      this.autoLoopingTimeout &&
        (m.i('already auto looping'), clearTimeout(this.autoLoopingTimeout))
      let a = 0,
        b = 0
      const c = this.speedCalcFn(),
        d = () => {
          const e = Date.now()
          c.call(this),
            (this.needSendHeartbeat || 15000 <= e - this.lastSendTimestamp) &&
              this.sendHeartbeat(),
            this.status > q.Waiting &&
              15000 < e - this.lastSyncTimestamp &&
              this.syncDebugMessages(),
            1e4 < e - a && ((a = e), this.checkCachedSendGroups()),
            3e4 < e - b && ((b = e), this.reportDataSend()),
            this.status === q.ServerBlocked && this.testSendDebugMessage(),
            (this.autoLoopingTimeout = setTimeout(d, 2e3))
        }
      this.autoLoopingTimeout = setTimeout(d, 0)
    }
    speedCalcFn() {
      const a = (() => {
        let a = this.inCount,
          b = this.outCount,
          c = this.outDebugMessageCount,
          d = this.inDebugMessageCount,
          e = this.inBytesCount,
          f = this.outBytesCount,
          g = Date.now()
        return () => {
          var h = Math.round
          if (
            this.inCount !== a ||
            this.outCount !== b ||
            this.outDebugMessageCount !== c ||
            this.inDebugMessageCount !== d ||
            this.inBytesCount !== e ||
            this.outBytesCount !== f
          ) {
            const j = Date.now()
            ;(this.compressionSavedBytes = i.model.getCompressionSavedBytes()),
              (this.inSpeed = h(1e3 * ((this.inCount - a) / (j - g)))),
              (this.outSpeed = h(1e3 * ((this.outCount - b) / (j - g)))),
              (this.outDebugMessageSpeed = h(
                1e3 * ((this.outDebugMessageCount - c) / (j - g))
              )),
              (this.inDebugMessageSpeed = h(
                1e3 * ((this.inDebugMessageCount - d) / (j - g))
              )),
              (a = this.inCount),
              (b = this.outCount),
              (c = this.outDebugMessageCount),
              (d = this.inDebugMessageCount),
              (e = this.inBytesCount),
              (f = this.outBytesCount),
              (g = j),
              this.emit('statuschange', this.status, void 0)
          }
        }
      })()
      return a
    }
    async restart(a = !1) {
      return this._restarting
        ? void m.i('already restarting')
        : void ((this._restarting = !0),
          a &&
            ((this.cachedDebugMessageSendGroups = []),
            (this.sendQueue = []),
            (this.missedMessageCount = 0),
            (this.serverErrorRetryCount = 0),
            (this.serverErrorStamp = void 0),
            (this.receivedSeq = 0),
            (this.managedSeq = 0),
            (this.lastSendSeq = 0),
            (this.serverAck = 0),
            this.debugMessagesCollectionTimeout &&
              (clearTimeout(this.debugMessagesCollectionTimeout),
              (this.debugMessagesCollectionTimeout = void 0)),
            (this.receivedDebugMessages = [])),
          this.status > q.Logout &&
            (await (() =>
              new Promise(a => {
                ;(this.resolvers[h.ResponseType.QuitRoom] = {
                  resolve: a,
                  reject: a
                }),
                  this.quit(),
                  setTimeout(a, 5e3)
              }))()),
          this.init())
    }
    sendHeartbeat() {
      this.needSendHeartbeat = !1
      const a = {
        base_request: this.getBaseRequestTemplate(),
        recv_ack: this.receivedSeq,
        serialized_uuid: `hb-${Date.now()}`
      }
      this.send(a, h.RequestType.Heartbeat)
    }
    onTimeout() {
      if ((m.e('on timeout detected'), this.status > q.Disconnected)) {
        this.setStatus(q.Disconnected)
        this.emit('event', {
          type: 'sessionerror',
          kind: 'warn',
          message: 'websocket timeout'
        }),
          this.retryIfNeeded()
      } else m.w('ontimeout while status <= disconnected')
    }
    async login() {
      this.setStatus(q.Logout)
      let a
      try {
        a = await l()
      } catch (a) {
        m.e('get ticket error', a)
        const b = {
          type: 'sessionerror',
          kind: 'error',
          message: 'login get ticket error ' + (a && a.message ? a.message : a)
        }
        return this.emit('event', b), void this.retryIfNeeded()
      }
      const b = {
        newticket: a,
        base_request: this.getBaseRequestTemplate(),
        serialized_uuid: `login-${a}`
      }
      this.send(b, h.RequestType.Login) || m.w('sending login request refused')
    }
    onReceiveHeartbeatResponse() {}
    onReceiveJoinRoomResponse() {}
    onReceiveQuitRoomResponse() {}
    onReceiveLoginResponse(a) {
      const b = a.room_info
      if (!b || !b.join_room)
        return (
          m.i('not yet in a room. join one.'),
          (this.roomInfo = { room_id: this.initialRoomInfo.room_id }),
          void this.requestJoinRoom()
        )
      if (!this.roomInfo || this.roomInfo.room_id !== b.room_id) {
        m.w('losing context, restart')
        this.emit('event', { type: 'losingcontext' }), this.restart(!0)
      } else {
        m.w('recover from current context'),
          this.setStatus(q.ActiveIdle),
          this.syncDebugMessages(),
          this.processSendQueue()
        this.emit('event', { type: 'recoverfromcurrentcontext', kind: 'event' })
      }
    }
    requestJoinRoom() {
      const a = {
        base_request: this.getBaseRequestTemplate(),
        room_id: this.initialRoomInfo.room_id,
        wxpkg_info: this.initialRoomInfo.wxpkg_info,
        username: this.initialRoomInfo.username,
        appid: this.initialRoomInfo.appid,
        serialized_uuid: `join-${this.initialRoomInfo.room_id}`
      }
      this.send(a, h.RequestType.JoinRoom)
    }
    onReceiveBeginEvent() {}
    onReceiveBlockEvent() {
      this.emit('event', {
        type: 'serverblock',
        blocked: !0,
        message: 'received server block',
        kind: 'warn'
      }),
        this.onServerSendMessageBusy()
    }
    onReceiveEndEvent() {
      if (this._restarting || this._retrying)
        return void m.i('retrying or restarting, no need to suicide.')
      this.quit()
      this.emit('event', { type: 'end', kind: 'event' }), this.destroy()
    }
    shouldSend(a) {
      const b = this.status
      return a === h.RequestType.EventNotifyBlock ||
        a === h.RequestType.EventNotifyEnd ||
        a === h.RequestType.EventNotifyBegin ||
        a === h.RequestType.QuitRoom ||
        a === h.RequestType.Heartbeat ||
        a === h.RequestType.Login
        ? b >= q.Logout
        : a === h.RequestType.JoinRoom
          ? b >= q.LoginHanged
          : a === h.RequestType.SyncMessage ||
            a === h.RequestType.MessageNotifyParallelly ||
            a === h.RequestType.MessageNotify
            ? b >= q.ServerBlocked
            : a === h.RequestType.Unknown ||
              a === h.RequestType.SendDebugMessageParallelly ||
              a === h.RequestType.SendDebugMessage
              ? b >= q.ActiveIdle
              : (j.assertNever(a), !1)
    }
    pushToSendQueue(a, b) {
      switch (b) {
        case h.RequestType.SyncMessage: {
          const c = this.sendQueue.findIndex(a => a.type === b)
          if (0 > c) this.sendQueue.push({ msg: a, type: b })
          else {
            const b = this.sendQueue[c].msg
            b.min_seq = Math.min(a.min_seq, b.min_seq)
            const e = a.max_seq,
              f = b.max_seq
            e && f ? (b.max_seq = d(e, f)) : delete b.max_seq
          }
          break
        }
        case h.RequestType.SendDebugMessageParallelly:
          break
        case h.RequestType.SendDebugMessage: {
          this.sendQueue
          let c = !1
          for (const d of this.sendQueue)
            if (d.type === b) {
              j
                .expect(d.msg, m)
                .as(b => {
                  return (
                    1 > b.debug_message.length ||
                    1 > a.debug_message.length ||
                    b.debug_message[0].seq >= a.debug_message[0].seq
                  )
                })
                .fail(() => {
                  this.emit('event', {
                    type: 'sendinginvalidmessage',
                    message:
                      'trying to send debug messages seq larger than send queue'
                  })
                }),
                (d.msg = a),
                (c = !0)
              break
            }
          c || this.sendQueue.push({ msg: a, type: b })
          break
        }
        case h.RequestType.QuitRoom:
        case h.RequestType.Login:
        case h.RequestType.Heartbeat: {
          const c = this.sendQueue.findIndex(a => a.type === b)
          if (0 > c) this.sendQueue.push({ msg: a, type: b })
          else {
            const b = this.sendQueue[c].msg
            b.recv_ack = d(b.recv_ack, a.recv_ack)
          }
          break
        }
        case h.RequestType.JoinRoom: {
          0 > this.sendQueue.findIndex(a => a.type === b) &&
            this.sendQueue.push({ msg: a, type: b })
          break
        }
        default: {
          this.sendQueue.push({ msg: a, type: b })
          break
        }
      }
    }
    setStatusByRequest(a) {
      let b = !1
      switch (a) {
        case h.RequestType.QuitRoom: {
          this.status > q.Logout
            ? this.setStatus(q.Logout)
            : m.w('request quit room while status <= logout'),
            (b = !0)
          break
        }
        case h.RequestType.Login: {
          this.status < q.LoginHanged
            ? this.setStatus(q.LoginHanged)
            : m.w('request login while status >= loginhanged'),
            (b = !0)
          break
        }
        case h.RequestType.JoinRoom: {
          this.status < q.Waiting
            ? this.setStatus(q.Waiting)
            : m.w('request join room while status >= Waiting'),
            (b = !0)
          break
        }
        case h.RequestType.SendDebugMessage: {
          this.status > q.ActiveHanged
            ? this.setStatus(q.ActiveHanged)
            : m.w('request send debug message while status <= activehanged'),
            (b = !0)
          break
        }
        case h.RequestType.SendDebugMessageParallelly:
          break
        default: {
          b = !0
          break
        }
      }
      b && this.processSendQueue()
    }
    setStatusByResponse(a) {
      let b = !1
      switch (a) {
        case h.ResponseType.Login: {
          this.status < q.LoginHanged
            ? m.w('received login response with no login request')
            : this.status >= q.Waiting
              ? m.w('received login response while waiting')
              : this.setStatus(q.LoginHanged),
            (b = !0)
          break
        }
        case h.ResponseType.EventNotifyBegin: {
          this.status < q.Waiting
            ? m.w('received begin event while not waiting', this.status)
            : this.setStatus(q.ActiveIdle),
            (b = !0)
          break
        }
        case h.ResponseType.EventNotifyEnd: {
          this.status < q.Logout
            ? m.w('received end event while not yet login')
            : this.setStatus(q.Logout),
            (b = !0)
          break
        }
        case h.ResponseType.EventNotifyBlock: {
          this.status < q.Waiting
            ? m.w('received block event while waiting')
            : this.setStatus(q.ServerBlocked),
            (b = !0)
          break
        }
        case h.ResponseType.SendDebugMessageParallelly: {
          this.status < q.ServerBlocked
            ? m.w('received send debug message response while not joint room')
            : this.status === q.ActiveHanged &&
              m.w('response cannot change the status of active hanged'),
            (b = !0)
          break
        }
        case h.ResponseType.SyncMessage: {
          this.status < q.ActiveHanged
            ? m.i('received sync message response while server blocked')
            : this.setStatus(q.ActiveIdle),
            (b = !0)
          break
        }
        default: {
          b = !0
          break
        }
      }
      b && this.processSendQueue()
    }
    quit() {
      if (this.status <= q.Logout) return void m.w('no need to quit')
      1 < this.sendQueue.length && m.w('quiting with non-empty send queue'),
        this.autoLoopingTimeout &&
          (clearTimeout(this.autoLoopingTimeout),
          (this.autoLoopingTimeout = void 0))
      const a = {
        base_request: this.getBaseRequestTemplate(),
        serialized_uuid: `quit-${Date.now()}`
      }
      this.send(a, h.RequestType.QuitRoom, !0) || m.w('quit room failed')
    }
    send(a, b, c = !1) {
      if (!c && !this.shouldSend(b)) {
        if (
          (m.i(
            'sending message of type',
            b,
            'has been delayed, status = ',
            this.status
          ),
          this.pushToSendQueue(a, b),
          200 < this.sendQueue.length)
        ) {
          this.emit('event', { type: 'queuetoomanyrequest', kind: 'error' })
        }
        return !1
      }
      const e = a.serialized_uuid ? a.serialized_uuid : j.randomId(),
        f = j.tryCatch(() => i.wrapOutgoingToProto(a, b, e))
      if (j.invalidTryCatchResult(f)) {
        m.e('trying to send a broken structure', f.error.stack, a)
        const b = {
          type: 'sendingbrokenmessage',
          kind: 'error',
          message: f.error.message
        }
        return this.emit('event', b), !1
      }
      if (!this.sendImmediately(f, b)) return this.pushToSendQueue(a, b), !1
      if (
        (m.f('<SEND>  ' + j.jsonStringify({ '(cmd)': b, '(uuid)': e })),
        b === h.RequestType.SendDebugMessageParallelly)
      ) {
        j
          .expect(a, m)
          .as(a => {
            const b = a.debug_message
            return !(1 > b.length)
          })
          .fail(() => {
            this.emit('event', {
              type: 'assertion',
              message: 'just sent an empty debug message',
              kind: 'error'
            })
          }),
          j
            .expect(a, m)
            .as(a => {
              const b = a.debug_message
              if (!b[0]) return !0
              let c = b[0].seq - 1
              for (const d of b) {
                if (c + 1 !== d.seq) return !1
                ++c
              }
              return !0
            })
            .fail(() => {
              const b = {
                type: 'sendinginvalidmessage',
                message: 'sending seq not well ordered ' + a.serialized_uuid
              }
              this.emit('event', b)
            })
        const b = a.debug_message || []
        0 < b.length &&
          ((this.lastSendSeq = d(this.lastSendSeq, b[b.length - 1].seq)),
          (this.outDebugMessageCount += b.length))
      }
      return !0
    }
    sendImmediately(a, b) {
      if (this.ws) {
        if (this.missedMessageCount >= 2)
          return m.e('heart beat timeout'), this.onTimeout(), !1
        this.setMissedMessageCountByRequest(b)
        const c = i.uint8ArrayToBuffer(a)
        return (
          this.ws.send(c, { binary: !0 }),
          ++this.outCount,
          (this.outBytesCount += c.byteLength || 0),
          (this.lastSendTimestamp = Date.now()),
          this.setStatusByRequest(b),
          !0
        )
      }
      return m.e('ws is not initialized sending message'), !1
    }
    setMissedMessageCountByRequest(a) {
      a !== h.RequestType.SyncMessage &&
        a !== h.RequestType.SendDebugMessageParallelly &&
        a !== h.RequestType.QuitRoom &&
        ++this.missedMessageCount
    }
    destroy() {
      return this.destroyed
        ? void m.w('messager has already been destroyed')
        : void ((this.destroyed = !0),
          this.ws &&
            (this.quit(),
            this.ws.removeAllListeners(),
            j.tryCatch(() => this.ws.close())),
          (this.ws = null),
          this.setStatus(q.Dead),
          this.autoLoopingTimeout && clearTimeout(this.autoLoopingTimeout),
          this.debugMessagesCollectionTimeout &&
            clearTimeout(this.debugMessagesCollectionTimeout),
          (this.autoLoopingTimeout = void 0),
          (this.sendQueue = []),
          (this.receivedDebugMessages = []),
          (this.debugMessagesToSend = []),
          (this.debugMessagesCollectionTimeout = void 0),
          i.model.resetStatistics(),
          this.emit('destroy'))
    }
  }
  e([n], r.prototype, 'onWsMessage', null),
    e([n], r.prototype, 'onReceiveDebugMessage', null),
    e([n], r.prototype, 'packTestSendGroup', null),
    e([n], r.prototype, 'sendDebugMessagesImmediately', null),
    e([n], r.prototype, 'checkCachedSendGroups', null),
    e([n], r.prototype, 'testSendDebugMessage', null),
    e([n], r.prototype, 'onReceiveServerSendAck', null),
    e([n], r.prototype, 'onReceiveSendDebugMessageParallellyResponse', null),
    e([n], r.prototype, 'setStatus', null),
    e([n], r.prototype, 'onErrorCode', null),
    e([n], r.prototype, 'onKnownErrorCode', null),
    e([n], r.prototype, 'onServerSendMessageBusy', null),
    e([n], r.prototype, 'onWsClose', null),
    e([o], r.prototype, 'retryIfNeeded', null),
    e([n], r.prototype, 'onWsError', null),
    e([n], r.prototype, 'onWsOpen', null),
    e([n], r.prototype, 'enableAutoLoop', null),
    e([o], r.prototype, 'restart', null),
    e([o], r.prototype, 'onTimeout', null),
    e([n], r.prototype, 'login', null),
    e([n], r.prototype, 'onReceiveHeartbeatResponse', null),
    e([n], r.prototype, 'onReceiveJoinRoomResponse', null),
    e([n], r.prototype, 'onReceiveQuitRoomResponse', null),
    e([n], r.prototype, 'onReceiveLoginResponse', null),
    e([n], r.prototype, 'requestJoinRoom', null),
    e([n], r.prototype, 'onReceiveBeginEvent', null),
    e([n], r.prototype, 'onReceiveBlockEvent', null),
    e([n], r.prototype, 'onReceiveEndEvent', null),
    e([n], r.prototype, 'setStatusByRequest', null),
    e([n], r.prototype, 'quit', null),
    e([n], r.prototype, 'sendImmediately', null),
    e([o], r.prototype, 'destroy', null),
    (exports.Messager = r)
})(require('lazyload'), require)
