@deadragdoll/tellymcp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example.client +93 -0
- package/.env.example.gateway +120 -0
- package/CHANGELOG.md +155 -0
- package/LICENSE +21 -0
- package/README-ru.md +338 -0
- package/README.md +1262 -0
- package/STANDALONE-ru.md +266 -0
- package/STANDALONE.md +266 -0
- package/TOOLS.md +1296 -0
- package/config/templates/env.both.template +83 -0
- package/config/templates/env.client.template +60 -0
- package/config/templates/env.gateway.template +82 -0
- package/dist/cli.js +636 -0
- package/dist/index.js +17 -0
- package/dist/lib/logfeed/store.js +52 -0
- package/dist/lib/middlewares/tracer.js +172 -0
- package/dist/lib/mixins/db.js +267 -0
- package/dist/lib/mixins/logfeed.js +34 -0
- package/dist/lib/mixins/session.errors.js +142 -0
- package/dist/lib/moleculer.js +2 -0
- package/dist/lib/trace.js +147 -0
- package/dist/lib/traceContext.js +116 -0
- package/dist/moleculer.config.js +274 -0
- package/dist/services/features/telegram-mcp/approval.service.js +33 -0
- package/dist/services/features/telegram-mcp/browser.service.js +42 -0
- package/dist/services/features/telegram-mcp/collaboration.service.js +53 -0
- package/dist/services/features/telegram-mcp/ensuredb.service.js +337 -0
- package/dist/services/features/telegram-mcp/gateway-delivery.service.js +378 -0
- package/dist/services/features/telegram-mcp/gateway-loopback.js +10 -0
- package/dist/services/features/telegram-mcp/gateway-rmq.service.js +294 -0
- package/dist/services/features/telegram-mcp/gateway-socket.service.js +1463 -0
- package/dist/services/features/telegram-mcp/gateway.service.js +1141 -0
- package/dist/services/features/telegram-mcp/inbox.service.js +33 -0
- package/dist/services/features/telegram-mcp/mcp-http.service.js +76 -0
- package/dist/services/features/telegram-mcp/mcp-server.service.js +127 -0
- package/dist/services/features/telegram-mcp/notify.service.js +33 -0
- package/dist/services/features/telegram-mcp/pair.service.js +33 -0
- package/dist/services/features/telegram-mcp/runtime.service.js +36 -0
- package/dist/services/features/telegram-mcp/session-context.service.js +33 -0
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +103 -0
- package/dist/services/features/telegram-mcp/src/app/config/env.js +317 -0
- package/dist/services/features/telegram-mcp/src/app/http.js +774 -0
- package/dist/services/features/telegram-mcp/src/app/index.js +2 -0
- package/dist/services/features/telegram-mcp/src/app/providers/mcp/server.js +13 -0
- package/dist/services/features/telegram-mcp/src/app/providers/redis/client.js +18 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +740 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +267 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/relay.js +69 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/tmux.js +9 -0
- package/dist/services/features/telegram-mcp/src/entities/auth/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/browser/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/collaboration/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/inbox/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +545 -0
- package/dist/services/features/telegram-mcp/src/entities/request/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/session/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/ask-user/model/askUserTelegram.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserClearLogsTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserClickTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserCloseTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserComputedStyleTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserConsoleTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDomTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserErrorsTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserFillTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserNetworkFailuresTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserOpenTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserPressTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserReloadTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +689 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForUrlTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/backend.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +26 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/localCollaborationBackend.js +390 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +102 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerNoteTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +69 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +657 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayReplyResolution.js +17 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/deleteTelegramInboxMessageTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/inboxService.js +77 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +93 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyTelegramTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/clearSessionPairingTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/createSessionPairCodeTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js +202 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/clearSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/getSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/getTmuxTargetTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/renameSessionTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +409 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/setSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/setTmuxTargetTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownService.js +123 -0
- package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/processes/human-approval/model/orchestrator.js +243 -0
- package/dist/services/features/telegram-mcp/src/shared/api/storage/contract.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/registry.js +8 -0
- package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/api/transport/contract.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +86 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +436 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabSemantics.js +21 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabUi.js +87 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/messageFormat.js +60 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/proxyFetch.js +46 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +6534 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/tmux/client.js +280 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/ids/ids.js +34 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/logger/logger.js +68 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +223 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/redact-secrets/redactSecrets.js +22 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/truncate/truncate.js +12 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/version/versionHandshake.js +124 -0
- package/dist/services/features/telegram-mcp/src/shared/types/common.js +2 -0
- package/dist/services/features/telegram-mcp/standalone-http.service.js +113 -0
- package/dist/services/features/telegram-mcp/tools-sync.service.js +33 -0
- package/package.json +110 -0
- package/scripts/postinstall.js +60 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TELEGRAM_MCP_GATEWAY_DELIVERY_SERVICE_NAME = void 0;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const runtime_service_1 = require("./runtime.service");
|
|
9
|
+
const ids_1 = require("./src/shared/lib/ids/ids");
|
|
10
|
+
const client_1 = require("./src/shared/integrations/tmux/client");
|
|
11
|
+
exports.TELEGRAM_MCP_GATEWAY_DELIVERY_SERVICE_NAME = "telegramMcp.gatewayDelivery";
|
|
12
|
+
function renderYamlArray(values) {
|
|
13
|
+
if (values.length === 0) {
|
|
14
|
+
return "[]";
|
|
15
|
+
}
|
|
16
|
+
return `\n${values.map((value) => ` - ${JSON.stringify(value)}`).join("\n")}`;
|
|
17
|
+
}
|
|
18
|
+
function buildNoteContent(input) {
|
|
19
|
+
const lines = ["---"];
|
|
20
|
+
lines.push(`message_uuid: ${JSON.stringify(input.delivery.message_uuid)}`);
|
|
21
|
+
lines.push(`kind: ${JSON.stringify(input.delivery.kind)}`);
|
|
22
|
+
lines.push(`from_session_id: ${JSON.stringify(input.delivery.source_session_uuid)}`);
|
|
23
|
+
lines.push(`from_label: ${JSON.stringify(input.delivery.source_session_label)}`);
|
|
24
|
+
lines.push(`to_session_id: ${JSON.stringify(input.delivery.target_session_uuid)}`);
|
|
25
|
+
lines.push(`to_label: ${JSON.stringify(input.delivery.target_session_label)}`);
|
|
26
|
+
lines.push(`created_at: ${JSON.stringify(input.delivery.created_at)}`);
|
|
27
|
+
if (input.delivery.project_uuid) {
|
|
28
|
+
lines.push(`project_uuid: ${JSON.stringify(input.delivery.project_uuid)}`);
|
|
29
|
+
}
|
|
30
|
+
if (input.delivery.requires_reply) {
|
|
31
|
+
lines.push("requires_reply: true");
|
|
32
|
+
}
|
|
33
|
+
if (input.delivery.in_reply_to) {
|
|
34
|
+
lines.push(`in_reply_to: ${JSON.stringify(input.delivery.in_reply_to)}`);
|
|
35
|
+
}
|
|
36
|
+
if (input.copiedArtifacts.length > 0) {
|
|
37
|
+
lines.push(`artifacts:${renderYamlArray(input.copiedArtifacts)}`);
|
|
38
|
+
}
|
|
39
|
+
lines.push("---", "", "# Summary", input.delivery.summary.trim(), "", "# Message", input.delivery.message.trim());
|
|
40
|
+
if (input.delivery.expected_reply?.trim()) {
|
|
41
|
+
lines.push("", "# Expected Reply", input.delivery.expected_reply.trim());
|
|
42
|
+
}
|
|
43
|
+
if (input.delivery.requires_reply) {
|
|
44
|
+
lines.push("", "# Reply Params", `message_uuid: ${input.delivery.message_uuid}`, `target_session_id: ${input.delivery.source_session_uuid}`, ...(input.delivery.project_uuid
|
|
45
|
+
? [`project_uuid: ${input.delivery.project_uuid}`]
|
|
46
|
+
: []), "", "# Action Required", "You must send a reply via send_partner_note.", "Your task is not complete until send_partner_note succeeds.", "Do not stop after local analysis or a chat explanation.", "Do not rely on linked partner.", "Pass target_session_id explicitly.", "If possible, also pass in_reply_to=message_uuid.", "Only after the tool succeeds may you say that the reply was sent.", "", "# Reply Tool Call Example", "send_partner_note(", ` session_id=${JSON.stringify(input.delivery.target_local_session_id)},`, ` target_session_id=${JSON.stringify(input.delivery.source_session_uuid)},`, ` kind=${JSON.stringify("reply")},`, ...(input.delivery.project_uuid
|
|
47
|
+
? [` project_uuid=${JSON.stringify(input.delivery.project_uuid)},`]
|
|
48
|
+
: []), ` in_reply_to=${JSON.stringify(input.delivery.message_uuid)},`, " summary=\"Короткий итог\",", " message=\"Подробный ответ\"", ")");
|
|
49
|
+
}
|
|
50
|
+
if (input.copiedArtifacts.length > 0) {
|
|
51
|
+
lines.push("", "# Artifacts", ...input.copiedArtifacts.map((artifact) => `- ${artifact}`));
|
|
52
|
+
}
|
|
53
|
+
return `${lines.join("\n")}\n`;
|
|
54
|
+
}
|
|
55
|
+
function buildShareIndexLine(input) {
|
|
56
|
+
return [
|
|
57
|
+
"-",
|
|
58
|
+
`[${input.delivery.created_at}]`,
|
|
59
|
+
`${input.delivery.source_session_label} → ${input.delivery.target_session_label}`,
|
|
60
|
+
`| ${input.delivery.kind} |`,
|
|
61
|
+
`${input.delivery.summary}`,
|
|
62
|
+
`| \`${input.relativeNotePath}\``,
|
|
63
|
+
].join(" ");
|
|
64
|
+
}
|
|
65
|
+
function buildPartnerInboxText(input) {
|
|
66
|
+
const sourceActorLabel = input.delivery.source_actor_label || input.delivery.source_session_label;
|
|
67
|
+
const kindTitle = input.delivery.kind === "question"
|
|
68
|
+
? `Получен вопрос от ${sourceActorLabel}.`
|
|
69
|
+
: input.delivery.kind === "reply"
|
|
70
|
+
? `Получен ответ от ${sourceActorLabel}.`
|
|
71
|
+
: input.delivery.kind === "request"
|
|
72
|
+
? `Получен запрос от ${sourceActorLabel}.`
|
|
73
|
+
: input.delivery.kind === "handoff"
|
|
74
|
+
? `Получен handoff от ${sourceActorLabel}.`
|
|
75
|
+
: `Получено обновление от ${sourceActorLabel}.`;
|
|
76
|
+
return [
|
|
77
|
+
kindTitle,
|
|
78
|
+
...(input.delivery.project_name
|
|
79
|
+
? [`Проект: ${input.delivery.project_name}`]
|
|
80
|
+
: []),
|
|
81
|
+
`Сессия: ${input.delivery.source_session_label} -> ${input.delivery.target_session_label}`,
|
|
82
|
+
`Кратко: ${input.delivery.summary}`,
|
|
83
|
+
"",
|
|
84
|
+
`Действие: открой ${input.delivery.share_index_file_name}, затем note ниже.`,
|
|
85
|
+
`Note: ${input.notePath}`,
|
|
86
|
+
...(input.copiedArtifacts.length > 0
|
|
87
|
+
? ["", "Файлы:", ...input.copiedArtifacts.map((item) => `- ${item}`)]
|
|
88
|
+
: []),
|
|
89
|
+
...(input.delivery.requires_reply
|
|
90
|
+
? [
|
|
91
|
+
"",
|
|
92
|
+
`Reply message_uuid: ${input.delivery.message_uuid}`,
|
|
93
|
+
`Reply target_session_id: ${input.delivery.source_session_uuid}`,
|
|
94
|
+
...(input.delivery.project_uuid
|
|
95
|
+
? [`Reply project_uuid: ${input.delivery.project_uuid}`]
|
|
96
|
+
: []),
|
|
97
|
+
"Обязательно отправь reply через send_partner_note.",
|
|
98
|
+
"Задача не завершена, пока send_partner_note не отработал успешно.",
|
|
99
|
+
"Не останавливайся на локальном объяснении.",
|
|
100
|
+
"Не используй linked partner для ответа. Передай эти параметры явно в send_partner_note.",
|
|
101
|
+
"Только после успешного tool call можно считать ответ отправленным.",
|
|
102
|
+
]
|
|
103
|
+
: []),
|
|
104
|
+
].join("\n");
|
|
105
|
+
}
|
|
106
|
+
function buildTelegramDeliveryNotification(input) {
|
|
107
|
+
const sourceActorLabel = input.delivery.source_actor_label || input.delivery.source_session_label;
|
|
108
|
+
const kindTitle = input.delivery.kind === "question"
|
|
109
|
+
? `Получен вопрос от ${sourceActorLabel}.`
|
|
110
|
+
: input.delivery.kind === "reply"
|
|
111
|
+
? `Получен ответ от ${sourceActorLabel}.`
|
|
112
|
+
: input.delivery.kind === "request"
|
|
113
|
+
? `Получен запрос от ${sourceActorLabel}.`
|
|
114
|
+
: input.delivery.kind === "handoff"
|
|
115
|
+
? input.copiedArtifacts.length > 0
|
|
116
|
+
? `Получен файл от ${sourceActorLabel}.`
|
|
117
|
+
: `Получен handoff от ${sourceActorLabel}.`
|
|
118
|
+
: `Получено обновление от ${sourceActorLabel}.`;
|
|
119
|
+
return [
|
|
120
|
+
kindTitle,
|
|
121
|
+
...(input.delivery.project_name
|
|
122
|
+
? [`Проект: ${input.delivery.project_name}`]
|
|
123
|
+
: []),
|
|
124
|
+
`Сессия: ${input.delivery.source_session_label} -> ${input.delivery.target_session_label}`,
|
|
125
|
+
`Тип: ${input.delivery.kind}`,
|
|
126
|
+
`Кратко: ${input.delivery.summary}`,
|
|
127
|
+
...(input.copiedArtifacts.length > 0
|
|
128
|
+
? [
|
|
129
|
+
"",
|
|
130
|
+
`Файлы: ${input.copiedArtifacts.length}`,
|
|
131
|
+
...input.copiedArtifacts.map((item) => `- ${node_path_1.default.basename(item)}`),
|
|
132
|
+
]
|
|
133
|
+
: []),
|
|
134
|
+
...(input.delivery.requires_reply
|
|
135
|
+
? [
|
|
136
|
+
"",
|
|
137
|
+
`Reply message_uuid: ${input.delivery.message_uuid}`,
|
|
138
|
+
`Reply target_session_id: ${input.delivery.source_session_uuid}`,
|
|
139
|
+
...(input.delivery.project_uuid
|
|
140
|
+
? [`Reply project_uuid: ${input.delivery.project_uuid}`]
|
|
141
|
+
: []),
|
|
142
|
+
]
|
|
143
|
+
: []),
|
|
144
|
+
"",
|
|
145
|
+
`Note: ${input.notePath}`,
|
|
146
|
+
].join("\n");
|
|
147
|
+
}
|
|
148
|
+
function buildOutgoingDeliveredText(input) {
|
|
149
|
+
return [
|
|
150
|
+
"✅ Доставка выполнена.",
|
|
151
|
+
...(input.notice.projectName ? [`Проект: ${input.notice.projectName}`] : []),
|
|
152
|
+
...(input.notice.targetLabel
|
|
153
|
+
? [`Получатель: ${input.notice.targetLabel}`]
|
|
154
|
+
: []),
|
|
155
|
+
...(input.notice.targetSessionLabel &&
|
|
156
|
+
input.notice.targetSessionLabel !== input.notice.targetLabel
|
|
157
|
+
? [`Сессия: ${input.notice.targetSessionLabel}`]
|
|
158
|
+
: []),
|
|
159
|
+
`Тип: ${input.notice.kind}`,
|
|
160
|
+
"Статус: доставлено",
|
|
161
|
+
`Кратко: ${input.notice.summary}`,
|
|
162
|
+
`Share: ${input.notice.shareId || input.status.share_id}`,
|
|
163
|
+
].join("\n");
|
|
164
|
+
}
|
|
165
|
+
function buildOutgoingFailedText(input) {
|
|
166
|
+
return [
|
|
167
|
+
"❌ Доставка не выполнена.",
|
|
168
|
+
...(input.notice.projectName ? [`Проект: ${input.notice.projectName}`] : []),
|
|
169
|
+
...(input.notice.targetLabel
|
|
170
|
+
? [`Получатель: ${input.notice.targetLabel}`]
|
|
171
|
+
: []),
|
|
172
|
+
...(input.notice.targetSessionLabel &&
|
|
173
|
+
input.notice.targetSessionLabel !== input.notice.targetLabel
|
|
174
|
+
? [`Сессия: ${input.notice.targetSessionLabel}`]
|
|
175
|
+
: []),
|
|
176
|
+
`Тип: ${input.notice.kind}`,
|
|
177
|
+
"Статус: ошибка",
|
|
178
|
+
`Кратко: ${input.notice.summary}`,
|
|
179
|
+
`Share: ${input.notice.shareId || input.status.share_id}`,
|
|
180
|
+
].join("\n");
|
|
181
|
+
}
|
|
182
|
+
const TelegramMcpGatewayDeliveryService = {
|
|
183
|
+
name: exports.TELEGRAM_MCP_GATEWAY_DELIVERY_SERVICE_NAME,
|
|
184
|
+
dependencies: [runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME],
|
|
185
|
+
methods: {
|
|
186
|
+
getRuntimeOrThrow() {
|
|
187
|
+
const runtimeService = this.runtimeService ??
|
|
188
|
+
this.broker.getLocalService(runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME);
|
|
189
|
+
if (!runtimeService) {
|
|
190
|
+
throw new Error(`Local Moleculer service '${runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME}' is unavailable`);
|
|
191
|
+
}
|
|
192
|
+
this.runtimeService = runtimeService;
|
|
193
|
+
return runtimeService.getRuntime();
|
|
194
|
+
},
|
|
195
|
+
async materializeIncomingDelivery(delivery) {
|
|
196
|
+
const runtime = this.getRuntimeOrThrow?.();
|
|
197
|
+
if (!runtime) {
|
|
198
|
+
throw new Error("Runtime is unavailable");
|
|
199
|
+
}
|
|
200
|
+
const targetSession = await runtime.sessionStore.getSession(delivery.target_local_session_id);
|
|
201
|
+
if (!targetSession) {
|
|
202
|
+
runtime.logger.warn("Skipping gateway delivery because target local session is not available", {
|
|
203
|
+
deliveryUuid: delivery.delivery_uuid,
|
|
204
|
+
targetLocalSessionId: delivery.target_local_session_id,
|
|
205
|
+
});
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const targetBinding = await runtime.bindingStore.getBinding(targetSession.sessionId);
|
|
209
|
+
if (!targetBinding) {
|
|
210
|
+
runtime.logger.warn("Skipping gateway delivery because target session is not paired with Telegram", {
|
|
211
|
+
deliveryUuid: delivery.delivery_uuid,
|
|
212
|
+
sessionId: targetSession.sessionId,
|
|
213
|
+
});
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const copiedArtifacts = [];
|
|
217
|
+
for (const artifact of delivery.artifacts) {
|
|
218
|
+
const relativePath = artifact.relative_path ||
|
|
219
|
+
`shares/files/${delivery.share_id}/${artifact.original_name}`;
|
|
220
|
+
let localArtifactPath;
|
|
221
|
+
if (artifact.content_base64) {
|
|
222
|
+
localArtifactPath = await (0, client_1.writeXchangeRelativeFile)(runtime.config.tmux, runtime.objectStore.resolveWorkspaceDir(targetSession), runtime.config.exchange.dir, relativePath, Buffer.from(artifact.content_base64, "base64"));
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
localArtifactPath = await runtime.objectStore.ensureLocalFile({
|
|
226
|
+
sessionId: targetSession.sessionId,
|
|
227
|
+
session: targetSession,
|
|
228
|
+
filePath: artifact.original_name,
|
|
229
|
+
relativePath,
|
|
230
|
+
storageRef: artifact.storage_ref,
|
|
231
|
+
source: "partner-artifact",
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
copiedArtifacts.push(localArtifactPath);
|
|
235
|
+
await runtime.xchangeFileMetaStore.setXchangeFileMeta({
|
|
236
|
+
sessionId: targetSession.sessionId,
|
|
237
|
+
filePath: localArtifactPath,
|
|
238
|
+
relativePath,
|
|
239
|
+
source: "partner-artifact",
|
|
240
|
+
uploadedAt: delivery.created_at,
|
|
241
|
+
originalName: artifact.original_name,
|
|
242
|
+
...(artifact.mime_type ? { mimeType: artifact.mime_type } : {}),
|
|
243
|
+
...(typeof artifact.size_bytes === "number"
|
|
244
|
+
? { sizeBytes: artifact.size_bytes }
|
|
245
|
+
: {}),
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
const noteContent = buildNoteContent({ delivery, copiedArtifacts });
|
|
249
|
+
const notePath = await (0, client_1.writeXchangeRelativeFile)(runtime.config.tmux, runtime.objectStore.resolveWorkspaceDir(targetSession), runtime.config.exchange.dir, delivery.note_relative_path, Buffer.from(noteContent, "utf8"));
|
|
250
|
+
await runtime.xchangeFileMetaStore.setXchangeFileMeta({
|
|
251
|
+
sessionId: targetSession.sessionId,
|
|
252
|
+
filePath: notePath,
|
|
253
|
+
relativePath: delivery.note_relative_path,
|
|
254
|
+
source: "partner-artifact",
|
|
255
|
+
uploadedAt: delivery.created_at,
|
|
256
|
+
mimeType: "text/markdown",
|
|
257
|
+
sizeBytes: Buffer.byteLength(noteContent, "utf8"),
|
|
258
|
+
});
|
|
259
|
+
await (0, client_1.writeXchangeRelativeFile)(runtime.config.tmux, runtime.objectStore.resolveWorkspaceDir(targetSession), runtime.config.exchange.dir, delivery.share_index_file_name, Buffer.from(`${buildShareIndexLine({
|
|
260
|
+
delivery,
|
|
261
|
+
relativeNotePath: delivery.note_relative_path,
|
|
262
|
+
})}\n`, "utf8"), { append: true });
|
|
263
|
+
const inboxMessage = {
|
|
264
|
+
id: (0, ids_1.createInboxMessageId)(new Date(delivery.created_at)),
|
|
265
|
+
sessionId: targetSession.sessionId,
|
|
266
|
+
telegramChatId: targetBinding.telegramChatId,
|
|
267
|
+
telegramUserId: targetBinding.telegramUserId,
|
|
268
|
+
sourceTelegramMessageId: Date.now(),
|
|
269
|
+
text: buildPartnerInboxText({
|
|
270
|
+
delivery,
|
|
271
|
+
notePath,
|
|
272
|
+
copiedArtifacts,
|
|
273
|
+
}),
|
|
274
|
+
attachments: [notePath, ...copiedArtifacts],
|
|
275
|
+
receivedAt: delivery.created_at,
|
|
276
|
+
};
|
|
277
|
+
await runtime.inboxStore.createInboxMessage(inboxMessage);
|
|
278
|
+
try {
|
|
279
|
+
await runtime.telegramTransport.sendNotification({
|
|
280
|
+
sessionId: targetSession.sessionId,
|
|
281
|
+
...(targetSession.label ? { sessionLabel: targetSession.label } : {}),
|
|
282
|
+
recipient: {
|
|
283
|
+
telegramChatId: targetBinding.telegramChatId,
|
|
284
|
+
telegramUserId: targetBinding.telegramUserId,
|
|
285
|
+
},
|
|
286
|
+
message: buildTelegramDeliveryNotification({
|
|
287
|
+
delivery,
|
|
288
|
+
notePath,
|
|
289
|
+
copiedArtifacts,
|
|
290
|
+
}),
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
runtime.logger.warn("Failed to send Telegram notification for gateway delivery", {
|
|
295
|
+
deliveryUuid: delivery.delivery_uuid,
|
|
296
|
+
sessionId: targetSession.sessionId,
|
|
297
|
+
error: error instanceof Error ? (error.stack ?? error.message) : String(error),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
try {
|
|
301
|
+
await runtime.telegramTransport.nudgeSessionPartnerNote(targetSession.sessionId);
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
runtime.logger.warn("Failed to nudge tmux after gateway delivery", {
|
|
305
|
+
deliveryUuid: delivery.delivery_uuid,
|
|
306
|
+
sessionId: targetSession.sessionId,
|
|
307
|
+
error: error instanceof Error ? (error.stack ?? error.message) : String(error),
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
runtime.logger.info("Gateway delivery materialized locally", {
|
|
311
|
+
deliveryUuid: delivery.delivery_uuid,
|
|
312
|
+
sessionId: targetSession.sessionId,
|
|
313
|
+
shareId: delivery.share_id,
|
|
314
|
+
kind: delivery.kind,
|
|
315
|
+
notePath,
|
|
316
|
+
copiedArtifacts,
|
|
317
|
+
});
|
|
318
|
+
},
|
|
319
|
+
async applyOutgoingDeliveryStatus(status) {
|
|
320
|
+
if (status.status !== "delivered" && status.status !== "failed") {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const runtime = this.getRuntimeOrThrow?.();
|
|
324
|
+
if (!runtime) {
|
|
325
|
+
throw new Error("Runtime is unavailable");
|
|
326
|
+
}
|
|
327
|
+
const outgoingNotices = await runtime.maintenanceStore.listOutgoingDeliveryNotices();
|
|
328
|
+
const notice = outgoingNotices.find((item) => item.deliveryUuid === status.delivery_uuid);
|
|
329
|
+
if (!notice) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
try {
|
|
333
|
+
await runtime.telegramTransport.editChatMessage(notice.telegramChatId, notice.telegramMessageId, status.status === "failed"
|
|
334
|
+
? buildOutgoingFailedText({ notice, status })
|
|
335
|
+
: buildOutgoingDeliveredText({ notice, status }));
|
|
336
|
+
await runtime.maintenanceStore.deleteOutgoingDeliveryNotice(notice.deliveryUuid);
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
runtime.logger.warn("Failed to update outgoing delivery status message in Telegram", {
|
|
340
|
+
deliveryUuid: notice.deliveryUuid,
|
|
341
|
+
sessionId: notice.sessionId,
|
|
342
|
+
telegramChatId: notice.telegramChatId,
|
|
343
|
+
telegramMessageId: notice.telegramMessageId,
|
|
344
|
+
error: error instanceof Error
|
|
345
|
+
? (error.stack ?? error.message)
|
|
346
|
+
: String(error),
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
actions: {
|
|
352
|
+
materializeIncomingDelivery: {
|
|
353
|
+
async handler(ctx) {
|
|
354
|
+
await this.materializeIncomingDelivery?.(ctx.params.delivery);
|
|
355
|
+
return { ok: true };
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
applyOutgoingDeliveryStatus: {
|
|
359
|
+
async handler(ctx) {
|
|
360
|
+
await this.applyOutgoingDeliveryStatus?.(ctx.params.status);
|
|
361
|
+
return { ok: true };
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
created() {
|
|
366
|
+
this.runtimeService = null;
|
|
367
|
+
},
|
|
368
|
+
async started() {
|
|
369
|
+
await this.broker.waitForServices([runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME]);
|
|
370
|
+
const runtimeService = this.broker.getLocalService(runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME);
|
|
371
|
+
if (!runtimeService) {
|
|
372
|
+
throw new Error(`Local Moleculer service '${runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME}' is unavailable`);
|
|
373
|
+
}
|
|
374
|
+
this.runtimeService = runtimeService;
|
|
375
|
+
},
|
|
376
|
+
async stopped() { },
|
|
377
|
+
};
|
|
378
|
+
exports.default = TelegramMcpGatewayDeliveryService;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hasLocalTargetSession = hasLocalTargetSession;
|
|
4
|
+
exports.hasOutgoingDeliveryNotice = hasOutgoingDeliveryNotice;
|
|
5
|
+
function hasLocalTargetSession(session) {
|
|
6
|
+
return Boolean(session?.sessionId);
|
|
7
|
+
}
|
|
8
|
+
function hasOutgoingDeliveryNotice(notices, deliveryUuid) {
|
|
9
|
+
return notices.some((item) => item.deliveryUuid === deliveryUuid);
|
|
10
|
+
}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TELEGRAM_MCP_GATEWAY_RMQ_SERVICE_NAME = void 0;
|
|
4
|
+
const amqplib_1 = require("amqplib");
|
|
5
|
+
const runtime_service_1 = require("./runtime.service");
|
|
6
|
+
exports.TELEGRAM_MCP_GATEWAY_RMQ_SERVICE_NAME = "telegramMcp.gatewayRmq";
|
|
7
|
+
function buildNodeSuffix() {
|
|
8
|
+
return (process.env.NODE_ID?.trim() ||
|
|
9
|
+
process.env.PROJECT_NAME?.trim() ||
|
|
10
|
+
"default").replace(/[^a-zA-Z0-9._-]+/gu, "-");
|
|
11
|
+
}
|
|
12
|
+
const QUEUE_NAME = `telegram_mcp.gateway.${buildNodeSuffix()}`;
|
|
13
|
+
const RECONNECT_DELAY_MS = 3000;
|
|
14
|
+
const TelegramMcpGatewayRmqService = {
|
|
15
|
+
name: exports.TELEGRAM_MCP_GATEWAY_RMQ_SERVICE_NAME,
|
|
16
|
+
dependencies: [runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME],
|
|
17
|
+
actions: {
|
|
18
|
+
publishDeliveryQueued: {
|
|
19
|
+
params: {
|
|
20
|
+
clientUuid: "string",
|
|
21
|
+
delivery: { type: "object" },
|
|
22
|
+
},
|
|
23
|
+
async handler(ctx) {
|
|
24
|
+
return {
|
|
25
|
+
published: await this.publishMessage?.({
|
|
26
|
+
type: "delivery.queued",
|
|
27
|
+
payload: ctx.params,
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
publishDeliveryStatus: {
|
|
33
|
+
params: {
|
|
34
|
+
clientUuid: "string",
|
|
35
|
+
status: { type: "object" },
|
|
36
|
+
},
|
|
37
|
+
async handler(ctx) {
|
|
38
|
+
return {
|
|
39
|
+
published: await this.publishMessage?.({
|
|
40
|
+
type: "delivery.status",
|
|
41
|
+
payload: ctx.params,
|
|
42
|
+
}),
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
publishProjectMemberJoined: {
|
|
47
|
+
params: {
|
|
48
|
+
clientUuids: { type: "array", items: "string" },
|
|
49
|
+
projectUuid: "string",
|
|
50
|
+
projectName: "string",
|
|
51
|
+
memberDisplayName: { type: "string", optional: true },
|
|
52
|
+
memberTelegramUsername: { type: "string", optional: true },
|
|
53
|
+
},
|
|
54
|
+
async handler(ctx) {
|
|
55
|
+
return {
|
|
56
|
+
published: await this.publishMessage?.({
|
|
57
|
+
type: "project.member_joined",
|
|
58
|
+
payload: ctx.params,
|
|
59
|
+
}),
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
publishProjectMemberLeft: {
|
|
64
|
+
params: {
|
|
65
|
+
clientUuids: { type: "array", items: "string" },
|
|
66
|
+
projectUuid: "string",
|
|
67
|
+
projectName: "string",
|
|
68
|
+
memberDisplayName: { type: "string", optional: true },
|
|
69
|
+
memberTelegramUsername: { type: "string", optional: true },
|
|
70
|
+
},
|
|
71
|
+
async handler(ctx) {
|
|
72
|
+
return {
|
|
73
|
+
published: await this.publishMessage?.({
|
|
74
|
+
type: "project.member_left",
|
|
75
|
+
payload: ctx.params,
|
|
76
|
+
}),
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
publishProjectDeleted: {
|
|
81
|
+
params: {
|
|
82
|
+
clientUuids: { type: "array", items: "string" },
|
|
83
|
+
projectUuid: "string",
|
|
84
|
+
projectName: "string",
|
|
85
|
+
},
|
|
86
|
+
async handler(ctx) {
|
|
87
|
+
return {
|
|
88
|
+
published: await this.publishMessage?.({
|
|
89
|
+
type: "project.deleted",
|
|
90
|
+
payload: ctx.params,
|
|
91
|
+
}),
|
|
92
|
+
};
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
created() {
|
|
97
|
+
this.runtimeService = null;
|
|
98
|
+
this.connection = null;
|
|
99
|
+
this.channel = null;
|
|
100
|
+
this.consumerTag = null;
|
|
101
|
+
this.reconnectTimer = null;
|
|
102
|
+
this.stopRequested = false;
|
|
103
|
+
},
|
|
104
|
+
methods: {
|
|
105
|
+
getRuntimeOrThrow() {
|
|
106
|
+
const runtimeService = this.runtimeService ??
|
|
107
|
+
this.broker.getLocalService(runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME);
|
|
108
|
+
if (!runtimeService) {
|
|
109
|
+
throw new Error(`Local Moleculer service '${runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME}' is unavailable`);
|
|
110
|
+
}
|
|
111
|
+
this.runtimeService = runtimeService;
|
|
112
|
+
return runtimeService.getRuntime();
|
|
113
|
+
},
|
|
114
|
+
isEnabled() {
|
|
115
|
+
const runtime = this.getRuntimeOrThrow?.();
|
|
116
|
+
return Boolean(runtime &&
|
|
117
|
+
(runtime.config.distributed.mode === "gateway" ||
|
|
118
|
+
runtime.config.distributed.mode === "both") &&
|
|
119
|
+
runtime.config.distributed.rmq?.host);
|
|
120
|
+
},
|
|
121
|
+
getExchangeName() {
|
|
122
|
+
return this.getRuntimeOrThrow?.().config.distributed.rmq?.exchange ??
|
|
123
|
+
"telegram_mcp.gateway";
|
|
124
|
+
},
|
|
125
|
+
getQueueName() {
|
|
126
|
+
return QUEUE_NAME;
|
|
127
|
+
},
|
|
128
|
+
async closeRmq() {
|
|
129
|
+
if (this.reconnectTimer) {
|
|
130
|
+
clearTimeout(this.reconnectTimer);
|
|
131
|
+
this.reconnectTimer = null;
|
|
132
|
+
}
|
|
133
|
+
const channel = this.channel;
|
|
134
|
+
this.channel = null;
|
|
135
|
+
this.consumerTag = null;
|
|
136
|
+
if (channel) {
|
|
137
|
+
await channel.close().catch(() => undefined);
|
|
138
|
+
}
|
|
139
|
+
const connection = this.connection;
|
|
140
|
+
this.connection = null;
|
|
141
|
+
if (connection) {
|
|
142
|
+
await connection.close().catch(() => undefined);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
scheduleReconnect() {
|
|
146
|
+
if (this.stopRequested || this.reconnectTimer || !this.isEnabled?.()) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
this.reconnectTimer = setTimeout(() => {
|
|
150
|
+
this.reconnectTimer = null;
|
|
151
|
+
void this.connectRmq?.();
|
|
152
|
+
}, RECONNECT_DELAY_MS);
|
|
153
|
+
this.logger.warn("Gateway RMQ reconnect scheduled", {
|
|
154
|
+
delayMs: RECONNECT_DELAY_MS,
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
async dispatchMessage(message) {
|
|
158
|
+
if (message.type === "delivery.queued") {
|
|
159
|
+
await this.broker.call("telegramMcp.gatewaySocket.notifyDeliveryQueued", message.payload, { meta: { internal_call: true } });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (message.type === "delivery.status") {
|
|
163
|
+
await this.broker.call("telegramMcp.gatewaySocket.notifyDeliveryStatus", message.payload, { meta: { internal_call: true } });
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (message.type === "project.member_joined") {
|
|
167
|
+
await this.broker.call("telegramMcp.gatewaySocket.notifyProjectMemberJoined", message.payload, { meta: { internal_call: true } });
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (message.type === "project.deleted") {
|
|
171
|
+
await this.broker.call("telegramMcp.gatewaySocket.notifyProjectDeleted", message.payload, { meta: { internal_call: true } });
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
await this.broker.call("telegramMcp.gatewaySocket.notifyProjectMemberLeft", message.payload, { meta: { internal_call: true } });
|
|
175
|
+
},
|
|
176
|
+
async connectRmq() {
|
|
177
|
+
if (this.stopRequested || !this.isEnabled?.() || this.channel) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const runtime = this.getRuntimeOrThrow?.();
|
|
181
|
+
const rmq = runtime?.config.distributed.rmq;
|
|
182
|
+
if (!runtime || !rmq) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
const connection = await (0, amqplib_1.connect)({
|
|
187
|
+
protocol: "amqp",
|
|
188
|
+
hostname: rmq.host,
|
|
189
|
+
port: rmq.port,
|
|
190
|
+
...(rmq.user ? { username: rmq.user } : {}),
|
|
191
|
+
...(rmq.password ? { password: rmq.password } : {}),
|
|
192
|
+
vhost: rmq.vhost,
|
|
193
|
+
});
|
|
194
|
+
const channel = await connection.createChannel();
|
|
195
|
+
const exchange = this.getExchangeName?.() ?? rmq.exchange;
|
|
196
|
+
const queue = this.getQueueName?.() ?? QUEUE_NAME;
|
|
197
|
+
await channel.assertExchange(exchange, "topic", { durable: true });
|
|
198
|
+
await channel.assertQueue(queue, { durable: true });
|
|
199
|
+
await channel.bindQueue(queue, exchange, "delivery.queued");
|
|
200
|
+
await channel.bindQueue(queue, exchange, "delivery.status");
|
|
201
|
+
await channel.bindQueue(queue, exchange, "project.member_joined");
|
|
202
|
+
await channel.bindQueue(queue, exchange, "project.member_left");
|
|
203
|
+
await channel.bindQueue(queue, exchange, "project.deleted");
|
|
204
|
+
const onDisconnected = (eventName, error) => {
|
|
205
|
+
this.logger.warn("Gateway RMQ connection closed", {
|
|
206
|
+
eventName,
|
|
207
|
+
error: error instanceof Error ? (error.stack ?? error.message) : undefined,
|
|
208
|
+
});
|
|
209
|
+
this.connection = null;
|
|
210
|
+
this.channel = null;
|
|
211
|
+
this.consumerTag = null;
|
|
212
|
+
this.scheduleReconnect?.();
|
|
213
|
+
};
|
|
214
|
+
connection.on("error", (error) => onDisconnected("error", error));
|
|
215
|
+
connection.on("close", () => onDisconnected("close"));
|
|
216
|
+
const consumeResult = await channel.consume(queue, async (msg) => {
|
|
217
|
+
if (!msg) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
const parsed = JSON.parse(msg.content.toString("utf8"));
|
|
222
|
+
await this.dispatchMessage?.(parsed);
|
|
223
|
+
channel.ack(msg);
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
this.logger.warn("Gateway RMQ message handling failed", {
|
|
227
|
+
error: error instanceof Error ? (error.stack ?? error.message) : String(error),
|
|
228
|
+
routingKey: msg.fields.routingKey,
|
|
229
|
+
});
|
|
230
|
+
channel.nack(msg, false, true);
|
|
231
|
+
}
|
|
232
|
+
}, { noAck: false });
|
|
233
|
+
this.connection = connection;
|
|
234
|
+
this.channel = channel;
|
|
235
|
+
this.consumerTag = consumeResult.consumerTag;
|
|
236
|
+
this.logger.warn("Gateway RMQ connected", {
|
|
237
|
+
host: rmq.host,
|
|
238
|
+
port: rmq.port,
|
|
239
|
+
queue,
|
|
240
|
+
exchange,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
this.logger.warn("Gateway RMQ connect failed", {
|
|
245
|
+
host: rmq.host,
|
|
246
|
+
port: rmq.port,
|
|
247
|
+
error: error instanceof Error ? (error.stack ?? error.message) : String(error),
|
|
248
|
+
});
|
|
249
|
+
await this.closeRmq?.();
|
|
250
|
+
this.scheduleReconnect?.();
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
async publishMessage(message) {
|
|
254
|
+
if (!this.isEnabled?.()) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
if (!this.channel) {
|
|
258
|
+
await this.connectRmq?.();
|
|
259
|
+
}
|
|
260
|
+
if (!this.channel) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
const routingKey = message.type;
|
|
264
|
+
const published = this.channel.publish(this.getExchangeName?.() ?? "telegram_mcp.gateway", routingKey, Buffer.from(JSON.stringify(message), "utf8"), {
|
|
265
|
+
contentType: "application/json",
|
|
266
|
+
deliveryMode: 2,
|
|
267
|
+
timestamp: Date.now(),
|
|
268
|
+
});
|
|
269
|
+
return published;
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
async started() {
|
|
273
|
+
await this.broker.waitForServices([runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME]);
|
|
274
|
+
const runtimeService = this.broker.getLocalService(runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME);
|
|
275
|
+
if (!runtimeService) {
|
|
276
|
+
throw new Error(`Local Moleculer service '${runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME}' is unavailable`);
|
|
277
|
+
}
|
|
278
|
+
this.runtimeService = runtimeService;
|
|
279
|
+
if (!this.isEnabled?.()) {
|
|
280
|
+
this.logger.info("Gateway RMQ is disabled", {
|
|
281
|
+
distributedMode: runtimeService.getRuntime().config.distributed.mode,
|
|
282
|
+
rmqConfigured: Boolean(runtimeService.getRuntime().config.distributed.rmq?.host),
|
|
283
|
+
});
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
this.stopRequested = false;
|
|
287
|
+
await this.connectRmq?.();
|
|
288
|
+
},
|
|
289
|
+
async stopped() {
|
|
290
|
+
this.stopRequested = true;
|
|
291
|
+
await this.closeRmq?.();
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
exports.default = TelegramMcpGatewayRmqService;
|