@linebridge/engine-neo 1.1.0 → 1.3.0
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 +2 -3
- package/lib/engine.d.ts +5 -3
- package/lib/engine.js +14 -9
- package/lib/listen.js +3 -1
- package/lib/request_iterator.d.ts +2 -2
- package/lib/response.d.ts +12 -3
- package/lib/response.js +153 -130
- package/lib/route_register.d.ts +3 -3
- package/lib/route_register.js +14 -48
- package/lib/utils.d.ts +1 -1
- package/lib/ws/Websocket.d.ts +70 -118
- package/lib/ws/Websocket.js +81 -209
- package/lib/ws/WebsocketRoute.d.ts +86 -0
- package/lib/ws/WebsocketRoute.js +139 -0
- package/package.json +2 -2
package/lib/route_register.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { Route, } from "linebridge/classes/Route/index";
|
|
2
|
-
import { HandlerKind } from "linebridge/classes/Handler/index";
|
|
3
1
|
/**
|
|
4
2
|
* Registers a route with the engine's uWS app.
|
|
5
3
|
*
|
|
@@ -11,57 +9,25 @@ export default function (route) {
|
|
|
11
9
|
if (!this.uws) {
|
|
12
10
|
throw new Error("Engine is not initialized");
|
|
13
11
|
}
|
|
14
|
-
let routeInstance;
|
|
15
|
-
// support passing a class constructor or an already-constructed instance
|
|
16
|
-
if (typeof route === "function") {
|
|
17
|
-
try {
|
|
18
|
-
routeInstance = new route();
|
|
19
|
-
}
|
|
20
|
-
catch (err) {
|
|
21
|
-
console.error(`Failed to construct route class:\n`, err);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
else if (route instanceof Route) {
|
|
26
|
-
routeInstance = route;
|
|
27
|
-
}
|
|
28
|
-
else if (typeof route.fn === "function") {
|
|
29
|
-
routeInstance = new Route();
|
|
30
|
-
routeInstance.kind = HandlerKind.http;
|
|
31
|
-
routeInstance.path = route.path ?? "/";
|
|
32
|
-
routeInstance.method = route.method ?? "get";
|
|
33
|
-
routeInstance.useContexts = route.useContexts ?? [];
|
|
34
|
-
routeInstance.useMiddlewares = route.useMiddlewares ?? [];
|
|
35
|
-
routeInstance.fn = route.fn;
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
throw new Error("Invalid route provided");
|
|
39
|
-
}
|
|
40
|
-
// try to initialize the route
|
|
41
|
-
try {
|
|
42
|
-
routeInstance._initialize(this.server);
|
|
43
|
-
}
|
|
44
|
-
catch (err) {
|
|
45
|
-
console.error(`Failed to initialize route:\n`, err);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
12
|
// normalize DELETE method for uWS compatibility (uWS uses "del" internally)
|
|
49
|
-
if (
|
|
50
|
-
|
|
13
|
+
if (route.method === "delete") {
|
|
14
|
+
route.method = "del";
|
|
51
15
|
}
|
|
52
16
|
// verify the method is a valid uWS route method before registering
|
|
53
|
-
if (typeof this.uws[
|
|
54
|
-
console.warn(`Invalid method (${
|
|
17
|
+
if (typeof this.uws[route.method] !== "function") {
|
|
18
|
+
console.warn(`Invalid method (${route.method}) for route handler [${route.path}]\nSkipping route..`);
|
|
55
19
|
return;
|
|
56
20
|
}
|
|
57
21
|
this.registers.add({
|
|
58
|
-
kind:
|
|
59
|
-
method:
|
|
60
|
-
path:
|
|
61
|
-
useContexts:
|
|
62
|
-
useMiddlewares:
|
|
63
|
-
_source_file:
|
|
64
|
-
handler:
|
|
22
|
+
kind: route.kind,
|
|
23
|
+
method: route.method,
|
|
24
|
+
path: route.path,
|
|
25
|
+
useContexts: route.useContexts,
|
|
26
|
+
useMiddlewares: route.useMiddlewares,
|
|
27
|
+
_source_file: route._source_file,
|
|
28
|
+
handler: route.handler,
|
|
65
29
|
});
|
|
66
|
-
|
|
30
|
+
if (route.kind === "http") {
|
|
31
|
+
this.uws[route.method](route.path, (res, req) => this.on_request(req, res, route));
|
|
32
|
+
}
|
|
67
33
|
}
|
package/lib/utils.d.ts
CHANGED
|
@@ -10,5 +10,5 @@ declare function wrap_object(original: any, target: any): void;
|
|
|
10
10
|
* @param {BufferEncoding} encoding
|
|
11
11
|
* @returns {String} String
|
|
12
12
|
*/
|
|
13
|
-
declare function array_buffer_to_string(array_buffer: ArrayBuffer, encoding?: BufferEncoding):
|
|
13
|
+
declare function array_buffer_to_string(array_buffer: ArrayBuffer, encoding?: BufferEncoding): string;
|
|
14
14
|
export { array_buffer_to_string, wrap_object };
|
package/lib/ws/Websocket.d.ts
CHANGED
|
@@ -1,173 +1,125 @@
|
|
|
1
1
|
import { EventEmitter } from "tseep/lib/ee-safe.js";
|
|
2
|
-
import { Readable, Writable } from "stream";
|
|
3
|
-
|
|
2
|
+
import { Readable, Writable } from "node:stream";
|
|
3
|
+
import type { uWebsockets } from "../uws.js";
|
|
4
|
+
/** Any payload accepted by uWebSockets or produced by streams. */
|
|
5
|
+
export type WebsocketMessage = string | Buffer | ArrayBuffer | ArrayBufferView;
|
|
6
|
+
/** Events emitted by the websocket polyfill. */
|
|
7
|
+
export type WebsocketEventMap = {
|
|
8
|
+
[event in string | symbol]: (...args: any[]) => void;
|
|
9
|
+
} & {
|
|
10
|
+
message: (message: WebsocketMessage, is_binary: boolean) => void;
|
|
11
|
+
close: (code: number, message: WebsocketMessage) => void;
|
|
12
|
+
drain: () => void;
|
|
13
|
+
ping: (message: WebsocketMessage) => void;
|
|
14
|
+
pong: (message: WebsocketMessage) => void;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Raw uws websocket with the context and polyfill attached by the engine.
|
|
18
|
+
* The native wrapper merges the upgrade user data into the socket object.
|
|
19
|
+
*/
|
|
20
|
+
export interface WebsocketRaw<TContext = Record<string, any>> extends uWebsockets.WebSocket<{
|
|
21
|
+
context?: TContext;
|
|
22
|
+
}> {
|
|
23
|
+
context?: TContext;
|
|
24
|
+
poly?: Websocket<TContext>;
|
|
25
|
+
}
|
|
26
|
+
declare const FRAGMENTS: {
|
|
27
|
+
readonly FIRST: "FIRST";
|
|
28
|
+
readonly MIDDLE: "MIDDLE";
|
|
29
|
+
readonly LAST: "LAST";
|
|
30
|
+
};
|
|
31
|
+
type Fragment = (typeof FRAGMENTS)[keyof typeof FRAGMENTS];
|
|
32
|
+
export default class Websocket<TContext = Record<string, any>> extends EventEmitter<WebsocketEventMap> {
|
|
4
33
|
#private;
|
|
5
|
-
constructor(ws:
|
|
6
|
-
/**
|
|
7
|
-
* Binds an event listener to this `Websocket` instance.
|
|
8
|
-
* See the Node.js `EventEmitter` documentation for more details on this extended method.
|
|
9
|
-
* @param {('message'|'close'|'drain'|'ping'|'pong')} eventName
|
|
10
|
-
* @param {Function} listener
|
|
11
|
-
* @returns {Websocket}
|
|
12
|
-
*/
|
|
13
|
-
on(eventName: ('message' | 'close' | 'drain' | 'ping' | 'pong'), listener: Function): Websocket;
|
|
14
|
-
/**
|
|
15
|
-
* Binds a `one-time` event listener to this `Websocket` instance.
|
|
16
|
-
* See the Node.js `EventEmitter` documentation for more details on this extended method.
|
|
17
|
-
* @param {('message'|'close'|'drain'|'ping'|'pong')} eventName
|
|
18
|
-
* @param {Function} listener
|
|
19
|
-
* @returns {Websocket}
|
|
20
|
-
*/
|
|
21
|
-
once(eventName: ('message' | 'close' | 'drain' | 'ping' | 'pong'), listener: Function): Websocket;
|
|
34
|
+
constructor(ws: WebsocketRaw<TContext>);
|
|
22
35
|
/**
|
|
23
|
-
* Alias of
|
|
24
|
-
*
|
|
25
|
-
* @param {Function} callback
|
|
26
|
-
* @returns {Websocket}
|
|
36
|
+
* Alias of uws cork, used to batch multiple operations for efficiency.
|
|
27
37
|
*/
|
|
28
|
-
atomic(callback:
|
|
38
|
+
atomic(callback: () => void): Websocket<TContext> | uWebsockets.WebSocket<{
|
|
39
|
+
context?: TContext;
|
|
40
|
+
}>;
|
|
29
41
|
/**
|
|
30
|
-
* Sends a message
|
|
31
|
-
* Returns
|
|
32
|
-
* Returns false if message was not sent due to buil up backpressure.
|
|
33
|
-
*
|
|
34
|
-
* @param {String|Buffer|ArrayBuffer} message
|
|
35
|
-
* @param {Boolean=} is_binary
|
|
36
|
-
* @param {Boolean=} compress
|
|
37
|
-
* @returns {Boolean}
|
|
42
|
+
* Sends a message over the connection.
|
|
43
|
+
* Returns the uws send status, or false when the socket is closed.
|
|
38
44
|
*/
|
|
39
|
-
send(message:
|
|
45
|
+
send(message: WebsocketMessage, is_binary?: boolean, compress?: boolean): number | false;
|
|
40
46
|
/**
|
|
41
47
|
* Sends a ping control message.
|
|
42
|
-
* Returns Boolean depending on backpressure similar to send().
|
|
43
|
-
*
|
|
44
|
-
* @param {String|Buffer|ArrayBuffer=} message
|
|
45
|
-
* @returns {Boolean}
|
|
46
48
|
*/
|
|
47
|
-
ping(message?:
|
|
49
|
+
ping(message?: WebsocketMessage): number | false;
|
|
48
50
|
/**
|
|
49
|
-
* Destroys this polyfill
|
|
51
|
+
* Destroys this polyfill and dereferences the underlying socket.
|
|
50
52
|
* @private
|
|
51
53
|
*/
|
|
52
|
-
|
|
54
|
+
_destroy(): void;
|
|
53
55
|
/**
|
|
54
|
-
* Gracefully closes
|
|
55
|
-
*
|
|
56
|
-
* @param {Number=} code
|
|
57
|
-
* @param {(String|Buffer|ArrayBuffer)=} message
|
|
56
|
+
* Gracefully closes the connection, sending an optional code and message.
|
|
58
57
|
*/
|
|
59
|
-
close(code?: number
|
|
58
|
+
close(code?: number, message?: WebsocketMessage): void;
|
|
60
59
|
/**
|
|
61
|
-
* Forcefully closes
|
|
62
|
-
* No websocket close code/message is sent.
|
|
63
|
-
* This will immediately emit the 'close' event.
|
|
60
|
+
* Forcefully closes the connection without a close message.
|
|
64
61
|
*/
|
|
65
62
|
destroy(): void;
|
|
66
63
|
/**
|
|
67
|
-
* Returns whether this
|
|
68
|
-
*
|
|
69
|
-
* @param {String} topic
|
|
70
|
-
* @returns {Boolean}
|
|
64
|
+
* Returns whether this connection is subscribed to the topic.
|
|
71
65
|
*/
|
|
72
66
|
is_subscribed(topic: string): boolean;
|
|
73
67
|
/**
|
|
74
|
-
*
|
|
75
|
-
* MQTT syntax includes things like "root/child/+/grandchild" where "+" is a wildcard and "root/#" where "#" is a terminating wildcard.
|
|
76
|
-
*
|
|
77
|
-
* @param {String} topic
|
|
78
|
-
* @returns {Boolean}
|
|
68
|
+
* Subscribes to a topic in mqtt syntax.
|
|
79
69
|
*/
|
|
80
70
|
subscribe(topic: string): boolean;
|
|
81
71
|
/**
|
|
82
|
-
*
|
|
83
|
-
* Returns true on success, if the WebSocket was subscribed.
|
|
84
|
-
*
|
|
85
|
-
* @param {String} topic
|
|
86
|
-
* @returns {Boolean}
|
|
72
|
+
* Unsubscribes from a topic.
|
|
87
73
|
*/
|
|
88
74
|
unsubscribe(topic: string): boolean;
|
|
89
75
|
/**
|
|
90
|
-
*
|
|
91
|
-
* You cannot publish using wildcards, only fully specified topics.
|
|
92
|
-
*
|
|
93
|
-
* @param {String} topic
|
|
94
|
-
* @param {String|Buffer|ArrayBuffer} message
|
|
95
|
-
* @param {Boolean=} is_binary
|
|
96
|
-
* @param {Boolean=} compress
|
|
76
|
+
* Publishes a message to a topic in mqtt syntax.
|
|
97
77
|
*/
|
|
98
|
-
publish(topic: string, message:
|
|
78
|
+
publish(topic: string, message: WebsocketMessage, is_binary?: boolean, compress?: boolean): boolean;
|
|
99
79
|
/**
|
|
100
|
-
* Buffers the provided fragment and returns the
|
|
101
|
-
*
|
|
102
|
-
* @param {String|Buffer|ArrayBuffer} fragment
|
|
103
|
-
* @returns {String|Buffer|ArrayBuffer|undefined}
|
|
80
|
+
* Buffers the provided fragment and returns the previously buffered one.
|
|
104
81
|
*/
|
|
105
|
-
_buffer_fragment(fragment
|
|
82
|
+
_buffer_fragment(fragment?: WebsocketMessage): WebsocketMessage | undefined;
|
|
106
83
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* @param {String} type
|
|
110
|
-
* @param {String|Buffer|ArrayBuffer} chunk
|
|
111
|
-
* @param {Boolean=} is_binary
|
|
112
|
-
* @param {Boolean=} compress
|
|
113
|
-
* @param {Function=} callback
|
|
114
|
-
* @returns {Boolean}
|
|
84
|
+
* Writes a fragment using the appropriate uws fragment method.
|
|
115
85
|
*/
|
|
116
|
-
_write(type:
|
|
86
|
+
_write(type: Fragment, chunk: WebsocketMessage, is_binary?: boolean, compress?: boolean, callback?: () => void): number;
|
|
117
87
|
/**
|
|
118
|
-
* Streams
|
|
119
|
-
*
|
|
120
|
-
* @param {Readable} stream
|
|
121
|
-
* @param {String} type
|
|
122
|
-
* @param {Buffer|ArrayBuffer} chunk
|
|
123
|
-
* @param {Boolean} is_binary
|
|
88
|
+
* Streams a chunk, pausing the source stream while under backpressure.
|
|
124
89
|
*/
|
|
125
|
-
_stream_chunk(stream: Readable, type:
|
|
90
|
+
_stream_chunk(stream: Readable, type: Fragment, chunk: WebsocketMessage, is_binary: boolean): void;
|
|
126
91
|
/**
|
|
127
|
-
*
|
|
128
|
-
* Note! The data is by default streamed as Binary due to how partial fragments are sent.
|
|
129
|
-
* This is done to prevent processing errors depending on client's receiver's incoming fragment processing strategy.
|
|
130
|
-
*
|
|
131
|
-
* @param {Readable} readable A Readable stream which will be consumed as message
|
|
132
|
-
* @param {Boolean=} is_binary Whether data being streamed is in binary. Default: true
|
|
133
|
-
* @returns {Promise}
|
|
92
|
+
* Streams a readable as a single fragmented message.
|
|
134
93
|
*/
|
|
135
|
-
stream(readable: Readable, is_binary?: boolean
|
|
94
|
+
stream(readable: Readable, is_binary?: boolean): Promise<void>;
|
|
136
95
|
/**
|
|
137
|
-
* Underlying
|
|
96
|
+
* Underlying uws websocket object.
|
|
138
97
|
*/
|
|
139
|
-
get raw():
|
|
98
|
+
get raw(): WebsocketRaw<TContext> | null;
|
|
140
99
|
/**
|
|
141
|
-
*
|
|
142
|
-
* @returns {String}
|
|
100
|
+
* Remote ip address of this connection.
|
|
143
101
|
*/
|
|
144
102
|
get ip(): string;
|
|
145
103
|
/**
|
|
146
|
-
*
|
|
147
|
-
* @returns {Object}
|
|
104
|
+
* Context values attached during the upgrade.
|
|
148
105
|
*/
|
|
149
|
-
get context():
|
|
106
|
+
get context(): TContext;
|
|
150
107
|
/**
|
|
151
|
-
*
|
|
152
|
-
* @returns {Boolean}
|
|
108
|
+
* Whether this connection is closed.
|
|
153
109
|
*/
|
|
154
110
|
get closed(): boolean;
|
|
155
111
|
/**
|
|
156
|
-
*
|
|
157
|
-
* This is similar to the bufferedAmount property in the browser counterpart.
|
|
158
|
-
* @returns {Number}
|
|
112
|
+
* Bytes currently buffered in backpressure.
|
|
159
113
|
*/
|
|
160
114
|
get buffered(): number;
|
|
161
115
|
/**
|
|
162
|
-
*
|
|
163
|
-
* @returns {Array<String>}
|
|
116
|
+
* Topics this connection is subscribed to.
|
|
164
117
|
*/
|
|
165
|
-
get topics():
|
|
118
|
+
get topics(): string[];
|
|
166
119
|
/**
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* @returns {Writable}
|
|
120
|
+
* Writable stream bound to this connection for piping.
|
|
121
|
+
* Only one writable can be used at a time.
|
|
171
122
|
*/
|
|
172
123
|
get writable(): Writable;
|
|
173
124
|
}
|
|
125
|
+
export {};
|