- Remove Queue-based server provisioning (moved to cloud-orchestrator) - Add manage_server tool with Service Binding to Cloud Orchestrator - Add CDN cache hit rate estimation based on tech_stack - Always display bandwidth info (show "포함 범위 내" when no overage) - Add language auto-detection (ko, ja, zh, en) - Update system prompt to always call tools fresh - Add Server System documentation to CLAUDE.md BREAKING: Server provisioning now requires cloud-orchestrator service Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
121 lines
3.8 KiB
TypeScript
121 lines
3.8 KiB
TypeScript
import { sendMessage, sendMessageWithKeyboard } from '../../telegram';
|
|
import { checkRateLimit } from '../../security';
|
|
import { handleCommand } from '../../commands';
|
|
import { UserService } from '../../services/user-service';
|
|
import { ConversationService } from '../../services/conversation-service';
|
|
import { ERROR_MESSAGES } from '../../constants/messages';
|
|
import type { Env, TelegramUpdate } from '../../types';
|
|
|
|
/**
|
|
* 메시지 처리 핸들러
|
|
*/
|
|
export async function handleMessage(
|
|
env: Env,
|
|
update: TelegramUpdate
|
|
): Promise<void> {
|
|
if (!update.message?.text) return;
|
|
|
|
const { message } = update;
|
|
const chatId = message.chat.id;
|
|
const chatIdStr = chatId.toString();
|
|
const text = message.text!;
|
|
const telegramUserId = message.from.id.toString();
|
|
|
|
// 1. Rate Limiting 체크
|
|
if (!(await checkRateLimit(env.RATE_LIMIT_KV, telegramUserId))) {
|
|
await sendMessage(
|
|
env.BOT_TOKEN,
|
|
chatId,
|
|
'⚠️ 너무 많은 요청입니다. 잠시 후 다시 시도해주세요.'
|
|
);
|
|
return;
|
|
}
|
|
|
|
// 2. 서비스 인스턴스 초기화
|
|
const userService = new UserService(env.DB);
|
|
const conversationService = new ConversationService(env);
|
|
|
|
// 3. 사용자 조회/생성
|
|
let userId: number;
|
|
try {
|
|
userId = await userService.getOrCreateUser(
|
|
telegramUserId,
|
|
message.from.first_name,
|
|
message.from.username
|
|
);
|
|
} catch (dbError) {
|
|
console.error('[handleMessage] 사용자 DB 오류:', dbError);
|
|
await sendMessage(
|
|
env.BOT_TOKEN,
|
|
chatId,
|
|
ERROR_MESSAGES.TEMPORARY_ERROR
|
|
);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// 4. 명령어 처리
|
|
if (text.startsWith('/')) {
|
|
const [command, ...argParts] = text.split(' ');
|
|
const args = argParts.join(' ');
|
|
const responseText = await handleCommand(env, userId, chatIdStr, command, args);
|
|
|
|
// /start 명령어는 미니앱 버튼과 함께 전송
|
|
if (command === '/start') {
|
|
const hostingUrl = env.HOSTING_SITE_URL || 'https://hosting.anvil.it.com';
|
|
await sendMessageWithKeyboard(env.BOT_TOKEN, chatId, responseText, [
|
|
[{ text: '🌐 서비스 보기', web_app: { url: hostingUrl } }],
|
|
[{ text: '💬 문의하기', url: 'https://t.me/AnvilForgeBot' }],
|
|
]);
|
|
return;
|
|
}
|
|
|
|
await sendMessage(env.BOT_TOKEN, chatId, responseText);
|
|
return;
|
|
}
|
|
|
|
// 5. 일반 대화 처리 (ConversationService 위임)
|
|
const result = await conversationService.processUserMessage(
|
|
userId,
|
|
chatIdStr,
|
|
text,
|
|
telegramUserId
|
|
);
|
|
|
|
let finalResponse = result.responseText;
|
|
if (result.isProfileUpdated) {
|
|
finalResponse += '\n\n<i>👤 프로필이 업데이트되었습니다.</i>';
|
|
}
|
|
|
|
// 6. 응답 전송 (키보드 포함 여부 확인)
|
|
if (result.keyboardData) {
|
|
console.log('[Webhook] Keyboard data received:', result.keyboardData.type);
|
|
if (result.keyboardData.type === 'domain_register') {
|
|
const { domain, price } = result.keyboardData;
|
|
const callbackData = `domain_reg:${domain}:${price}`;
|
|
|
|
await sendMessageWithKeyboard(env.BOT_TOKEN, chatId, finalResponse, [
|
|
[
|
|
{ text: '✅ 등록하기', callback_data: callbackData },
|
|
{ text: '❌ 취소', callback_data: 'domain_cancel' }
|
|
]
|
|
]);
|
|
} else {
|
|
// TypeScript exhaustiveness check - should never reach here
|
|
console.warn('[Webhook] Unknown keyboard type:', (result.keyboardData as { type: string }).type);
|
|
await sendMessage(env.BOT_TOKEN, chatId, finalResponse);
|
|
}
|
|
} else {
|
|
await sendMessage(env.BOT_TOKEN, chatId, finalResponse);
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('[handleMessage] 처리 오류:', error);
|
|
await sendMessage(
|
|
env.BOT_TOKEN,
|
|
chatId,
|
|
'⚠️ 메시지 처리 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요.'
|
|
);
|
|
}
|
|
}
|