@zlr_236/popo 0.0.4 → 0.0.6
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/package.json +1 -1
- package/src/bot.ts +28 -24
- package/src/monitor.ts +53 -8
- package/src/types.ts +1 -1
package/package.json
CHANGED
package/src/bot.ts
CHANGED
|
@@ -27,7 +27,7 @@ export type PopoMessageEvent = {
|
|
|
27
27
|
from: string; // Sender email
|
|
28
28
|
sessionId: string; // P2P=email, group=groupId
|
|
29
29
|
notify: string; // Message content
|
|
30
|
-
msgType?: string; // text, image, file, etc.
|
|
30
|
+
msgType?: string | number; // text, image, file, etc.
|
|
31
31
|
fileId?: string; // File message ID
|
|
32
32
|
timestamp?: number;
|
|
33
33
|
groupId?: string;
|
|
@@ -51,7 +51,10 @@ export type PopoActionEvent = {
|
|
|
51
51
|
};
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
-
function parseMessageContent(
|
|
54
|
+
function parseMessageContent(
|
|
55
|
+
notify: string,
|
|
56
|
+
msgType?: string | number,
|
|
57
|
+
): string {
|
|
55
58
|
if (msgType === "text" || !msgType) {
|
|
56
59
|
return notify;
|
|
57
60
|
}
|
|
@@ -62,15 +65,19 @@ function parseMessageContent(notify: string, msgType?: string): string {
|
|
|
62
65
|
/**
|
|
63
66
|
* Infer placeholder text based on message type.
|
|
64
67
|
*/
|
|
65
|
-
function inferPlaceholder(msgType?: string): string {
|
|
68
|
+
function inferPlaceholder(msgType?: string | number): string {
|
|
66
69
|
switch (msgType) {
|
|
67
70
|
case "image":
|
|
71
|
+
case 171:
|
|
68
72
|
return "<media:image>";
|
|
69
73
|
case "file":
|
|
74
|
+
case 171:
|
|
70
75
|
return "<media:document>";
|
|
71
76
|
case "audio":
|
|
77
|
+
case 171:
|
|
72
78
|
return "<media:audio>";
|
|
73
79
|
case "video":
|
|
80
|
+
case 142:
|
|
74
81
|
return "<media:video>";
|
|
75
82
|
default:
|
|
76
83
|
return "";
|
|
@@ -88,17 +95,10 @@ async function resolvePopoMediaList(params: {
|
|
|
88
95
|
}): Promise<PopoMediaInfo[]> {
|
|
89
96
|
const { cfg, event, maxBytes, log } = params;
|
|
90
97
|
const { msgType, fileId, fileInfo } = event.eventData;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const __dirname = dirname(__filename);
|
|
94
|
-
const resFilePath = join(__dirname, "res.txt");
|
|
95
|
-
await fs.writeFile(
|
|
96
|
-
resFilePath,
|
|
97
|
-
JSON.stringify(event.eventData, null, 2),
|
|
98
|
-
"utf-8",
|
|
99
|
-
);
|
|
98
|
+
log?.(`popo: resolvePopoMediaList: ${JSON.stringify(event)}`);
|
|
99
|
+
|
|
100
100
|
// Only process media message types
|
|
101
|
-
const mediaTypes = ["image", "file", "audio", "video", 171];
|
|
101
|
+
const mediaTypes = ["image", "file", "audio", "video", 171, 142];
|
|
102
102
|
if (
|
|
103
103
|
!msgType ||
|
|
104
104
|
!mediaTypes.includes(msgType) ||
|
|
@@ -117,15 +117,19 @@ async function resolvePopoMediaList(params: {
|
|
|
117
117
|
fileId: fileId || fileInfo?.fileId,
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
120
|
+
try {
|
|
121
|
+
// Write urlResult to res.txt
|
|
122
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
123
|
+
const __dirname = dirname(__filename);
|
|
124
|
+
const resFilePath = join(__dirname, "res.txt");
|
|
125
|
+
await fs.writeFile(
|
|
126
|
+
resFilePath,
|
|
127
|
+
JSON.stringify(urlResult, null, 2),
|
|
128
|
+
"utf-8",
|
|
129
|
+
);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
log?.(`popo: DEBUG failed to write event data: ${String(e)}`);
|
|
132
|
+
}
|
|
129
133
|
|
|
130
134
|
if (!urlResult.success || !urlResult.downloadUrl) {
|
|
131
135
|
throw new Error(urlResult.error || "Failed to get download URL");
|
|
@@ -209,7 +213,7 @@ export function parsePopoMessageEvent(
|
|
|
209
213
|
chatType: isGroup ? "group" : "p2p",
|
|
210
214
|
content,
|
|
211
215
|
contentType: eventData.msgType ?? "text",
|
|
212
|
-
fileId: eventData.fileId,
|
|
216
|
+
fileId: eventData.fileId || eventData.fileInfo?.fileId,
|
|
213
217
|
};
|
|
214
218
|
}
|
|
215
219
|
|
|
@@ -228,7 +232,7 @@ export async function handlePopoMessage(params: {
|
|
|
228
232
|
const isGroup = ctx.chatType === "group";
|
|
229
233
|
|
|
230
234
|
log(
|
|
231
|
-
`popo: received message from ${ctx.senderEmail} in ${ctx.sessionId} (${ctx.chatType})`,
|
|
235
|
+
`popo: received message from ${ctx.senderEmail} in ${ctx.sessionId} (${ctx.chatType}) ${JSON.stringify(event)}`,
|
|
232
236
|
);
|
|
233
237
|
|
|
234
238
|
const historyLimit = Math.max(
|
package/src/monitor.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import http from "http";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
registerPluginHttpRoute,
|
|
4
|
+
normalizePluginHttpPath,
|
|
5
|
+
} from "openclaw/plugin-sdk";
|
|
6
|
+
import type {
|
|
7
|
+
ClawdbotConfig,
|
|
8
|
+
RuntimeEnv,
|
|
9
|
+
HistoryEntry,
|
|
10
|
+
} from "openclaw/plugin-sdk";
|
|
4
11
|
import type { PopoConfig } from "./types.js";
|
|
5
12
|
import { resolvePopoCredentials } from "./accounts.js";
|
|
6
13
|
import { verifySignature, decryptMessage, encryptMessage } from "./crypto.js";
|
|
@@ -24,7 +31,9 @@ function readRequestBody(req: http.IncomingMessage): Promise<string> {
|
|
|
24
31
|
});
|
|
25
32
|
}
|
|
26
33
|
|
|
27
|
-
export async function monitorPopoProvider(
|
|
34
|
+
export async function monitorPopoProvider(
|
|
35
|
+
opts: MonitorPopoOpts = {},
|
|
36
|
+
): Promise<void> {
|
|
28
37
|
const cfg = opts.config;
|
|
29
38
|
if (!cfg) {
|
|
30
39
|
throw new Error("Config is required for POPO monitor");
|
|
@@ -33,7 +42,9 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
|
|
|
33
42
|
const popoCfg = cfg.channels?.popo as PopoConfig | undefined;
|
|
34
43
|
const creds = resolvePopoCredentials(popoCfg);
|
|
35
44
|
if (!creds) {
|
|
36
|
-
throw new Error(
|
|
45
|
+
throw new Error(
|
|
46
|
+
"POPO credentials not configured (appKey, appSecret required)",
|
|
47
|
+
);
|
|
37
48
|
}
|
|
38
49
|
|
|
39
50
|
const log = opts.runtime?.log ?? console.log;
|
|
@@ -50,7 +61,8 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
|
|
|
50
61
|
const chatHistories = new Map<string, HistoryEntry[]>();
|
|
51
62
|
|
|
52
63
|
// Normalize path
|
|
53
|
-
const normalizedPath =
|
|
64
|
+
const normalizedPath =
|
|
65
|
+
normalizePluginHttpPath(webhookPath, "/popo/events") ?? "/popo/events";
|
|
54
66
|
|
|
55
67
|
// Register HTTP route to gateway
|
|
56
68
|
const unregisterHttp = registerPluginHttpRoute({
|
|
@@ -79,7 +91,9 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
|
|
|
79
91
|
const timestamp = url.searchParams.get("timestamp");
|
|
80
92
|
const signature = url.searchParams.get("signature");
|
|
81
93
|
|
|
82
|
-
log(
|
|
94
|
+
log(
|
|
95
|
+
`popo: URL validation attempt - nonce=${nonce}, timestamp=${timestamp}, signature=${signature}`,
|
|
96
|
+
);
|
|
83
97
|
|
|
84
98
|
if (nonce && timestamp && signature && creds.token) {
|
|
85
99
|
const valid = verifySignature({
|
|
@@ -141,6 +155,31 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
|
|
|
141
155
|
}
|
|
142
156
|
|
|
143
157
|
const event = eventData as { eventType?: string };
|
|
158
|
+
// Debug: write ALL events before any filtering
|
|
159
|
+
try {
|
|
160
|
+
const fsDebug = await import("node:fs/promises");
|
|
161
|
+
const debugPath =
|
|
162
|
+
"/home/node/.openclaw/workspace/popo_raw_event.json";
|
|
163
|
+
await fsDebug.writeFile(
|
|
164
|
+
debugPath,
|
|
165
|
+
JSON.stringify(
|
|
166
|
+
{
|
|
167
|
+
ts: new Date().toISOString(),
|
|
168
|
+
eventType: event.eventType,
|
|
169
|
+
eventData,
|
|
170
|
+
},
|
|
171
|
+
null,
|
|
172
|
+
2,
|
|
173
|
+
),
|
|
174
|
+
"utf-8",
|
|
175
|
+
);
|
|
176
|
+
log(`popo: DEBUG wrote raw event to ${debugPath}`);
|
|
177
|
+
} catch (e) {
|
|
178
|
+
log(`popo: DEBUG write failed: ${String(e)}`);
|
|
179
|
+
}
|
|
180
|
+
log(
|
|
181
|
+
`popo: DEBUG eventType=${event.eventType} eventData=${JSON.stringify(eventData).slice(0, 500)}`,
|
|
182
|
+
);
|
|
144
183
|
|
|
145
184
|
// Handle valid_url event
|
|
146
185
|
if (event.eventType === "valid_url") {
|
|
@@ -148,7 +187,10 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
|
|
|
148
187
|
const response = { eventType: "valid_url" };
|
|
149
188
|
|
|
150
189
|
if (creds.aesKey) {
|
|
151
|
-
const encrypted = encryptMessage(
|
|
190
|
+
const encrypted = encryptMessage(
|
|
191
|
+
JSON.stringify(response),
|
|
192
|
+
creds.aesKey,
|
|
193
|
+
);
|
|
152
194
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
153
195
|
res.end(JSON.stringify({ encrypt: encrypted }));
|
|
154
196
|
} else {
|
|
@@ -186,7 +228,10 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
|
|
|
186
228
|
// Return success response
|
|
187
229
|
const successResponse = { success: true };
|
|
188
230
|
if (creds.aesKey) {
|
|
189
|
-
const encrypted = encryptMessage(
|
|
231
|
+
const encrypted = encryptMessage(
|
|
232
|
+
JSON.stringify(successResponse),
|
|
233
|
+
creds.aesKey,
|
|
234
|
+
);
|
|
190
235
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
191
236
|
res.end(JSON.stringify({ encrypt: encrypted }));
|
|
192
237
|
} else {
|