opencode-gateway 0.2.2 → 0.2.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.
- package/dist/telegram/client.d.ts +1 -1
- package/dist/telegram/client.js +4 -3
- package/dist/telegram/poller.d.ts +16 -1
- package/dist/telegram/poller.js +77 -8
- package/dist/telegram/runtime.d.ts +3 -1
- package/dist/telegram/runtime.js +27 -3
- package/dist/telegram/state.d.ts +7 -0
- package/dist/telegram/state.js +21 -0
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ export declare class TelegramApiError extends Error {
|
|
|
6
6
|
export declare class TelegramBotClient {
|
|
7
7
|
private readonly botToken;
|
|
8
8
|
constructor(botToken: string);
|
|
9
|
-
getUpdates(offset: number | null, timeoutSeconds: number): Promise<TelegramUpdate[]>;
|
|
9
|
+
getUpdates(offset: number | null, timeoutSeconds: number, signal?: AbortSignal): Promise<TelegramUpdate[]>;
|
|
10
10
|
getMe(): Promise<TelegramBotProfile>;
|
|
11
11
|
getChat(chatId: string): Promise<TelegramChat>;
|
|
12
12
|
getFile(fileId: string): Promise<TelegramFileRecord>;
|
package/dist/telegram/client.js
CHANGED
|
@@ -12,12 +12,12 @@ export class TelegramBotClient {
|
|
|
12
12
|
constructor(botToken) {
|
|
13
13
|
this.botToken = botToken;
|
|
14
14
|
}
|
|
15
|
-
async getUpdates(offset, timeoutSeconds) {
|
|
15
|
+
async getUpdates(offset, timeoutSeconds, signal) {
|
|
16
16
|
return this.call("getUpdates", {
|
|
17
17
|
offset,
|
|
18
18
|
timeout: timeoutSeconds,
|
|
19
19
|
allowed_updates: ["message", "callback_query"],
|
|
20
|
-
});
|
|
20
|
+
}, signal);
|
|
21
21
|
}
|
|
22
22
|
async getMe() {
|
|
23
23
|
return this.call("getMe", {});
|
|
@@ -100,7 +100,7 @@ export class TelegramBotClient {
|
|
|
100
100
|
text,
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
|
-
async call(method, body) {
|
|
103
|
+
async call(method, body, signal) {
|
|
104
104
|
let response;
|
|
105
105
|
try {
|
|
106
106
|
response = await fetch(`https://api.telegram.org/bot${this.botToken}/${method}`, {
|
|
@@ -109,6 +109,7 @@ export class TelegramBotClient {
|
|
|
109
109
|
"content-type": "application/json",
|
|
110
110
|
},
|
|
111
111
|
body: JSON.stringify(stripUndefined(body)),
|
|
112
|
+
signal,
|
|
112
113
|
});
|
|
113
114
|
}
|
|
114
115
|
catch (error) {
|
|
@@ -6,6 +6,11 @@ import type { GatewayMailboxRuntime } from "../runtime/mailbox";
|
|
|
6
6
|
import type { SqliteStore } from "../store/sqlite";
|
|
7
7
|
import { type TelegramPollingClientLike } from "./client";
|
|
8
8
|
import type { TelegramInboundMediaStore } from "./media";
|
|
9
|
+
type PollerTiming = {
|
|
10
|
+
timeoutFloorMs: number;
|
|
11
|
+
timeoutGraceMs: number;
|
|
12
|
+
stallGraceMs: number;
|
|
13
|
+
};
|
|
9
14
|
export declare class TelegramPollingService {
|
|
10
15
|
private readonly client;
|
|
11
16
|
private readonly mailbox;
|
|
@@ -16,14 +21,24 @@ export declare class TelegramPollingService {
|
|
|
16
21
|
private readonly mediaStore;
|
|
17
22
|
private readonly questions;
|
|
18
23
|
private readonly allowlist;
|
|
24
|
+
private readonly timing;
|
|
19
25
|
private running;
|
|
26
|
+
private inFlightStartedAtMs;
|
|
27
|
+
private consecutiveFailures;
|
|
28
|
+
private recoveredAtMs;
|
|
20
29
|
constructor(client: TelegramPollingClientLike, mailbox: GatewayMailboxRuntimeLike, store: SqliteStore, logger: BindingLoggerHost, config: Extract<TelegramConfig, {
|
|
21
30
|
enabled: true;
|
|
22
|
-
}>, mailboxRouter:
|
|
31
|
+
}>, mailboxRouter: MailboxRouterLike, mediaStore: TelegramInboundMediaStoreLike, questions: GatewayQuestionRuntimeLike, timing?: Partial<PollerTiming>);
|
|
23
32
|
start(): void;
|
|
24
33
|
isRunning(): boolean;
|
|
34
|
+
currentPollStartedAtMs(): number | null;
|
|
35
|
+
requestTimeoutMs(): number;
|
|
36
|
+
recoveryRecordedAtMs(): number | null;
|
|
25
37
|
private runLoop;
|
|
26
38
|
private advanceOffset;
|
|
27
39
|
}
|
|
28
40
|
type GatewayMailboxRuntimeLike = Pick<GatewayMailboxRuntime, "enqueueInboundMessage">;
|
|
41
|
+
type MailboxRouterLike = Pick<GatewayMailboxRouter, "resolve">;
|
|
42
|
+
type TelegramInboundMediaStoreLike = Pick<TelegramInboundMediaStore, "materializeInboundMessage">;
|
|
43
|
+
type GatewayQuestionRuntimeLike = Pick<GatewayQuestionRuntime, "handleTelegramCallbackQuery">;
|
|
29
44
|
export {};
|
package/dist/telegram/poller.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { formatError } from "../utils/error";
|
|
2
2
|
import { TelegramApiError } from "./client";
|
|
3
3
|
import { buildTelegramAllowlist, normalizeTelegramUpdate } from "./normalize";
|
|
4
|
-
import { recordTelegramChatType, recordTelegramPollFailure, recordTelegramPollSuccess } from "./state";
|
|
4
|
+
import { recordTelegramChatType, recordTelegramPollCompleted, recordTelegramPollFailure, recordTelegramPollStarted, recordTelegramPollSuccess, recordTelegramPollTimeout, } from "./state";
|
|
5
|
+
const POLL_TIMEOUT_FLOOR_MS = 15_000;
|
|
6
|
+
const POLL_TIMEOUT_GRACE_MS = 10_000;
|
|
7
|
+
const POLL_STALL_GRACE_MS = 5_000;
|
|
5
8
|
export class TelegramPollingService {
|
|
6
9
|
client;
|
|
7
10
|
mailbox;
|
|
@@ -12,8 +15,12 @@ export class TelegramPollingService {
|
|
|
12
15
|
mediaStore;
|
|
13
16
|
questions;
|
|
14
17
|
allowlist;
|
|
18
|
+
timing;
|
|
15
19
|
running = false;
|
|
16
|
-
|
|
20
|
+
inFlightStartedAtMs = null;
|
|
21
|
+
consecutiveFailures = 0;
|
|
22
|
+
recoveredAtMs = null;
|
|
23
|
+
constructor(client, mailbox, store, logger, config, mailboxRouter, mediaStore, questions, timing) {
|
|
17
24
|
this.client = client;
|
|
18
25
|
this.mailbox = mailbox;
|
|
19
26
|
this.store = store;
|
|
@@ -23,6 +30,11 @@ export class TelegramPollingService {
|
|
|
23
30
|
this.mediaStore = mediaStore;
|
|
24
31
|
this.questions = questions;
|
|
25
32
|
this.allowlist = buildTelegramAllowlist(config);
|
|
33
|
+
this.timing = {
|
|
34
|
+
timeoutFloorMs: timing?.timeoutFloorMs ?? POLL_TIMEOUT_FLOOR_MS,
|
|
35
|
+
timeoutGraceMs: timing?.timeoutGraceMs ?? POLL_TIMEOUT_GRACE_MS,
|
|
36
|
+
stallGraceMs: timing?.stallGraceMs ?? POLL_STALL_GRACE_MS,
|
|
37
|
+
};
|
|
26
38
|
}
|
|
27
39
|
start() {
|
|
28
40
|
if (this.running) {
|
|
@@ -36,18 +48,40 @@ export class TelegramPollingService {
|
|
|
36
48
|
isRunning() {
|
|
37
49
|
return this.running;
|
|
38
50
|
}
|
|
51
|
+
currentPollStartedAtMs() {
|
|
52
|
+
return this.inFlightStartedAtMs;
|
|
53
|
+
}
|
|
54
|
+
requestTimeoutMs() {
|
|
55
|
+
return Math.max(this.config.pollTimeoutSeconds * 1_000 + this.timing.timeoutGraceMs, this.timing.timeoutFloorMs);
|
|
56
|
+
}
|
|
57
|
+
recoveryRecordedAtMs() {
|
|
58
|
+
return this.recoveredAtMs;
|
|
59
|
+
}
|
|
39
60
|
async runLoop() {
|
|
40
61
|
let offset = this.store.getTelegramUpdateOffset();
|
|
41
62
|
let retryDelayMs = 1_000;
|
|
42
63
|
for (;;) {
|
|
64
|
+
const pollStartedAtMs = Date.now();
|
|
65
|
+
recordTelegramPollStarted(this.store, pollStartedAtMs);
|
|
66
|
+
const controller = new AbortController();
|
|
67
|
+
const timeoutHandle = setTimeout(() => {
|
|
68
|
+
controller.abort();
|
|
69
|
+
}, this.requestTimeoutMs() + this.timing.stallGraceMs);
|
|
70
|
+
this.inFlightStartedAtMs = pollStartedAtMs;
|
|
43
71
|
try {
|
|
44
|
-
const updates = await this.client.getUpdates(offset, this.config.pollTimeoutSeconds);
|
|
45
|
-
|
|
72
|
+
const updates = await this.client.getUpdates(offset, this.config.pollTimeoutSeconds, controller.signal);
|
|
73
|
+
const recordedAtMs = Date.now();
|
|
74
|
+
recordTelegramPollCompleted(this.store, recordedAtMs);
|
|
75
|
+
recordTelegramPollSuccess(this.store, recordedAtMs);
|
|
76
|
+
if (this.consecutiveFailures > 0) {
|
|
77
|
+
this.recoveredAtMs = recordedAtMs;
|
|
78
|
+
this.logger.log("info", `telegram poller recovered after ${this.consecutiveFailures} consecutive failure(s)`);
|
|
79
|
+
}
|
|
46
80
|
for (const update of updates) {
|
|
47
81
|
const nextOffset = update.update_id + 1;
|
|
48
82
|
const normalized = normalizeTelegramUpdate(update, this.allowlist, this.mailboxRouter);
|
|
49
83
|
if (normalized.kind === "ignore") {
|
|
50
|
-
this.logger.log("
|
|
84
|
+
this.logger.log("debug", `ignoring telegram update ${update.update_id}: ${normalized.reason}`);
|
|
51
85
|
offset = this.advanceOffset(nextOffset);
|
|
52
86
|
continue;
|
|
53
87
|
}
|
|
@@ -64,18 +98,32 @@ export class TelegramPollingService {
|
|
|
64
98
|
await this.mailbox.enqueueInboundMessage(await this.mediaStore.materializeInboundMessage(normalized.message, "telegram_update", String(update.update_id)), "telegram_update", String(update.update_id));
|
|
65
99
|
offset = this.advanceOffset(nextOffset);
|
|
66
100
|
}
|
|
101
|
+
this.consecutiveFailures = 0;
|
|
67
102
|
retryDelayMs = 1_000;
|
|
68
103
|
}
|
|
69
104
|
catch (error) {
|
|
70
|
-
|
|
105
|
+
const recordedAtMs = Date.now();
|
|
106
|
+
recordTelegramPollCompleted(this.store, recordedAtMs);
|
|
107
|
+
const pollError = classifyTelegramPollError(error, this.requestTimeoutMs());
|
|
108
|
+
this.consecutiveFailures += 1;
|
|
109
|
+
if (pollError.kind === "timeout") {
|
|
110
|
+
recordTelegramPollTimeout(this.store, pollError.message, recordedAtMs);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
recordTelegramPollFailure(this.store, pollError.message, recordedAtMs);
|
|
114
|
+
}
|
|
71
115
|
if (isPermanentTelegramFailure(error)) {
|
|
72
|
-
this.logger.log("error",
|
|
116
|
+
this.logger.log("error", pollError.message);
|
|
73
117
|
return;
|
|
74
118
|
}
|
|
75
|
-
this.logger.log("warn",
|
|
119
|
+
this.logger.log("warn", pollError.message);
|
|
76
120
|
await sleep(retryDelayMs);
|
|
77
121
|
retryDelayMs = Math.min(retryDelayMs * 2, 15_000);
|
|
78
122
|
}
|
|
123
|
+
finally {
|
|
124
|
+
clearTimeout(timeoutHandle);
|
|
125
|
+
this.inFlightStartedAtMs = null;
|
|
126
|
+
}
|
|
79
127
|
}
|
|
80
128
|
}
|
|
81
129
|
advanceOffset(offset) {
|
|
@@ -90,6 +138,27 @@ function isPermanentTelegramFailure(error) {
|
|
|
90
138
|
function formatTelegramPollerError(error) {
|
|
91
139
|
return `telegram poller failure: ${formatError(error)}`;
|
|
92
140
|
}
|
|
141
|
+
function classifyTelegramPollError(error, requestTimeoutMs) {
|
|
142
|
+
if (isAbortError(error)) {
|
|
143
|
+
return {
|
|
144
|
+
kind: "timeout",
|
|
145
|
+
message: `telegram poller timeout after ${requestTimeoutMs}ms`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
kind: "error",
|
|
150
|
+
message: formatTelegramPollerError(error),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function isAbortError(error) {
|
|
154
|
+
if (error instanceof DOMException) {
|
|
155
|
+
return error.name === "AbortError";
|
|
156
|
+
}
|
|
157
|
+
if (error instanceof Error) {
|
|
158
|
+
return error.name === "AbortError";
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
93
162
|
function sleep(durationMs) {
|
|
94
163
|
return new Promise((resolve) => {
|
|
95
164
|
setTimeout(resolve, durationMs);
|
|
@@ -13,6 +13,7 @@ type OpencodeEventStreamLike = {
|
|
|
13
13
|
export type GatewayTelegramStatus = TelegramHealthSnapshot & {
|
|
14
14
|
enabled: boolean;
|
|
15
15
|
polling: boolean;
|
|
16
|
+
pollState: "disabled" | "idle" | "running" | "stalled" | "recovering";
|
|
16
17
|
allowlistMode: "disabled" | "explicit";
|
|
17
18
|
allowedChatsCount: number;
|
|
18
19
|
allowedUsersCount: number;
|
|
@@ -32,6 +33,7 @@ export type TelegramSendTestResult = {
|
|
|
32
33
|
mode: "oneshot" | "progressive";
|
|
33
34
|
};
|
|
34
35
|
type TelegramTextDeliveryLike = Pick<GatewayTextDelivery, "sendTest">;
|
|
36
|
+
type TelegramPollingStateLike = Pick<TelegramPollingService, "currentPollStartedAtMs" | "isRunning" | "recoveryRecordedAtMs" | "requestTimeoutMs" | "start">;
|
|
35
37
|
export declare class GatewayTelegramRuntime {
|
|
36
38
|
private readonly client;
|
|
37
39
|
private readonly delivery;
|
|
@@ -40,7 +42,7 @@ export declare class GatewayTelegramRuntime {
|
|
|
40
42
|
private readonly config;
|
|
41
43
|
private readonly polling;
|
|
42
44
|
private readonly opencodeEvents;
|
|
43
|
-
constructor(client: TelegramRuntimeClientLike | null, delivery: TelegramTextDeliveryLike, store: SqliteStore, logger: BindingLoggerHost, config: TelegramConfig, polling:
|
|
45
|
+
constructor(client: TelegramRuntimeClientLike | null, delivery: TelegramTextDeliveryLike, store: SqliteStore, logger: BindingLoggerHost, config: TelegramConfig, polling: TelegramPollingStateLike | null, opencodeEvents: OpencodeEventStreamLike);
|
|
44
46
|
isEnabled(): boolean;
|
|
45
47
|
isPolling(): boolean;
|
|
46
48
|
allowlistMode(): "disabled" | "explicit";
|
package/dist/telegram/runtime.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { formatUnixMsAsUtc } from "../tools/time";
|
|
2
2
|
import { formatError } from "../utils/error";
|
|
3
3
|
import { readTelegramHealthSnapshot, recordTelegramProbeFailure, recordTelegramProbeSuccess, recordTelegramSendFailure, } from "./state";
|
|
4
|
+
const RECENT_RECOVERY_WINDOW_MS = 60_000;
|
|
5
|
+
const POLL_STALLED_GRACE_MS = 5_000;
|
|
4
6
|
export class GatewayTelegramRuntime {
|
|
5
7
|
client;
|
|
6
8
|
delivery;
|
|
@@ -37,6 +39,7 @@ export class GatewayTelegramRuntime {
|
|
|
37
39
|
...snapshot,
|
|
38
40
|
enabled: false,
|
|
39
41
|
polling: false,
|
|
42
|
+
pollState: "disabled",
|
|
40
43
|
allowlistMode: "disabled",
|
|
41
44
|
allowedChatsCount: 0,
|
|
42
45
|
allowedUsersCount: 0,
|
|
@@ -53,14 +56,14 @@ export class GatewayTelegramRuntime {
|
|
|
53
56
|
const bot = await this.client.getMe();
|
|
54
57
|
const recordedAtMs = Date.now();
|
|
55
58
|
recordTelegramProbeSuccess(this.store, bot, recordedAtMs);
|
|
56
|
-
return buildEnabledStatus(this.config, readTelegramHealthSnapshot(this.store), this.
|
|
59
|
+
return buildEnabledStatus(this.config, readTelegramHealthSnapshot(this.store), this.polling, "ok", null, bot, this.opencodeEvents);
|
|
57
60
|
}
|
|
58
61
|
catch (error) {
|
|
59
62
|
const message = formatError(error);
|
|
60
63
|
const recordedAtMs = Date.now();
|
|
61
64
|
recordTelegramProbeFailure(this.store, message, recordedAtMs);
|
|
62
65
|
this.logger.log("warn", `telegram live probe failed: ${message}`);
|
|
63
|
-
return buildEnabledStatus(this.config, readTelegramHealthSnapshot(this.store), this.
|
|
66
|
+
return buildEnabledStatus(this.config, readTelegramHealthSnapshot(this.store), this.polling, "failed", message, null, this.opencodeEvents);
|
|
64
67
|
}
|
|
65
68
|
}
|
|
66
69
|
async sendTest(chatId, topic, text, mode) {
|
|
@@ -97,10 +100,12 @@ export class GatewayTelegramRuntime {
|
|
|
97
100
|
}
|
|
98
101
|
}
|
|
99
102
|
function buildEnabledStatus(config, snapshot, polling, liveProbe, liveProbeError, bot, opencodeEvents) {
|
|
103
|
+
const pollingEnabled = polling?.isRunning() ?? false;
|
|
100
104
|
return {
|
|
101
105
|
...snapshot,
|
|
102
106
|
enabled: true,
|
|
103
|
-
polling,
|
|
107
|
+
polling: pollingEnabled,
|
|
108
|
+
pollState: resolvePollState(snapshot, polling),
|
|
104
109
|
allowlistMode: "explicit",
|
|
105
110
|
allowedChatsCount: config.allowedChats.length,
|
|
106
111
|
allowedUsersCount: config.allowedUsers.length,
|
|
@@ -113,6 +118,25 @@ function buildEnabledStatus(config, snapshot, polling, liveProbe, liveProbeError
|
|
|
113
118
|
lastEventStreamError: opencodeEvents.lastStreamError(),
|
|
114
119
|
};
|
|
115
120
|
}
|
|
121
|
+
function resolvePollState(snapshot, polling) {
|
|
122
|
+
if (polling === null || !polling.isRunning()) {
|
|
123
|
+
return "idle";
|
|
124
|
+
}
|
|
125
|
+
const now = Date.now();
|
|
126
|
+
const inFlightStartedAtMs = polling.currentPollStartedAtMs();
|
|
127
|
+
if (inFlightStartedAtMs !== null &&
|
|
128
|
+
now - inFlightStartedAtMs > polling.requestTimeoutMs() + POLL_STALLED_GRACE_MS) {
|
|
129
|
+
return "stalled";
|
|
130
|
+
}
|
|
131
|
+
const recoveredAtMs = polling.recoveryRecordedAtMs();
|
|
132
|
+
if (recoveredAtMs !== null && now - recoveredAtMs <= RECENT_RECOVERY_WINDOW_MS) {
|
|
133
|
+
return "recovering";
|
|
134
|
+
}
|
|
135
|
+
if (snapshot.lastPollStartedMs !== null) {
|
|
136
|
+
return "running";
|
|
137
|
+
}
|
|
138
|
+
return "idle";
|
|
139
|
+
}
|
|
116
140
|
function normalizeRequiredField(value, field) {
|
|
117
141
|
const trimmed = value.trim();
|
|
118
142
|
if (trimmed.length === 0) {
|
package/dist/telegram/state.d.ts
CHANGED
|
@@ -4,8 +4,12 @@ export type TelegramStreamingFallbackReason = "non_private_chat" | "progressive_
|
|
|
4
4
|
export type TelegramHealthSnapshot = {
|
|
5
5
|
updateOffset: number | null;
|
|
6
6
|
lastPollSuccessMs: number | null;
|
|
7
|
+
lastPollStartedMs: number | null;
|
|
8
|
+
lastPollCompletedMs: number | null;
|
|
7
9
|
lastPollErrorAtMs: number | null;
|
|
8
10
|
lastPollErrorMessage: string | null;
|
|
11
|
+
lastPollTimeoutAtMs: number | null;
|
|
12
|
+
lastPollTimeoutMessage: string | null;
|
|
9
13
|
lastSendSuccessMs: number | null;
|
|
10
14
|
lastSendErrorAtMs: number | null;
|
|
11
15
|
lastSendErrorMessage: string | null;
|
|
@@ -22,8 +26,11 @@ export type TelegramHealthSnapshot = {
|
|
|
22
26
|
lastStreamFallbackReason: TelegramStreamingFallbackReason | null;
|
|
23
27
|
};
|
|
24
28
|
export declare function readTelegramHealthSnapshot(store: SqliteStore): TelegramHealthSnapshot;
|
|
29
|
+
export declare function recordTelegramPollStarted(store: SqliteStore, recordedAtMs: number): void;
|
|
30
|
+
export declare function recordTelegramPollCompleted(store: SqliteStore, recordedAtMs: number): void;
|
|
25
31
|
export declare function recordTelegramPollSuccess(store: SqliteStore, recordedAtMs: number): void;
|
|
26
32
|
export declare function recordTelegramPollFailure(store: SqliteStore, message: string, recordedAtMs: number): void;
|
|
33
|
+
export declare function recordTelegramPollTimeout(store: SqliteStore, message: string, recordedAtMs: number): void;
|
|
27
34
|
export declare function recordTelegramSendSuccess(store: SqliteStore, recordedAtMs: number): void;
|
|
28
35
|
export declare function recordTelegramSendFailure(store: SqliteStore, message: string, recordedAtMs: number): void;
|
|
29
36
|
export declare function recordTelegramProbeSuccess(store: SqliteStore, bot: TelegramBotProfile, recordedAtMs: number): void;
|
package/dist/telegram/state.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
const TELEGRAM_UPDATE_OFFSET_KEY = "telegram.update_offset";
|
|
2
2
|
const TELEGRAM_LAST_POLL_SUCCESS_MS_KEY = "telegram.last_poll_success_ms";
|
|
3
|
+
const TELEGRAM_LAST_POLL_STARTED_MS_KEY = "telegram.last_poll_started_ms";
|
|
4
|
+
const TELEGRAM_LAST_POLL_COMPLETED_MS_KEY = "telegram.last_poll_completed_ms";
|
|
3
5
|
const TELEGRAM_LAST_POLL_ERROR_AT_MS_KEY = "telegram.last_poll_error_at_ms";
|
|
4
6
|
const TELEGRAM_LAST_POLL_ERROR_MESSAGE_KEY = "telegram.last_poll_error_message";
|
|
7
|
+
const TELEGRAM_LAST_POLL_TIMEOUT_AT_MS_KEY = "telegram.last_poll_timeout_at_ms";
|
|
8
|
+
const TELEGRAM_LAST_POLL_TIMEOUT_MESSAGE_KEY = "telegram.last_poll_timeout_message";
|
|
5
9
|
const TELEGRAM_LAST_SEND_SUCCESS_MS_KEY = "telegram.last_send_success_ms";
|
|
6
10
|
const TELEGRAM_LAST_SEND_ERROR_AT_MS_KEY = "telegram.last_send_error_at_ms";
|
|
7
11
|
const TELEGRAM_LAST_SEND_ERROR_MESSAGE_KEY = "telegram.last_send_error_message";
|
|
@@ -20,8 +24,12 @@ export function readTelegramHealthSnapshot(store) {
|
|
|
20
24
|
return {
|
|
21
25
|
updateOffset: readStoredInteger(store, TELEGRAM_UPDATE_OFFSET_KEY),
|
|
22
26
|
lastPollSuccessMs: readStoredInteger(store, TELEGRAM_LAST_POLL_SUCCESS_MS_KEY),
|
|
27
|
+
lastPollStartedMs: readStoredInteger(store, TELEGRAM_LAST_POLL_STARTED_MS_KEY),
|
|
28
|
+
lastPollCompletedMs: readStoredInteger(store, TELEGRAM_LAST_POLL_COMPLETED_MS_KEY),
|
|
23
29
|
lastPollErrorAtMs: readStoredInteger(store, TELEGRAM_LAST_POLL_ERROR_AT_MS_KEY),
|
|
24
30
|
lastPollErrorMessage: readStoredText(store, TELEGRAM_LAST_POLL_ERROR_MESSAGE_KEY),
|
|
31
|
+
lastPollTimeoutAtMs: readStoredInteger(store, TELEGRAM_LAST_POLL_TIMEOUT_AT_MS_KEY),
|
|
32
|
+
lastPollTimeoutMessage: readStoredText(store, TELEGRAM_LAST_POLL_TIMEOUT_MESSAGE_KEY),
|
|
25
33
|
lastSendSuccessMs: readStoredInteger(store, TELEGRAM_LAST_SEND_SUCCESS_MS_KEY),
|
|
26
34
|
lastSendErrorAtMs: readStoredInteger(store, TELEGRAM_LAST_SEND_ERROR_AT_MS_KEY),
|
|
27
35
|
lastSendErrorMessage: readStoredText(store, TELEGRAM_LAST_SEND_ERROR_MESSAGE_KEY),
|
|
@@ -38,15 +46,28 @@ export function readTelegramHealthSnapshot(store) {
|
|
|
38
46
|
lastStreamFallbackReason: readStoredFallbackReason(store),
|
|
39
47
|
};
|
|
40
48
|
}
|
|
49
|
+
export function recordTelegramPollStarted(store, recordedAtMs) {
|
|
50
|
+
store.putStateValue(TELEGRAM_LAST_POLL_STARTED_MS_KEY, String(recordedAtMs), recordedAtMs);
|
|
51
|
+
}
|
|
52
|
+
export function recordTelegramPollCompleted(store, recordedAtMs) {
|
|
53
|
+
store.putStateValue(TELEGRAM_LAST_POLL_COMPLETED_MS_KEY, String(recordedAtMs), recordedAtMs);
|
|
54
|
+
}
|
|
41
55
|
export function recordTelegramPollSuccess(store, recordedAtMs) {
|
|
42
56
|
store.putStateValue(TELEGRAM_LAST_POLL_SUCCESS_MS_KEY, String(recordedAtMs), recordedAtMs);
|
|
43
57
|
store.putStateValue(TELEGRAM_LAST_POLL_ERROR_AT_MS_KEY, "", recordedAtMs);
|
|
44
58
|
store.putStateValue(TELEGRAM_LAST_POLL_ERROR_MESSAGE_KEY, "", recordedAtMs);
|
|
59
|
+
store.putStateValue(TELEGRAM_LAST_POLL_TIMEOUT_AT_MS_KEY, "", recordedAtMs);
|
|
60
|
+
store.putStateValue(TELEGRAM_LAST_POLL_TIMEOUT_MESSAGE_KEY, "", recordedAtMs);
|
|
45
61
|
}
|
|
46
62
|
export function recordTelegramPollFailure(store, message, recordedAtMs) {
|
|
47
63
|
store.putStateValue(TELEGRAM_LAST_POLL_ERROR_AT_MS_KEY, String(recordedAtMs), recordedAtMs);
|
|
48
64
|
store.putStateValue(TELEGRAM_LAST_POLL_ERROR_MESSAGE_KEY, message, recordedAtMs);
|
|
49
65
|
}
|
|
66
|
+
export function recordTelegramPollTimeout(store, message, recordedAtMs) {
|
|
67
|
+
store.putStateValue(TELEGRAM_LAST_POLL_TIMEOUT_AT_MS_KEY, String(recordedAtMs), recordedAtMs);
|
|
68
|
+
store.putStateValue(TELEGRAM_LAST_POLL_TIMEOUT_MESSAGE_KEY, message, recordedAtMs);
|
|
69
|
+
recordTelegramPollFailure(store, message, recordedAtMs);
|
|
70
|
+
}
|
|
50
71
|
export function recordTelegramSendSuccess(store, recordedAtMs) {
|
|
51
72
|
store.putStateValue(TELEGRAM_LAST_SEND_SUCCESS_MS_KEY, String(recordedAtMs), recordedAtMs);
|
|
52
73
|
store.putStateValue(TELEGRAM_LAST_SEND_ERROR_AT_MS_KEY, "", recordedAtMs);
|