@max1874/feishu 0.3.0 → 0.3.1
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/monitor.ts +34 -0
package/package.json
CHANGED
package/src/monitor.ts
CHANGED
|
@@ -19,6 +19,32 @@ const wsClients = new Map<string, Lark.WSClient>();
|
|
|
19
19
|
const httpServers = new Map<string, http.Server>();
|
|
20
20
|
const botOpenIds = new Map<string, string>();
|
|
21
21
|
|
|
22
|
+
// --- Message dedup ---
|
|
23
|
+
// Feishu may deliver the same event multiple times (webhook retries, websocket reconnects).
|
|
24
|
+
// Track seen message_ids for a short window to skip duplicates.
|
|
25
|
+
const DEDUP_TTL_MS = 10 * 60 * 1000; // 10 minutes
|
|
26
|
+
const seenMessageIds = new Map<string, number>();
|
|
27
|
+
|
|
28
|
+
function isDuplicateMessage(messageId: string | undefined): boolean {
|
|
29
|
+
if (!messageId) return false;
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
|
|
32
|
+
// Lazy cleanup: prune expired entries when map grows
|
|
33
|
+
if (seenMessageIds.size > 200) {
|
|
34
|
+
for (const [id, ts] of seenMessageIds) {
|
|
35
|
+
if (now - ts > DEDUP_TTL_MS) seenMessageIds.delete(id);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const seenAt = seenMessageIds.get(messageId);
|
|
40
|
+
if (seenAt !== undefined) {
|
|
41
|
+
if (now - seenAt <= DEDUP_TTL_MS) return true;
|
|
42
|
+
// Expired — treat as new message
|
|
43
|
+
}
|
|
44
|
+
seenMessageIds.set(messageId, now);
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
22
48
|
async function fetchBotOpenId(cfg: FeishuConfig): Promise<string | undefined> {
|
|
23
49
|
try {
|
|
24
50
|
const result = await probeFeishu(cfg);
|
|
@@ -88,6 +114,10 @@ async function monitorWebSocket(params: {
|
|
|
88
114
|
"im.message.receive_v1": async (data) => {
|
|
89
115
|
try {
|
|
90
116
|
const event = data as unknown as FeishuMessageEvent;
|
|
117
|
+
if (isDuplicateMessage(event.message?.message_id)) {
|
|
118
|
+
log(`feishu[${accountId}]: skipping duplicate message ${event.message.message_id}`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
91
121
|
await handleFeishuMessage({
|
|
92
122
|
cfg,
|
|
93
123
|
event,
|
|
@@ -199,6 +229,10 @@ async function monitorWebhook(params: {
|
|
|
199
229
|
"im.message.receive_v1": async (data) => {
|
|
200
230
|
try {
|
|
201
231
|
const event = data as unknown as FeishuMessageEvent;
|
|
232
|
+
if (isDuplicateMessage(event.message?.message_id)) {
|
|
233
|
+
log(`feishu[${accountId}]: skipping duplicate message ${event.message.message_id}`);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
202
236
|
await handleFeishuMessage({
|
|
203
237
|
cfg,
|
|
204
238
|
event,
|