http-air 1.3.3 → 1.3.5
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 +9 -0
- package/lib/client/events.d.ts +1 -0
- package/lib/client/events.js +12 -3
- package/lib/server/events.d.ts +4 -1
- package/lib/server/events.js +15 -1
- package/lib/server/index.d.ts +1 -0
- package/lib/server/server.d.ts +2 -0
- package/lib/server/server.js +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,6 +80,12 @@ server.handleRpc(async ({ method, params }) => {
|
|
|
80
80
|
return myService[method](...params)
|
|
81
81
|
})
|
|
82
82
|
|
|
83
|
+
// validate session before accepting an events connection
|
|
84
|
+
server.handleEventsConnect(async (req, res) => {
|
|
85
|
+
const token = req.getHeader('authorization')
|
|
86
|
+
if (!isValid(token)) throw new Error('unauthorized')
|
|
87
|
+
})
|
|
88
|
+
|
|
83
89
|
// push to all subscribers whenever something happens
|
|
84
90
|
server.notifyEvent('price-update', { symbol: 'BTC', price: 70000 })
|
|
85
91
|
```
|
|
@@ -157,6 +163,9 @@ const router = new Router()
|
|
|
157
163
|
const rpc = new RpcServer(router)
|
|
158
164
|
rpc.handle(handler)
|
|
159
165
|
const events = new EventsServer(router)
|
|
166
|
+
events.handleEventsConnect(async (req, res) => {
|
|
167
|
+
if (!isValid(req.getHeader('authorization'))) throw new Error('unauthorized')
|
|
168
|
+
})
|
|
160
169
|
```
|
|
161
170
|
|
|
162
171
|
---
|
package/lib/client/events.d.ts
CHANGED
package/lib/client/events.js
CHANGED
|
@@ -54,6 +54,7 @@ class EventsClient {
|
|
|
54
54
|
response;
|
|
55
55
|
abortController;
|
|
56
56
|
status = Status.Disconnected;
|
|
57
|
+
connectionGen = 0;
|
|
57
58
|
listenersMap = new Map();
|
|
58
59
|
subscribedSet = new Set();
|
|
59
60
|
subscribeBatch;
|
|
@@ -103,12 +104,19 @@ class EventsClient {
|
|
|
103
104
|
if (this.status !== Status.Disconnected)
|
|
104
105
|
return;
|
|
105
106
|
this.status = Status.Connecting;
|
|
106
|
-
|
|
107
|
+
const gen = ++this.connectionGen;
|
|
108
|
+
return (0, p_retry_1.default)(() => this.performConnect(gen), {
|
|
107
109
|
retries: connectRetries,
|
|
108
|
-
onFailedAttempt: () => {
|
|
110
|
+
onFailedAttempt: () => {
|
|
111
|
+
if (this.connectionGen !== gen)
|
|
112
|
+
throw new p_retry_1.AbortError(new Error('cancelled'));
|
|
113
|
+
this.status = Status.Disconnected;
|
|
114
|
+
},
|
|
109
115
|
});
|
|
110
116
|
}
|
|
111
|
-
async performConnect() {
|
|
117
|
+
async performConnect(gen) {
|
|
118
|
+
if (this.connectionGen !== gen)
|
|
119
|
+
return;
|
|
112
120
|
if (this.status === Status.Connected)
|
|
113
121
|
return;
|
|
114
122
|
const [pResponse, abortController] = this.fetcher({ action: 'events-connect' });
|
|
@@ -178,6 +186,7 @@ class EventsClient {
|
|
|
178
186
|
}
|
|
179
187
|
}
|
|
180
188
|
disconnect() {
|
|
189
|
+
this.connectionGen++;
|
|
181
190
|
this.status = Status.Disconnected;
|
|
182
191
|
this.abortController?.abort();
|
|
183
192
|
this.listenersMap.forEach((_, name) => this.unsubscribeBatch.add(name));
|
package/lib/server/events.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { Router } from './router';
|
|
1
|
+
import { Router, ServerReq, ServerRes } from './router';
|
|
2
|
+
export type EventsConnectHandler = (req: ServerReq, res: ServerRes) => Promise<void> | void;
|
|
2
3
|
export declare class EventsServer {
|
|
3
4
|
readonly serverId: string;
|
|
5
|
+
private connectHandler;
|
|
4
6
|
private responsesMap;
|
|
5
7
|
private messageQueueMap;
|
|
6
8
|
private drainingSet;
|
|
7
9
|
private listenersMap;
|
|
8
10
|
private heartbeatInterval;
|
|
9
11
|
constructor(server: Router);
|
|
12
|
+
handleEventsConnect(handler: EventsConnectHandler): void;
|
|
10
13
|
notify(eventName: string, data: any): void;
|
|
11
14
|
private push;
|
|
12
15
|
private drain;
|
package/lib/server/events.js
CHANGED
|
@@ -6,6 +6,7 @@ const json_stream_1 = require("../shared/json-stream");
|
|
|
6
6
|
const stream_constants_1 = require("../shared/stream-constants");
|
|
7
7
|
class EventsServer {
|
|
8
8
|
serverId = (0, crypto_1.randomBytes)(16).toString('base64url');
|
|
9
|
+
connectHandler;
|
|
9
10
|
responsesMap = new Map();
|
|
10
11
|
messageQueueMap = new Map();
|
|
11
12
|
drainingSet = new Set();
|
|
@@ -16,6 +17,9 @@ class EventsServer {
|
|
|
16
17
|
server.setHandler('events-subscribe', this.handleSubscribe.bind(this));
|
|
17
18
|
server.setHandler('events-unsubscribe', this.handleUnsubscribe.bind(this));
|
|
18
19
|
}
|
|
20
|
+
handleEventsConnect(handler) {
|
|
21
|
+
this.connectHandler = handler;
|
|
22
|
+
}
|
|
19
23
|
notify(eventName, data) {
|
|
20
24
|
const sessions = this.listenersMap.get(eventName) ?? [];
|
|
21
25
|
sessions.forEach(sessionId => this.push(sessionId, { type: 'event', name: eventName, data }));
|
|
@@ -86,7 +90,17 @@ class EventsServer {
|
|
|
86
90
|
parser.close();
|
|
87
91
|
return names;
|
|
88
92
|
}
|
|
89
|
-
handleConnect(req, res) {
|
|
93
|
+
async handleConnect(req, res) {
|
|
94
|
+
if (this.connectHandler) {
|
|
95
|
+
try {
|
|
96
|
+
await this.connectHandler(req, res);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
res.writeHead(401, {});
|
|
100
|
+
res.end();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
90
104
|
let sessionId = req.getHeader(stream_constants_1.SESSION_ID_KEY).trim();
|
|
91
105
|
if (!sessionId.startsWith(stream_constants_1.SESSION_ID_PREFIX)) {
|
|
92
106
|
sessionId = stream_constants_1.SESSION_ID_PREFIX + (0, crypto_1.randomBytes)(60).toString('base64url');
|
package/lib/server/index.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ export { Server } from './server';
|
|
|
2
2
|
export { RpcServer } from './rpc';
|
|
3
3
|
export type { RpcHandler } from './rpc';
|
|
4
4
|
export { EventsServer } from './events';
|
|
5
|
+
export type { EventsConnectHandler } from './events';
|
|
5
6
|
export { Router } from './router';
|
|
6
7
|
export type { ServerReq, ServerRes, HttpHandler } from './router';
|
package/lib/server/server.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HttpHandler, Router, ServerReq, ServerRes } from './router';
|
|
2
2
|
import { RpcHandler } from './rpc';
|
|
3
|
+
import { EventsConnectHandler } from './events';
|
|
3
4
|
export { ServerReq, ServerRes, HttpHandler, Router };
|
|
4
5
|
export declare class Server implements HttpHandler {
|
|
5
6
|
private router;
|
|
@@ -7,6 +8,7 @@ export declare class Server implements HttpHandler {
|
|
|
7
8
|
private eventsServer;
|
|
8
9
|
constructor();
|
|
9
10
|
handleRpc(handler: RpcHandler): void;
|
|
11
|
+
handleEventsConnect(handler: EventsConnectHandler): void;
|
|
10
12
|
notifyEvent(eventName: string, data: any): void;
|
|
11
13
|
handleHttp(req: ServerReq, res: ServerRes): void;
|
|
12
14
|
}
|
package/lib/server/server.js
CHANGED
package/package.json
CHANGED