import * as SignalR from '@microsoft/signalr'
|
import store from '../store/index'
|
|
const EventEmitter = require('events')
|
|
const defaultOptions = {
|
log: false
|
}
|
|
class SocketConnection extends EventEmitter {
|
constructor(connection, options = {}) {
|
super()
|
this.connection = connection
|
this.options = Object.assign(defaultOptions, options)
|
this.listened = []
|
this.toSend = []
|
this.offline = false
|
this.socket = undefined
|
}
|
|
/**
|
* 同一种消息只定义一次
|
*
|
* @param {string| symbol} event
|
* @param {(...args: any[]) => void} listener
|
* @memberof SocketConnection
|
*/
|
one(event, listener) {
|
if (this.listeners(event).length === 0) {
|
this.on(event, listener)
|
}
|
}
|
|
async _initialize() {
|
try {
|
await this.socket.start()
|
this.emit('onstart')
|
if (this.offline) {
|
this.emit('onrestart')
|
}
|
this.offline = false
|
} catch (error) {
|
setTimeout(async () => {
|
await this._initialize()
|
}, 5000)
|
}
|
}
|
|
async start(token) {
|
// 组件重新加载时, 如果 socket 存在, 不需要新建
|
if (!this.socket) {
|
this.socket = new SignalR.HubConnectionBuilder()
|
.configureLogging(SignalR.LogLevel.Information)
|
.withUrl(
|
`/hubs/chathub`, {
|
accessTokenFactory: () => token,
|
skipNegotiation: true,
|
transport: SignalR.HttpTransportType.WebSockets
|
}
|
)
|
.build()
|
|
this.socket.on('ForceExist', () => { //可以做相关业务逻辑
|
store.dispatch("Logout").then(()=>{
|
window.location.reload()
|
}).catch(err=>{
|
this.$message.error({
|
title: '错误',
|
description: err.message
|
})
|
})
|
})
|
|
this.socket.on('AppendNotice', (notice) => {
|
store.commit("APPEND_NOTICE",notice)
|
})
|
|
this.socket.onclose(async () => {
|
this.offline = true
|
this.emit('onclose')
|
await this._initialize()
|
})
|
|
await this._initialize()
|
|
}
|
}
|
|
async authenticate(token) {
|
await this.start(token)
|
}
|
|
listen(method) {
|
if (this.offline) return
|
if (this.listened.some((v) => v === method)) return
|
this.listened.push(method)
|
this.one('onstart', () => {
|
this.listened.forEach((method) => {
|
this.socket.on(method, (data) => {
|
if (this.options.log) {
|
console.log({
|
type: 'receive',
|
method,
|
data
|
})
|
}
|
this.emit(method, data)
|
})
|
})
|
})
|
}
|
|
send(methodName, ...args) {
|
if (this.options.log) {
|
console.log({
|
type: 'send',
|
methodName,
|
args
|
})
|
}
|
if (this.offline) return
|
|
if (this.socket) {
|
this.socket.send(methodName, ...args)
|
return
|
}
|
|
this.one('onstart', () => this.socket.send(methodName, ...args))
|
}
|
|
async invoke(methodName, ...args) {
|
if (this.options.log) {
|
console.log({
|
type: 'invoke',
|
methodName,
|
args
|
})
|
}
|
if (this.offline) return false
|
|
if (this.socket) {
|
return this.socket.invoke(methodName, ...args)
|
}
|
|
// eslint-disable-next-line no-async-promise-executor
|
return new Promise(async (resolve) => this.one('onstart', () => resolve(this.socket.invoke(methodName, ...args))))
|
}
|
}
|
|
if (!SignalR) {
|
throw new Error('[Vue-SignalR] Cannot locate signalr-client')
|
}
|
|
function install(Vue, connection) {
|
if (!connection) {
|
throw new Error('[Vue-SignalR] Cannot locate connection')
|
}
|
|
const Socket = new SocketConnection(connection)
|
|
Vue.socket = Socket
|
|
Object.defineProperties(Vue.prototype, {
|
$socket: {
|
get() {
|
return Socket
|
}
|
}
|
})
|
|
Vue.mixin({
|
created() {
|
if (this.$options.sockets) {
|
const methods = Object.getOwnPropertyNames(this.$options.sockets)
|
|
methods.forEach((method) => {
|
Socket.listen(method)
|
|
Socket.one(method, (data) => this.$options.sockets[method].call(this, data))
|
})
|
}
|
|
if (this.$options.subscribe) {
|
Socket.one('authenticated', () => {
|
this.$options.subscribe.forEach((channel) => {
|
Socket.invoke('join', channel)
|
})
|
})
|
}
|
}
|
})
|
}
|
|
export default install
|