@socket-mesh/server 18.0.6 → 18.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/broker/broker-events.d.ts +16 -0
- package/dist/broker/broker.d.ts +28 -0
- package/dist/broker/broker.js +17 -0
- package/dist/broker/exchange-client.d.ts +5 -0
- package/dist/broker/exchange.d.ts +4 -0
- package/dist/broker/exchange.js +3 -0
- package/dist/broker/simple-broker.d.ts +16 -0
- package/dist/broker/simple-broker.js +65 -0
- package/dist/broker/simple-exchange.d.ts +13 -0
- package/dist/broker/simple-exchange.js +33 -0
- package/dist/handlers/authenticate.d.ts +20 -0
- package/dist/handlers/authenticate.js +67 -0
- package/dist/handlers/handshake.d.ts +7 -0
- package/dist/handlers/handshake.js +61 -0
- package/dist/handlers/publish.d.ts +9 -0
- package/dist/handlers/publish.js +21 -0
- package/dist/handlers/remove-auth-token.d.ts +3 -0
- package/dist/handlers/remove-auth-token.js +7 -0
- package/dist/handlers/subscribe.d.ts +7 -0
- package/dist/handlers/subscribe.js +43 -0
- package/dist/handlers/unsubscribe.d.ts +6 -0
- package/dist/handlers/unsubscribe.js +9 -0
- package/dist/index.d.ts +30 -0
- package/{index.js → dist/index.js} +6 -6
- package/dist/maps/client-map.d.ts +10 -0
- package/dist/maps/client-map.js +1 -0
- package/dist/maps/server-map.d.ts +24 -0
- package/dist/maps/server-map.js +1 -0
- package/dist/maps/socket-map.d.ts +19 -0
- package/dist/maps/socket-map.js +1 -0
- package/dist/plugin/server-plugin.d.ts +33 -0
- package/dist/plugin/server-plugin.js +2 -0
- package/dist/server-event.d.ts +52 -0
- package/dist/server-event.js +1 -0
- package/dist/server-options.d.ts +25 -0
- package/dist/server-options.js +1 -0
- package/dist/server-socket-state.d.ts +6 -0
- package/dist/server-socket-state.js +1 -0
- package/dist/server-socket.d.ts +28 -0
- package/dist/server-socket.js +50 -0
- package/dist/server-transport.d.ts +37 -0
- package/dist/server-transport.js +247 -0
- package/dist/server.d.ts +119 -0
- package/dist/server.js +281 -0
- package/package.json +40 -47
- package/action.d.ts +0 -106
- package/action.js +0 -141
- package/auth-engine.d.ts +0 -13
- package/auth-engine.js +0 -32
- package/events.d.ts +0 -54
- package/inbound-packet.d.ts +0 -48
- package/inbound-packet.js +0 -18
- package/index.d.ts +0 -32
- package/middleware-stream.d.ts +0 -7
- package/middleware-stream.js +0 -8
- package/middleware-type.d.ts +0 -6
- package/middleware-type.js +0 -7
- package/outbound-packet.d.ts +0 -25
- package/outbound-packet.js +0 -3
- package/remote-procedure.d.ts +0 -13
- package/remote-procedure.js +0 -9
- package/request.d.ts +0 -24
- package/request.js +0 -16
- package/server-options.d.ts +0 -38
- package/server.d.ts +0 -113
- package/server.js +0 -361
- package/serversocket.d.ts +0 -182
- package/serversocket.js +0 -1262
- package/socket-state.d.ts +0 -5
- package/socket-state.js +0 -6
- /package/{events.js → dist/broker/broker-events.js} +0 -0
- /package/{server-options.js → dist/broker/exchange-client.js} +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ChannelMap } from "@socket-mesh/channels";
|
|
2
|
+
import { ClientPrivateMap, ServerPrivateMap } from "@socket-mesh/client";
|
|
3
|
+
import { PublicMethodMap } from "@socket-mesh/core";
|
|
4
|
+
import { ServerSocketState } from "../server-socket-state.js";
|
|
5
|
+
import { ServerMap } from "./server-map.js";
|
|
6
|
+
export interface BasicSocketMapServer<TIncoming extends PublicMethodMap = {}, TChannels extends ChannelMap = {}, TState extends object = {}, TOutgoing extends object = {}> {
|
|
7
|
+
Incoming: TIncoming & ServerPrivateMap;
|
|
8
|
+
Service: {};
|
|
9
|
+
Outgoing: TOutgoing;
|
|
10
|
+
PrivateOutgoing: ClientPrivateMap;
|
|
11
|
+
State: TState & ServerSocketState;
|
|
12
|
+
}
|
|
13
|
+
export interface SocketMapFromServer<T extends ServerMap> {
|
|
14
|
+
Incoming: T['Incoming'] & T['PrivateIncoming'] & ServerPrivateMap;
|
|
15
|
+
Service: T['Service'];
|
|
16
|
+
Outgoing: T['Outgoing'];
|
|
17
|
+
PrivateOutgoing: T['PrivateOutgoing'] & ClientPrivateMap;
|
|
18
|
+
State: T['State'] & ServerSocketState;
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { IncomingMessage } from "http";
|
|
2
|
+
import { ServerMap } from "../maps/server-map.js";
|
|
3
|
+
import { SocketMapFromServer } from "../maps/socket-map.js";
|
|
4
|
+
import { Plugin } from "@socket-mesh/core";
|
|
5
|
+
import { AuthInfo } from "../handlers/authenticate.js";
|
|
6
|
+
import { ServerSocket } from "../server-socket.js";
|
|
7
|
+
import { ServerTransport } from "../server-transport.js";
|
|
8
|
+
import { ChannelOptions } from "@socket-mesh/channels";
|
|
9
|
+
export interface HandshakePluginArgs<T extends ServerMap> {
|
|
10
|
+
socket: ServerSocket<T>;
|
|
11
|
+
transport: ServerTransport<T>;
|
|
12
|
+
authInfo: AuthInfo;
|
|
13
|
+
}
|
|
14
|
+
export interface PublishPluginArgs<T extends ServerMap> {
|
|
15
|
+
channel: string;
|
|
16
|
+
data: any;
|
|
17
|
+
socket: ServerSocket<T>;
|
|
18
|
+
transport: ServerTransport<T>;
|
|
19
|
+
}
|
|
20
|
+
export interface SubscribePluginArgs<T extends ServerMap> {
|
|
21
|
+
channel: string;
|
|
22
|
+
options: ChannelOptions;
|
|
23
|
+
socket: ServerSocket<T>;
|
|
24
|
+
transport: ServerTransport<T>;
|
|
25
|
+
}
|
|
26
|
+
export interface ServerPlugin<T extends ServerMap> extends Plugin<SocketMapFromServer<T>> {
|
|
27
|
+
onAuthenticate?: (authInfo: AuthInfo) => void;
|
|
28
|
+
onConnection?: (request: IncomingMessage) => Promise<void>;
|
|
29
|
+
onHandshake?: (options: HandshakePluginArgs<T>) => Promise<void>;
|
|
30
|
+
onPublishIn?: (options: PublishPluginArgs<T>) => Promise<any>;
|
|
31
|
+
onPublishOut?: (options: PublishPluginArgs<T>) => Promise<any>;
|
|
32
|
+
onSubscribe?: (options: SubscribePluginArgs<T>) => Promise<void>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { IncomingMessage } from "http";
|
|
2
|
+
import { ClientSocket } from "@socket-mesh/client";
|
|
3
|
+
import { ServerSocket } from "./server-socket.js";
|
|
4
|
+
import { AuthenticateEvent, BadAuthTokenEvent, ConnectEvent, CloseEvent as SCloseEvent, DisconnectEvent, ErrorEvent as SErrorEvent, MessageEvent, PingEvent, PongEvent, RequestEvent, ResponseEvent, ConnectingEvent, RemoveAuthTokenEvent, DeauthenticateEvent, AuthStateChangeEvent } from "@socket-mesh/core";
|
|
5
|
+
import { ServerMap } from "./maps/server-map.js";
|
|
6
|
+
import { ClientMapFromServer } from "./maps/client-map.js";
|
|
7
|
+
import { SubscribeEvent, SubscribeFailEvent, SubscribeStateChangeEvent, UnsubscribeEvent } from "@socket-mesh/channels";
|
|
8
|
+
import { SocketMapFromServer } from "./maps/socket-map.js";
|
|
9
|
+
export type ServerEvent<T extends ServerMap> = ConnectionEvent<T> | CloseEvent | ErrorEvent | HeadersEvent | HandshakeEvent<T> | ListeningEvent | SocketAuthStateChangeEvent<T> | SocketAuthenticateEvent<T> | SocketBadAuthTokenEvent<T> | SocketCloseEvent<T> | SocketDeauthenticateEvent<T> | SocketErrorEvent<T> | SocketMessageEvent<T> | SocketConnectEvent<T> | SocketConnectingEvent<T> | SocketDisconnectEvent<T> | SocketPingEvent<T> | SocketPongEvent<T> | SocketRemoveAuthTokenEvent<T> | SocketRequestEvent<T> | SocketResponseEvent<T> | WarningEvent;
|
|
10
|
+
export interface ConnectionEvent<T extends ServerMap> {
|
|
11
|
+
socket: ServerSocket<T>;
|
|
12
|
+
upgradeReq: IncomingMessage;
|
|
13
|
+
}
|
|
14
|
+
export interface CloseEvent {
|
|
15
|
+
}
|
|
16
|
+
export interface ErrorEvent {
|
|
17
|
+
error: Error;
|
|
18
|
+
}
|
|
19
|
+
export interface HandshakeEvent<T extends ServerMap> {
|
|
20
|
+
socket: ServerSocket<T>;
|
|
21
|
+
}
|
|
22
|
+
export interface WarningEvent {
|
|
23
|
+
warning: Error;
|
|
24
|
+
}
|
|
25
|
+
export interface HeadersEvent {
|
|
26
|
+
headers: string[];
|
|
27
|
+
request: IncomingMessage;
|
|
28
|
+
}
|
|
29
|
+
export interface ListeningEvent {
|
|
30
|
+
}
|
|
31
|
+
export interface ServerSocketEvent<T extends ServerMap> {
|
|
32
|
+
socket: ClientSocket<ClientMapFromServer<T>> | ServerSocket<T>;
|
|
33
|
+
}
|
|
34
|
+
export type SocketAuthStateChangeEvent<T extends ServerMap> = AuthStateChangeEvent & ServerSocketEvent<T>;
|
|
35
|
+
export type SocketAuthenticateEvent<T extends ServerMap> = AuthenticateEvent & ServerSocketEvent<T>;
|
|
36
|
+
export type SocketBadAuthTokenEvent<T extends ServerMap> = BadAuthTokenEvent & ServerSocketEvent<T>;
|
|
37
|
+
export type SocketCloseEvent<T extends ServerMap> = SCloseEvent & ServerSocketEvent<T>;
|
|
38
|
+
export type SocketDeauthenticateEvent<T extends ServerMap> = DeauthenticateEvent & ServerSocketEvent<T>;
|
|
39
|
+
export type SocketErrorEvent<T extends ServerMap> = SErrorEvent & ServerSocketEvent<T>;
|
|
40
|
+
export type SocketMessageEvent<T extends ServerMap> = MessageEvent & ServerSocketEvent<T>;
|
|
41
|
+
export type SocketConnectEvent<T extends ServerMap> = ConnectEvent & ServerSocketEvent<T>;
|
|
42
|
+
export type SocketConnectingEvent<T extends ServerMap> = ConnectingEvent & ServerSocketEvent<T>;
|
|
43
|
+
export type SocketDisconnectEvent<T extends ServerMap> = DisconnectEvent & ServerSocketEvent<T>;
|
|
44
|
+
export type SocketPingEvent<T extends ServerMap> = PingEvent & ServerSocketEvent<T>;
|
|
45
|
+
export type SocketPongEvent<T extends ServerMap> = PongEvent & ServerSocketEvent<T>;
|
|
46
|
+
export type SocketRemoveAuthTokenEvent<T extends ServerMap> = RemoveAuthTokenEvent & ServerSocketEvent<T>;
|
|
47
|
+
export type SocketRequestEvent<T extends ServerMap> = RequestEvent<SocketMapFromServer<T>>;
|
|
48
|
+
export type SocketResponseEvent<T extends ServerMap> = ResponseEvent<T> & ServerSocketEvent<T>;
|
|
49
|
+
export type SocketSubscribeEvent<T extends ServerMap> = SubscribeEvent & ServerSocketEvent<T>;
|
|
50
|
+
export type SocketSubscribeFailEvent<T extends ServerMap> = SubscribeFailEvent & ServerSocketEvent<T>;
|
|
51
|
+
export type SocketSubscribeStateChangeEvent<T extends ServerMap> = SubscribeStateChangeEvent & ServerSocketEvent<T>;
|
|
52
|
+
export type SocketUnsubscribeEvent<T extends ServerMap> = UnsubscribeEvent & ServerSocketEvent<T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import ws from "ws";
|
|
2
|
+
import { AuthEngine, AuthOptions } from "@socket-mesh/auth-engine";
|
|
3
|
+
import { CallIdGenerator, HandlerMap, EmptySocketMap, StreamCleanupMode } from "@socket-mesh/core";
|
|
4
|
+
import { CodecEngine } from "@socket-mesh/formatter";
|
|
5
|
+
import { ServerPlugin } from "./plugin/server-plugin.js";
|
|
6
|
+
import { ServerMap } from "./maps/server-map.js";
|
|
7
|
+
import { Broker } from "./broker/broker.js";
|
|
8
|
+
export interface ServerOptions<T extends ServerMap> extends ws.ServerOptions {
|
|
9
|
+
ackTimeoutMs?: number;
|
|
10
|
+
allowClientPublish?: boolean;
|
|
11
|
+
authEngine?: AuthEngine | AuthOptions;
|
|
12
|
+
brokerEngine?: Broker<T['Channel']>;
|
|
13
|
+
callIdGenerator?: CallIdGenerator;
|
|
14
|
+
codecEngine?: CodecEngine;
|
|
15
|
+
handshakeTimeoutMs?: number;
|
|
16
|
+
handlers?: HandlerMap<EmptySocketMap>;
|
|
17
|
+
isPingTimeoutDisabled?: boolean;
|
|
18
|
+
plugins?: ServerPlugin<T>[];
|
|
19
|
+
origins?: string;
|
|
20
|
+
pingIntervalMs?: number;
|
|
21
|
+
pingTimeoutMs?: number;
|
|
22
|
+
socketChannelLimit?: number;
|
|
23
|
+
socketStreamCleanupMode?: StreamCleanupMode;
|
|
24
|
+
strictHandshake?: boolean;
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { HandlerMap, Socket, SocketOptions } from "@socket-mesh/core";
|
|
2
|
+
import ws from "ws";
|
|
3
|
+
import { SocketMapFromServer } from "./maps/socket-map.js";
|
|
4
|
+
import { ServerMap } from "./maps/server-map.js";
|
|
5
|
+
import { Exchange } from "./broker/exchange.js";
|
|
6
|
+
import { Server } from "./server.js";
|
|
7
|
+
import { IncomingMessage } from "http";
|
|
8
|
+
import { ServerPlugin } from "./plugin/server-plugin.js";
|
|
9
|
+
export interface ServerSocketOptions<T extends ServerMap> extends SocketOptions<SocketMapFromServer<T>> {
|
|
10
|
+
handlers: HandlerMap<SocketMapFromServer<T>>;
|
|
11
|
+
plugins?: ServerPlugin<T>[];
|
|
12
|
+
id?: string;
|
|
13
|
+
service?: string;
|
|
14
|
+
server: Server<T>;
|
|
15
|
+
request: IncomingMessage;
|
|
16
|
+
socket: ws.WebSocket;
|
|
17
|
+
}
|
|
18
|
+
export declare class ServerSocket<T extends ServerMap> extends Socket<SocketMapFromServer<T>> {
|
|
19
|
+
readonly server: Server<T>;
|
|
20
|
+
private _serverTransport;
|
|
21
|
+
constructor(options: ServerSocketOptions<T>);
|
|
22
|
+
deauthenticate(rejectOnFailedDelivery?: boolean): Promise<boolean>;
|
|
23
|
+
get exchange(): Exchange<T['Channel']>;
|
|
24
|
+
kickOut(channel: string, message: string): Promise<void[]>;
|
|
25
|
+
ping(): Promise<void>;
|
|
26
|
+
get service(): string;
|
|
27
|
+
get type(): 'server';
|
|
28
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Socket } from "@socket-mesh/core";
|
|
2
|
+
import { ServerTransport } from "./server-transport.js";
|
|
3
|
+
export class ServerSocket extends Socket {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
const transport = new ServerTransport(options);
|
|
6
|
+
super(transport, options);
|
|
7
|
+
this.server = options.server;
|
|
8
|
+
this._serverTransport = transport;
|
|
9
|
+
}
|
|
10
|
+
async deauthenticate(rejectOnFailedDelivery) {
|
|
11
|
+
await super.deauthenticate();
|
|
12
|
+
if (rejectOnFailedDelivery) {
|
|
13
|
+
try {
|
|
14
|
+
await this._serverTransport.invoke('#removeAuthToken', undefined)[0];
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
this._serverTransport.onError(error);
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
await this.transmit('#removeAuthToken');
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
if (err.name !== 'BadConnectionError') {
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
get exchange() {
|
|
32
|
+
return this.server.exchange;
|
|
33
|
+
}
|
|
34
|
+
kickOut(channel, message) {
|
|
35
|
+
const channels = channel ? [channel] : Object.keys(this.state.channelSubscriptions);
|
|
36
|
+
return Promise.all(channels.map((channelName) => {
|
|
37
|
+
this.transmit('#kickOut', { channel: channelName, message });
|
|
38
|
+
return this._serverTransport.unsubscribe(channelName);
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
ping() {
|
|
42
|
+
return this._serverTransport.ping();
|
|
43
|
+
}
|
|
44
|
+
get service() {
|
|
45
|
+
return this._serverTransport.service;
|
|
46
|
+
}
|
|
47
|
+
get type() {
|
|
48
|
+
return this._serverTransport.type;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ServerMap } from "./maps/server-map.js";
|
|
2
|
+
import { ServerSocket, ServerSocketOptions } from "./server-socket.js";
|
|
3
|
+
import { AuthToken, SignedAuthToken } from "@socket-mesh/auth";
|
|
4
|
+
import { SocketMapFromServer } from "./maps/socket-map.js";
|
|
5
|
+
import { AuthTokenOptions } from "@socket-mesh/auth-engine";
|
|
6
|
+
import { Data } from "ws";
|
|
7
|
+
import { AnyPacket, AnyResponse, SocketStatus, SocketTransport, InvokeMethodRequest, InvokeServiceRequest, TransmitMethodRequest, TransmitServiceRequest, InboundMessage } from "@socket-mesh/core";
|
|
8
|
+
import { IncomingMessage } from "http";
|
|
9
|
+
import { ServerPlugin } from "./plugin/server-plugin.js";
|
|
10
|
+
import { PublishOptions } from "@socket-mesh/channels";
|
|
11
|
+
export declare class ServerTransport<T extends ServerMap> extends SocketTransport<SocketMapFromServer<T>> {
|
|
12
|
+
readonly plugins: ServerPlugin<T>[];
|
|
13
|
+
readonly service?: string;
|
|
14
|
+
readonly request: IncomingMessage;
|
|
15
|
+
constructor(options: ServerSocketOptions<T>);
|
|
16
|
+
changeToUnauthenticatedState(): Promise<boolean>;
|
|
17
|
+
protected handleInboudMessage({ packet, timestamp }: InboundMessage<SocketMapFromServer<T>>): Promise<void>;
|
|
18
|
+
protected onClose(code: number, reason?: string | Buffer): void;
|
|
19
|
+
protected onDisconnect(status: SocketStatus, code: number, reason?: string): void;
|
|
20
|
+
onError(error: Error): void;
|
|
21
|
+
protected onInvoke<TService extends keyof T["Service"], TServiceMethod extends keyof T["Service"][TService], TMethod extends keyof T["Outgoing"], TPrivateMethod extends keyof T["PrivateOutgoing"]>(request: InvokeMethodRequest<T["Outgoing"], TMethod> | InvokeMethodRequest<T["PrivateOutgoing"], TPrivateMethod> | InvokeServiceRequest<T["Service"], TService, TServiceMethod>): void;
|
|
22
|
+
protected onMessage(data: Data, isBinary: boolean): void;
|
|
23
|
+
protected onPingPong(): void;
|
|
24
|
+
protected onPublish(options: PublishOptions): Promise<void>;
|
|
25
|
+
protected onRequest(packet: AnyPacket<SocketMapFromServer<T>>, timestamp: Date, pluginError?: Error): Promise<boolean>;
|
|
26
|
+
protected onResponse(response: AnyResponse<SocketMapFromServer<T>>): void;
|
|
27
|
+
protected onTransmit<TService extends keyof T["Service"], TServiceMethod extends keyof T["Service"][TService], TMethod extends keyof T["Outgoing"]>(request: TransmitMethodRequest<T["Outgoing"], TMethod> | TransmitServiceRequest<T["Service"], TService, TServiceMethod>): void;
|
|
28
|
+
ping(): Promise<void>;
|
|
29
|
+
setAuthorization(authToken: AuthToken, options?: AuthTokenOptions): Promise<boolean>;
|
|
30
|
+
setAuthorization(signedAuthToken: SignedAuthToken, authToken?: AuthToken): Promise<boolean>;
|
|
31
|
+
setReadyStatus(pingTimeoutMs: number, authError?: Error): void;
|
|
32
|
+
get socket(): ServerSocket<T>;
|
|
33
|
+
set socket(value: ServerSocket<T>);
|
|
34
|
+
triggerAuthenticationEvents(wasSigned: boolean, wasAuthenticated: boolean): void;
|
|
35
|
+
type: 'server';
|
|
36
|
+
unsubscribe(channel: string): Promise<void>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { AuthError, BrokerError, InvalidActionError, socketProtocolErrorStatuses } from "@socket-mesh/errors";
|
|
2
|
+
import { SocketTransport, abortRequest } from "@socket-mesh/core";
|
|
3
|
+
import base64id from "base64id";
|
|
4
|
+
export class ServerTransport extends SocketTransport {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
super(options);
|
|
7
|
+
this.type = 'server';
|
|
8
|
+
this.request = options.request;
|
|
9
|
+
this.plugins = options.plugins;
|
|
10
|
+
this.service = options.service;
|
|
11
|
+
this.webSocket = options.socket;
|
|
12
|
+
this.id = (options.id || base64id.generateId());
|
|
13
|
+
// Server is not set on socket until the socket constructor is completed so pull it from the options.
|
|
14
|
+
this.resetPingTimeout(options.server.isPingTimeoutDisabled ? false : options.server.pingTimeoutMs, 4001);
|
|
15
|
+
}
|
|
16
|
+
async changeToUnauthenticatedState() {
|
|
17
|
+
if (this.signedAuthToken) {
|
|
18
|
+
const authToken = this.authToken;
|
|
19
|
+
const signedAuthToken = this.signedAuthToken;
|
|
20
|
+
this.socket.server.emit('socketAuthStateChange', { socket: this.socket, wasAuthenticated: true, isAuthenticated: false });
|
|
21
|
+
await super.changeToUnauthenticatedState();
|
|
22
|
+
this.socket.server.emit('socketDeauthenticate', { socket: this.socket, signedAuthToken, authToken });
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
handleInboudMessage({ packet, timestamp }) {
|
|
28
|
+
if ((packet === null || typeof packet !== 'object') && this.socket.server.strictHandshake && this.status === 'connecting') {
|
|
29
|
+
this.disconnect(4009);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
return super.handleInboudMessage({ packet, timestamp });
|
|
33
|
+
}
|
|
34
|
+
onClose(code, reason) {
|
|
35
|
+
const status = this.status;
|
|
36
|
+
const strReason = reason?.toString() || socketProtocolErrorStatuses[code];
|
|
37
|
+
super.onClose(code, reason);
|
|
38
|
+
this.socket.server.emit('socketClose', { socket: this.socket, code, reason: strReason });
|
|
39
|
+
this.onDisconnect(status, code, strReason);
|
|
40
|
+
}
|
|
41
|
+
onDisconnect(status, code, reason) {
|
|
42
|
+
if (status === 'ready') {
|
|
43
|
+
this.socket.server.emit('socketDisconnect', { socket: this.socket, code, reason });
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
this.socket.server.emit('socketConnectAbort', { socket: this.socket, code, reason });
|
|
47
|
+
}
|
|
48
|
+
super.onDisconnect(status, code, reason);
|
|
49
|
+
if (this.socket.state.channelSubscriptions) {
|
|
50
|
+
const channels = Object.keys(this.socket.state.channelSubscriptions);
|
|
51
|
+
channels.map((channel) => this.unsubscribe(channel));
|
|
52
|
+
}
|
|
53
|
+
if (this.streamCleanupMode !== 'none') {
|
|
54
|
+
(async () => {
|
|
55
|
+
await this.socket.listen('end').once();
|
|
56
|
+
if (this.streamCleanupMode === 'kill') {
|
|
57
|
+
this.socket.killListeners();
|
|
58
|
+
}
|
|
59
|
+
else if (this.streamCleanupMode === 'close') {
|
|
60
|
+
this.socket.closeListeners();
|
|
61
|
+
}
|
|
62
|
+
for (let i = 0; i < this.plugins.length; i++) {
|
|
63
|
+
const plugin = this.plugins[i];
|
|
64
|
+
if (plugin.onEnd) {
|
|
65
|
+
plugin.onEnd({ socket: this.socket, transport: this });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
})();
|
|
69
|
+
}
|
|
70
|
+
this.socket.emit('end');
|
|
71
|
+
}
|
|
72
|
+
onError(error) {
|
|
73
|
+
super.onError(error);
|
|
74
|
+
this.socket.server.emit('socketError', { socket: this.socket, error });
|
|
75
|
+
}
|
|
76
|
+
onInvoke(request) {
|
|
77
|
+
if (request.method !== '#publish') {
|
|
78
|
+
super.onInvoke(request);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.onPublish(request.data)
|
|
82
|
+
.then(() => {
|
|
83
|
+
super.onInvoke(request);
|
|
84
|
+
})
|
|
85
|
+
.catch(err => {
|
|
86
|
+
abortRequest(request, err);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
onMessage(data, isBinary) {
|
|
90
|
+
this.socket.server.emit('socketMessage', { socket: this.socket, data, isBinary });
|
|
91
|
+
super.onMessage(data, isBinary);
|
|
92
|
+
}
|
|
93
|
+
/*
|
|
94
|
+
protected override onPing(data: Buffer): void {
|
|
95
|
+
if (this.socket.server.strictHandshake && this.status === 'connecting') {
|
|
96
|
+
this.disconnect(4009);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
super.onPing(data);
|
|
101
|
+
this.socket.server.emit('socketPing', { socket: this.socket, data });
|
|
102
|
+
}
|
|
103
|
+
*/
|
|
104
|
+
onPingPong() {
|
|
105
|
+
if (this.socket.server.strictHandshake && this.status === 'connecting') {
|
|
106
|
+
this.disconnect(4009);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
this.resetPingTimeout(this.socket.server.isPingTimeoutDisabled ? false : this.socket.server.pingTimeoutMs, 4001);
|
|
110
|
+
this.socket.emit('pong', {});
|
|
111
|
+
this.socket.server.emit('socketPong', { socket: this.socket });
|
|
112
|
+
}
|
|
113
|
+
async onPublish(options) {
|
|
114
|
+
let data = options.data;
|
|
115
|
+
for (const plugin of this.plugins) {
|
|
116
|
+
if ('onPublishOut' in plugin) {
|
|
117
|
+
data = await plugin.onPublishOut({ socket: this.socket, transport: this, channel: options.channel, data });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
options.data = data;
|
|
121
|
+
}
|
|
122
|
+
async onRequest(packet, timestamp, pluginError) {
|
|
123
|
+
let wasHandled = false;
|
|
124
|
+
if (!this.service || !('service' in packet) || packet.service === this.service) {
|
|
125
|
+
if (this.socket.server.strictHandshake && this.status === 'connecting' && packet.method !== '#handshake') {
|
|
126
|
+
this.disconnect(4009);
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
wasHandled = await super.onRequest(packet, timestamp, pluginError);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
wasHandled = this.onUnhandledRequest(packet);
|
|
133
|
+
}
|
|
134
|
+
return wasHandled;
|
|
135
|
+
}
|
|
136
|
+
onResponse(response) {
|
|
137
|
+
super.onResponse(response);
|
|
138
|
+
this.socket.server.emit('socketResponse', { socket: this.socket, response });
|
|
139
|
+
}
|
|
140
|
+
onTransmit(request) {
|
|
141
|
+
if (request.method !== '#publish') {
|
|
142
|
+
super.onTransmit(request);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
this.onPublish(request.data)
|
|
146
|
+
.then(() => {
|
|
147
|
+
super.onTransmit(request);
|
|
148
|
+
})
|
|
149
|
+
.catch(err => {
|
|
150
|
+
abortRequest(request, err);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
ping() {
|
|
154
|
+
return this.send('');
|
|
155
|
+
}
|
|
156
|
+
async setAuthorization(authToken, options) {
|
|
157
|
+
const wasAuthenticated = !!this.signedAuthToken;
|
|
158
|
+
if (typeof authToken === 'string') {
|
|
159
|
+
const changed = await super.setAuthorization(authToken, options);
|
|
160
|
+
if (changed && this.status === 'ready') {
|
|
161
|
+
this.triggerAuthenticationEvents(false, wasAuthenticated);
|
|
162
|
+
}
|
|
163
|
+
return changed;
|
|
164
|
+
}
|
|
165
|
+
if (this.status === 'connecting') {
|
|
166
|
+
const err = new InvalidActionError('Cannot call setAuthToken before completing the handshake');
|
|
167
|
+
throw err;
|
|
168
|
+
}
|
|
169
|
+
const auth = this.socket.server.auth;
|
|
170
|
+
const rejectOnFailedDelivery = options?.rejectOnFailedDelivery;
|
|
171
|
+
let signedAuthToken;
|
|
172
|
+
delete options?.rejectOnFailedDelivery;
|
|
173
|
+
try {
|
|
174
|
+
signedAuthToken = await auth.signToken(authToken, options);
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
this.onError(err);
|
|
178
|
+
this.disconnect(4002, err.toString());
|
|
179
|
+
throw err;
|
|
180
|
+
}
|
|
181
|
+
const changed = await super.setAuthorization(signedAuthToken, authToken);
|
|
182
|
+
if (changed && this.status === 'ready') {
|
|
183
|
+
this.triggerAuthenticationEvents(true, wasAuthenticated);
|
|
184
|
+
}
|
|
185
|
+
if (rejectOnFailedDelivery) {
|
|
186
|
+
try {
|
|
187
|
+
await this.invoke('#setAuthToken', signedAuthToken)[0];
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
let error;
|
|
191
|
+
if (err && typeof err.message === 'string') {
|
|
192
|
+
error = new AuthError(`Failed to deliver auth token to client - ${err.message}`);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
error = new AuthError('Failed to confirm delivery of auth token to client due to malformatted error response');
|
|
196
|
+
}
|
|
197
|
+
this.onError(error);
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
await this.transmit('#setAuthToken', signedAuthToken);
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
if (err.name !== 'BadConnectionError') {
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return changed;
|
|
211
|
+
}
|
|
212
|
+
setReadyStatus(pingTimeoutMs, authError) {
|
|
213
|
+
super.setReadyStatus(pingTimeoutMs, authError);
|
|
214
|
+
this.socket.server.emit('socketConnect', { socket: this.socket, pingTimeoutMs, id: this.socket.id, isAuthenticated: !!this.signedAuthToken, authError });
|
|
215
|
+
}
|
|
216
|
+
get socket() {
|
|
217
|
+
return super.socket;
|
|
218
|
+
}
|
|
219
|
+
set socket(value) {
|
|
220
|
+
super.socket = value;
|
|
221
|
+
}
|
|
222
|
+
triggerAuthenticationEvents(wasSigned, wasAuthenticated) {
|
|
223
|
+
super.triggerAuthenticationEvents(wasSigned, wasAuthenticated);
|
|
224
|
+
this.socket.server.emit('socketAuthStateChange', { socket: this.socket, wasAuthenticated, isAuthenticated: true, authToken: this.authToken, signedAuthToken: this.signedAuthToken });
|
|
225
|
+
this.socket.server.emit('socketAuthenticate', { socket: this.socket, wasSigned, signedAuthToken: this.signedAuthToken, authToken: this.authToken });
|
|
226
|
+
}
|
|
227
|
+
async unsubscribe(channel) {
|
|
228
|
+
if (typeof channel !== 'string') {
|
|
229
|
+
throw new InvalidActionError(`Socket ${this.id} tried to unsubscribe from an invalid channel name`);
|
|
230
|
+
}
|
|
231
|
+
if (!this.socket.state.channelSubscriptions?.[channel]) {
|
|
232
|
+
throw new InvalidActionError(`Socket ${this.id} tried to unsubscribe from a channel which it is not subscribed to`);
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const server = this.socket.server;
|
|
236
|
+
await server.brokerEngine.unsubscribe(this, channel);
|
|
237
|
+
delete this.socket.state.channelSubscriptions[channel];
|
|
238
|
+
if (this.socket.state.channelSubscriptionsCount != null) {
|
|
239
|
+
this.socket.state.channelSubscriptionsCount--;
|
|
240
|
+
}
|
|
241
|
+
server.exchange.emit('unsubscribe', { channel });
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
throw new BrokerError(`Failed to unsubscribe socket from the ${channel} channel - ${err}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { ServerSocket } from "./server-socket.js";
|
|
2
|
+
import { Server as HttpServer } from 'http';
|
|
3
|
+
import { CodecEngine } from "@socket-mesh/formatter";
|
|
4
|
+
import { StreamCleanupMode } from "@socket-mesh/core";
|
|
5
|
+
import { AuthEngine } from "@socket-mesh/auth-engine";
|
|
6
|
+
import { ServerPlugin } from "./plugin/server-plugin.js";
|
|
7
|
+
import { CloseEvent, ConnectionEvent, ErrorEvent, HandshakeEvent, HeadersEvent, ListeningEvent, ServerEvent, SocketAuthenticateEvent, SocketAuthStateChangeEvent, SocketBadAuthTokenEvent, SocketCloseEvent, SocketConnectEvent, SocketConnectingEvent, SocketDeauthenticateEvent, SocketDisconnectEvent, SocketErrorEvent, SocketMessageEvent, SocketPingEvent, SocketPongEvent, SocketRemoveAuthTokenEvent, SocketRequestEvent, SocketResponseEvent, SocketSubscribeEvent, SocketSubscribeFailEvent, SocketSubscribeStateChangeEvent, SocketUnsubscribeEvent, WarningEvent } from "./server-event.js";
|
|
8
|
+
import { AsyncStreamEmitter } from "@socket-mesh/async-stream-emitter";
|
|
9
|
+
import { DemuxedConsumableStream, StreamEvent } from "@socket-mesh/stream-demux";
|
|
10
|
+
import { ServerOptions } from "./server-options.js";
|
|
11
|
+
import { ServerMap } from "./maps/server-map.js";
|
|
12
|
+
import { Broker } from "./broker/broker.js";
|
|
13
|
+
import { Exchange } from "./broker/exchange.js";
|
|
14
|
+
export declare class Server<T extends ServerMap> extends AsyncStreamEmitter<ServerEvent<T>> {
|
|
15
|
+
private readonly _callIdGenerator;
|
|
16
|
+
private readonly _wss;
|
|
17
|
+
private _isReady;
|
|
18
|
+
private _isListening;
|
|
19
|
+
private _pingIntervalRef;
|
|
20
|
+
private _handlers;
|
|
21
|
+
ackTimeoutMs: number;
|
|
22
|
+
allowClientPublish: boolean;
|
|
23
|
+
pingIntervalMs: number;
|
|
24
|
+
isPingTimeoutDisabled: boolean;
|
|
25
|
+
origins: string;
|
|
26
|
+
pingTimeoutMs: number;
|
|
27
|
+
socketChannelLimit?: number;
|
|
28
|
+
strictHandshake: boolean;
|
|
29
|
+
readonly auth: AuthEngine;
|
|
30
|
+
readonly brokerEngine: Broker<T['Channel']>;
|
|
31
|
+
readonly clients: {
|
|
32
|
+
[id: string]: ServerSocket<T>;
|
|
33
|
+
};
|
|
34
|
+
clientCount: number;
|
|
35
|
+
readonly codecEngine: CodecEngine;
|
|
36
|
+
readonly pendingClients: {
|
|
37
|
+
[id: string]: ServerSocket<T>;
|
|
38
|
+
};
|
|
39
|
+
pendingClientCount: number;
|
|
40
|
+
readonly socketStreamCleanupMode: StreamCleanupMode;
|
|
41
|
+
readonly httpServer: HttpServer;
|
|
42
|
+
readonly plugins: ServerPlugin<T>[];
|
|
43
|
+
constructor(options?: ServerOptions<T>);
|
|
44
|
+
addPlugin(...plugin: ServerPlugin<T>[]): void;
|
|
45
|
+
private bind;
|
|
46
|
+
close(keepSocketsOpen?: boolean): Promise<void>;
|
|
47
|
+
get exchange(): Exchange<T['Channel']>;
|
|
48
|
+
get isListening(): boolean;
|
|
49
|
+
get isReady(): boolean;
|
|
50
|
+
private onClose;
|
|
51
|
+
private onConnection;
|
|
52
|
+
private onError;
|
|
53
|
+
private onHeaders;
|
|
54
|
+
private onListening;
|
|
55
|
+
private onUnhandledRequest;
|
|
56
|
+
private socketDisconnected;
|
|
57
|
+
private startPinging;
|
|
58
|
+
private stopPinging;
|
|
59
|
+
private verifyClient;
|
|
60
|
+
emit(event: "close", data: CloseEvent): void;
|
|
61
|
+
emit(event: "connection", data: ConnectionEvent<T>): void;
|
|
62
|
+
emit(event: "error", data: ErrorEvent): void;
|
|
63
|
+
emit(event: "headers", data: HeadersEvent): void;
|
|
64
|
+
emit(event: "handshake", data: HandshakeEvent<T>): void;
|
|
65
|
+
emit(event: "listening", data: ListeningEvent): void;
|
|
66
|
+
emit(event: "ready", data: {}): void;
|
|
67
|
+
emit(event: 'socketAuthStateChange', data: SocketAuthStateChangeEvent<T>): void;
|
|
68
|
+
emit(event: 'socketAuthenticate', data: SocketAuthenticateEvent<T>): void;
|
|
69
|
+
emit(event: 'socketBadAuthToken', data: SocketBadAuthTokenEvent<T>): void;
|
|
70
|
+
emit(event: 'socketClose', data: SocketCloseEvent<T>): void;
|
|
71
|
+
emit(event: 'socketConnect', data: SocketConnectEvent<T>): void;
|
|
72
|
+
emit(event: 'socketConnectAbort', data: SocketDisconnectEvent<T>): void;
|
|
73
|
+
emit(event: 'socketConnecting', data: SocketConnectingEvent<T>): void;
|
|
74
|
+
emit(event: 'socketDeauthenticate', data: SocketDeauthenticateEvent<T>): void;
|
|
75
|
+
emit(event: 'socketDisconnect', data: SocketDisconnectEvent<T>): void;
|
|
76
|
+
emit(event: 'socketError', data: SocketErrorEvent<T>): void;
|
|
77
|
+
emit(event: 'socketMessage', data: SocketMessageEvent<T>): void;
|
|
78
|
+
emit(event: 'socketPing', data: SocketPingEvent<T>): void;
|
|
79
|
+
emit(event: 'socketPong', data: SocketPongEvent<T>): void;
|
|
80
|
+
emit(event: 'socketRemoveAuthToken', data: SocketRemoveAuthTokenEvent<T>): void;
|
|
81
|
+
emit(event: 'socketRequest', data: SocketRequestEvent<T>): void;
|
|
82
|
+
emit(event: 'socketResponse', data: SocketResponseEvent<T>): void;
|
|
83
|
+
emit(event: 'socketSubscribe', data: SocketSubscribeEvent<T>): void;
|
|
84
|
+
emit(event: 'socketSubscribeFail', data: SocketSubscribeFailEvent<T>): void;
|
|
85
|
+
emit(event: 'socketSubscribeRequest', data: SocketSubscribeEvent<T>): void;
|
|
86
|
+
emit(event: 'socketSubscribeStateChange', data: SocketSubscribeStateChangeEvent<T>): void;
|
|
87
|
+
emit(event: 'socketUnsubscribe', data: SocketUnsubscribeEvent<T>): void;
|
|
88
|
+
emit(event: "warning", data: WarningEvent): void;
|
|
89
|
+
listen(): DemuxedConsumableStream<StreamEvent<ServerEvent<T>>>;
|
|
90
|
+
listen(event: "close"): DemuxedConsumableStream<CloseEvent>;
|
|
91
|
+
listen(event: "connection"): DemuxedConsumableStream<ConnectionEvent<T>>;
|
|
92
|
+
listen(event: "error"): DemuxedConsumableStream<ErrorEvent>;
|
|
93
|
+
listen(event: "handshake"): DemuxedConsumableStream<HandshakeEvent<T>>;
|
|
94
|
+
listen(event: "headers"): DemuxedConsumableStream<HeadersEvent>;
|
|
95
|
+
listen(event: "listening"): DemuxedConsumableStream<ListeningEvent>;
|
|
96
|
+
listen(event: "ready"): DemuxedConsumableStream<{}>;
|
|
97
|
+
listen(event: 'socketAuthStateChange'): DemuxedConsumableStream<SocketAuthStateChangeEvent<T>>;
|
|
98
|
+
listen(event: 'socketAuthenticate'): DemuxedConsumableStream<SocketAuthenticateEvent<T>>;
|
|
99
|
+
listen(event: 'socketBadAuthToken'): DemuxedConsumableStream<SocketBadAuthTokenEvent<T>>;
|
|
100
|
+
listen(event: 'socketClose'): DemuxedConsumableStream<SocketCloseEvent<T>>;
|
|
101
|
+
listen(event: 'socketConnect'): DemuxedConsumableStream<SocketConnectEvent<T>>;
|
|
102
|
+
listen(event: 'socketConnectAbort'): DemuxedConsumableStream<SocketDisconnectEvent<T>>;
|
|
103
|
+
listen(event: 'socketConnecting'): DemuxedConsumableStream<SocketConnectingEvent<T>>;
|
|
104
|
+
listen(event: 'socketDeauthenticate'): DemuxedConsumableStream<SocketDeauthenticateEvent<T>>;
|
|
105
|
+
listen(event: 'socketDisconnect'): DemuxedConsumableStream<SocketDisconnectEvent<T>>;
|
|
106
|
+
listen(event: 'socketError'): DemuxedConsumableStream<SocketErrorEvent<T>>;
|
|
107
|
+
listen(event: 'socketMessage'): DemuxedConsumableStream<SocketMessageEvent<T>>;
|
|
108
|
+
listen(event: 'socketPing'): DemuxedConsumableStream<SocketPingEvent<T>>;
|
|
109
|
+
listen(event: 'socketPong'): DemuxedConsumableStream<SocketPongEvent<T>>;
|
|
110
|
+
listen(event: 'socketRemoveAuthToken'): DemuxedConsumableStream<SocketRemoveAuthTokenEvent<T>>;
|
|
111
|
+
listen(event: 'socketRequest'): DemuxedConsumableStream<SocketRequestEvent<T>>;
|
|
112
|
+
listen(event: 'socketResponse'): DemuxedConsumableStream<SocketResponseEvent<T>>;
|
|
113
|
+
listen(event: 'socketSubscribe'): DemuxedConsumableStream<SocketSubscribeEvent<T>>;
|
|
114
|
+
listen(event: 'socketSubscribeFail'): DemuxedConsumableStream<SocketSubscribeFailEvent<T>>;
|
|
115
|
+
listen(event: 'socketSubscribeRequest'): DemuxedConsumableStream<SocketSubscribeEvent<T>>;
|
|
116
|
+
listen(event: 'socketSubscribeStateChange'): DemuxedConsumableStream<SocketSubscribeStateChangeEvent<T>>;
|
|
117
|
+
listen(event: 'socketUnsubscribe'): DemuxedConsumableStream<SocketUnsubscribeEvent<T>>;
|
|
118
|
+
listen(event: "warning"): DemuxedConsumableStream<WarningEvent>;
|
|
119
|
+
}
|