feat: complate socket.io base framework
Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
		@@ -27,7 +27,9 @@
 | 
			
		||||
        "typescript": "^3.8.3"
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@ms/nashorn": "^0.3.1"
 | 
			
		||||
        "@ms/container": "^0.3.2",
 | 
			
		||||
        "@ms/nashorn": "^0.3.1",
 | 
			
		||||
        "socket.io-parser": "^3.4.0"
 | 
			
		||||
    },
 | 
			
		||||
    "gitHead": "781524f83e52cad26d7c480513e3c525df867121"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1,3 @@
 | 
			
		||||
/// <reference types="@ms/nashorn" />
 | 
			
		||||
 | 
			
		||||
export * from './socket-io'
 | 
			
		||||
@@ -2,17 +2,18 @@ const TypeParameterMatcher = Java.type('io.netty.util.internal.TypeParameterMatc
 | 
			
		||||
const SimpleChannelInboundHandler = Java.type('io.netty.channel.SimpleChannelInboundHandler')
 | 
			
		||||
const FullHttpRequestMatcher = TypeParameterMatcher.get(base.getClass('io.netty.handler.codec.http.FullHttpRequest'))
 | 
			
		||||
 | 
			
		||||
export default abstract class HttpRequestHandlerAdapter {
 | 
			
		||||
export abstract class HttpRequestHandlerAdapter {
 | 
			
		||||
    private _Handler;
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this._Handler == Java.extend(SimpleChannelInboundHandler, {
 | 
			
		||||
        let HttpRequestHandlerAdapterImpl = Java.extend(SimpleChannelInboundHandler, {
 | 
			
		||||
            acceptInboundMessage: (msg: any) => {
 | 
			
		||||
                return FullHttpRequestMatcher.match(msg)
 | 
			
		||||
            },
 | 
			
		||||
            channelRead0: this.channelRead0
 | 
			
		||||
            channelRead0: this.channelRead0.bind(this)
 | 
			
		||||
        })
 | 
			
		||||
        this._Handler = new HttpRequestHandlerAdapterImpl();
 | 
			
		||||
    }
 | 
			
		||||
    abstract channelRead0(ctx: any, msg: any);
 | 
			
		||||
    abstract channelRead0(ctx: any, request: any);
 | 
			
		||||
    getHandler() {
 | 
			
		||||
        return this._Handler;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								packages/websocket/src/netty/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								packages/websocket/src/netty/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export * from './text_websocket_frame'
 | 
			
		||||
export * from './websocket'
 | 
			
		||||
export * from './httprequest'
 | 
			
		||||
@@ -2,16 +2,17 @@ const TypeParameterMatcher = Java.type('io.netty.util.internal.TypeParameterMatc
 | 
			
		||||
const TextWebSocketFrameMatcher = TypeParameterMatcher.get(base.getClass('io.netty.handler.codec.http.websocketx.TextWebSocketFrame'))
 | 
			
		||||
const SimpleChannelInboundHandler = Java.type('io.netty.channel.SimpleChannelInboundHandler')
 | 
			
		||||
 | 
			
		||||
export default abstract class TextWebSocketFrameHandlerAdapter {
 | 
			
		||||
export abstract class TextWebSocketFrameHandlerAdapter {
 | 
			
		||||
    private _Handler;
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this._Handler == Java.extend(SimpleChannelInboundHandler, {
 | 
			
		||||
            userEventTriggered: this.userEventTriggered,
 | 
			
		||||
        let TextWebSocketFrameHandlerAdapterImpl = Java.extend(SimpleChannelInboundHandler, {
 | 
			
		||||
            userEventTriggered: this.userEventTriggered.bind(this),
 | 
			
		||||
            acceptInboundMessage: (msg: any) => {
 | 
			
		||||
                return TextWebSocketFrameMatcher.match(msg)
 | 
			
		||||
            },
 | 
			
		||||
            channelRead0: this.channelRead0
 | 
			
		||||
            channelRead0: this.channelRead0.bind(this)
 | 
			
		||||
        })
 | 
			
		||||
        this._Handler = new TextWebSocketFrameHandlerAdapterImpl();
 | 
			
		||||
    }
 | 
			
		||||
    abstract userEventTriggered(ctx: any, evt: any);
 | 
			
		||||
    abstract channelRead0(ctx: any, msg: any);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,14 @@
 | 
			
		||||
const MiaoWebSocket = 'miaowebsocket'
 | 
			
		||||
const CharsetUtil = Java.type('io.netty.util.CharsetUtil')
 | 
			
		||||
const ChannelInboundHandlerAdapter = Java.type('io.netty.channel.ChannelInboundHandlerAdapter')
 | 
			
		||||
 | 
			
		||||
export default abstract class WebSocketHandlerAdapter {
 | 
			
		||||
export abstract class WebSocketHandlerAdapter {
 | 
			
		||||
    private _Handler;
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this._Handler = Java.extend(ChannelInboundHandlerAdapter, {
 | 
			
		||||
            channelRead: this.channelRead
 | 
			
		||||
        let ChannelInboundHandlerAdapterImpl = Java.extend(ChannelInboundHandlerAdapter, {
 | 
			
		||||
            channelRead: this.channelRead.bind(this)
 | 
			
		||||
        })
 | 
			
		||||
        this._Handler = new ChannelInboundHandlerAdapterImpl()
 | 
			
		||||
    }
 | 
			
		||||
    abstract channelRead(ctx: any, msg: any);
 | 
			
		||||
    abstract channelRead(ctx: any, channel: any);
 | 
			
		||||
    getHandler() {
 | 
			
		||||
        return this._Handler;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								packages/websocket/src/server/client.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								packages/websocket/src/server/client.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
 | 
			
		||||
const TextWebSocketFrame = Java.type('io.netty.handler.codec.http.websocketx.TextWebSocketFrame')
 | 
			
		||||
 | 
			
		||||
export class NettyClient {
 | 
			
		||||
    private event: EventEmitter
 | 
			
		||||
 | 
			
		||||
    private _id: string;
 | 
			
		||||
    private channel: any
 | 
			
		||||
    constructor(channel: any) {
 | 
			
		||||
        this.channel = channel;
 | 
			
		||||
        this._id = channel.id();
 | 
			
		||||
        this.event = new EventEmitter();
 | 
			
		||||
    }
 | 
			
		||||
    get id() {
 | 
			
		||||
        return this._id;
 | 
			
		||||
    }
 | 
			
		||||
    on(event: string, callback: (...args: any[]) => void) {
 | 
			
		||||
        this.event.on(event, callback);
 | 
			
		||||
    }
 | 
			
		||||
    emit(event: string, text: string) {
 | 
			
		||||
        this.event.emit(event, text);
 | 
			
		||||
    }
 | 
			
		||||
    send(text: string) {
 | 
			
		||||
        this.channel.writeAndFlush(new TextWebSocketFrame(text))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								packages/websocket/src/server/constants.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								packages/websocket/src/server/constants.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
export enum ServerEvent {
 | 
			
		||||
    detect = 'detect',
 | 
			
		||||
    connect = 'connect',
 | 
			
		||||
    connection = 'connection',
 | 
			
		||||
    message = 'message',
 | 
			
		||||
    disconnect = 'disconnect'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum Keys {
 | 
			
		||||
    Detect = "miao_detect",
 | 
			
		||||
    Handler = "miaowebsocket",
 | 
			
		||||
    Default = "DefaultChannelPipeline"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								packages/websocket/src/server/httprequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								packages/websocket/src/server/httprequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
import { HttpRequestHandlerAdapter } from '../netty'
 | 
			
		||||
 | 
			
		||||
const DefaultHttpResponse = Java.type('io.netty.handler.codec.http.DefaultHttpResponse')
 | 
			
		||||
const DefaultFullHttpResponse = Java.type('io.netty.handler.codec.http.DefaultFullHttpResponse')
 | 
			
		||||
const HttpHeaders = Java.type('io.netty.handler.codec.http.HttpHeaders')
 | 
			
		||||
const HttpVersion = Java.type('io.netty.handler.codec.http.HttpVersion')
 | 
			
		||||
const HttpResponseStatus = Java.type('io.netty.handler.codec.http.HttpResponseStatus')
 | 
			
		||||
const LastHttpContent = Java.type('io.netty.handler.codec.http.LastHttpContent')
 | 
			
		||||
 | 
			
		||||
const File = Java.type('java.io.File')
 | 
			
		||||
const Runnable = Java.type('java.lang.Runnable')
 | 
			
		||||
const RandomAccessFile = Java.type('java.io.RandomAccessFile')
 | 
			
		||||
const DefaultFileRegion = Java.type('io.netty.channel.DefaultFileRegion')
 | 
			
		||||
const ChannelFutureListener = Java.type('io.netty.channel.ChannelFutureListener')
 | 
			
		||||
 | 
			
		||||
export type HttpRequestConfig = {
 | 
			
		||||
    root?: string;
 | 
			
		||||
    ws?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class HttpRequestHandler extends HttpRequestHandlerAdapter {
 | 
			
		||||
    private ws: string;
 | 
			
		||||
    private root: string;
 | 
			
		||||
    constructor(config: HttpRequestConfig = {
 | 
			
		||||
        root: root + '/wwwroot',
 | 
			
		||||
        ws: '/ws'
 | 
			
		||||
    }) {
 | 
			
		||||
        super()
 | 
			
		||||
        this.root = config.root;
 | 
			
		||||
        this.ws = config.ws;
 | 
			
		||||
    }
 | 
			
		||||
    channelRead0(ctx: any, request: any) {
 | 
			
		||||
        if (request.getUri().startsWith(this.ws)) {
 | 
			
		||||
            ctx.fireChannelRead(request.retain())
 | 
			
		||||
        } else {
 | 
			
		||||
            ctx.executor().execute(new Runnable({
 | 
			
		||||
                run: () => {
 | 
			
		||||
                    if (HttpHeaders.is100ContinueExpected(request)) {
 | 
			
		||||
                        ctx.writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE))
 | 
			
		||||
                    }
 | 
			
		||||
                    let filename = request.getUri().split('?')[0].substr(1)
 | 
			
		||||
                    let file = new File(this.root, filename || 'index.html')
 | 
			
		||||
                    if (!file.exists() || !file.isFile()) {
 | 
			
		||||
                        ctx.write(new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.NOT_FOUND))
 | 
			
		||||
                        ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT).addListener(ChannelFutureListener.CLOSE)
 | 
			
		||||
                        return
 | 
			
		||||
                    }
 | 
			
		||||
                    let response = new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK)
 | 
			
		||||
                    response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/html charset=UTF-8")
 | 
			
		||||
                    let raf = new RandomAccessFile(file, 'r')
 | 
			
		||||
                    let keepAlive = HttpHeaders.isKeepAlive(request)
 | 
			
		||||
                    if (keepAlive) {
 | 
			
		||||
                        response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, file.length())
 | 
			
		||||
                        response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE)
 | 
			
		||||
                    }
 | 
			
		||||
                    ctx.write(response)
 | 
			
		||||
                    ctx.write(new DefaultFileRegion(raf.getChannel(), 0, raf.length()))
 | 
			
		||||
                    let future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT)
 | 
			
		||||
                    if (!keepAlive) {
 | 
			
		||||
                        future.addListener(ChannelFutureListener.CLOSE)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								packages/websocket/src/server/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								packages/websocket/src/server/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
 | 
			
		||||
import { ServerEvent, Keys } from './constants'
 | 
			
		||||
import { WebSocketDetect } from './websocket_detect'
 | 
			
		||||
import { WebSocketHandler } from './websocket_handler'
 | 
			
		||||
import { NettyClient } from './client'
 | 
			
		||||
 | 
			
		||||
interface NettyWebSocketServerOptions {
 | 
			
		||||
    path?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class NettyWebSocketServer {
 | 
			
		||||
    private event: EventEmitter
 | 
			
		||||
    private pipeline: any;
 | 
			
		||||
    private allClients: { [key: string]: NettyClient };
 | 
			
		||||
 | 
			
		||||
    constructor(pipeline: any, options: NettyWebSocketServerOptions) {
 | 
			
		||||
        this.event = new EventEmitter();
 | 
			
		||||
        this.allClients = {};
 | 
			
		||||
        this.pipeline = pipeline;
 | 
			
		||||
        let connectEvent = new EventEmitter();
 | 
			
		||||
        this.pipeline.addFirst(Keys.Detect, new WebSocketDetect(connectEvent).getHandler())
 | 
			
		||||
        connectEvent.on(ServerEvent.detect, (ctx, channel) => {
 | 
			
		||||
            channel.pipeline().addFirst(Keys.Handler, new WebSocketHandler(connectEvent).getHandler())
 | 
			
		||||
            ctx.fireChannelRead(channel)
 | 
			
		||||
        })
 | 
			
		||||
        connectEvent.on(ServerEvent.connect, (ctx) => {
 | 
			
		||||
            let nettyClient = new NettyClient(ctx.channel());
 | 
			
		||||
            this.allClients[nettyClient.id] = nettyClient;
 | 
			
		||||
            this.event.emit(ServerEvent.connect, nettyClient);
 | 
			
		||||
        })
 | 
			
		||||
        connectEvent.on(ServerEvent.message, (ctx, msg) => {
 | 
			
		||||
            let channel = ctx.channel();
 | 
			
		||||
            this.allClients[channel.id()]?.emit(ServerEvent.message, msg.text())
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    disable() {
 | 
			
		||||
        if (this.pipeline.names().contains(Keys.Detect)) {
 | 
			
		||||
            this.pipeline.remove(Keys.Detect)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    on(event: string, listener: (...args: any[]) => void) {
 | 
			
		||||
        this.event.on(event, listener)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
    NettyWebSocketServer,
 | 
			
		||||
    ServerEvent,
 | 
			
		||||
    NettyClient
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										19
									
								
								packages/websocket/src/server/text_websocket_frame.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								packages/websocket/src/server/text_websocket_frame.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import { TextWebSocketFrameHandlerAdapter } from '../netty'
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
import { ServerEvent } from './constants'
 | 
			
		||||
 | 
			
		||||
export class TextWebSocketFrameHandler extends TextWebSocketFrameHandlerAdapter {
 | 
			
		||||
    private event: EventEmitter;
 | 
			
		||||
    constructor(event: EventEmitter) {
 | 
			
		||||
        super()
 | 
			
		||||
        this.event = event;
 | 
			
		||||
    }
 | 
			
		||||
    userEventTriggered(ctx: any, evt: any) {
 | 
			
		||||
        if (evt == 'HANDSHAKE_COMPLETE') {
 | 
			
		||||
            this.event.emit(ServerEvent.connect, ctx)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    channelRead0(ctx: any, msg: any) {
 | 
			
		||||
        this.event.emit(ServerEvent.message, ctx, msg)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								packages/websocket/src/server/websocket_detect.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								packages/websocket/src/server/websocket_detect.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
import { WebSocketHandlerAdapter } from "../netty"
 | 
			
		||||
import { ServerEvent } from './constants'
 | 
			
		||||
 | 
			
		||||
export class WebSocketDetect extends WebSocketHandlerAdapter {
 | 
			
		||||
    private event: EventEmitter;
 | 
			
		||||
    constructor(event: EventEmitter) {
 | 
			
		||||
        super()
 | 
			
		||||
        this.event = event;
 | 
			
		||||
    }
 | 
			
		||||
    channelRead(ctx: any, channel: any) {
 | 
			
		||||
        this.event.emit(ServerEvent.detect, ctx, channel);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								packages/websocket/src/server/websocket_handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								packages/websocket/src/server/websocket_handler.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
 | 
			
		||||
import { Keys } from './constants'
 | 
			
		||||
import { WebSocketHandlerAdapter } from "../netty"
 | 
			
		||||
import { HttpRequestHandler } from './httprequest'
 | 
			
		||||
import { TextWebSocketFrameHandler } from './text_websocket_frame'
 | 
			
		||||
 | 
			
		||||
const CharsetUtil = Java.type('io.netty.util.CharsetUtil')
 | 
			
		||||
 | 
			
		||||
const HttpServerCodec = Java.type('io.netty.handler.codec.http.HttpServerCodec')
 | 
			
		||||
const ChunkedWriteHandler = Java.type('io.netty.handler.stream.ChunkedWriteHandler')
 | 
			
		||||
const HttpObjectAggregator = Java.type('io.netty.handler.codec.http.HttpObjectAggregator')
 | 
			
		||||
const WebSocketServerProtocolHandler = Java.type('io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler')
 | 
			
		||||
 | 
			
		||||
export class WebSocketHandler extends WebSocketHandlerAdapter {
 | 
			
		||||
    private event: EventEmitter;
 | 
			
		||||
    constructor(event: EventEmitter) {
 | 
			
		||||
        super()
 | 
			
		||||
        this.event = event;
 | 
			
		||||
    }
 | 
			
		||||
    channelRead(ctx: any, msg: any) {
 | 
			
		||||
        msg.markReaderIndex()
 | 
			
		||||
        let message: string = msg.toString(CharsetUtil.UTF_8)
 | 
			
		||||
        let channel = ctx.channel()
 | 
			
		||||
        let pipeline = channel.pipeline()
 | 
			
		||||
        if (message.indexOf('HTTP/1.1') > 0) {
 | 
			
		||||
            pipeline.names().forEach(f => {
 | 
			
		||||
                if (f == Keys.Handler || f.indexOf(Keys.Default) > -1) { return }
 | 
			
		||||
                pipeline.remove(f)
 | 
			
		||||
            })
 | 
			
		||||
            pipeline.addLast('http', new HttpServerCodec())
 | 
			
		||||
            pipeline.addLast('chunk', new ChunkedWriteHandler())
 | 
			
		||||
            pipeline.addLast('httpobj', new HttpObjectAggregator(64 * 1024))
 | 
			
		||||
            pipeline.addLast('http_request', new HttpRequestHandler().getHandler())
 | 
			
		||||
            pipeline.addLast('websocket', new WebSocketServerProtocolHandler("/ws", true))
 | 
			
		||||
            pipeline.addLast('websocket_handler', new TextWebSocketFrameHandler(this.event).getHandler())
 | 
			
		||||
        }
 | 
			
		||||
        pipeline.remove(Keys.Handler)
 | 
			
		||||
        msg.resetReaderIndex()
 | 
			
		||||
        ctx.fireChannelRead(msg)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										84
									
								
								packages/websocket/src/socket-io/client.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								packages/websocket/src/socket-io/client.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
import { Parser } from './parser'
 | 
			
		||||
import { Packet } from './packet';
 | 
			
		||||
import { PacketTypes, SubPacketTypes } from './types';
 | 
			
		||||
import { ServerEvent, NettyClient } from '../server';
 | 
			
		||||
import { SocketIO } from './interfaces'
 | 
			
		||||
 | 
			
		||||
const parser = new Parser();
 | 
			
		||||
 | 
			
		||||
export class SocketIOClient implements SocketIO.Client {
 | 
			
		||||
    private nettyClient: NettyClient;
 | 
			
		||||
    private event: EventEmitter
 | 
			
		||||
    private _id: string;
 | 
			
		||||
 | 
			
		||||
    server: SocketIO.Server;
 | 
			
		||||
    conn: SocketIO.EngineSocket;
 | 
			
		||||
    request: any;
 | 
			
		||||
    sockets: { [id: string]: SocketIO.Socket; };
 | 
			
		||||
    nsps: { [nsp: string]: SocketIO.Socket; };
 | 
			
		||||
 | 
			
		||||
    constructor(nettyClient: NettyClient) {
 | 
			
		||||
        this.event = new EventEmitter()
 | 
			
		||||
        this.nettyClient = nettyClient;
 | 
			
		||||
        this._id = this.nettyClient.id;
 | 
			
		||||
        this.event.emit('connect', this);
 | 
			
		||||
        this.nettyClient.on(ServerEvent.message, (text) => this.process(text))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get id() {
 | 
			
		||||
        return this._id;
 | 
			
		||||
    }
 | 
			
		||||
    connect() {
 | 
			
		||||
        this.packet({
 | 
			
		||||
            type: PacketTypes.OPEN,
 | 
			
		||||
            data: {
 | 
			
		||||
                sid: this._id,
 | 
			
		||||
                upgrades: [],
 | 
			
		||||
                pingInterval: 25000,
 | 
			
		||||
                pingTimeout: 5000
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        this.packet({
 | 
			
		||||
            type: PacketTypes.MESSAGE,
 | 
			
		||||
            sub_type: SubPacketTypes.CONNECT
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    emit(event: string, data: any) {
 | 
			
		||||
        this.packet({
 | 
			
		||||
            type: PacketTypes.MESSAGE,
 | 
			
		||||
            sub_type: SubPacketTypes.EVENT,
 | 
			
		||||
            name: event,
 | 
			
		||||
            data
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    send(data: any) {
 | 
			
		||||
        this.emit("message", data);
 | 
			
		||||
    }
 | 
			
		||||
    packet(packet: Packet) {
 | 
			
		||||
        this.nettyClient.send(parser.encode(packet))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private process(text: string) {
 | 
			
		||||
        let packet = parser.decode(text);
 | 
			
		||||
        switch (packet.type) {
 | 
			
		||||
            case PacketTypes.OPEN:
 | 
			
		||||
                break;
 | 
			
		||||
            case PacketTypes.PING:
 | 
			
		||||
                this.packet({
 | 
			
		||||
                    type: PacketTypes.PONG
 | 
			
		||||
                })
 | 
			
		||||
                break;
 | 
			
		||||
            case PacketTypes.MESSAGE:
 | 
			
		||||
                switch (packet.sub_type) {
 | 
			
		||||
                    case SubPacketTypes.CONNECT:
 | 
			
		||||
                        this.nettyClient.send(text);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case SubPacketTypes.EVENT:
 | 
			
		||||
                        this.event.emit(packet.name, packet.data);
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										118
									
								
								packages/websocket/src/socket-io/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								packages/websocket/src/socket-io/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
 | 
			
		||||
import { NettyWebSocketServer } from '../server'
 | 
			
		||||
import { ServerEvent } from '../server/constants';
 | 
			
		||||
 | 
			
		||||
import { Namespace } from './namespace';
 | 
			
		||||
import { SocketIOClient } from './client';
 | 
			
		||||
import { SocketIO } from './interfaces'
 | 
			
		||||
 | 
			
		||||
export class SocketIOServer implements SocketIO.Server {
 | 
			
		||||
    private event: EventEmitter;
 | 
			
		||||
    private nettyServer: NettyWebSocketServer;
 | 
			
		||||
    private allClients: { [key: string]: SocketIOClient };
 | 
			
		||||
    private namespaces: { [key: string]: Namespace };
 | 
			
		||||
 | 
			
		||||
    engine: { ws: any; };
 | 
			
		||||
    nsps: { [namespace: string]: SocketIO.Namespace; };
 | 
			
		||||
    sockets: SocketIO.Namespace;
 | 
			
		||||
    json: SocketIO.Server;
 | 
			
		||||
    volatile: SocketIO.Server;
 | 
			
		||||
    local: SocketIO.Server;
 | 
			
		||||
 | 
			
		||||
    constructor(pipeline: any, options: SocketIO.ServerOptions) {
 | 
			
		||||
        if (!pipeline) { throw new Error('Netty Pipeline can\'t be undefiend!') }
 | 
			
		||||
        this.event = new EventEmitter();
 | 
			
		||||
        this.allClients = {};
 | 
			
		||||
        this.namespaces = {};
 | 
			
		||||
        this.nettyServer = new NettyWebSocketServer(pipeline, {
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
        this.nettyServer.on(ServerEvent.connect, (nettyClient) => {
 | 
			
		||||
            let client = new SocketIOClient(nettyClient);
 | 
			
		||||
            this.allClients[client.id] = client;
 | 
			
		||||
            client.connect();
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    checkRequest(req: any, fn: (err: any, success: boolean) => void): void {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    serveClient(): boolean;
 | 
			
		||||
    serveClient(v: boolean): SocketIO.Server;
 | 
			
		||||
    serveClient(v?: any): boolean | SocketIO.Server {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    path(): string;
 | 
			
		||||
    path(v: string): SocketIO.Server;
 | 
			
		||||
    path(v?: any): string | SocketIO.Server {
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
    adapter();
 | 
			
		||||
    adapter(v: any): SocketIO.Server;
 | 
			
		||||
    adapter(v?: any): SocketIO.Server {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    origins(): string | string[];
 | 
			
		||||
    origins(v: string | string[]): SocketIO.Server;
 | 
			
		||||
    origins(fn: (origin: string, callback: (error: string, success: boolean) => void) => void): SocketIO.Server;
 | 
			
		||||
    origins(fn?: any): string | string[] | SocketIO.Server {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    attach(srv: any, opts?: SocketIO.ServerOptions): SocketIO.Server;
 | 
			
		||||
    attach(port: number, opts?: SocketIO.ServerOptions): SocketIO.Server;
 | 
			
		||||
    attach(port: any, opts?: any): SocketIO.Server {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    listen(srv: any, opts?: SocketIO.ServerOptions): SocketIO.Server;
 | 
			
		||||
    listen(port: number, opts?: SocketIO.ServerOptions): SocketIO.Server;
 | 
			
		||||
    listen(port: any, opts?: any): SocketIO.Server {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    bind(srv: any): SocketIO.Server {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    onconnection(socket: any): SocketIO.Server {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    of(nsp: string | Function | RegExp): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    close(fn?: () => void): void {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    on(event: "connection", listener: (socket: SocketIO.Socket) => void): SocketIO.Namespace;
 | 
			
		||||
    on(event: "connect", listener: (socket: SocketIO.Socket) => void): SocketIO.Namespace;
 | 
			
		||||
    on(event: string, listener: Function): SocketIO.Namespace;
 | 
			
		||||
    on(event: any, listener: any): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    to(room: string): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    in(room: string): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    use(fn: (socket: SocketIO.Socket, fn: (err?: any) => void) => void): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    emit(event: string, ...args: any[]): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    send(...args: any[]): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    write(...args: any[]): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    clients(...args: any[]): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    compress(...args: any[]): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    disable() {
 | 
			
		||||
        this.nettyServer.disable();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										824
									
								
								packages/websocket/src/socket-io/interfaces.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										824
									
								
								packages/websocket/src/socket-io/interfaces.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,824 @@
 | 
			
		||||
export declare namespace SocketIO {
 | 
			
		||||
    interface Server {
 | 
			
		||||
        engine: { ws: any };
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * A dictionary of all the namespaces currently on this Server
 | 
			
		||||
		 */
 | 
			
		||||
        nsps: { [namespace: string]: Namespace };
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The default '/' Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        sockets: Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the 'json' flag when emitting an event
 | 
			
		||||
		 */
 | 
			
		||||
        json: Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets a modifier for a subsequent event emission that the event data may be lost if the clients are not ready to receive messages
 | 
			
		||||
		 */
 | 
			
		||||
        volatile: Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets a modifier for a subsequent event emission that the event data will only be broadcast to the current node
 | 
			
		||||
		 */
 | 
			
		||||
        local: Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Server request verification function, that checks for allowed origins
 | 
			
		||||
		 * @param req The http.IncomingMessage request
 | 
			
		||||
		 * @param fn The callback to be called. It should take one parameter, err,
 | 
			
		||||
		 * which will be null if there was no problem, and one parameter, success,
 | 
			
		||||
		 * of type boolean
 | 
			
		||||
		 */
 | 
			
		||||
        checkRequest(req: any, fn: (err: any, success: boolean) => void): void;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Gets whether we're serving the client.js file or not
 | 
			
		||||
		 * @default true
 | 
			
		||||
		 */
 | 
			
		||||
        serveClient(): boolean;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets whether we're serving the client.js file or not
 | 
			
		||||
		 * @param v True if we want to serve the file, false otherwise
 | 
			
		||||
		 * @default true
 | 
			
		||||
		 * @return This Server
 | 
			
		||||
		 */
 | 
			
		||||
        serveClient(v: boolean): Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Gets the client serving path
 | 
			
		||||
		 * @default '/socket.io'
 | 
			
		||||
		 */
 | 
			
		||||
        path(): string;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the client serving path
 | 
			
		||||
		 * @param v The path to serve the client file on
 | 
			
		||||
		 * @default '/socket.io'
 | 
			
		||||
		 * @return This Server
 | 
			
		||||
		 */
 | 
			
		||||
        path(v: string): Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Gets the adapter that we're going to use for handling rooms
 | 
			
		||||
		 * @default typeof Adapter
 | 
			
		||||
		 */
 | 
			
		||||
        adapter(): any;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the adapter (class) that we're going to use for handling rooms
 | 
			
		||||
		 * @param v The class for the adapter to create
 | 
			
		||||
		 * @default typeof Adapter
 | 
			
		||||
		 * @return This Server
 | 
			
		||||
		 */
 | 
			
		||||
        adapter(v: any): Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Gets the allowed origins for requests
 | 
			
		||||
		 * @default "*:*"
 | 
			
		||||
		 */
 | 
			
		||||
        origins(): string | string[];
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the allowed origins for requests
 | 
			
		||||
		 * @param v The allowed origins, in host:port form
 | 
			
		||||
		 * @default "*:*"
 | 
			
		||||
		 * return This Server
 | 
			
		||||
		 */
 | 
			
		||||
        origins(v: string | string[]): Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Provides a function taking two arguments origin:String
 | 
			
		||||
		 * and callback(error, success), where success is a boolean
 | 
			
		||||
		 * value indicating whether origin is allowed or not. If
 | 
			
		||||
		 * success is set to false, error must be provided as a string
 | 
			
		||||
		 * value that will be appended to the server response, e.g. “Origin not allowed”.
 | 
			
		||||
		 * @param fn The function that will be called to check the origin
 | 
			
		||||
		 * return This Server
 | 
			
		||||
		 */
 | 
			
		||||
        origins(fn: (origin: string, callback: (error: string | null, success: boolean) => void) => void): Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Attaches socket.io to a server
 | 
			
		||||
		 * @param srv The http.Server that we want to attach to
 | 
			
		||||
		 * @param opts An optional parameters object
 | 
			
		||||
		 * @return This Server
 | 
			
		||||
		 */
 | 
			
		||||
        attach(srv: any, opts?: ServerOptions): Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Attaches socket.io to a port
 | 
			
		||||
		 * @param port The port that we want to attach to
 | 
			
		||||
		 * @param opts An optional parameters object
 | 
			
		||||
		 * @return This Server
 | 
			
		||||
		 */
 | 
			
		||||
        attach(port: number, opts?: ServerOptions): Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @see attach( srv, opts )
 | 
			
		||||
		 */
 | 
			
		||||
        listen(srv: any, opts?: ServerOptions): Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @see attach( port, opts )
 | 
			
		||||
		 */
 | 
			
		||||
        listen(port: number, opts?: ServerOptions): Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Binds socket.io to an engine.io instance
 | 
			
		||||
		 * @param src The Engine.io (or compatible) server to bind to
 | 
			
		||||
		 * @return This Server
 | 
			
		||||
		 */
 | 
			
		||||
        bind(srv: any): Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Called with each incoming connection
 | 
			
		||||
		 * @param socket The Engine.io Socket
 | 
			
		||||
		 * @return This Server
 | 
			
		||||
		 */
 | 
			
		||||
        onconnection(socket: any): Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Looks up/creates a Namespace
 | 
			
		||||
		 * @param nsp The name of the NameSpace to look up/create. Should start
 | 
			
		||||
		 * with a '/'
 | 
			
		||||
		 * @return The Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        of(nsp: string | RegExp | Function): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Closes the server connection
 | 
			
		||||
		 */
 | 
			
		||||
        close(fn?: () => void): void;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The event fired when we get a new connection
 | 
			
		||||
		 * @param event The event being fired: 'connection'
 | 
			
		||||
		 * @param listener A listener that should take one parameter of type Socket
 | 
			
		||||
		 * @return The default '/' Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        on(event: 'connection', listener: (socket: Socket) => void): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @see on( 'connection', listener )
 | 
			
		||||
		 */
 | 
			
		||||
        on(event: 'connect', listener: (socket: Socket) => void): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Base 'on' method to add a listener for an event
 | 
			
		||||
		 * @param event The event that we want to add a listener for
 | 
			
		||||
		 * @param listener The callback to call when we get the event. The parameters
 | 
			
		||||
		 * for the callback depend on the event
 | 
			
		||||
		 * @return The default '/' Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        on(event: string, listener: Function): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Targets a room when emitting to the default '/' Namespace
 | 
			
		||||
		 * @param room The name of the room that we're targeting
 | 
			
		||||
		 * @return The default '/' Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        to(room: string): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @see to( room )
 | 
			
		||||
		 */
 | 
			
		||||
        in(room: string): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Registers a middleware function, which is a function that gets executed
 | 
			
		||||
		 * for every incoming Socket, on the default '/' Namespace
 | 
			
		||||
		 * @param fn The function to call when we get a new incoming socket. It should
 | 
			
		||||
		 * take one parameter of type Socket, and one callback function to call to
 | 
			
		||||
		 * execute the next middleware function. The callback can take one optional
 | 
			
		||||
		 * parameter, err, if there was an error. Errors passed to middleware callbacks
 | 
			
		||||
		 * are sent as special 'error' packets to clients
 | 
			
		||||
		 * @return The default '/' Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        use(fn: (socket: Socket, fn: (err?: any) => void) => void): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Emits an event to the default Namespace
 | 
			
		||||
		 * @param event The event that we want to emit
 | 
			
		||||
		 * @param args Any number of optional arguments to pass with the event. If the
 | 
			
		||||
		 * last argument is a function, it will be called as an ack. The ack should
 | 
			
		||||
		 * take whatever data was sent with the packet
 | 
			
		||||
		 * @return The default '/' Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        emit(event: string, ...args: any[]): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sends a 'message' event
 | 
			
		||||
		 * @see emit( event, ...args )
 | 
			
		||||
		 * @return The default '/' Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        send(...args: any[]): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @see send( ...args )
 | 
			
		||||
		 */
 | 
			
		||||
        write(...args: any[]): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Gets a list of clients
 | 
			
		||||
		 * @return The default '/' Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        clients(...args: any[]): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the compress flag
 | 
			
		||||
		 * @return The default '/' Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        compress(...args: any[]): Namespace;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Options to pass to our server when creating it
 | 
			
		||||
	 */
 | 
			
		||||
    interface ServerOptions {
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The path to server the client file to
 | 
			
		||||
		 * @default '/socket.io'
 | 
			
		||||
		 */
 | 
			
		||||
        path?: string;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Should we serve the client file?
 | 
			
		||||
		 * @default true
 | 
			
		||||
		 */
 | 
			
		||||
        serveClient?: boolean;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The adapter to use for handling rooms. NOTE: this should be a class,
 | 
			
		||||
		 * not an object
 | 
			
		||||
		 * @default typeof Adapter
 | 
			
		||||
		 */
 | 
			
		||||
        adapter?: Adapter;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Accepted origins
 | 
			
		||||
		 * @default '*:*'
 | 
			
		||||
		 */
 | 
			
		||||
        origins?: string | string[];
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * How many milliseconds without a pong packed to consider the connection closed (engine.io)
 | 
			
		||||
		 * @default 60000
 | 
			
		||||
		 */
 | 
			
		||||
        pingTimeout?: number;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * How many milliseconds before sending a new ping packet (keep-alive) (engine.io)
 | 
			
		||||
		 * @default 25000
 | 
			
		||||
		 */
 | 
			
		||||
        pingInterval?: number;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * How many bytes or characters a message can be when polling, before closing the session
 | 
			
		||||
		 * (to avoid Dos) (engine.io)
 | 
			
		||||
		 * @default 10E7
 | 
			
		||||
		 */
 | 
			
		||||
        maxHttpBufferSize?: number;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * A function that receives a given handshake or upgrade request as its first parameter,
 | 
			
		||||
		 * and can decide whether to continue or not. The second argument is a function that needs
 | 
			
		||||
		 * to be called with the decided information: fn( err, success ), where success is a boolean
 | 
			
		||||
		 * value where false means that the request is rejected, and err is an error code (engine.io)
 | 
			
		||||
		 * @default null
 | 
			
		||||
		 */
 | 
			
		||||
        allowRequest?: (request: any, callback: (err: number, success: boolean) => void) => void;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Transports to allow connections to (engine.io)
 | 
			
		||||
		 * @default ['polling','websocket']
 | 
			
		||||
		 */
 | 
			
		||||
        transports?: string[];
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Whether to allow transport upgrades (engine.io)
 | 
			
		||||
		 * @default true
 | 
			
		||||
		 */
 | 
			
		||||
        allowUpgrades?: boolean;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * parameters of the WebSocket permessage-deflate extension (see ws module).
 | 
			
		||||
		 * Set to false to disable (engine.io)
 | 
			
		||||
		 * @default true
 | 
			
		||||
		 */
 | 
			
		||||
        perMessageDeflate?: Object | boolean;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Parameters of the http compression for the polling transports (see zlib).
 | 
			
		||||
		 * Set to false to disable, or set an object with parameter "threshold:number"
 | 
			
		||||
		 * to only compress data if the byte size is above this value (1024) (engine.io)
 | 
			
		||||
		 * @default true|1024
 | 
			
		||||
		 */
 | 
			
		||||
        httpCompression?: Object | boolean;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Name of the HTTP cookie that contains the client sid to send as part of
 | 
			
		||||
		 * handshake response headers. Set to false to not send one (engine.io)
 | 
			
		||||
		 * @default "io"
 | 
			
		||||
		 */
 | 
			
		||||
        cookie?: string | boolean;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Whether to let engine.io handle the OPTIONS requests.
 | 
			
		||||
         * You can also pass a custom function to handle the requests
 | 
			
		||||
         * @default true
 | 
			
		||||
         */
 | 
			
		||||
        handlePreflightRequest?: ((req: any, res: any) => void) | boolean;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The Namespace, sandboxed environments for sockets, each connection
 | 
			
		||||
	 * to a Namespace requires a new Socket
 | 
			
		||||
	 */
 | 
			
		||||
    interface Namespace extends NodeJS.EventEmitter {
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The name of the NameSpace
 | 
			
		||||
		 */
 | 
			
		||||
        name: string;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The controller Server for this Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        server: Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * A dictionary of all the Sockets connected to this Namespace, where
 | 
			
		||||
		 * the Socket ID is the key
 | 
			
		||||
		 */
 | 
			
		||||
        sockets: { [id: string]: Socket };
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * A dictionary of all the Sockets connected to this Namespace, where
 | 
			
		||||
		 * the Socket ID is the key
 | 
			
		||||
		 */
 | 
			
		||||
        connected: { [id: string]: Socket };
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The Adapter that we're using to handle dealing with rooms etc
 | 
			
		||||
		 */
 | 
			
		||||
        adapter: Adapter;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the 'json' flag when emitting an event
 | 
			
		||||
		 */
 | 
			
		||||
        json: Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Registers a middleware function, which is a function that gets executed
 | 
			
		||||
		 * for every incoming Socket
 | 
			
		||||
		 * @param fn The function to call when we get a new incoming socket. It should
 | 
			
		||||
		 * take one parameter of type Socket, and one callback function to call to
 | 
			
		||||
		 * execute the next middleware function. The callback can take one optional
 | 
			
		||||
		 * parameter, err, if there was an error. Errors passed to middleware callbacks
 | 
			
		||||
		 * are sent as special 'error' packets to clients
 | 
			
		||||
		 * @return This Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        use(fn: (socket: Socket, fn: (err?: any) => void) => void): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Targets a room when emitting
 | 
			
		||||
		 * @param room The name of the room that we're targeting
 | 
			
		||||
		 * @return This Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        to(room: string): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @see to( room )
 | 
			
		||||
		 */
 | 
			
		||||
        in(room: string): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sends a 'message' event
 | 
			
		||||
		 * @see emit( event, ...args )
 | 
			
		||||
		 * @return This Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        send(...args: any[]): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @see send( ...args )
 | 
			
		||||
		 */
 | 
			
		||||
        write(...args: any[]): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The event fired when we get a new connection
 | 
			
		||||
		 * @param event The event being fired: 'connection'
 | 
			
		||||
		 * @param listener A listener that should take one parameter of type Socket
 | 
			
		||||
		 * @return This Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        on(event: 'connection', listener: (socket: Socket) => void): this;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @see on( 'connection', listener )
 | 
			
		||||
		 */
 | 
			
		||||
        on(event: 'connect', listener: (socket: Socket) => void): this;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Base 'on' method to add a listener for an event
 | 
			
		||||
		 * @param event The event that we want to add a listener for
 | 
			
		||||
		 * @param listener The callback to call when we get the event. The parameters
 | 
			
		||||
		 * for the callback depend on the event
 | 
			
		||||
		 * @ This Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        on(event: string, listener: Function): this;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Gets a list of clients.
 | 
			
		||||
		 * @return This Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        clients(fn: Function): Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the compress flag.
 | 
			
		||||
		 * @param compress If `true`, compresses the sending data
 | 
			
		||||
		 * @return This Namespace
 | 
			
		||||
		 */
 | 
			
		||||
        compress(compress: boolean): Namespace;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    interface Packet extends Array<any> {
 | 
			
		||||
		/**
 | 
			
		||||
		 * Event name
 | 
			
		||||
		 */
 | 
			
		||||
        [0]: string;
 | 
			
		||||
		/**
 | 
			
		||||
		 * Packet data
 | 
			
		||||
		 */
 | 
			
		||||
        [1]: any;
 | 
			
		||||
		/**
 | 
			
		||||
		 * Ack function
 | 
			
		||||
		 */
 | 
			
		||||
        [2]: (...args: any[]) => void;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The socket, which handles our connection for a namespace. NOTE: while
 | 
			
		||||
	 * we technically extend NodeJS.EventEmitter, we're not putting it here
 | 
			
		||||
	 * as we have a problem with the emit() event (as it's overridden with a
 | 
			
		||||
	 * different return)
 | 
			
		||||
	 */
 | 
			
		||||
    interface Socket extends NodeJS.EventEmitter {
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The namespace that this socket is for
 | 
			
		||||
		 */
 | 
			
		||||
        nsp: Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The Server that our namespace is in
 | 
			
		||||
		 */
 | 
			
		||||
        server: Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The Adapter that we use to handle our rooms
 | 
			
		||||
		 */
 | 
			
		||||
        adapter: Adapter;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The unique ID for this Socket. Regenerated at every connection. This is
 | 
			
		||||
		 * also the name of the room that the Socket automatically joins on connection
 | 
			
		||||
		 */
 | 
			
		||||
        id: string;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The http.IncomingMessage request sent with the connection. Useful
 | 
			
		||||
		 * for recovering headers etc
 | 
			
		||||
		 */
 | 
			
		||||
        request: any;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The Client associated with this Socket
 | 
			
		||||
		 */
 | 
			
		||||
        client: Client;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The underlying Engine.io Socket instance
 | 
			
		||||
		 */
 | 
			
		||||
        conn: EngineSocket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The list of rooms that this Socket is currently in, where
 | 
			
		||||
		 * the ID the the room ID
 | 
			
		||||
		 */
 | 
			
		||||
        rooms: { [id: string]: string };
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Is the Socket currently connected?
 | 
			
		||||
		 */
 | 
			
		||||
        connected: boolean;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Is the Socket currently disconnected?
 | 
			
		||||
		 */
 | 
			
		||||
        disconnected: boolean;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The object used when negociating the handshake
 | 
			
		||||
		 */
 | 
			
		||||
        handshake: Handshake;
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the 'json' flag when emitting an event
 | 
			
		||||
		 */
 | 
			
		||||
        json: Socket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the 'volatile' flag when emitting an event. Volatile messages are
 | 
			
		||||
		 * messages that can be dropped because of network issues and the like. Use
 | 
			
		||||
		 * for high-volume/real-time messages where you don't need to receive *all*
 | 
			
		||||
		 * of them
 | 
			
		||||
		 */
 | 
			
		||||
        volatile: Socket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the 'broadcast' flag when emitting an event. Broadcasting an event
 | 
			
		||||
		 * will send it to all the other sockets in the namespace except for yourself
 | 
			
		||||
		 */
 | 
			
		||||
        broadcast: Socket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Targets a room when broadcasting
 | 
			
		||||
		 * @param room The name of the room that we're targeting
 | 
			
		||||
		 * @return This Socket
 | 
			
		||||
		 */
 | 
			
		||||
        to(room: string): Socket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @see to( room )
 | 
			
		||||
		 */
 | 
			
		||||
        in(room: string): Socket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Registers a middleware, which is a function that gets executed for every incoming Packet and receives as parameter the packet and a function to optionally defer execution to the next registered middleware.
 | 
			
		||||
		 *
 | 
			
		||||
		 * Errors passed to middleware callbacks are sent as special error packets to clients.
 | 
			
		||||
		 */
 | 
			
		||||
        use(fn: (packet: Packet, next: (err?: any) => void) => void): Socket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sends a 'message' event
 | 
			
		||||
		 * @see emit( event, ...args )
 | 
			
		||||
		 */
 | 
			
		||||
        send(...args: any[]): Socket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @see send( ...args )
 | 
			
		||||
		 */
 | 
			
		||||
        write(...args: any[]): Socket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Joins a room. You can join multiple rooms, and by default, on connection,
 | 
			
		||||
		 * you join a room with the same name as your ID
 | 
			
		||||
		 * @param name The name of the room that we want to join
 | 
			
		||||
		 * @param fn An optional callback to call when we've joined the room. It should
 | 
			
		||||
		 * take an optional parameter, err, of a possible error
 | 
			
		||||
		 * @return This Socket
 | 
			
		||||
		 */
 | 
			
		||||
        join(name: string | string[], fn?: (err?: any) => void): Socket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Leaves a room
 | 
			
		||||
		 * @param name The name of the room to leave
 | 
			
		||||
		 * @param fn An optional callback to call when we've left the room. It should
 | 
			
		||||
		 * take on optional parameter, err, of a possible error
 | 
			
		||||
		 */
 | 
			
		||||
        leave(name: string, fn?: Function): Socket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Leaves all the rooms that we've joined
 | 
			
		||||
		 */
 | 
			
		||||
        leaveAll(): void;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Disconnects this Socket
 | 
			
		||||
		 * @param close If true, also closes the underlying connection
 | 
			
		||||
		 * @return This Socket
 | 
			
		||||
		 */
 | 
			
		||||
        disconnect(close?: boolean): Socket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Returns all the callbacks for a particular event
 | 
			
		||||
		 * @param event The event that we're looking for the callbacks of
 | 
			
		||||
		 * @return An array of callback Functions, or an empty array if we don't have any
 | 
			
		||||
		 */
 | 
			
		||||
        listeners(event: string): Function[];
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the compress flag
 | 
			
		||||
		 * @param compress If `true`, compresses the sending data
 | 
			
		||||
		 * @return This Socket
 | 
			
		||||
		 */
 | 
			
		||||
        compress(compress: boolean): Socket;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Emits the error
 | 
			
		||||
         * @param err Error message=
 | 
			
		||||
         */
 | 
			
		||||
        error(err: any): void;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    interface Handshake {
 | 
			
		||||
		/**
 | 
			
		||||
		 * The headers passed along with the request. e.g. 'host',
 | 
			
		||||
		 * 'connection', 'accept', 'referer', 'cookie'
 | 
			
		||||
		 */
 | 
			
		||||
        headers: any;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The current time, as a string
 | 
			
		||||
		 */
 | 
			
		||||
        time: string;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The remote address of the connection request
 | 
			
		||||
		 */
 | 
			
		||||
        address: string;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Is this a cross-domain request?
 | 
			
		||||
		 */
 | 
			
		||||
        xdomain: boolean;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Is this a secure request?
 | 
			
		||||
		 */
 | 
			
		||||
        secure: boolean;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The timestamp for when this was issued
 | 
			
		||||
		 */
 | 
			
		||||
        issued: number;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The request url
 | 
			
		||||
		 */
 | 
			
		||||
        url: string;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Any query string parameters in the request url
 | 
			
		||||
		 */
 | 
			
		||||
        query: any;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The interface describing a room
 | 
			
		||||
	 */
 | 
			
		||||
    interface Room {
 | 
			
		||||
        sockets: { [id: string]: boolean };
 | 
			
		||||
        length: number;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The interface describing a dictionary of rooms
 | 
			
		||||
	 * Where room is the name of the room
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
    interface Rooms {
 | 
			
		||||
        [room: string]: Room;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The interface used when dealing with rooms etc
 | 
			
		||||
	 */
 | 
			
		||||
    interface Adapter extends NodeJS.EventEmitter {
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The namespace that this adapter is for
 | 
			
		||||
		 */
 | 
			
		||||
        nsp: Namespace;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * A dictionary of all the rooms that we have in this namespace
 | 
			
		||||
		 */
 | 
			
		||||
        rooms: Rooms;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * A dictionary of all the socket ids that we're dealing with, and all
 | 
			
		||||
		 * the rooms that the socket is currently in
 | 
			
		||||
		 */
 | 
			
		||||
        sids: { [id: string]: { [room: string]: boolean } };
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Adds a socket to a room. If the room doesn't exist, it's created
 | 
			
		||||
		 * @param id The ID of the socket to add
 | 
			
		||||
		 * @param room The name of the room to add the socket to
 | 
			
		||||
		 * @param callback An optional callback to call when the socket has been
 | 
			
		||||
		 * added. It should take an optional parameter, error, if there was a problem
 | 
			
		||||
		 */
 | 
			
		||||
        add(id: string, room: string, callback?: (err?: any) => void): void;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Removes a socket from a room. If there are no more sockets in the room,
 | 
			
		||||
		 * the room is deleted
 | 
			
		||||
		 * @param id The ID of the socket that we're removing
 | 
			
		||||
		 * @param room The name of the room to remove the socket from
 | 
			
		||||
		 * @param callback An optional callback to call when the socket has been
 | 
			
		||||
		 * removed. It should take on optional parameter, error, if there was a problem
 | 
			
		||||
		 */
 | 
			
		||||
        del(id: string, room: string, callback?: (err?: any) => void): void;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Removes a socket from all the rooms that it's joined
 | 
			
		||||
		 * @param id The ID of the socket that we're removing
 | 
			
		||||
		 */
 | 
			
		||||
        delAll(id: string): void;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Broadcasts a packet
 | 
			
		||||
		 * @param packet The packet to broadcast
 | 
			
		||||
		 * @param opts Any options to send along:
 | 
			
		||||
		 * 	- rooms: An optional list of rooms to broadcast to. If empty, the packet is broadcast to all sockets
 | 
			
		||||
		 * 	- except: A list of Socket IDs to exclude
 | 
			
		||||
		 * 	- flags: Any flags that we want to send along ('json', 'volatile', 'broadcast')
 | 
			
		||||
		 */
 | 
			
		||||
        broadcast(packet: any, opts: { rooms?: string[]; except?: string[]; flags?: { [flag: string]: boolean } }): void;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The client behind each socket (can have multiple sockets)
 | 
			
		||||
	 */
 | 
			
		||||
    interface Client {
 | 
			
		||||
		/**
 | 
			
		||||
		 * The Server that this client belongs to
 | 
			
		||||
		 */
 | 
			
		||||
        server: Server;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The underlying Engine.io Socket instance
 | 
			
		||||
		 */
 | 
			
		||||
        conn: EngineSocket;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The ID for this client. Regenerated at every connection
 | 
			
		||||
		 */
 | 
			
		||||
        id: string;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The http.IncomingMessage request sent with the connection. Useful
 | 
			
		||||
		 * for recovering headers etc
 | 
			
		||||
		 */
 | 
			
		||||
        request: any;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The dictionary of sockets currently connect via this client (i.e. to different
 | 
			
		||||
		 * namespaces) where the Socket ID is the key
 | 
			
		||||
		 */
 | 
			
		||||
        sockets: { [id: string]: Socket };
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * A dictionary of all the namespaces for this client, with the Socket that
 | 
			
		||||
		 * deals with that namespace
 | 
			
		||||
		 */
 | 
			
		||||
        nsps: { [nsp: string]: Socket };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * A reference to the underlying engine.io Socket connection.
 | 
			
		||||
	 */
 | 
			
		||||
    interface EngineSocket extends NodeJS.EventEmitter {
 | 
			
		||||
		/**
 | 
			
		||||
		 * The ID for this socket - matches Client.id
 | 
			
		||||
		 */
 | 
			
		||||
        id: string;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The Engine.io Server for this socket
 | 
			
		||||
		 */
 | 
			
		||||
        server: any;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The ready state for the client. Either 'opening', 'open', 'closing', or 'closed'
 | 
			
		||||
		 */
 | 
			
		||||
        readyState: string;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * The remote IP for this connection
 | 
			
		||||
		 */
 | 
			
		||||
        remoteAddress: string;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * whether the transport has been upgraded
 | 
			
		||||
		 */
 | 
			
		||||
        upgraded: boolean;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * (http.IncomingMessage): request that originated the Socket
 | 
			
		||||
		 */
 | 
			
		||||
        request: any;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * (Transport): transport reference
 | 
			
		||||
		 */
 | 
			
		||||
        transport: any;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								packages/websocket/src/socket-io/namespace.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								packages/websocket/src/socket-io/namespace.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
 | 
			
		||||
import { SocketIOClient } from './client'
 | 
			
		||||
import { SocketIO } from './interfaces';
 | 
			
		||||
 | 
			
		||||
export class Namespace implements SocketIO.Namespace {
 | 
			
		||||
    private event: EventEmitter;
 | 
			
		||||
    private allClients: { [key: string]: SocketIOClient };
 | 
			
		||||
    private roomClients: { [key: string]: Set<string> };
 | 
			
		||||
    private clientRooms: { [key: string]: Set<string> };
 | 
			
		||||
 | 
			
		||||
    name: string;
 | 
			
		||||
    server: SocketIO.Server;
 | 
			
		||||
    sockets: { [id: string]: SocketIO.Socket; };
 | 
			
		||||
    connected: { [id: string]: SocketIO.Socket; };
 | 
			
		||||
    adapter: SocketIO.Adapter;
 | 
			
		||||
    json: SocketIO.Namespace;
 | 
			
		||||
 | 
			
		||||
    constructor(name: string) {
 | 
			
		||||
        this.name = name;
 | 
			
		||||
        this.event = new EventEmitter();
 | 
			
		||||
        this.allClients = {};
 | 
			
		||||
        this.roomClients = {};
 | 
			
		||||
        this.clientRooms = {};
 | 
			
		||||
    }
 | 
			
		||||
    use(fn: (socket: SocketIO.Socket, fn: (err?: any) => void) => void): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    to(room: string): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    in(room: string): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    send(...args: any[]): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    write(...args: any[]): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    on(event: "connection", listener: (socket: SocketIO.Socket) => void): this;
 | 
			
		||||
    on(event: "connect", listener: (socket: SocketIO.Socket) => void): this;
 | 
			
		||||
    on(event: string, listener: Function): this;
 | 
			
		||||
    on(event: any, listener: any) {
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
    clients(fn: Function): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    compress(compress: boolean): SocketIO.Namespace {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    addListener(event: string | symbol, listener: (...args: any[]) => void): this {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    once(event: string | symbol, listener: (...args: any[]) => void): this {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    removeListener(event: string | symbol, listener: (...args: any[]) => void): this {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    off(event: string | symbol, listener: (...args: any[]) => void): this {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    removeAllListeners(event?: string | symbol): this {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    setMaxListeners(n: number): this {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    getMaxListeners(): number {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    listeners(event: string | symbol): Function[] {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    rawListeners(event: string | symbol): Function[] {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    emit(event: string | symbol, ...args: any[]): boolean {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    listenerCount(type: string | symbol): number {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    prependListener(event: string | symbol, listener: (...args: any[]) => void): this {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
    eventNames(): (string | symbol)[] {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								packages/websocket/src/socket-io/packet.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								packages/websocket/src/socket-io/packet.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
import { PacketTypes, SubPacketTypes } from './types'
 | 
			
		||||
 | 
			
		||||
export interface Packet {
 | 
			
		||||
    type: PacketTypes;
 | 
			
		||||
    sub_type?: SubPacketTypes;
 | 
			
		||||
    nsp?: string;
 | 
			
		||||
    id?: number;
 | 
			
		||||
    name?: string;
 | 
			
		||||
    data?: any;
 | 
			
		||||
    attachments?: any;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										160
									
								
								packages/websocket/src/socket-io/parser.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								packages/websocket/src/socket-io/parser.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
			
		||||
import { Packet } from "./packet";
 | 
			
		||||
import { PacketTypes, SubPacketTypes } from "./types";
 | 
			
		||||
 | 
			
		||||
export class Parser {
 | 
			
		||||
    encode(packet: Packet): string {
 | 
			
		||||
        // first is type
 | 
			
		||||
        var str = '' + packet.type;
 | 
			
		||||
        if (packet.type == PacketTypes.PONG) {
 | 
			
		||||
            if (packet.data) { str += packet.data };
 | 
			
		||||
            return str;
 | 
			
		||||
        }
 | 
			
		||||
        if (packet.sub_type != undefined) {
 | 
			
		||||
            str += packet.sub_type;
 | 
			
		||||
        }
 | 
			
		||||
        // attachments if we have them
 | 
			
		||||
        if ([SubPacketTypes.BINARY_EVENT, SubPacketTypes.BINARY_ACK].includes(packet.sub_type)) {
 | 
			
		||||
            str += packet.attachments + '-';
 | 
			
		||||
        }
 | 
			
		||||
        // if we have a namespace other than `/`
 | 
			
		||||
        // we append it followed by a comma `,`
 | 
			
		||||
        if (packet.nsp && '/' !== packet.nsp) {
 | 
			
		||||
            str += packet.nsp + ',';
 | 
			
		||||
        }
 | 
			
		||||
        // immediately followed by the id
 | 
			
		||||
        if (null != packet.id) {
 | 
			
		||||
            str += packet.id;
 | 
			
		||||
        }
 | 
			
		||||
        if (packet.sub_type == SubPacketTypes.EVENT) {
 | 
			
		||||
            packet.data = [packet.name, packet.data]
 | 
			
		||||
        }
 | 
			
		||||
        // json data
 | 
			
		||||
        if (null != packet.data) {
 | 
			
		||||
            var payload = this.tryStringify(packet.data);
 | 
			
		||||
            if (payload !== false) {
 | 
			
		||||
                str += payload;
 | 
			
		||||
            } else {
 | 
			
		||||
                return '4"encode error"'
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        console.debug(`encoded ${JSON.stringify(packet)} as ${str}`);
 | 
			
		||||
        return str;
 | 
			
		||||
    }
 | 
			
		||||
    tryStringify(str) {
 | 
			
		||||
        try {
 | 
			
		||||
            return JSON.stringify(str);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    decode(str: string): Packet {
 | 
			
		||||
        var i = 0;
 | 
			
		||||
        // ignore parse binary
 | 
			
		||||
        // if ((frame.getByte(0) == 'b' && frame.getByte(1) == '4')
 | 
			
		||||
        //     || frame.getByte(0) == 4 || frame.getByte(0) == 1) {
 | 
			
		||||
        //     return parseBinary(head, frame);
 | 
			
		||||
        // }
 | 
			
		||||
        // look up type
 | 
			
		||||
        var p: Packet = {
 | 
			
		||||
            type: Number(str.charAt(i))
 | 
			
		||||
        };
 | 
			
		||||
        if (null == PacketTypes[p.type]) {
 | 
			
		||||
            return this.error('unknown packet type ' + p.type);
 | 
			
		||||
        }
 | 
			
		||||
        // if str empty return
 | 
			
		||||
        if (str.length == i + 1) {
 | 
			
		||||
            return p;
 | 
			
		||||
        }
 | 
			
		||||
        // if is ping packet read data and return
 | 
			
		||||
        if (PacketTypes.PING == p.type) {
 | 
			
		||||
            p.data = str.substr(++i);
 | 
			
		||||
            return p;
 | 
			
		||||
        }
 | 
			
		||||
        // look up sub type
 | 
			
		||||
        p.sub_type = Number(str.charAt(++i));
 | 
			
		||||
        if (null == PacketTypes[p.sub_type]) {
 | 
			
		||||
            return this.error('unknown sub packet type ' + p.type);
 | 
			
		||||
        }
 | 
			
		||||
        // look up attachments if type binary
 | 
			
		||||
        if ([SubPacketTypes.BINARY_ACK, SubPacketTypes.BINARY_EVENT].includes(p.sub_type)) {
 | 
			
		||||
            var buf = '';
 | 
			
		||||
            while (str.charAt(++i) !== '-') {
 | 
			
		||||
                buf += str.charAt(i);
 | 
			
		||||
                if (i == str.length) break;
 | 
			
		||||
            }
 | 
			
		||||
            if (buf != `${Number(buf)}` || str.charAt(i) !== '-') {
 | 
			
		||||
                throw new Error('Illegal attachments');
 | 
			
		||||
            }
 | 
			
		||||
            p.attachments = Number(buf);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // look up namespace (if any)
 | 
			
		||||
        if ('/' === str.charAt(i + 1)) {
 | 
			
		||||
            p.nsp = '';
 | 
			
		||||
            while (++i) {
 | 
			
		||||
                var c = str.charAt(i);
 | 
			
		||||
                if (',' === c) break;
 | 
			
		||||
                p.nsp += c;
 | 
			
		||||
                if (i === str.length) break;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            p.nsp = '/';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // look up id
 | 
			
		||||
        var next = str.charAt(i + 1);
 | 
			
		||||
        if ('' !== next && Number.isNaN(Number(next))) {
 | 
			
		||||
            var id = ''
 | 
			
		||||
            while (++i) {
 | 
			
		||||
                var c = str.charAt(i);
 | 
			
		||||
                if (null == c || Number.isNaN(Number(c))) {
 | 
			
		||||
                    --i;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                id += str.charAt(i);
 | 
			
		||||
                if (i === str.length) break;
 | 
			
		||||
            }
 | 
			
		||||
            p.id = Number(id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // look up packet name
 | 
			
		||||
        if (p.sub_type == SubPacketTypes.EVENT) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        // ignore binary packet
 | 
			
		||||
        if (p.sub_type == SubPacketTypes.BINARY_EVENT) {
 | 
			
		||||
            return this.error('not support binary parse...')
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // look up json data
 | 
			
		||||
        if (str.charAt(++i)) {
 | 
			
		||||
            var payload = this.tryParse(str.substr(i));
 | 
			
		||||
            var isPayloadValid = payload !== false && (p.sub_type == SubPacketTypes.ERROR || Array.isArray(payload));
 | 
			
		||||
            if (isPayloadValid) {
 | 
			
		||||
                p.name = payload[0];
 | 
			
		||||
                p.data = payload[1];
 | 
			
		||||
            } else {
 | 
			
		||||
                return this.error('invalid payload');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        console.debug(`decoded ${str} as ${JSON.stringify(p)}`);
 | 
			
		||||
        return p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tryParse(str) {
 | 
			
		||||
        try {
 | 
			
		||||
            return JSON.parse(str);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    error(error: string): Packet {
 | 
			
		||||
        return {
 | 
			
		||||
            type: PacketTypes.MESSAGE,
 | 
			
		||||
            sub_type: SubPacketTypes.ERROR,
 | 
			
		||||
            data: 'parser error: ' + error
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								packages/websocket/src/socket-io/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								packages/websocket/src/socket-io/types.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
export enum PacketTypes {
 | 
			
		||||
    OPEN,
 | 
			
		||||
    CLOSE,
 | 
			
		||||
    PING,
 | 
			
		||||
    PONG,
 | 
			
		||||
    MESSAGE,
 | 
			
		||||
    UPGRADE,
 | 
			
		||||
    NOOP,
 | 
			
		||||
}
 | 
			
		||||
export enum SubPacketTypes {
 | 
			
		||||
    CONNECT,
 | 
			
		||||
    DISCONNECT,
 | 
			
		||||
    EVENT,
 | 
			
		||||
    ACK,
 | 
			
		||||
    ERROR,
 | 
			
		||||
    BINARY_EVENT,
 | 
			
		||||
    BINARY_ACK
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user