feat: 更新WebSocket 优化逻辑

Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
2021-08-03 16:59:43 +08:00
parent def62e2940
commit 586b6acbbc
45 changed files with 5465 additions and 2376 deletions

View File

@@ -0,0 +1,7 @@
import { EventEmitter } from 'events'
export abstract class WebSocketClient extends EventEmitter {
public id: string
public _socket: any
abstract send(text: string, opts?: any, callback?: (err?: Error) => void)
abstract close()
}

View File

@@ -1,52 +1,90 @@
import { EventEmitter } from 'events'
import { ServerOptions } from '../socket.io'
import { WebSocketClient } from './client'
import { Transport } from '../transport'
import type { Request } from './request'
interface ServerOptions {
export enum ServerEvent {
detect = 'detect',
request = 'request',
upgrade = 'upgrade',
connect = 'connect',
connection = 'connection',
message = 'message',
error = 'error',
disconnecting = 'disconnecting',
disconnect = 'disconnect',
}
export interface JavaServerOptions extends ServerOptions {
event?: EventEmitter
root?: string
/**
* name of the path to capture
* @default "/socket.io"
*/
path: string
}
interface WebSocketServerImpl extends EventEmitter {
close(): void
}
export class WebSocketServer extends EventEmitter {
options: Partial<ServerOptions>
private websocketServer: WebSocketServerImpl
constructor(instance: any, options: Partial<ServerOptions>) {
export abstract class WebSocketServer extends EventEmitter {
protected instance: any
protected options: JavaServerOptions
private clients: Map<string, WebSocketClient>
constructor(instance: any, options: JavaServerOptions) {
super()
if (!instance) { throw new Error('instance can\'t be undefiend!') }
this.options = Object.assign({
event: new EventEmitter(),
path: '/ws',
root: root + '/wwwroot',
}, options)
this.selectServerImpl(instance)
this.instance = instance
this.options = options
this.clients = new Map()
console.debug('create websocket server from ' + this.constructor.name)
this.initialize()
}
on(event: "connect", cb: (transport: Transport) => void): this
on(event: "message", cb: (transport: Transport, text: string) => void): this
on(event: "disconnect", cb: (transport: Transport, reason: string) => void): this
on(event: "error", cb: (transport: Transport, cause: Error) => void): this
on(event: string, cb: (transport: Transport, extra?: any) => void): this {
this.websocketServer.on(event, cb)
return this
protected onconnect(handler: any) {
let id = this.getId(handler)
console.log('client', id, 'connect')
let request = this.getRequest(handler)
request.id = id
let websocket = this.getSocket(handler)
this.clients.set(this.getId(handler), websocket)
this.emit(ServerEvent.connect, request, websocket)
}
private selectServerImpl(instance: any) {
let WebSocketServerImpl = undefined
if (instance.class.name.startsWith('io.netty.channel')) {
WebSocketServerImpl = require("../netty").NettyWebSocketServer
} else {
WebSocketServerImpl = require("../tomcat").TomcatWebSocketServer
protected onmessage(handler: any, message: string) {
this.execute(handler, (websocket) => websocket.emit(ServerEvent.message, message))
}
protected ondisconnect(handler: any, cause: string) {
this.execute(handler, (websocket) => websocket.emit(ServerEvent.disconnect, cause))
}
protected onerror(handler: any, error: Error) {
if (global.debug) {
console.ex(error)
}
this.websocketServer = new WebSocketServerImpl(instance, this.options)
this.execute(handler, (websocket) => websocket.emit(ServerEvent.error, error))
}
protected execute(handler: any, callback: (websocket: WebSocketClient) => void) {
let id = this.getId(handler)
if (this.clients.has(id)) {
this.clients.has(id) && callback(this.clients.get(id))
} else {
console.debug('ignore execute', handler, 'callback', callback)
}
}
public close() {
this.clients.forEach(websocket => websocket.close())
this.doClose()
}
protected abstract initialize(): void
protected abstract getId(handler: any): string
protected abstract getRequest(handler: any): Request
protected abstract getSocket(handler: any): WebSocketClient
protected abstract doClose(): void
}
export const attach = (instance, options) => {
if (!instance) { throw new Error('instance can\'t be undefiend!') }
options = Object.assign({
event: new EventEmitter(),
path: '/ws',
root: root + '/wwwroot',
}, options)
let WebSocketServerImpl = undefined
if (instance.class.name.startsWith('io.netty.channel')) {
WebSocketServerImpl = require("../netty").NettyWebSocketServer
} else {
WebSocketServerImpl = require("../tomcat").TomcatWebSocketServer
}
return new WebSocketServerImpl(instance, options)
}

View File

@@ -0,0 +1,23 @@
import { WebSocketClient } from "./client"
interface HttpHeaders {
[name: string]: string
}
interface Connection {
remoteAddress: string
}
export class Request {
public id: string
public url: string
public method: string
public headers: HttpHeaders
public connection: Connection
public websocket: WebSocketClient
public _query: any
constructor(url: string, method = "GET", headers = {}) {
this.url = url
this.method = method
this.headers = headers
}
}