mirror of
https://github.com/zhigang1992/telert.git
synced 2026-01-12 16:43:18 +08:00
feat: add basic implementation
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20230404.0",
|
||||
"@grammyjs/types": "^3.1.1",
|
||||
"prettier": "^2.8.8",
|
||||
"typescript": "^5.0.4",
|
||||
"vitest": "^0.30.1",
|
||||
"wrangler": "2.17.0"
|
||||
@@ -15,7 +17,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@cfworker/web": "^1.12.5",
|
||||
"cfworker-middleware-telegraf": "^2.0.2",
|
||||
"telegraf": "^4.12.2"
|
||||
}
|
||||
}
|
||||
|
||||
34
pnpm-lock.yaml
generated
34
pnpm-lock.yaml
generated
@@ -4,9 +4,6 @@ dependencies:
|
||||
'@cfworker/web':
|
||||
specifier: ^1.12.5
|
||||
version: 1.12.5
|
||||
cfworker-middleware-telegraf:
|
||||
specifier: ^2.0.2
|
||||
version: 2.0.2(@cfworker/web@1.12.5)(telegraf@4.12.2)
|
||||
telegraf:
|
||||
specifier: ^4.12.2
|
||||
version: 4.12.2
|
||||
@@ -15,6 +12,12 @@ devDependencies:
|
||||
'@cloudflare/workers-types':
|
||||
specifier: ^4.20230404.0
|
||||
version: 4.20230404.0
|
||||
'@grammyjs/types':
|
||||
specifier: ^3.1.1
|
||||
version: 3.1.1
|
||||
prettier:
|
||||
specifier: ^2.8.8
|
||||
version: 2.8.8
|
||||
typescript:
|
||||
specifier: ^5.0.4
|
||||
version: 5.0.4
|
||||
@@ -480,6 +483,10 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@grammyjs/types@3.1.1:
|
||||
resolution: {integrity: sha512-nTNYvk+Al/nXZAMTEzPYEyW6pfgYgNuf/gxfx17kCxjHpAYhV+pcmROuD9eOBDLaBDh/hZJkQTIY6S3CfTAC0Q==}
|
||||
dev: true
|
||||
|
||||
/@iarna/toml@2.2.5:
|
||||
resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
|
||||
dev: true
|
||||
@@ -741,10 +748,6 @@ packages:
|
||||
event-target-shim: 5.0.1
|
||||
dev: false
|
||||
|
||||
/abortcontroller-polyfill@1.7.5:
|
||||
resolution: {integrity: sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==}
|
||||
dev: false
|
||||
|
||||
/acorn-walk@8.2.0:
|
||||
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
@@ -835,17 +838,6 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/cfworker-middleware-telegraf@2.0.2(@cfworker/web@1.12.5)(telegraf@4.12.2):
|
||||
resolution: {integrity: sha512-3tj4R60AyTioaxS88shO4AYcL4N6QLPEeU5kflF5zIXHc4EI3yzbZLUEphe7/ExTVVrLJI9IwPP3JfOUZltiJw==}
|
||||
peerDependencies:
|
||||
'@cfworker/web': ^1.12.0
|
||||
telegraf: ^4.6.0
|
||||
dependencies:
|
||||
'@cfworker/web': 1.12.5
|
||||
abortcontroller-polyfill: 1.7.5
|
||||
telegraf: 4.12.2
|
||||
dev: false
|
||||
|
||||
/chai@4.3.7:
|
||||
resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -1378,6 +1370,12 @@ packages:
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/prettier@2.8.8:
|
||||
resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/pretty-format@27.5.1:
|
||||
resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
|
||||
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
|
||||
|
||||
101
src/index.ts
101
src/index.ts
@@ -7,34 +7,93 @@
|
||||
*
|
||||
* Learn more at https://developers.cloudflare.com/workers/
|
||||
*/
|
||||
import {Telegraf} from "telegraf";
|
||||
import { Application, Router } from "@cfworker/web";
|
||||
import createTelegrafMiddleware from 'cfworker-middleware-telegraf'
|
||||
|
||||
export interface Env {
|
||||
// Example binding to KV. Learn more at https://developers.cloudflare.com/workers/runtime-apis/kv/
|
||||
TG_GROUPS: KVNamespace;
|
||||
//
|
||||
// Example binding to Durable Object. Learn more at https://developers.cloudflare.com/workers/runtime-apis/durable-objects/
|
||||
// MY_DURABLE_OBJECT: DurableObjectNamespace;
|
||||
//
|
||||
// Example binding to R2. Learn more at https://developers.cloudflare.com/workers/runtime-apis/r2/
|
||||
// MY_BUCKET: R2Bucket;
|
||||
//
|
||||
// Example binding to a Service. Learn more at https://developers.cloudflare.com/workers/runtime-apis/service-bindings/
|
||||
// MY_SERVICE: Fetcher;
|
||||
}
|
||||
import type { Update } from "@grammyjs/types";
|
||||
import { formatRichMessage, RichMessage } from "./message";
|
||||
|
||||
declare global {
|
||||
const BOT_TOKEN: string
|
||||
const SECRET_PATH: string
|
||||
}
|
||||
const BOT_TOKEN: string;
|
||||
|
||||
const bot = new Telegraf(BOT_TOKEN);
|
||||
const WEBHOOK_PREFIX: string;
|
||||
|
||||
const TG_GROUPS: KVNamespace;
|
||||
}
|
||||
|
||||
// Your code here, but do not `bot.launch()`
|
||||
// Do not forget to set environment variables BOT_TOKEN and SECRET_PATH on your worker
|
||||
|
||||
const router = new Router();
|
||||
router.post(`/${SECRET_PATH}`, createTelegrafMiddleware(bot));
|
||||
router.post("/bot", async (context) => {
|
||||
const result: Update = await context.req.body.json();
|
||||
await processUpdate(result);
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
context.res.body = { ok: true };
|
||||
});
|
||||
|
||||
router.post("/t/:webhookId/raw", async (context) => {
|
||||
const chatId = await TG_GROUPS.get(
|
||||
`webhook-chat:${context.req.params.webhookId}`
|
||||
);
|
||||
if (chatId == null) {
|
||||
context.res.body = { ok: false, error: "chatId not found" };
|
||||
context.res.status = 404;
|
||||
}
|
||||
const result = await context.req.body.text();
|
||||
await sendToChat(Number(chatId), result);
|
||||
context.res.body = { ok: true };
|
||||
});
|
||||
|
||||
router.post("/t/:webhookId", async (context) => {
|
||||
const chatId = await TG_GROUPS.get(
|
||||
`webhook-chat:${context.req.params.webhookId}`
|
||||
);
|
||||
if (chatId == null) {
|
||||
context.res.body = { ok: false, error: "chatId not found" };
|
||||
context.res.status = 404;
|
||||
}
|
||||
const result: RichMessage = await context.req.body.json();
|
||||
await sendToChat(Number(chatId), formatRichMessage(result), "HTML");
|
||||
context.res.body = { ok: true };
|
||||
});
|
||||
|
||||
new Application().use(router.middleware).listen();
|
||||
|
||||
async function processUpdate(update: Update): Promise<void> {
|
||||
if (update.message == null) {
|
||||
return;
|
||||
}
|
||||
if (update.message.text === "/webhook") {
|
||||
const chatId = update.message.chat.id;
|
||||
const key = `chat-webhook:${chatId}`;
|
||||
const result = await TG_GROUPS.get(key);
|
||||
let webhookUrl: string;
|
||||
if (result == null) {
|
||||
const uuid = crypto.randomUUID();
|
||||
await TG_GROUPS.put(key, uuid);
|
||||
await TG_GROUPS.put(`webhook-chat:${uuid}`, chatId.toString());
|
||||
webhookUrl = `${WEBHOOK_PREFIX}/t/${uuid}`;
|
||||
} else {
|
||||
await TG_GROUPS.put(`webhook-chat:${result}`, chatId.toString());
|
||||
webhookUrl = `${WEBHOOK_PREFIX}/t/${result}`;
|
||||
}
|
||||
await sendToChat(chatId, webhookUrl);
|
||||
}
|
||||
}
|
||||
|
||||
async function sendToChat(
|
||||
chatId: number,
|
||||
text: string,
|
||||
parseMode?: "HTML"
|
||||
): Promise<void> {
|
||||
await fetch(`https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
chat_id: chatId,
|
||||
text,
|
||||
parse_mode: parseMode,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
22
src/message.ts
Normal file
22
src/message.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export type RichMessage = {
|
||||
topic: string;
|
||||
event: string;
|
||||
text?: string;
|
||||
emoji?: string;
|
||||
metadata?: Record<string, string>;
|
||||
};
|
||||
|
||||
export function formatRichMessage(message: RichMessage): string {
|
||||
const metadata = Object.entries(message.metadata ?? {})
|
||||
.map(([key, value]) => `#${key}: ${value}`)
|
||||
.join("\n");
|
||||
return `${message.emoji ? message.emoji + " • " : ""}<ins>#${
|
||||
message.topic
|
||||
}</ins>
|
||||
|
||||
<b>${message.event}</b>${message.text ? `
|
||||
|
||||
<code>${message.text}</code>` : ""}
|
||||
|
||||
${metadata}`;
|
||||
}
|
||||
Reference in New Issue
Block a user