@andrey4emk/npm-app-back-b24 4.0.1 → 4.0.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/logs/logs.ts +74 -24
- package/package.json +1 -1
package/logs/logs.ts
CHANGED
|
@@ -39,6 +39,17 @@ const B24_TEXT_LIMIT = 4000;
|
|
|
39
39
|
*/
|
|
40
40
|
const B24_CHAT_TIMEOUT_MS = 5_000;
|
|
41
41
|
|
|
42
|
+
/** Сколько символов тела неуспешного ответа чата показывать в `console.error` */
|
|
43
|
+
const B24_CHAT_BODY_PREVIEW = 300;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Ошибка — обрыв по бюджету `AbortSignal.timeout`. Проверка локальная, без импорта
|
|
47
|
+
* `isTimeoutError` из `utils/fetchRetry.ts` — тот модуль импортирует `logs`, был бы цикл
|
|
48
|
+
*/
|
|
49
|
+
function isTimeout(error: unknown): boolean {
|
|
50
|
+
return (error as { name?: unknown } | null)?.name === "TimeoutError";
|
|
51
|
+
}
|
|
52
|
+
|
|
42
53
|
// ==================== Настройки ====================
|
|
43
54
|
|
|
44
55
|
const configDir: string = process.env.CONFIG_DIR || "../config";
|
|
@@ -198,31 +209,70 @@ class LogsAPI {
|
|
|
198
209
|
text = this.stripBbCodes(text);
|
|
199
210
|
}
|
|
200
211
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
212
|
+
void this.postToB24Chat(url, text);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Сам запрос в чат и разбор ответа. Никогда не бросает: все ошибки — в `console.error`,
|
|
217
|
+
* не через `logs`, иначе отказ канала порождал бы новый error и зацикливался.
|
|
218
|
+
*
|
|
219
|
+
* Сигнал `AbortSignal.timeout` отдан в `fetch`, а он действует и на чтение тела
|
|
220
|
+
* ответа: зависшее тело обрывается тем же бюджетом с `TimeoutError`. До общего `catch`
|
|
221
|
+
* такая ошибка не доходит — у каждого чтения тела свой `.catch`, поэтому таймаут
|
|
222
|
+
* разбирается прямо там: при `!ok` к статусу дописывается пометка «тело не дочитано»,
|
|
223
|
+
* при 200 пишется отдельная строка «доставка не подтверждена».
|
|
224
|
+
*/
|
|
225
|
+
private async postToB24Chat(url: string, text: string): Promise<void> {
|
|
226
|
+
try {
|
|
227
|
+
const response = await fetch(url, {
|
|
228
|
+
method: "POST",
|
|
229
|
+
headers: { "Content-Type": "application/json" },
|
|
230
|
+
body: JSON.stringify({
|
|
231
|
+
BOT_ID: B24_BOT_ID,
|
|
232
|
+
CLIENT_ID: B24_CLIENT_ID,
|
|
233
|
+
DIALOG_ID: this.b24ChatId,
|
|
234
|
+
MESSAGE: text,
|
|
235
|
+
}),
|
|
236
|
+
signal: AbortSignal.timeout(B24_CHAT_TIMEOUT_MS),
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
if (!response.ok) {
|
|
240
|
+
// Тело — подсказка к причине отказа, его чтение отправку уронить не должно
|
|
241
|
+
const body = await response.text().catch((error: unknown) =>
|
|
242
|
+
isTimeout(error) ? `[тело не дочитано за ${B24_CHAT_TIMEOUT_MS / 1000}с]` : "",
|
|
243
|
+
);
|
|
244
|
+
const bodyPart = body ? ` — ${body.slice(0, B24_CHAT_BODY_PREVIEW)}` : "";
|
|
245
|
+
console.error(`Logs B24 Chat: HTTP ${response.status}, сообщение не доставлено${bodyPart}`);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// B24 умеет отвечать 200 с телом {error, error_description} — сообщения при этом нет.
|
|
250
|
+
// Нечитаемый JSON — молча null (портал ответил 200, ошибки в теле не видно),
|
|
251
|
+
// а вот зависшее тело — отказ канала: доставку подтвердить нечем, молчать нельзя
|
|
252
|
+
let bodyTimedOut = false;
|
|
253
|
+
const data: unknown = await response.json().catch((error: unknown) => {
|
|
254
|
+
bodyTimedOut = isTimeout(error);
|
|
255
|
+
return null;
|
|
225
256
|
});
|
|
257
|
+
if (bodyTimedOut) {
|
|
258
|
+
console.error(
|
|
259
|
+
`Logs B24 Chat: HTTP ${response.status}, но ответ не дочитан за ${B24_CHAT_TIMEOUT_MS / 1000}с — доставка не подтверждена`,
|
|
260
|
+
);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (data && typeof data === "object" && "error" in data) {
|
|
264
|
+
const { error, error_description: description } = data as { error?: unknown; error_description?: unknown };
|
|
265
|
+
const reason = description ? String(description) : String(error);
|
|
266
|
+
console.error(`Logs B24 Chat: портал отклонил сообщение — ${reason}`);
|
|
267
|
+
}
|
|
268
|
+
} catch (error: unknown) {
|
|
269
|
+
if (isTimeout(error)) {
|
|
270
|
+
console.error(`Logs B24 Chat: не ответил за ${B24_CHAT_TIMEOUT_MS / 1000}с, сообщение не доставлено`);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
274
|
+
console.error(`Logs B24 Chat: ошибка отправки — ${errMsg}`);
|
|
275
|
+
}
|
|
226
276
|
}
|
|
227
277
|
}
|
|
228
278
|
|