oa_app仓库初始化
This commit is contained in:
+252
@@ -0,0 +1,252 @@
|
||||
const ImType = {
|
||||
login: 0,
|
||||
keepAlive: 1,
|
||||
commonData: 2,
|
||||
logout: 3,
|
||||
recived: 4,
|
||||
responseLogin: 50,
|
||||
responseKeepAlive: 51,
|
||||
kickout: 54
|
||||
}
|
||||
|
||||
export const ImTypeu = {
|
||||
text: 1,
|
||||
image: 2,
|
||||
file: 3,
|
||||
card: 4,
|
||||
recall: 5,
|
||||
read: 6,
|
||||
call: 8,
|
||||
group: 9
|
||||
}
|
||||
|
||||
function frame(partial) {
|
||||
return {
|
||||
bridge: false,
|
||||
type: 0,
|
||||
dataContent: null,
|
||||
from: '-1',
|
||||
to: '-1',
|
||||
fp: null,
|
||||
QoS: false,
|
||||
typeu: -1,
|
||||
sm: Date.now(),
|
||||
...partial
|
||||
}
|
||||
}
|
||||
|
||||
function uuid() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
||||
const r = (Math.random() * 16) | 0
|
||||
const v = c === 'x' ? r : (r & 0x3) | 0x8
|
||||
return v.toString(16)
|
||||
})
|
||||
}
|
||||
|
||||
class ImClient {
|
||||
constructor() {
|
||||
this.userId = ''
|
||||
this.token = ''
|
||||
this.url = ''
|
||||
this._closed = true
|
||||
this._tries = 0
|
||||
this._alive = 0
|
||||
this._reconnect = 0
|
||||
this._handlers = {}
|
||||
this._bound = false
|
||||
this._opened = false
|
||||
this._ready = false
|
||||
this._queue = []
|
||||
}
|
||||
|
||||
on(event, fn) {
|
||||
this._handlers[event] = fn
|
||||
}
|
||||
|
||||
emit(event, payload) {
|
||||
const fn = this._handlers[event]
|
||||
if (fn) fn(payload)
|
||||
}
|
||||
|
||||
connect({ userId, token, url }) {
|
||||
this._closed = false
|
||||
this.userId = userId
|
||||
this.token = token
|
||||
this.url = url
|
||||
this._open()
|
||||
}
|
||||
|
||||
_bindSocket() {
|
||||
if (this._bound) return
|
||||
this._bound = true
|
||||
uni.onSocketOpen(() => {
|
||||
this._tries = 0
|
||||
this._opened = true
|
||||
this._send(frame({
|
||||
type: ImType.login,
|
||||
from: String(this.userId || ''),
|
||||
to: '0',
|
||||
dataContent: JSON.stringify({
|
||||
loginUserId: String(this.userId || ''),
|
||||
loginToken: this.token,
|
||||
extra: 'hbuilder-app',
|
||||
firstLoginTime: 0
|
||||
})
|
||||
}))
|
||||
})
|
||||
uni.onSocketMessage((res) => this._onMessage(res.data))
|
||||
uni.onSocketClose(() => {
|
||||
this._opened = false
|
||||
this._ready = false
|
||||
this._clearAlive()
|
||||
if (!this._closed) this._schedule()
|
||||
})
|
||||
uni.onSocketError(() => {
|
||||
if (!this._closed) this._schedule()
|
||||
})
|
||||
}
|
||||
|
||||
_open() {
|
||||
this._clear()
|
||||
this.emit('status', 'reconnecting')
|
||||
this._bindSocket()
|
||||
uni.connectSocket({ url: this.url })
|
||||
}
|
||||
|
||||
_onMessage(raw) {
|
||||
let p
|
||||
try {
|
||||
p = typeof raw === 'string' ? JSON.parse(raw) : raw
|
||||
} catch (_) {
|
||||
return
|
||||
}
|
||||
if (!p || typeof p !== 'object') return
|
||||
const type = p.type
|
||||
if (type === ImType.responseLogin) {
|
||||
let info = {}
|
||||
try {
|
||||
info = JSON.parse(p.dataContent || '{}')
|
||||
} catch (_) {}
|
||||
if (info.code === 0) {
|
||||
this._ready = true
|
||||
this.emit('status', 'connected')
|
||||
this._keep()
|
||||
this._flush()
|
||||
} else {
|
||||
this.emit('status', 'offline')
|
||||
this.emit('loginFailed', info)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (type === ImType.responseKeepAlive) return
|
||||
if (type === ImType.kickout) {
|
||||
this._closed = true
|
||||
this.emit('kick')
|
||||
try { uni.closeSocket() } catch (_) {}
|
||||
return
|
||||
}
|
||||
if (type === ImType.recived) {
|
||||
this.emit('ack', p.fp || p.dataContent)
|
||||
return
|
||||
}
|
||||
if (type === ImType.commonData) {
|
||||
if (p.QoS && p.fp) {
|
||||
this._send(frame({
|
||||
type: ImType.recived,
|
||||
from: this.userId,
|
||||
to: '0',
|
||||
dataContent: p.fp,
|
||||
fp: p.fp
|
||||
}))
|
||||
}
|
||||
let data = {}
|
||||
try {
|
||||
const dc = p.dataContent
|
||||
data = typeof dc === 'string' ? JSON.parse(dc) : (dc || {})
|
||||
} catch (_) {
|
||||
data = { text: p.dataContent, kind: 'text' }
|
||||
}
|
||||
this.emit('data', { ...p, data, typeu: p.typeu || ImTypeu.text })
|
||||
}
|
||||
}
|
||||
|
||||
sendData({ to, typeu, payload, qos = true }) {
|
||||
const fp = uuid()
|
||||
this._send(frame({
|
||||
type: ImType.commonData,
|
||||
from: String(this.userId || ''),
|
||||
to: String(to || ''),
|
||||
typeu,
|
||||
QoS: qos,
|
||||
fp,
|
||||
dataContent: JSON.stringify(payload)
|
||||
}))
|
||||
return fp
|
||||
}
|
||||
|
||||
logout() {
|
||||
this._closed = true
|
||||
try {
|
||||
this._send(frame({ type: ImType.logout, from: this.userId, to: '0' }))
|
||||
} catch (_) {}
|
||||
try { uni.closeSocket() } catch (_) {}
|
||||
this._clear()
|
||||
}
|
||||
|
||||
_send(p) {
|
||||
const raw = JSON.stringify(p)
|
||||
const ctrl = p.type === ImType.login || p.type === ImType.keepAlive || p.type === ImType.logout || p.type === ImType.recived
|
||||
if (!this._opened || (!this._ready && !ctrl)) {
|
||||
if (!ctrl) this._queue.push(raw)
|
||||
return
|
||||
}
|
||||
try {
|
||||
uni.sendSocketMessage({
|
||||
data: raw,
|
||||
fail: () => {
|
||||
if (!ctrl) this._queue.push(raw)
|
||||
}
|
||||
})
|
||||
} catch (_) {
|
||||
if (!ctrl) this._queue.push(raw)
|
||||
}
|
||||
}
|
||||
|
||||
_flush() {
|
||||
const pending = this._queue.splice(0, this._queue.length)
|
||||
pending.forEach((raw) => {
|
||||
try { uni.sendSocketMessage({ data: raw }) } catch (_) {}
|
||||
})
|
||||
}
|
||||
|
||||
_keep() {
|
||||
this._clearAlive()
|
||||
this._alive = setInterval(() => {
|
||||
this._send(frame({ type: ImType.keepAlive, from: this.userId, to: '0', dataContent: '{}' }))
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
_schedule() {
|
||||
this.emit('status', 'reconnecting')
|
||||
const wait = Math.min(15000, 800 * Math.pow(2, this._tries))
|
||||
this._tries += 1
|
||||
this._reconnect = setTimeout(() => this._open(), wait)
|
||||
}
|
||||
|
||||
_clearAlive() {
|
||||
if (this._alive) {
|
||||
clearInterval(this._alive)
|
||||
this._alive = 0
|
||||
}
|
||||
}
|
||||
|
||||
_clear() {
|
||||
this._clearAlive()
|
||||
if (this._reconnect) {
|
||||
clearTimeout(this._reconnect)
|
||||
this._reconnect = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const imClient = new ImClient()
|
||||
Reference in New Issue
Block a user