mirror of
https://github.com/different-ai/openwork
synced 2026-05-12 18:16:24 +02:00
205 lines
5.3 KiB
JavaScript
205 lines
5.3 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
|
|
import { MediaStore } from "../dist/media-store.js";
|
|
import { createTelegramAdapter } from "../dist/telegram.js";
|
|
|
|
function createLoggerStub() {
|
|
const base = {
|
|
child() {
|
|
return base;
|
|
},
|
|
debug() {},
|
|
info() {},
|
|
warn() {},
|
|
error() {},
|
|
};
|
|
return base;
|
|
}
|
|
|
|
let lastFakeBot = null;
|
|
|
|
class FakeBot {
|
|
constructor(token) {
|
|
this.token = token;
|
|
this.handlers = new Map();
|
|
this.me = { id: 999, username: "routerbot" };
|
|
this.calls = {
|
|
sendMessage: [],
|
|
sendPhoto: [],
|
|
sendAudio: [],
|
|
sendDocument: [],
|
|
getFile: [],
|
|
};
|
|
this.api = {
|
|
sendMessage: async (chatId, text) => {
|
|
this.calls.sendMessage.push({ chatId, text });
|
|
return { ok: true };
|
|
},
|
|
sendPhoto: async (chatId, file, options) => {
|
|
this.calls.sendPhoto.push({ chatId, file, options });
|
|
return { ok: true };
|
|
},
|
|
sendAudio: async (chatId, file, options) => {
|
|
this.calls.sendAudio.push({ chatId, file, options });
|
|
return { ok: true };
|
|
},
|
|
sendDocument: async (chatId, file, options) => {
|
|
this.calls.sendDocument.push({ chatId, file, options });
|
|
return { ok: true };
|
|
},
|
|
getFile: async (fileId) => {
|
|
this.calls.getFile.push({ fileId });
|
|
return { file_path: `downloads/${fileId}.bin` };
|
|
},
|
|
};
|
|
lastFakeBot = this;
|
|
}
|
|
|
|
catch(handler) {
|
|
this.errorHandler = handler;
|
|
}
|
|
|
|
on(event, handler) {
|
|
this.handlers.set(event, handler);
|
|
}
|
|
|
|
async start() {
|
|
this.started = true;
|
|
}
|
|
|
|
stop() {
|
|
this.started = false;
|
|
}
|
|
|
|
async emitMessage(message) {
|
|
const handler = this.handlers.get("message");
|
|
if (handler) {
|
|
await handler({ message, me: this.me });
|
|
}
|
|
}
|
|
}
|
|
|
|
test("createTelegramAdapter sends text/images/audio/files", async () => {
|
|
const logger = createLoggerStub();
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "opencode-router-tg-send-"));
|
|
const imagePath = path.join(tempDir, "sample.jpg");
|
|
const audioPath = path.join(tempDir, "sample.ogg");
|
|
const filePath = path.join(tempDir, "sample.txt");
|
|
fs.writeFileSync(imagePath, "img");
|
|
fs.writeFileSync(audioPath, "aud");
|
|
fs.writeFileSync(filePath, "doc");
|
|
|
|
const adapter = createTelegramAdapter(
|
|
{
|
|
id: "default",
|
|
token: "tg-token",
|
|
enabled: true,
|
|
},
|
|
{ groupsEnabled: false },
|
|
logger,
|
|
async () => {},
|
|
undefined,
|
|
{ Bot: FakeBot },
|
|
);
|
|
|
|
const result = await adapter.sendMessage("12345", {
|
|
parts: [
|
|
{ type: "text", text: "hello" },
|
|
{ type: "image", filePath: imagePath, caption: "image caption" },
|
|
{ type: "audio", filePath: audioPath },
|
|
{ type: "file", filePath },
|
|
],
|
|
});
|
|
|
|
assert.equal(result.attemptedParts, 4);
|
|
assert.equal(result.sentParts, 4);
|
|
assert.ok(lastFakeBot);
|
|
assert.equal(lastFakeBot.calls.sendMessage.length, 1);
|
|
assert.equal(lastFakeBot.calls.sendPhoto.length, 1);
|
|
assert.equal(lastFakeBot.calls.sendAudio.length, 1);
|
|
assert.equal(lastFakeBot.calls.sendDocument.length, 1);
|
|
});
|
|
|
|
test("createTelegramAdapter downloads inbound media to store", async () => {
|
|
const logger = createLoggerStub();
|
|
const inbound = [];
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "opencode-router-tg-inbound-"));
|
|
const mediaStore = new MediaStore(path.join(tempDir, "media"));
|
|
await mediaStore.ensureReady();
|
|
|
|
const originalFetch = globalThis.fetch;
|
|
globalThis.fetch = async () =>
|
|
new Response("telegram-media", {
|
|
status: 200,
|
|
headers: { "content-type": "image/jpeg" },
|
|
});
|
|
|
|
try {
|
|
const adapter = createTelegramAdapter(
|
|
{
|
|
id: "default",
|
|
token: "tg-token",
|
|
enabled: true,
|
|
},
|
|
{ groupsEnabled: false },
|
|
logger,
|
|
async (message) => inbound.push(message),
|
|
mediaStore,
|
|
{ Bot: FakeBot },
|
|
);
|
|
|
|
await lastFakeBot.emitMessage({
|
|
chat: { id: 777, type: "private" },
|
|
caption: "here is photo",
|
|
photo: [{ file_id: "FILE123", file_unique_id: "UNIQ123", file_size: 13 }],
|
|
});
|
|
|
|
assert.equal(inbound.length, 1);
|
|
assert.equal(inbound[0].text, "here is photo");
|
|
const mediaPart = inbound[0].parts.find((part) => part.type === "media");
|
|
assert.ok(mediaPart);
|
|
assert.equal(mediaPart.media.status, "ready");
|
|
assert.ok(mediaPart.media.filePath);
|
|
assert.equal(fs.existsSync(mediaPart.media.filePath), true);
|
|
assert.equal(fs.readFileSync(mediaPart.media.filePath, "utf8"), "telegram-media");
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|
|
|
|
test("createTelegramAdapter ignores bot-originated inbound messages", async () => {
|
|
const logger = createLoggerStub();
|
|
const inbound = [];
|
|
|
|
createTelegramAdapter(
|
|
{
|
|
id: "default",
|
|
token: "tg-token",
|
|
enabled: true,
|
|
},
|
|
{ groupsEnabled: false },
|
|
logger,
|
|
async (message) => inbound.push(message),
|
|
undefined,
|
|
{ Bot: FakeBot },
|
|
);
|
|
|
|
await lastFakeBot.emitMessage({
|
|
chat: { id: 777, type: "private" },
|
|
from: { id: 999, is_bot: true },
|
|
text: "bot says hi",
|
|
});
|
|
|
|
await lastFakeBot.emitMessage({
|
|
chat: { id: 777, type: "private" },
|
|
from: { id: 123, is_bot: true },
|
|
text: "another bot says hi",
|
|
});
|
|
|
|
assert.equal(inbound.length, 0);
|
|
});
|