@ynhcj/xiaoyi-channel 0.0.195-next → 0.0.196-next

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.
@@ -4,6 +4,7 @@
4
4
  import https from 'https';
5
5
  import { URL } from 'url';
6
6
  import { getConfig } from './config.js';
7
+ import { logger } from '../utils/logger.js';
7
8
  import { DEFAULT_HTTPS_PORT, DEFAULT_HTTP_PORT, HTTP_STATUS_BAD_REQUEST } from './constants.js';
8
9
  function buildHeadersForCelia(config, sessionId) {
9
10
  if (!config.uid || !config.apiKey || !config.skillId || !config.requestFrom) {
@@ -69,6 +70,7 @@ function handleResponse(res, resolve, reject) {
69
70
  data += chunk;
70
71
  });
71
72
  res.on('end', () => {
73
+ logger.log(`[SENTINEL HOOK] callApi response body: ${data}`);
72
74
  try {
73
75
  const result = parseResponseData(data);
74
76
  resolve(result);
@@ -84,6 +86,8 @@ export async function callApi(payload, api, sessionId) {
84
86
  // 确保 uid 存在于消息体中(从 config 注入)
85
87
  const payloadWithUid = { ...payload, uid: config.uid };
86
88
  const httpBody = JSON.stringify(payloadWithUid);
89
+ logger.log(`[SENTINEL HOOK] callApi request URL: ${config.api.url}`);
90
+ logger.log(`[SENTINEL HOOK] callApi request body: ${httpBody}`);
87
91
  return new Promise((resolve, reject) => {
88
92
  const options = buildRequestOptions(config.api.url, headersForCelia, config.api.timeout);
89
93
  const req = https.request(options, (res) => {
@@ -1,5 +1,6 @@
1
1
  import type { ReportPayload, LogReporterEnv } from "./types.js";
2
2
  /**
3
- * Send a log report to the sync API.
3
+ * Send a log report to the sync API with retry on failure.
4
+ * Retries up to 3 times with delays of 10s, 20s, 30s.
4
5
  */
5
6
  export declare function sendReport(payload: ReportPayload, env: LogReporterEnv): Promise<void>;
@@ -2,8 +2,16 @@
2
2
  import fetch from "node-fetch";
3
3
  import { calculateSHA256String } from "../utils/crypto.js";
4
4
  import { logger } from "../utils/logger.js";
5
+ /** Retry delays in milliseconds: 10s, 20s, 30s */
6
+ const RETRY_DELAYS_MS = [10000, 20000, 30000];
7
+ const MAX_RETRIES = RETRY_DELAYS_MS.length;
8
+ /** Sleep for a given duration in milliseconds */
9
+ function sleep(ms) {
10
+ return new Promise((resolve) => setTimeout(resolve, ms));
11
+ }
5
12
  /**
6
- * Send a log report to the sync API.
13
+ * Send a log report to the sync API with retry on failure.
14
+ * Retries up to 3 times with delays of 10s, 20s, 30s.
7
15
  */
8
16
  export async function sendReport(payload, env) {
9
17
  if (payload.logFiles.length === 0) {
@@ -19,14 +27,30 @@ export async function sendReport(payload, env) {
19
27
  "x-request-from": "openclaw",
20
28
  };
21
29
  logger.log(`[log-reporter] Sending report to ${url}, ${payload.logFiles.length} log file(s)`);
22
- const resp = await fetch(url, {
23
- method: "POST",
24
- headers,
25
- body: JSON.stringify(payload),
26
- });
27
- if (!resp.ok) {
28
- const body = await resp.text().catch(() => "");
29
- throw new Error(`Report API returned HTTP ${resp.status}: ${body}`);
30
+ let lastError;
31
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
32
+ try {
33
+ const resp = await fetch(url, {
34
+ method: "POST",
35
+ headers,
36
+ body: JSON.stringify(payload),
37
+ });
38
+ if (!resp.ok) {
39
+ const body = await resp.text().catch(() => "");
40
+ throw new Error(`Report API returned HTTP ${resp.status}: ${body}`);
41
+ }
42
+ logger.log(`[log-reporter] Report sent successfully, status: ${resp.status}`);
43
+ return; // success, exit
44
+ }
45
+ catch (err) {
46
+ lastError = err instanceof Error ? err : new Error(String(err));
47
+ if (attempt < MAX_RETRIES) {
48
+ const delay = RETRY_DELAYS_MS[attempt];
49
+ logger.warn(`[log-reporter] Report failed (attempt ${attempt + 1}/${MAX_RETRIES + 1}): ${lastError.message}. Retrying in ${delay / 1000}s...`);
50
+ await sleep(delay);
51
+ }
52
+ }
30
53
  }
31
- logger.log(`[log-reporter] Report sent successfully, status: ${resp.status}`);
54
+ // All retries exhausted
55
+ throw lastError;
32
56
  }
@@ -1,6 +1,7 @@
1
1
  import type { UploadService } from "./types.js";
2
2
  /**
3
3
  * Write content to a .bak file, upload, and return the URL.
4
+ * Retries upload up to 3 times with delays of 10s, 20s, 30s.
4
5
  * Cleans up .bak file regardless of success/failure.
5
6
  */
6
7
  export declare function uploadContent(content: string, name: string, bakDir: string, uploadService: UploadService): Promise<string>;
@@ -2,8 +2,17 @@
2
2
  import { writeFileSync, unlinkSync } from "fs";
3
3
  import { join } from "path";
4
4
  import { mkdirSync } from "fs";
5
+ import { logger } from "../utils/logger.js";
6
+ /** Retry delays in milliseconds: 10s, 20s, 30s */
7
+ const RETRY_DELAYS_MS = [10000, 20000, 30000];
8
+ const MAX_RETRIES = RETRY_DELAYS_MS.length;
9
+ /** Sleep for a given duration in milliseconds */
10
+ function sleep(ms) {
11
+ return new Promise((resolve) => setTimeout(resolve, ms));
12
+ }
5
13
  /**
6
14
  * Write content to a .bak file, upload, and return the URL.
15
+ * Retries upload up to 3 times with delays of 10s, 20s, 30s.
7
16
  * Cleans up .bak file regardless of success/failure.
8
17
  */
9
18
  export async function uploadContent(content, name, bakDir, uploadService) {
@@ -15,12 +24,26 @@ export async function uploadContent(content, name, bakDir, uploadService) {
15
24
  mkdirSync(bakDir, { recursive: true });
16
25
  }
17
26
  catch { }
27
+ // Write incremental content to .bak file (only once)
28
+ writeFileSync(bakPath, content, "utf-8");
29
+ let lastError;
18
30
  try {
19
- // Write incremental content to .bak file
20
- writeFileSync(bakPath, content, "utf-8");
21
- // Upload and get URL
22
- const url = await uploadService.uploadFileAndGetUrl(bakPath);
23
- return url;
31
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
32
+ try {
33
+ const url = await uploadService.uploadFileAndGetUrl(bakPath);
34
+ return url; // success
35
+ }
36
+ catch (err) {
37
+ lastError = err instanceof Error ? err : new Error(String(err));
38
+ if (attempt < MAX_RETRIES) {
39
+ const delay = RETRY_DELAYS_MS[attempt];
40
+ logger.warn(`[log-reporter] Upload failed for "${name}" (attempt ${attempt + 1}/${MAX_RETRIES + 1}): ${lastError.message}. Retrying in ${delay / 1000}s...`);
41
+ await sleep(delay);
42
+ }
43
+ }
44
+ }
45
+ // All retries exhausted
46
+ throw lastError;
24
47
  }
25
48
  finally {
26
49
  // Always clean up the .bak file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.195-next",
3
+ "version": "0.0.196-next",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",