@interactive-inc/flume 0.9.0 → 0.9.2
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/dist/index.js +4 -0
- package/dist/slack.js +48 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -545,6 +545,10 @@ var FlumeConfluence = class {
|
|
|
545
545
|
reconnect: this.props.reconnect
|
|
546
546
|
}).open();
|
|
547
547
|
if (running instanceof Error) return running;
|
|
548
|
+
if (this.running.has(id)) {
|
|
549
|
+
await running.close();
|
|
550
|
+
return new FlumeStartError(`FlumeConfluence: id already added: ${id}`);
|
|
551
|
+
}
|
|
548
552
|
this.running.set(id, running);
|
|
549
553
|
return null;
|
|
550
554
|
}
|
package/dist/slack.js
CHANGED
|
@@ -177,6 +177,8 @@ const FlumeSlackEnvelopeSchema = z.object({
|
|
|
177
177
|
});
|
|
178
178
|
//#endregion
|
|
179
179
|
//#region lib/slack/slack-socket-mode.ts
|
|
180
|
+
const DEFAULT_IDLE_TIMEOUT_MS = 9e4;
|
|
181
|
+
const IDLE_CHECK_INTERVAL_MS = 15e3;
|
|
180
182
|
const WS_OPEN = 1;
|
|
181
183
|
/**
|
|
182
184
|
* Slack Socket Mode の最小 WebSocket 実装。`apps.connections.open` で URL を取得し
|
|
@@ -191,6 +193,8 @@ var FlumeSlackSocketMode = class {
|
|
|
191
193
|
hasConnected = false;
|
|
192
194
|
pendingResolve = null;
|
|
193
195
|
pendingResolved = false;
|
|
196
|
+
lastFrameAt = 0;
|
|
197
|
+
idleWatchdog = null;
|
|
194
198
|
constructor(props) {
|
|
195
199
|
this.props = props;
|
|
196
200
|
this.log = new FlumeLogger({
|
|
@@ -249,9 +253,50 @@ var FlumeSlackSocketMode = class {
|
|
|
249
253
|
message: "stopping socket mode"
|
|
250
254
|
});
|
|
251
255
|
this.isStoppedFlag = true;
|
|
256
|
+
this.disarmIdleWatchdog();
|
|
252
257
|
this.closeSocket(this.ws);
|
|
253
258
|
this.ws = null;
|
|
254
259
|
}
|
|
260
|
+
armIdleWatchdog() {
|
|
261
|
+
this.disarmIdleWatchdog();
|
|
262
|
+
const idleLimit = this.props.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
|
|
263
|
+
const handle = attempt(() => this.props.deps.setInterval(() => this.checkIdle(idleLimit), IDLE_CHECK_INTERVAL_MS));
|
|
264
|
+
if (handle instanceof Error) {
|
|
265
|
+
this.log.error({
|
|
266
|
+
action: "idle.watchdog.schedule.error",
|
|
267
|
+
message: safeErrorMessage({ error: handle }),
|
|
268
|
+
error: handle
|
|
269
|
+
});
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
this.idleWatchdog = handle;
|
|
273
|
+
}
|
|
274
|
+
disarmIdleWatchdog() {
|
|
275
|
+
if (!this.idleWatchdog) return;
|
|
276
|
+
const handle = this.idleWatchdog;
|
|
277
|
+
this.idleWatchdog = null;
|
|
278
|
+
const result = attempt(() => this.props.deps.clearInterval(handle));
|
|
279
|
+
if (result instanceof Error) this.log.error({
|
|
280
|
+
action: "idle.watchdog.clear.error",
|
|
281
|
+
message: safeErrorMessage({ error: result }),
|
|
282
|
+
error: result
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
checkIdle(idleLimit) {
|
|
286
|
+
if (!this.hasConnected || this.isStoppedFlag) return;
|
|
287
|
+
const elapsed = this.props.deps.now() - this.lastFrameAt;
|
|
288
|
+
if (elapsed < idleLimit) return;
|
|
289
|
+
this.log.warn({
|
|
290
|
+
action: "idle.timeout",
|
|
291
|
+
message: `no frames for ${elapsed}ms (limit ${idleLimit}ms) — force-closing socket`,
|
|
292
|
+
detail: {
|
|
293
|
+
elapsedMs: elapsed,
|
|
294
|
+
limitMs: idleLimit
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
this.disarmIdleWatchdog();
|
|
298
|
+
this.closeSocket(this.ws);
|
|
299
|
+
}
|
|
255
300
|
isConnected() {
|
|
256
301
|
return this.ws !== null && this.ws.readyState === WS_OPEN;
|
|
257
302
|
}
|
|
@@ -357,12 +402,14 @@ var FlumeSlackSocketMode = class {
|
|
|
357
402
|
message: `type=${typeof json.type === "string" ? json.type : "-"} length=${raw.length}`,
|
|
358
403
|
detail: { length: raw.length }
|
|
359
404
|
});
|
|
405
|
+
this.lastFrameAt = this.props.deps.now();
|
|
360
406
|
if (json.type === "hello") {
|
|
361
407
|
this.log.info({
|
|
362
408
|
action: "socket.hello",
|
|
363
409
|
message: "connection ready"
|
|
364
410
|
});
|
|
365
411
|
this.hasConnected = true;
|
|
412
|
+
this.armIdleWatchdog();
|
|
366
413
|
this.props.onConnected();
|
|
367
414
|
this.completeConnect(null);
|
|
368
415
|
return;
|
|
@@ -419,6 +466,7 @@ var FlumeSlackSocketMode = class {
|
|
|
419
466
|
reason: ev.reason
|
|
420
467
|
}
|
|
421
468
|
});
|
|
469
|
+
this.disarmIdleWatchdog();
|
|
422
470
|
this.ws = null;
|
|
423
471
|
if (this.hasConnected) this.props.onDisconnected();
|
|
424
472
|
if (!this.pendingResolved) {
|
package/package.json
CHANGED