feat: 添加通知功能自定义telegram域名功能

This commit is contained in:
Baobhan Sith
2025-05-11 13:02:09 +08:00
parent 598df938bf
commit d7bee11383
34 changed files with 121 additions and 71 deletions
@@ -121,7 +121,7 @@ export const uploadTerminalBackgroundController = async (req: Request, res: Resp
};
/**
* 新增:获取背景图片文件
* 获取背景图片文件
*/
export const getBackgroundFileController = async (req: Request, res: Response): Promise<void> => {
const filename = req.params.filename;
@@ -27,7 +27,7 @@ router.post(
appearanceController.uploadTerminalBackgroundController
);
// 新增:GET /api/v1/appearance/background/file/:filename - 获取背景图片文件
// GET /api/v1/appearance/background/file/:filename - 获取背景图片文件
router.get('/background/file/:filename', appearanceController.getBackgroundFileController);
// DELETE /api/v1/appearance/background/page - 删除页面背景图片
+1 -1
View File
@@ -19,7 +19,7 @@ import {
// 新的 Passkey 管理处理器
listUserPasskeysHandler,
deleteUserPasskeyHandler,
updateUserPasskeyNameHandler, // 新增:更新 Passkey 名称的处理器
updateUserPasskeyNameHandler, // 更新 Passkey 名称的处理器
checkHasPasskeys
} from './auth.controller';
import { isAuthenticated } from './auth.middleware';
@@ -18,7 +18,7 @@ interface DbAppearanceSettingsRow {
const mapRowsToAppearanceSettings = (rows: DbAppearanceSettingsRow[]): AppearanceSettings => {
const settings: Partial<AppearanceSettings> = {};
let latestUpdatedAt = 0;
let terminalBackgroundEnabledFound = false; // 新增:标记是否在数据库中找到该设置
let terminalBackgroundEnabledFound = false; // 标记是否在数据库中找到该设置
for (const row of rows) {
// 更新 latestUpdatedAt
@@ -85,7 +85,7 @@ const getDefaultAppearanceSettings = (): Omit<AppearanceSettings, '_id'> => {
editorFontSize: 14,
terminalBackgroundImage: undefined,
pageBackgroundImage: undefined,
terminalBackgroundEnabled: true, // 新增:默认启用
terminalBackgroundEnabled: true, // 默认启用
updatedAt: Date.now(), // 提供默认时间戳
};
};
@@ -249,7 +249,7 @@ const updateAppearanceSettingsInternal = async (db: sqlite3.Database, settingsDt
dbValue = key === 'activeTerminalThemeId' ? 'null' : ''; // 主题 ID 特殊存储为 'null'
} else if (typeof value === 'object') {
dbValue = JSON.stringify(value);
} else if (typeof value === 'boolean') { // 新增:处理布尔值
} else if (typeof value === 'boolean') { // 处理布尔值
dbValue = value ? 'true' : 'false';
} else {
dbValue = String(value);
@@ -356,7 +356,17 @@ export class NotificationService {
);
console.log(`[通知测试 - Telegram] 渲染的消息文本:`, messageText);
const telegramApiUrl = `https://api.telegram.org/bot${config.botToken}/sendMessage`;
let baseApiUrl = "https://api.telegram.org";
if (config.customDomain) {
try {
const url = new URL(config.customDomain);
baseApiUrl = `${url.protocol}//${url.host}`;
console.log(`[通知测试 - Telegram] 使用自定义域名: ${baseApiUrl}`);
} catch (e) {
console.warn(`[通知测试 - Telegram] 无效的自定义域名 URL: ${config.customDomain}。将回退到默认 Telegram API。`);
}
}
const telegramApiUrl = `${baseApiUrl}/bot${config.botToken}/sendMessage`;
try {
console.log(
@@ -802,7 +812,18 @@ export class NotificationService {
}
console.log(`[_sendTelegram] Final message text to send:`, messageText);
const telegramApiUrl = `https://api.telegram.org/bot${config.botToken}/sendMessage`;
let baseApiUrlSend = "https://api.telegram.org";
if (config.customDomain) {
try {
const url = new URL(config.customDomain);
baseApiUrlSend = `${url.protocol}//${url.host}`;
console.log(`[_sendTelegram] 使用自定义域名: ${baseApiUrlSend} (事件: ${payload.event})`);
} catch (e) {
console.warn(`[_sendTelegram] 无效的自定义域名 URL: ${config.customDomain} (事件: ${payload.event})。将回退到默认 Telegram API。`);
}
}
const telegramApiUrl = `${baseApiUrlSend}/bot${config.botToken}/sendMessage`;
try {
console.log(
`[通知] 发送 Telegram 消息到聊天 ID ${config.chatId} (事件: ${payload.event})`
@@ -6,7 +6,7 @@ import { TelegramConfig } from "../../types/notification.types";
class TelegramSenderService implements INotificationSender {
async send(notification: ProcessedNotification): Promise<void> {
const config = notification.config as TelegramConfig;
const { botToken, chatId } = config;
const { botToken, chatId, customDomain } = config; // Destructure customDomain
const messageBody = notification.body;
if (!botToken || !chatId) {
@@ -18,7 +18,19 @@ class TelegramSenderService implements INotificationSender {
);
}
const apiUrl = `https://api.telegram.org/bot${botToken}/sendMessage`;
let baseApiUrl = "https://api.telegram.org";
if (customDomain) {
try {
const url = new URL(customDomain); // Validate and parse the custom domain
baseApiUrl = `${url.protocol}//${url.host}`; // Use protocol and host from customDomain
console.log(`[TelegramSender] Using custom domain: ${baseApiUrl}`);
} catch (e) {
console.warn(`[TelegramSender] Invalid customDomain URL: ${customDomain}. Falling back to default Telegram API.`);
// Optionally, you could throw an error here or decide to proceed with the default
}
}
const apiUrl = `${baseApiUrl}/bot${botToken}/sendMessage`;
try {
console.log(
@@ -753,7 +753,7 @@ export class SftpService {
}
try {
// --- 新增:移动前检查目标是否存在 ---
// --- 移动前检查目标是否存在 ---
let targetExists = false;
try {
await this.getStats(sftp, newPath);
@@ -1011,7 +1011,7 @@ export class SftpService {
console.log(`[SFTP Upload ${uploadId}] Starting upload for ${remotePath} (${totalSize} bytes) in session ${sessionId}`);
try {
// --- 新增:在创建流之前确保目录存在 ---
// --- 在创建流之前确保目录存在 ---
if (relativePath) {
const targetDirectory = pathModule.dirname(remotePath).replace(/\\/g, '/');
console.log(`[SFTP Upload ${uploadId}] Ensuring directory exists: ${targetDirectory}`);
@@ -1029,7 +1029,7 @@ export class SftpService {
}
// --- 结束新增 ---
// --- 新增:预检查文件是否可写 ---
// --- 预检查文件是否可写 ---
console.log(`[SFTP Upload ${uploadId}] Pre-checking writability for: ${remotePath}`);
try {
// 确保 state.sftp 存在
@@ -16,7 +16,7 @@ export interface AppearanceSettings {
terminalBackgroundImage?: string; // 终端背景图片 URL 或路径
pageBackgroundImage?: string; // 页面背景图片 URL 或路径
editorFontSize?: number; // 编辑器字体大小 (px)
terminalBackgroundEnabled?: boolean; // 新增:终端背景是否启用
terminalBackgroundEnabled?: boolean; // 终端背景是否启用
updatedAt?: number;
}
@@ -40,6 +40,7 @@ export interface TelegramConfig {
botToken: string; // Consider storing this securely, maybe encrypted or via env vars
chatId: string; // Target chat ID
messageTemplate?: string; // Optional message template
customDomain?: string; // 允许用户自定义 Telegram API 域名
}
export type NotificationChannelConfig = WebhookConfig | EmailConfig | TelegramConfig;
@@ -16,7 +16,7 @@ export function handleRdpProxyConnection(
const rdpWidthStr = (request as any).rdpWidth; // Get as string first
const rdpHeightStr = (request as any).rdpHeight; // Get as string first
// --- 新增:参数验证和 DPI 计算 ---
// --- 参数验证和 DPI 计算 ---
if (!rdpToken || !rdpWidthStr || !rdpHeightStr) { // Check string presence
console.error(`WebSocket: RDP Proxy connection for ${ws.username} missing required parameters (token, width, height).`);
ws.send(JSON.stringify({ type: 'rdp:error', payload: 'Missing RDP connection parameters (token, width, height).' }));
+4 -4
View File
@@ -20,10 +20,10 @@ export interface ClientState { // 导出以便 Service 可以导入
statusIntervalId?: NodeJS.Timeout; // 添加状态轮询 ID (由 StatusMonitorService 管理)
dockerStatusIntervalId?: NodeJS.Timeout; // NEW: Docker 状态轮询 ID
ipAddress?: string; // 添加 IP 地址字段
isShellReady?: boolean; // 新增:标记 Shell 是否已准备好处理输入和调整大小
isSuspendedByService?: boolean; // 新增:标记此会话是否已被 SshSuspendService 接管
isMarkedForSuspend?: boolean; // 新增:标记此会话是否已被用户请求挂起(等待断开连接)
suspendLogPath?: string; // 新增:如果标记挂起,则存储日志路径 (基于原始 sessionId)
isShellReady?: boolean; // 标记 Shell 是否已准备好处理输入和调整大小
isSuspendedByService?: boolean; // 标记此会话是否已被 SshSuspendService 接管
isMarkedForSuspend?: boolean; // 标记此会话是否已被用户请求挂起(等待断开连接)
suspendLogPath?: string; // 如果标记挂起,则存储日志路径 (基于原始 sessionId)
// suspendLogWritableStream?: NodeJS.WritableStream; // 移除,将直接使用 temporaryLogStorageService.writeToLog
}