Skip to content

Commit

Permalink
perf: 减少全局临时变量
Browse files Browse the repository at this point in the history
  • Loading branch information
TBXark committed Aug 24, 2024
1 parent a6e1ff2 commit 10e1fd9
Show file tree
Hide file tree
Showing 11 changed files with 283 additions and 268 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"eslint": "^9.8.0",
"eslint-plugin-format": "^0.1.2",
"rollup-plugin-cleanup": "^3.2.1",
"telegram-bot-api-types": "^7.9.2",
"telegram-bot-api-types": "^7.9.3",
"typescript": "^5.5.4",
"vite": "^5.2.10",
"vite-plugin-checker": "^0.7.2",
Expand Down
62 changes: 13 additions & 49 deletions src/config/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,15 @@ import { DATABASE, ENV, mergeEnvironment } from './env';
import type { AgentUserConfig } from './config';

export class ShareContext {
currentBotId: number;
currentBotToken: string;
currentBotName: string | null = null;
botId: number;
botToken: string;
botName: string | null = null;

// KV 保存的键
chatHistoryKey: string;
chatLastMessageIdKey: string;

lastMessageKey: string;
configStoreKey: string;
groupAdminKey: string | null;
usageKey: string;

chatType: string;
chatId: number;
speakerId: number;

extraMessageContext: Telegram.Message | null = null;
groupAdminsKey?: string;

constructor(token: string, message: Telegram.Message) {
const botId = Number.parseInt(token.split(':')[0]);
Expand All @@ -28,12 +21,11 @@ export class ShareContext {
throw new Error('Token not allowed');
}
if (ENV.TELEGRAM_BOT_NAME.length > telegramIndex) {
this.currentBotName = ENV.TELEGRAM_BOT_NAME[telegramIndex];
this.botName = ENV.TELEGRAM_BOT_NAME[telegramIndex];
}

this.currentBotToken = token;
this.currentBotId = botId;
this.usageKey = `usage:${botId}`;
this.botToken = token;
this.botId = botId;
const id = message?.chat?.id;
if (id === undefined || id === null) {
throw new Error('Chat id not found');
Expand All @@ -50,7 +42,6 @@ export class ShareContext {

let historyKey = `history:${id}`;
let configStoreKey = `user_config:${id}`;
let groupAdminKey: string | null = null;

if (botId) {
historyKey += `:${botId}`;
Expand All @@ -64,7 +55,7 @@ export class ShareContext {
historyKey += `:${message.from.id}`;
configStoreKey += `:${message.from.id}`;
}
groupAdminKey = `group_admin:${id}`;
this.groupAdminsKey = `group_admin:${id}`;
break;
default:
break;
Expand All @@ -79,57 +70,30 @@ export class ShareContext {
}

this.chatHistoryKey = historyKey;
this.chatLastMessageIdKey = `last_message_id:${historyKey}`;
this.lastMessageKey = `last_message_id:${historyKey}`;
this.configStoreKey = configStoreKey;
this.groupAdminKey = groupAdminKey;

this.chatType = message.chat?.type;
this.chatId = message.chat.id;
this.speakerId = message.from?.id || message.chat.id;
}
}

export class CurrentChatContext {
chat_id: number;
message_id: number | null = null; // 当前发生的消息,用于后续编辑
reply_to_message_id: number | null;
parse_mode: string | null = ENV.DEFAULT_PARSE_MODE;
allow_sending_without_reply: boolean | null = null;
disable_web_page_preview: boolean | null = null;

constructor(message: Telegram.Message) {
this.chat_id = message.chat.id;
if (message.chat.type === 'group' || message.chat.type === 'supergroup') {
this.reply_to_message_id = message.message_id;
this.allow_sending_without_reply = true;
} else {
this.reply_to_message_id = null;
}
}
}

export class WorkerContext {
// 用户配置
USER_CONFIG: AgentUserConfig;
CURRENT_CHAT_CONTEXT: CurrentChatContext;
SHARE_CONTEXT: ShareContext;

constructor(USER_CONFIG: AgentUserConfig, CURRENT_CHAT_CONTEXT: CurrentChatContext, SHARE_CONTEXT: ShareContext) {
constructor(USER_CONFIG: AgentUserConfig, SHARE_CONTEXT: ShareContext) {
this.USER_CONFIG = USER_CONFIG;
this.CURRENT_CHAT_CONTEXT = CURRENT_CHAT_CONTEXT;
this.SHARE_CONTEXT = SHARE_CONTEXT;
}

static async from(token: string, message: Telegram.Message): Promise<WorkerContext> {
const SHARE_CONTEXT = new ShareContext(token, message);
const CURRENT_CHAT_CONTEXT = new CurrentChatContext(message);
const USER_CONFIG = Object.assign({}, ENV.USER_CONFIG);
try {
const userConfig: AgentUserConfig = JSON.parse(await DATABASE.get(SHARE_CONTEXT.configStoreKey));
mergeEnvironment(USER_CONFIG, userConfig?.trim(ENV.LOCK_USER_CONFIG_KEYS) || {});
} catch (e) {
console.warn(e);
}
return new WorkerContext(USER_CONFIG, CURRENT_CHAT_CONTEXT, SHARE_CONTEXT);
return new WorkerContext(USER_CONFIG, SHARE_CONTEXT);
}
}
23 changes: 11 additions & 12 deletions src/telegram/command/auth.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
import type { WorkerContext } from '../../config/context';
import { DATABASE } from '../../config/env';
import { createTelegramBotAPI } from '../api/api';
import type { Telegram, TelegramAPISuccess } from '../../types/telegram';
import type { Telegram } from '../../types/telegram';

export async function loadChatRoleWithContext(context: WorkerContext): Promise<string | null> {
const {
chatId,
speakerId,
groupAdminKey,
currentBotToken: token,
} = context.SHARE_CONTEXT;
export async function loadChatRoleWithContext(message: Telegram.Message, context: WorkerContext): Promise<string | null> {
const { groupAdminsKey } = context.SHARE_CONTEXT;

if (groupAdminKey === null) {
const chatId = message.chat.id;
const speakerId = message.from?.id || chatId;

if (!groupAdminsKey) {
return null;
}

let groupAdmin: Telegram.ChatMemberAdministrator[] | null = null;
try {
groupAdmin = JSON.parse(await DATABASE.get(groupAdminKey));
groupAdmin = JSON.parse(await DATABASE.get(groupAdminsKey));
} catch (e) {
console.error(e);
}
if (groupAdmin === null || !Array.isArray(groupAdmin) || groupAdmin.length === 0) {
const result = await createTelegramBotAPI(token).getChatAdministrators({ chat_id: chatId }).then(res => res.json()).catch(() => null) as TelegramAPISuccess<Telegram.ChatMemberAdministrator[]>;
const api = createTelegramBotAPI(context.SHARE_CONTEXT.botToken);
const result = await api.getChatAdministrators({ chat_id: chatId }).then(res => res.json()).catch(() => null) as Telegram.ResponseSuccess<Telegram.ChatMemberAdministrator[]>;
if (result == null) {
return null;
}
groupAdmin = result.result;
// 缓存120s
await DATABASE.put(
groupAdminKey,
groupAdminsKey,
JSON.stringify(groupAdmin),
{ expiration: (Date.now() / 1000) + 120 },
);
Expand Down
30 changes: 14 additions & 16 deletions src/telegram/command/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { WorkerContext } from '../../config/context';
import type { RequestTemplate } from '../../plugins/template';
import { executeRequest, formatInput } from '../../plugins/template';
import type { Telegram } from '../../types/telegram';
import { sendMessageToTelegramWithContext, sendPhotoToTelegramWithContext } from '../utils/send';
import { MessageSender } from '../utils/send';
import type { CommandHandler } from './type';
import {
ClearEnvCommandHandler,
Expand Down Expand Up @@ -36,33 +36,35 @@ const SYSTEM_COMMANDS: CommandHandler[] = [
];

async function handleSystemCommand(message: Telegram.Message, raw: string, command: CommandHandler, context: WorkerContext): Promise<Response> {
const sender = MessageSender.from(context.SHARE_CONTEXT.botToken, message);
try {
// 如果存在权限条件
if (command.needAuth) {
const roleList = command.needAuth(context.SHARE_CONTEXT.chatType);
const roleList = command.needAuth(message.chat.type);
if (roleList) {
// 获取身份并判断
const chatRole = await loadChatRoleWithContext(context);
const chatRole = await loadChatRoleWithContext(message, context);
if (chatRole === null) {
return sendMessageToTelegramWithContext(context)('ERROR: Get chat role failed');
return sender.sendPlainText('ERROR: Get chat role failed');
}
if (!roleList.includes(chatRole)) {
return sendMessageToTelegramWithContext(context)(`ERROR: Permission denied, need ${roleList.join(' or ')}`);
return sender.sendPlainText(`ERROR: Permission denied, need ${roleList.join(' or ')}`);
}
}
}
} catch (e) {
return sendMessageToTelegramWithContext(context)(`ERROR: ${(e as Error).message}`);
return sender.sendPlainText(`ERROR: ${(e as Error).message}`);
}
const subcommand = raw.substring(command.command.length).trim();
try {
return await command.handle(message, subcommand, context);
} catch (e) {
return sendMessageToTelegramWithContext(context)(`ERROR: ${(e as Error).message}`);
return sender.sendPlainText(`ERROR: ${(e as Error).message}`);
}
}

async function handlePluginCommand(message: Telegram.Message, command: string, raw: string, template: RequestTemplate, context: WorkerContext): Promise<Response> {
const sender = MessageSender.from(context.SHARE_CONTEXT.botToken, message);
try {
const subcommand = raw.substring(command.length).trim();
const DATA = formatInput(subcommand, template.input?.type);
Expand All @@ -71,24 +73,20 @@ async function handlePluginCommand(message: Telegram.Message, command: string, r
ENV: ENV.PLUGINS_ENV,
});
if (type === 'image') {
return sendPhotoToTelegramWithContext(context)(content);
return sender.sendPhoto(content);
}
switch (type) {
case 'html':
context.CURRENT_CHAT_CONTEXT.parse_mode = 'HTML';
break;
return sender.sendRichText(content, 'HTML');
case 'markdown':
context.CURRENT_CHAT_CONTEXT.parse_mode = 'Markdown';
break;
return sender.sendRichText(content, 'Markdown');
case 'text':
default:
context.CURRENT_CHAT_CONTEXT.parse_mode = null;
break;
return sender.sendPlainText(content);
}
return sendMessageToTelegramWithContext(context)(content);
} catch (e) {
const help = PLUGINS_COMMAND[command].description;
return sendMessageToTelegramWithContext(context)(`ERROR: ${(e as Error).message}${help ? `\n${help}` : ''}`);
return sender.sendPlainText(`ERROR: ${(e as Error).message}${help ? `\n${help}` : ''}`);
}
}

Expand Down
Loading

0 comments on commit 10e1fd9

Please sign in to comment.