MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / TelegramTransport

Class TelegramTransport

src/bot/adapters/telegram.ts:14–137  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

12const sleep = (ms: number) => new Promise(r => setTimeout(r, ms));
13
14export class TelegramTransport implements Transport {
15 readonly platform = 'telegram' as const;
16 readonly maxLen = 4096;
17 readonly minEditIntervalMs = 1100; // Telegram allows ~1 edit/s per chat
18 private offset = 0;
19 private running = false;
20
21 constructor(private token: string) {}
22
23 private async api(method: string, body: unknown): Promise<any> {
24 const res = await fetch(`https://api.telegram.org/bot${this.token}/${method}`, {
25 method: 'POST',
26 headers: { 'content-type': 'application/json' },
27 body: JSON.stringify(body),
28 });
29 return res.json();
30 }
31
32 private keyboard(buttons?: Button[][]) {
33 if (!buttons) return {};
34 return { reply_markup: { inline_keyboard: buttons.map(row => row.map(b => ({ text: b.label, callback_data: b.data }))) } };
35 }
36
37 async start(onMessage: (m: Incoming) => void): Promise<void> {
38 const me = await this.api('getMe', {});
39 if (!me.ok) throw new Error(`Telegram getMe failed: ${me.description ?? 'bad token'}`);
40 logger.info('telegram bot online', { username: me.result?.username });
41 this.running = true;
42 void this.loop(onMessage);
43 }
44
45 async stop(): Promise<void> { this.running = false; }
46
47 private async loop(onMessage: (m: Incoming) => void): Promise<void> {
48 while (this.running) {
49 try {
50 const res = await this.api('getUpdates', { offset: this.offset, timeout: 30, allowed_updates: ['message', 'callback_query'] });
51 if (!res.ok) { await sleep(2000); continue; }
52 for (const u of res.result) {
53 this.offset = u.update_id + 1;
54 if (u.message?.text) {
55 onMessage({ platform: 'telegram', chatId: String(u.message.chat.id), userId: String(u.message.from?.id), userName: u.message.from?.username, text: u.message.text });
56 } else if (u.message?.voice || u.message?.audio) {
57 // Voice memo → transcribe (local-first) → feed as text. Fire-and-forget so the
58 // poll loop keeps flowing; failures reply with a note instead of crashing.
59 void this.handleVoice(u.message, onMessage);
60 } else if (u.callback_query) {
61 const cq = u.callback_query;
62 onMessage({ platform: 'telegram', chatId: String(cq.message?.chat?.id), userId: String(cq.from?.id), text: '', callbackData: cq.data, callbackId: cq.id });
63 }
64 }
65 } catch (e: any) {
66 logger.warn('telegram poll error', { err: e?.message });
67 await sleep(2000);
68 }
69 }
70 }
71

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected