@webda/fs 4.0.0-beta.3

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.
@@ -0,0 +1,348 @@
1
+ import { PubSubService, ServiceParameters } from "@webda/core";
2
+ import { CancelablePromise, JSONUtils } from "@webda/utils";
3
+ import { useLog } from "@webda/workout";
4
+ import { existsSync, mkdirSync, unlinkSync } from "fs";
5
+ import * as net from "net";
6
+ import { dirname } from "path";
7
+ /**
8
+ * Configuration for {@link SocketPubSubService}.
9
+ */
10
+ export class SocketPubSubParameters extends ServiceParameters {
11
+ /**
12
+ * Filesystem path of the unix-domain socket. The first peer to bind this
13
+ * path becomes the broker; subsequent peers connect as clients.
14
+ */
15
+ path;
16
+ /**
17
+ * Reconnect delay in milliseconds when the broker disconnects. A small
18
+ * random jitter is added on top to avoid stampedes when several clients
19
+ * race to bind a new socket.
20
+ *
21
+ * @default 100
22
+ */
23
+ reconnectDelay;
24
+ /**
25
+ * @override
26
+ * @param params - the input parameters
27
+ * @returns this
28
+ */
29
+ load(params = {}) {
30
+ super.load(params);
31
+ this.reconnectDelay ??= 100;
32
+ return this;
33
+ }
34
+ }
35
+ /**
36
+ * Pub/sub backed by a unix-domain socket. Designed for single-host IPC:
37
+ * one peer binds the socket file and acts as broker, fanning each
38
+ * published message out to every connected client; other peers connect as
39
+ * clients. Any peer can publish — non-broker publishers send through the
40
+ * socket and the broker fanouts. Every connected peer (publisher
41
+ * included) receives every message, so the in-process semantics match the
42
+ * cross-process ones.
43
+ *
44
+ * If the broker disconnects, surviving clients reconnect after a short
45
+ * randomized delay; one of them wins the bind race and becomes the new
46
+ * broker. Stale socket files left by killed brokers are detected via
47
+ * `connect()` returning ECONNREFUSED and unlinked before re-binding.
48
+ *
49
+ * Wire format: 4-byte big-endian uint32 length prefix followed by a UTF-8
50
+ * JSON payload.
51
+ *
52
+ * @WebdaModda SocketPubSub
53
+ */
54
+ export default class SocketPubSubService extends PubSubService {
55
+ /**
56
+ * Broker-mode listener. Set when this peer is the broker, undefined
57
+ * otherwise. Mutually exclusive with {@link clientSocket}.
58
+ */
59
+ server;
60
+ /**
61
+ * Outbound socket to the broker, when this peer is a client.
62
+ */
63
+ clientSocket;
64
+ /**
65
+ * Active subscriber sockets the broker fans messages out to.
66
+ */
67
+ subscribers = new Set();
68
+ /**
69
+ * Local callback registrations made via {@link consume}. The broker
70
+ * dispatches to these directly; client-mode peers feed them from the
71
+ * broker socket's incoming frames.
72
+ */
73
+ callbacks = new Set();
74
+ /**
75
+ * Set during {@link stop} so disconnect handlers don't try to reconnect
76
+ * after we've torn down.
77
+ */
78
+ stopping = false;
79
+ /**
80
+ * @override
81
+ * @returns this service
82
+ */
83
+ async init() {
84
+ await super.init();
85
+ await this.connect();
86
+ return this;
87
+ }
88
+ /**
89
+ * Connect to an existing broker, or bind ourselves as broker if there
90
+ * isn't one. Handles the EADDRINUSE race by retrying as a client.
91
+ */
92
+ async connect() {
93
+ const path = this.parameters.path;
94
+ try {
95
+ await this.connectAsClient(path);
96
+ return;
97
+ }
98
+ catch (err) {
99
+ const code = err.code;
100
+ if (code !== "ENOENT" && code !== "ECONNREFUSED")
101
+ throw err;
102
+ // Stale socket file or no listener — clean up before binding.
103
+ if (existsSync(path)) {
104
+ try {
105
+ unlinkSync(path);
106
+ }
107
+ catch {
108
+ /* race: another peer may have already removed it */
109
+ }
110
+ }
111
+ }
112
+ try {
113
+ await this.bindAsBroker(path);
114
+ }
115
+ catch (err) {
116
+ if (err.code === "EADDRINUSE") {
117
+ await this.connectAsClient(path);
118
+ return;
119
+ }
120
+ throw err;
121
+ }
122
+ }
123
+ /**
124
+ * Bind the socket file and start listening. On every accepted connection
125
+ * we frame-decode incoming bytes, fanout the raw frame to all OTHER
126
+ * subscribers, and dispatch the parsed payload to local callbacks.
127
+ * @param path - filesystem path of the unix socket
128
+ * @returns resolves once the listener is up
129
+ */
130
+ bindAsBroker(path) {
131
+ const dir = dirname(path);
132
+ if (!existsSync(dir))
133
+ mkdirSync(dir, { recursive: true });
134
+ return new Promise((resolve, reject) => {
135
+ const server = net.createServer(socket => {
136
+ this.subscribers.add(socket);
137
+ const reader = makeFrameReader(buf => {
138
+ this.fanout(buf, socket);
139
+ this.dispatchToCallbacks(buf);
140
+ });
141
+ socket.on("data", reader);
142
+ socket.on("close", () => this.subscribers.delete(socket));
143
+ socket.on("error", () => this.subscribers.delete(socket));
144
+ });
145
+ server.once("error", reject);
146
+ server.listen(path, () => {
147
+ this.server = server;
148
+ resolve();
149
+ });
150
+ });
151
+ }
152
+ /**
153
+ * Open a client socket to the broker.
154
+ * @param path - filesystem path of the unix socket
155
+ * @returns resolves once connected, rejects on the first connection error
156
+ */
157
+ connectAsClient(path) {
158
+ return new Promise((resolve, reject) => {
159
+ const socket = net.createConnection(path);
160
+ const onError = (err) => {
161
+ socket.removeAllListeners();
162
+ socket.destroy();
163
+ reject(err);
164
+ };
165
+ socket.once("error", onError);
166
+ socket.once("connect", () => {
167
+ socket.removeListener("error", onError);
168
+ this.clientSocket = socket;
169
+ const reader = makeFrameReader(buf => this.dispatchToCallbacks(buf));
170
+ socket.on("data", reader);
171
+ socket.on("close", () => this.handleBrokerDisconnect());
172
+ socket.on("error", err => useLog("WARN", `SocketPubSub broker socket error: ${err.message}`));
173
+ resolve();
174
+ });
175
+ });
176
+ }
177
+ /**
178
+ * Schedule a reconnect attempt after a randomized backoff. The jitter
179
+ * keeps surviving clients from all racing to bind the new socket on the
180
+ * same tick.
181
+ */
182
+ handleBrokerDisconnect() {
183
+ if (this.stopping)
184
+ return;
185
+ this.clientSocket = undefined;
186
+ const delay = this.parameters.reconnectDelay + Math.floor(Math.random() * 100);
187
+ setTimeout(() => {
188
+ if (this.stopping)
189
+ return;
190
+ this.connect().catch(err => useLog("WARN", `SocketPubSub reconnect failed: ${err.message}`));
191
+ }, delay);
192
+ }
193
+ /**
194
+ * Write a framed payload to every subscriber except the optional sender
195
+ * (used to avoid echoing a client's own message back to it via the
196
+ * broker — the client receives it via its local callback dispatch
197
+ * instead).
198
+ * @param buf - the unframed JSON payload bytes
199
+ * @param except - optional socket to exclude from fanout
200
+ */
201
+ fanout(buf, except) {
202
+ const framed = frame(buf);
203
+ for (const sub of this.subscribers) {
204
+ if (sub === except)
205
+ continue;
206
+ sub.write(framed);
207
+ }
208
+ }
209
+ /**
210
+ * Decode a JSON frame and run every registered callback against it.
211
+ * Errors thrown by callbacks are swallowed (logged + counted) so one bad
212
+ * subscriber doesn't break others.
213
+ * @param buf - the unframed JSON payload bytes
214
+ */
215
+ dispatchToCallbacks(buf) {
216
+ let raw;
217
+ try {
218
+ raw = JSONUtils.parse(buf.toString("utf-8"));
219
+ }
220
+ catch (err) {
221
+ this.metrics?.errors?.inc();
222
+ useLog("WARN", `SocketPubSub invalid frame: ${err.message}`);
223
+ return;
224
+ }
225
+ this.metrics?.messages_received?.inc();
226
+ for (const sub of this.callbacks) {
227
+ const event = sub.proto ? Object.assign(new sub.proto(), raw) : raw;
228
+ const start = Date.now();
229
+ sub
230
+ .callback(event)
231
+ .catch(err => {
232
+ this.metrics?.errors?.inc();
233
+ useLog("ERROR", `SocketPubSub callback failed: ${err.message}`);
234
+ })
235
+ .finally(() => {
236
+ this.metrics?.processing_duration?.observe((Date.now() - start) / 1000);
237
+ });
238
+ }
239
+ }
240
+ /**
241
+ * @override
242
+ * @param event - the event to publish
243
+ */
244
+ async sendMessage(event) {
245
+ const buf = Buffer.from(JSONUtils.stringify(event), "utf-8");
246
+ this.metrics?.messages_sent?.inc();
247
+ if (this.server) {
248
+ // Broker mode: fanout to every subscriber and dispatch locally.
249
+ this.fanout(buf);
250
+ this.dispatchToCallbacks(buf);
251
+ }
252
+ else if (this.clientSocket) {
253
+ // Client mode: send to broker, also dispatch locally so the publisher
254
+ // observes its own message without round-tripping.
255
+ this.clientSocket.write(frame(buf));
256
+ this.dispatchToCallbacks(buf);
257
+ }
258
+ else {
259
+ throw new Error("SocketPubSub not connected");
260
+ }
261
+ }
262
+ /**
263
+ * @override
264
+ * @returns 0 — pub/sub is transient, no queueing
265
+ */
266
+ async size() {
267
+ return 0;
268
+ }
269
+ /**
270
+ * @override
271
+ * @param callback - invoked with each event received
272
+ * @param eventPrototype - optional class to rehydrate JSON into
273
+ * @param onBind - invoked once the subscription is registered
274
+ * @returns a cancelable subscription handle
275
+ */
276
+ consume(callback, eventPrototype, onBind) {
277
+ const entry = { callback, proto: eventPrototype };
278
+ // Register the callback synchronously and resolve the promise so the
279
+ // returned handle is "settled-but-cancelable" — onCancel removes the
280
+ // callback when the caller invokes .cancel(). A long-lived pending
281
+ // promise would just produce unhandled "Cancelled" rejections in the
282
+ // typical usage where the caller never awaits the handle.
283
+ this.callbacks.add(entry);
284
+ onBind?.();
285
+ return new CancelablePromise(resolve => resolve(), async () => {
286
+ this.callbacks.delete(entry);
287
+ });
288
+ }
289
+ /**
290
+ * @override
291
+ */
292
+ async stop() {
293
+ this.stopping = true;
294
+ this.callbacks.clear();
295
+ if (this.clientSocket) {
296
+ this.clientSocket.destroy();
297
+ this.clientSocket = undefined;
298
+ }
299
+ if (this.server) {
300
+ const server = this.server;
301
+ this.server = undefined;
302
+ for (const sub of this.subscribers)
303
+ sub.destroy();
304
+ this.subscribers.clear();
305
+ await new Promise(resolve => server.close(() => resolve()));
306
+ try {
307
+ unlinkSync(this.parameters.path);
308
+ }
309
+ catch {
310
+ /* already gone */
311
+ }
312
+ }
313
+ await super.stop();
314
+ }
315
+ }
316
+ export { SocketPubSubService };
317
+ /**
318
+ * Length-prefix-frame a JSON payload. 4-byte big-endian uint32 length
319
+ * followed by the payload bytes.
320
+ * @param buf - the payload to frame
321
+ * @returns the framed bytes
322
+ */
323
+ function frame(buf) {
324
+ const len = Buffer.allocUnsafe(4);
325
+ len.writeUInt32BE(buf.length, 0);
326
+ return Buffer.concat([len, buf]);
327
+ }
328
+ /**
329
+ * Build a stateful frame decoder. Returns a function that consumes raw
330
+ * socket chunks and calls `onFrame` once for each complete frame read.
331
+ * @param onFrame - invoked with each complete unframed payload
332
+ * @returns the chunk consumer
333
+ */
334
+ function makeFrameReader(onFrame) {
335
+ let pending = Buffer.alloc(0);
336
+ return chunk => {
337
+ pending = Buffer.concat([pending, chunk]);
338
+ while (pending.length >= 4) {
339
+ const len = pending.readUInt32BE(0);
340
+ if (pending.length < 4 + len)
341
+ break;
342
+ const payload = pending.subarray(4, 4 + len);
343
+ pending = pending.subarray(4 + len);
344
+ onFrame(payload);
345
+ }
346
+ };
347
+ }
348
+ //# sourceMappingURL=socketpubsub.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socketpubsub.service.js","sourceRoot":"","sources":["../src/socketpubsub.service.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@webda/fs",
3
+ "version": "4.0.0-beta.3",
4
+ "description": "Filesystem-based implementations of Store, Binary, and Queue for Webda",
5
+ "author": "Remi Cattiau <remi@cattiau.com>",
6
+ "repository": "git://github.com/loopingz/webda.io.git",
7
+ "main": "lib/index.js",
8
+ "typings": "lib/index.d.ts",
9
+ "dependencies": {
10
+ "mime-types": "^2.1.31",
11
+ "@webda/utils": "4.0.0-beta.3",
12
+ "@webda/ql": "4.0.0-beta.3",
13
+ "@webda/workout": "4.0.0-beta.3",
14
+ "@webda/core": "4.0.0-beta.3"
15
+ },
16
+ "devDependencies": {
17
+ "@vitest/coverage-v8": "^4.1.2",
18
+ "fs-extra": "^11.0.0",
19
+ "sinon": "^21.0.3",
20
+ "skott": "^0.35.8",
21
+ "typescript": "7.1.0-dev.20260929.1",
22
+ "vite": "^6.0.0",
23
+ "vitest": "^4.1.2",
24
+ "@webda/test": "4.0.0-beta.3",
25
+ "@webda/compiler": "4.0.0-beta.3"
26
+ },
27
+ "files": [
28
+ "lib",
29
+ "webda.module.json"
30
+ ],
31
+ "homepage": "https://webda.io",
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "webda": {
36
+ "namespace": "Webda"
37
+ },
38
+ "type": "module",
39
+ "engines": {
40
+ "node": ">=22.0.0"
41
+ },
42
+ "license": "LGPL-3.0-only",
43
+ "scripts": {
44
+ "build": "webdac build",
45
+ "lint": "eslint",
46
+ "lint:fix": "eslint --fix",
47
+ "test": "vitest run",
48
+ "deps:graph": "skott --showCircularDependencies --no-trackTypeOnlyDependencies --displayMode=raw -e .ts"
49
+ }
50
+ }