chz-telegram-bot 0.5.3 → 0.5.5
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/dist/builtin/helpAction.d.ts +2 -0
- package/dist/builtin/helpAction.d.ts.map +1 -0
- package/dist/builtin/helpAction.js +14 -0
- package/dist/dtos/chatHistoryMessage.d.ts +35 -0
- package/dist/dtos/chatHistoryMessage.d.ts.map +1 -0
- package/dist/dtos/chatHistoryMessage.js +32 -0
- package/dist/dtos/chatInfo.d.ts +17 -0
- package/dist/dtos/chatInfo.d.ts.map +1 -0
- package/dist/dtos/chatInfo.js +16 -0
- package/dist/dtos/commandTriggerCheckResult.d.ts +24 -0
- package/dist/dtos/commandTriggerCheckResult.d.ts.map +1 -0
- package/dist/dtos/commandTriggerCheckResult.js +34 -0
- package/dist/dtos/cooldownInfo.d.ts +13 -0
- package/dist/dtos/cooldownInfo.d.ts.map +1 -0
- package/dist/dtos/cooldownInfo.js +12 -0
- package/dist/dtos/incomingMessage.d.ts +19 -0
- package/dist/dtos/incomingMessage.d.ts.map +1 -0
- package/dist/dtos/incomingMessage.js +63 -0
- package/dist/dtos/incomingQuery.d.ts +10 -0
- package/dist/dtos/incomingQuery.d.ts.map +1 -0
- package/dist/dtos/incomingQuery.js +14 -0
- package/dist/dtos/messageInfo.d.ts +22 -0
- package/dist/dtos/messageInfo.d.ts.map +1 -0
- package/dist/dtos/messageInfo.js +20 -0
- package/dist/dtos/propertyProviderSets.d.ts +16 -0
- package/dist/dtos/propertyProviderSets.d.ts.map +1 -0
- package/dist/dtos/propertyProviderSets.js +1 -0
- package/dist/dtos/replyInfo.d.ts +6 -0
- package/dist/dtos/replyInfo.d.ts.map +1 -0
- package/dist/dtos/replyInfo.js +8 -0
- package/dist/dtos/responses/delay.d.ts +16 -0
- package/dist/dtos/responses/delay.d.ts.map +1 -0
- package/dist/dtos/responses/delay.js +15 -0
- package/dist/dtos/responses/imageMessage.d.ts +22 -0
- package/dist/dtos/responses/imageMessage.d.ts.map +1 -0
- package/dist/dtos/responses/imageMessage.js +21 -0
- package/dist/dtos/responses/inlineQueryResponse.d.ts +13 -0
- package/dist/dtos/responses/inlineQueryResponse.d.ts.map +1 -0
- package/dist/dtos/responses/inlineQueryResponse.js +15 -0
- package/dist/dtos/responses/reaction.d.ts +16 -0
- package/dist/dtos/responses/reaction.d.ts.map +1 -0
- package/dist/dtos/responses/reaction.js +17 -0
- package/dist/dtos/responses/textMessage.d.ts +23 -0
- package/dist/dtos/responses/textMessage.d.ts.map +1 -0
- package/dist/dtos/responses/textMessage.js +24 -0
- package/dist/dtos/responses/unpin.d.ts +15 -0
- package/dist/dtos/responses/unpin.d.ts.map +1 -0
- package/dist/dtos/responses/unpin.js +15 -0
- package/dist/dtos/responses/videoMessage.d.ts +22 -0
- package/dist/dtos/responses/videoMessage.d.ts.map +1 -0
- package/dist/dtos/responses/videoMessage.js +21 -0
- package/dist/dtos/userInfo.d.ts +12 -0
- package/dist/dtos/userInfo.d.ts.map +1 -0
- package/dist/dtos/userInfo.js +12 -0
- package/dist/entities/actions/commandAction.d.ts +31 -0
- package/dist/entities/actions/commandAction.d.ts.map +1 -0
- package/dist/entities/actions/commandAction.js +139 -0
- package/dist/entities/actions/inlineQueryAction.d.ts +14 -0
- package/dist/entities/actions/inlineQueryAction.d.ts.map +1 -0
- package/dist/entities/actions/inlineQueryAction.js +43 -0
- package/dist/entities/actions/replyCaptureAction.d.ts +15 -0
- package/dist/entities/actions/replyCaptureAction.d.ts.map +1 -0
- package/dist/entities/actions/replyCaptureAction.js +58 -0
- package/dist/entities/actions/scheduledAction.d.ts +24 -0
- package/dist/entities/actions/scheduledAction.d.ts.map +1 -0
- package/dist/entities/actions/scheduledAction.js +72 -0
- package/dist/entities/botInstance.d.ts +37 -0
- package/dist/entities/botInstance.d.ts.map +1 -0
- package/dist/entities/botInstance.js +37 -0
- package/dist/entities/cachedStateFactory.d.ts +7 -0
- package/dist/entities/cachedStateFactory.d.ts.map +1 -0
- package/dist/entities/cachedStateFactory.js +8 -0
- package/dist/entities/context/baseContext.d.ts +39 -0
- package/dist/entities/context/baseContext.d.ts.map +1 -0
- package/dist/entities/context/baseContext.js +55 -0
- package/dist/entities/context/chatContext.d.ts +50 -0
- package/dist/entities/context/chatContext.d.ts.map +1 -0
- package/dist/entities/context/chatContext.js +65 -0
- package/dist/entities/context/inlineQueryContext.d.ts +27 -0
- package/dist/entities/context/inlineQueryContext.d.ts.map +1 -0
- package/dist/entities/context/inlineQueryContext.js +29 -0
- package/dist/entities/context/messageContext.d.ts +92 -0
- package/dist/entities/context/messageContext.d.ts.map +1 -0
- package/dist/entities/context/messageContext.js +116 -0
- package/dist/entities/context/replyContext.d.ts +89 -0
- package/dist/entities/context/replyContext.d.ts.map +1 -0
- package/dist/entities/context/replyContext.js +124 -0
- package/dist/entities/states/actionStateBase.d.ts +6 -0
- package/dist/entities/states/actionStateBase.d.ts.map +1 -0
- package/dist/entities/states/actionStateBase.js +4 -0
- package/dist/entities/taskRecord.d.ts +8 -0
- package/dist/entities/taskRecord.d.ts.map +1 -0
- package/dist/entities/taskRecord.js +10 -0
- package/dist/eslint.config.d.ts +3 -0
- package/dist/eslint.config.d.ts.map +1 -0
- package/dist/eslint.config.js +51 -0
- package/dist/helpers/builders/commandActionBuilder.d.ts +100 -0
- package/dist/helpers/builders/commandActionBuilder.d.ts.map +1 -0
- package/dist/helpers/builders/commandActionBuilder.js +146 -0
- package/dist/helpers/builders/inlineQueryActionBuilder.d.ts +37 -0
- package/dist/helpers/builders/inlineQueryActionBuilder.d.ts.map +1 -0
- package/dist/helpers/builders/inlineQueryActionBuilder.js +50 -0
- package/dist/helpers/builders/scheduledActionBuilder.d.ts +68 -0
- package/dist/helpers/builders/scheduledActionBuilder.d.ts.map +1 -0
- package/dist/helpers/builders/scheduledActionBuilder.js +95 -0
- package/dist/helpers/mapUtils.d.ts +10 -0
- package/dist/helpers/mapUtils.d.ts.map +1 -0
- package/dist/helpers/mapUtils.js +13 -0
- package/dist/helpers/noop.d.ts +9 -0
- package/dist/helpers/noop.d.ts.map +1 -0
- package/dist/helpers/noop.js +17 -0
- package/dist/helpers/objectFromEntries.d.ts +2 -0
- package/dist/helpers/objectFromEntries.d.ts.map +1 -0
- package/dist/helpers/objectFromEntries.js +3 -0
- package/dist/helpers/timeConvertions.d.ts +5 -0
- package/dist/helpers/timeConvertions.d.ts.map +1 -0
- package/dist/helpers/timeConvertions.js +9 -0
- package/dist/helpers/toArray.d.ts +2 -0
- package/dist/helpers/toArray.d.ts.map +1 -0
- package/dist/helpers/toArray.js +3 -0
- package/dist/helpers/traceFactory.d.ts +3 -0
- package/dist/helpers/traceFactory.d.ts.map +1 -0
- package/dist/helpers/traceFactory.js +3 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/main.d.ts +52 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +34 -0
- package/dist/services/actionProcessingService.d.ts +25 -0
- package/dist/services/actionProcessingService.d.ts.map +1 -0
- package/dist/services/actionProcessingService.js +50 -0
- package/dist/services/actionProcessors/baseProcessor.d.ts +18 -0
- package/dist/services/actionProcessors/baseProcessor.d.ts.map +1 -0
- package/dist/services/actionProcessors/baseProcessor.js +29 -0
- package/dist/services/actionProcessors/commandActionProcessor.d.ts +20 -0
- package/dist/services/actionProcessors/commandActionProcessor.d.ts.map +1 -0
- package/dist/services/actionProcessors/commandActionProcessor.js +116 -0
- package/dist/services/actionProcessors/inlineQueryActionProcessor.d.ts +11 -0
- package/dist/services/actionProcessors/inlineQueryActionProcessor.d.ts.map +1 -0
- package/dist/services/actionProcessors/inlineQueryActionProcessor.js +61 -0
- package/dist/services/actionProcessors/scheduledActionProcessor.d.ts +17 -0
- package/dist/services/actionProcessors/scheduledActionProcessor.d.ts.map +1 -0
- package/dist/services/actionProcessors/scheduledActionProcessor.js +56 -0
- package/dist/services/jsonFileStorage.d.ts +23 -0
- package/dist/services/jsonFileStorage.d.ts.map +1 -0
- package/dist/services/jsonFileStorage.js +109 -0
- package/dist/services/jsonLogger.d.ts +11 -0
- package/dist/services/jsonLogger.d.ts.map +1 -0
- package/dist/services/jsonLogger.js +66 -0
- package/dist/services/nodeTimeoutScheduler.d.ts +13 -0
- package/dist/services/nodeTimeoutScheduler.d.ts.map +1 -0
- package/dist/services/nodeTimeoutScheduler.js +31 -0
- package/dist/services/responseProcessingQueue.d.ts +12 -0
- package/dist/services/responseProcessingQueue.d.ts.map +1 -0
- package/dist/services/responseProcessingQueue.js +37 -0
- package/dist/services/telegramApi.d.ts +23 -0
- package/dist/services/telegramApi.d.ts.map +1 -0
- package/dist/services/telegramApi.js +133 -0
- package/dist/types/action.d.ts +14 -0
- package/dist/types/action.d.ts.map +1 -0
- package/dist/types/action.js +1 -0
- package/dist/types/actionState.d.ts +5 -0
- package/dist/types/actionState.d.ts.map +1 -0
- package/dist/types/actionState.js +1 -0
- package/dist/types/cachedValueAccessor.d.ts +2 -0
- package/dist/types/cachedValueAccessor.d.ts.map +1 -0
- package/dist/types/cachedValueAccessor.js +1 -0
- package/dist/types/capture.d.ts +24 -0
- package/dist/types/capture.d.ts.map +1 -0
- package/dist/types/capture.js +1 -0
- package/dist/types/commandCondition.d.ts +8 -0
- package/dist/types/commandCondition.d.ts.map +1 -0
- package/dist/types/commandCondition.js +1 -0
- package/dist/types/commandTrigger.d.ts +2 -0
- package/dist/types/commandTrigger.d.ts.map +1 -0
- package/dist/types/commandTrigger.js +1 -0
- package/dist/types/externalAliases.d.ts +11 -0
- package/dist/types/externalAliases.d.ts.map +1 -0
- package/dist/types/externalAliases.js +1 -0
- package/dist/types/handlers.d.ts +21 -0
- package/dist/types/handlers.d.ts.map +1 -0
- package/dist/types/handlers.js +1 -0
- package/dist/types/inputFile.d.ts +5 -0
- package/dist/types/inputFile.d.ts.map +1 -0
- package/dist/types/inputFile.js +1 -0
- package/dist/types/logger.d.ts +13 -0
- package/dist/types/logger.d.ts.map +1 -0
- package/dist/types/logger.js +1 -0
- package/dist/types/messageSendingOptions.d.ts +9 -0
- package/dist/types/messageSendingOptions.d.ts.map +1 -0
- package/dist/types/messageSendingOptions.js +1 -0
- package/dist/types/messageTypes.d.ts +20 -0
- package/dist/types/messageTypes.d.ts.map +1 -0
- package/dist/types/messageTypes.js +18 -0
- package/dist/types/propertyProvider.d.ts +8 -0
- package/dist/types/propertyProvider.d.ts.map +1 -0
- package/dist/types/propertyProvider.js +1 -0
- package/dist/types/response.d.ts +39 -0
- package/dist/types/response.d.ts.map +1 -0
- package/dist/types/response.js +9 -0
- package/dist/types/scheduler.d.ts +7 -0
- package/dist/types/scheduler.d.ts.map +1 -0
- package/dist/types/scheduler.js +1 -0
- package/dist/types/storage.d.ts +11 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +1 -0
- package/dist/types/timeValues.d.ts +15 -0
- package/dist/types/timeValues.d.ts.map +1 -0
- package/dist/types/timeValues.js +1 -0
- package/dist/types/trace.d.ts +6 -0
- package/dist/types/trace.d.ts.map +1 -0
- package/dist/types/trace.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { IncomingMessage } from '../../dtos/incomingMessage';
|
|
2
|
+
import { ReplyCaptureAction } from '../../entities/actions/replyCaptureAction';
|
|
3
|
+
import { MessageContextInternal } from '../../entities/context/messageContext';
|
|
4
|
+
import { ReplyContextInternal } from '../../entities/context/replyContext';
|
|
5
|
+
import { INTERNAL_MESSAGE_TYPE_PREFIX, MessageType } from '../../types/messageTypes';
|
|
6
|
+
import { typeSafeObjectFromEntries } from '../../helpers/objectFromEntries';
|
|
7
|
+
import { BaseActionProcessor } from './baseProcessor';
|
|
8
|
+
import { getOrSetIfNotExists } from '../../helpers/mapUtils';
|
|
9
|
+
import { MessageInfo } from '../../dtos/messageInfo';
|
|
10
|
+
import { UserInfo } from '../../dtos/userInfo';
|
|
11
|
+
import { ChatHistoryMessage } from '../../dtos/chatHistoryMessage';
|
|
12
|
+
const MESSAGE_HISTORY_LENGTH_LIMIT = 100;
|
|
13
|
+
export class CommandActionProcessor extends BaseActionProcessor {
|
|
14
|
+
replyCaptures = [];
|
|
15
|
+
chatHistory = new Map();
|
|
16
|
+
botInfo;
|
|
17
|
+
commands = typeSafeObjectFromEntries(Object.values(MessageType).map((x) => [
|
|
18
|
+
x,
|
|
19
|
+
[]
|
|
20
|
+
]));
|
|
21
|
+
initialize(api, telegram, commands, verboseLoggingForIncomingMessage, botInfo) {
|
|
22
|
+
this.botInfo = botInfo;
|
|
23
|
+
this.initializeDependencies(api);
|
|
24
|
+
for (const msgType of Object.values(MessageType)) {
|
|
25
|
+
if (msgType == MessageType.Text) {
|
|
26
|
+
this.commands[msgType] = commands.filter((cmd) => cmd.triggers.some((x) => typeof x != 'string') ||
|
|
27
|
+
cmd.triggers.some((x) => typeof x == 'string' &&
|
|
28
|
+
!x.startsWith(INTERNAL_MESSAGE_TYPE_PREFIX)) ||
|
|
29
|
+
cmd.triggers.includes(MessageType.Text) ||
|
|
30
|
+
cmd.triggers.includes(MessageType.Any));
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
this.commands[msgType] = commands.filter((cmd) => cmd.triggers.includes(msgType) ||
|
|
34
|
+
cmd.triggers.includes(MessageType.Any));
|
|
35
|
+
}
|
|
36
|
+
if (commands.length > 0) {
|
|
37
|
+
telegram.on('message', ({ message }) => {
|
|
38
|
+
const internalMessage = new IncomingMessage(message, this.botName, getOrSetIfNotExists(this.chatHistory, message.chat.id, []));
|
|
39
|
+
const logger = this.logger.createScope(this.botName, internalMessage.traceId, internalMessage.chatInfo.name);
|
|
40
|
+
if (verboseLoggingForIncomingMessage) {
|
|
41
|
+
logger.logObjectWithTraceId(message);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
logger.logWithTraceId(`${internalMessage.from?.first_name ?? 'Unknown'} (${internalMessage.from?.id ?? 'Unknown'}): ${internalMessage.text || internalMessage.type}`);
|
|
45
|
+
}
|
|
46
|
+
void this.processMessage(internalMessage);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
captureRegistrationCallback(capture, parentMessageId, chatInfo, traceId) {
|
|
51
|
+
const replyAction = new ReplyCaptureAction(parentMessageId, capture.action, capture.handler, capture.trigger, capture.abortController);
|
|
52
|
+
const logger = this.logger.createScope(this.botName, traceId, chatInfo.name);
|
|
53
|
+
logger.logWithTraceId(`Starting capturing replies to message ${parentMessageId} with action ${replyAction.key}`);
|
|
54
|
+
this.replyCaptures.push(replyAction);
|
|
55
|
+
capture.abortController.signal.addEventListener('abort', () => {
|
|
56
|
+
const index = this.replyCaptures.indexOf(replyAction);
|
|
57
|
+
this.replyCaptures.splice(index, 1);
|
|
58
|
+
logger.logWithTraceId(`Stopping capturing replies to message ${parentMessageId} with action ${replyAction.key}`);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async processMessage(msg) {
|
|
62
|
+
const chatHistoryArray = getOrSetIfNotExists(this.chatHistory, msg.chatInfo.id, []);
|
|
63
|
+
while (chatHistoryArray.length > MESSAGE_HISTORY_LENGTH_LIMIT)
|
|
64
|
+
chatHistoryArray.shift();
|
|
65
|
+
chatHistoryArray.push(new ChatHistoryMessage(msg.messageId, msg.from, msg.text, msg.type, msg.traceId, msg.replyToMessageId, msg.updateObject.date));
|
|
66
|
+
const ctx = new MessageContextInternal(this.storage, this.scheduler);
|
|
67
|
+
const commandsToCheck = new Set(this.commands[msg.type]);
|
|
68
|
+
if (msg.type != MessageType.Text && msg.text != '') {
|
|
69
|
+
for (const command of this.commands[MessageType.Text]) {
|
|
70
|
+
commandsToCheck.add(command);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
for (const commandAction of commandsToCheck) {
|
|
74
|
+
this.initializeMessageContext(ctx, commandAction, msg);
|
|
75
|
+
await this.executeAction(commandAction, ctx);
|
|
76
|
+
}
|
|
77
|
+
if (this.replyCaptures.length != 0) {
|
|
78
|
+
const replyCtx = new ReplyContextInternal(this.storage, this.scheduler);
|
|
79
|
+
for (const replyAction of this.replyCaptures) {
|
|
80
|
+
this.initializeReplyCaptureContext(replyCtx, replyAction, msg);
|
|
81
|
+
await this.executeAction(replyAction, replyCtx);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
this.api.flushResponses();
|
|
85
|
+
}
|
|
86
|
+
initializeReplyCaptureContext(ctx, action, message) {
|
|
87
|
+
ctx.replyMessageId = message.replyToMessageId;
|
|
88
|
+
ctx.messageInfo = new MessageInfo(message.messageId, message.text, message.type, message.updateObject);
|
|
89
|
+
ctx.userInfo = new UserInfo(message.from?.id ?? -1, (message.from?.first_name ?? 'Unknown user') +
|
|
90
|
+
(message.from?.last_name ? ` ${message.from.last_name}` : ''));
|
|
91
|
+
ctx.botName = this.botName;
|
|
92
|
+
ctx.action = action;
|
|
93
|
+
ctx.chatInfo = message.chatInfo;
|
|
94
|
+
ctx.traceId = message.traceId;
|
|
95
|
+
ctx.botInfo = this.botInfo;
|
|
96
|
+
ctx.isInitialized = true;
|
|
97
|
+
ctx.matchResults = [];
|
|
98
|
+
ctx.logger = this.logger.createScope(this.botName, message.traceId, message.chatInfo.name);
|
|
99
|
+
}
|
|
100
|
+
initializeMessageContext(ctx, action, message) {
|
|
101
|
+
ctx.messageInfo = new MessageInfo(message.messageId, message.text, message.type, message.updateObject);
|
|
102
|
+
ctx.userInfo = new UserInfo(message.from?.id ?? -1, (message.from?.first_name ?? 'Unknown user') +
|
|
103
|
+
(message.from?.last_name ? ` ${message.from.last_name}` : ''));
|
|
104
|
+
ctx.matchResults = [];
|
|
105
|
+
ctx.startCooldown = true;
|
|
106
|
+
ctx.responses = [];
|
|
107
|
+
ctx.isInitialized = true;
|
|
108
|
+
ctx.botName = this.botName;
|
|
109
|
+
ctx.action = action;
|
|
110
|
+
ctx.chatInfo = message.chatInfo;
|
|
111
|
+
ctx.traceId = message.traceId;
|
|
112
|
+
ctx.botInfo = this.botInfo;
|
|
113
|
+
ctx.customCooldown = undefined;
|
|
114
|
+
ctx.logger = this.logger.createScope(this.botName, message.traceId, message.chatInfo.name);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { InlineQueryAction } from '../../entities/actions/inlineQueryAction';
|
|
2
|
+
import { TelegramBot } from '../../types/externalAliases';
|
|
3
|
+
import { Milliseconds } from '../../types/timeValues';
|
|
4
|
+
import { TelegramApiService } from '../telegramApi';
|
|
5
|
+
import { BaseActionProcessor } from './baseProcessor';
|
|
6
|
+
export declare class InlineQueryActionProcessor extends BaseActionProcessor {
|
|
7
|
+
private inlineQueries;
|
|
8
|
+
initialize(api: TelegramApiService, telegram: TelegramBot, inlineQueries: InlineQueryAction[], period: Milliseconds): void;
|
|
9
|
+
private initializeInlineQueryContext;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=inlineQueryActionProcessor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inlineQueryActionProcessor.d.ts","sourceRoot":"","sources":["../../../services/actionProcessors/inlineQueryActionProcessor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAG7E,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,qBAAa,0BAA2B,SAAQ,mBAAmB;IAC/D,OAAO,CAAC,aAAa,CAAuB;IAE5C,UAAU,CACN,GAAG,EAAE,kBAAkB,EACvB,QAAQ,EAAE,WAAW,EACrB,aAAa,EAAE,iBAAiB,EAAE,EAClC,MAAM,EAAE,YAAY;IAuGxB,OAAO,CAAC,4BAA4B;CAqBvC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { IncomingInlineQuery } from '../../dtos/incomingQuery';
|
|
2
|
+
import { InlineQueryContextInternal } from '../../entities/context/inlineQueryContext';
|
|
3
|
+
import { createTrace } from '../../helpers/traceFactory';
|
|
4
|
+
import { BaseActionProcessor } from './baseProcessor';
|
|
5
|
+
export class InlineQueryActionProcessor extends BaseActionProcessor {
|
|
6
|
+
inlineQueries;
|
|
7
|
+
initialize(api, telegram, inlineQueries, period) {
|
|
8
|
+
this.initializeDependencies(api);
|
|
9
|
+
this.inlineQueries = inlineQueries;
|
|
10
|
+
let pendingInlineQueries = [];
|
|
11
|
+
const queriesInProcessing = new Map();
|
|
12
|
+
if (this.inlineQueries.length > 0) {
|
|
13
|
+
telegram.on('inline_query', ({ inlineQuery }) => {
|
|
14
|
+
const query = new IncomingInlineQuery(inlineQuery.id, inlineQuery.query, inlineQuery.from.id, createTrace('InlineQuery', this.botName, inlineQuery.id));
|
|
15
|
+
const logger = this.logger.createScope(this.botName, query.traceId, 'Query');
|
|
16
|
+
logger.logWithTraceId(`${inlineQuery.from.username ?? 'Unknown'} (${inlineQuery.from.id}): Query for ${inlineQuery.query}`);
|
|
17
|
+
const queryBeingProcessed = queriesInProcessing.get(query.userId);
|
|
18
|
+
if (queryBeingProcessed) {
|
|
19
|
+
logger.logWithTraceId(`Aborting query ${queryBeingProcessed.queryId} (${queryBeingProcessed.query}): new query recieved from ${query.userId}`);
|
|
20
|
+
queryBeingProcessed.abortController.abort();
|
|
21
|
+
queriesInProcessing.delete(query.userId);
|
|
22
|
+
}
|
|
23
|
+
pendingInlineQueries = pendingInlineQueries.filter((q) => q.userId != query.userId);
|
|
24
|
+
pendingInlineQueries.push(query);
|
|
25
|
+
});
|
|
26
|
+
this.scheduler.createTask('InlineQueryProcessing', async () => {
|
|
27
|
+
const ctx = new InlineQueryContextInternal(this.storage, this.scheduler);
|
|
28
|
+
const queriesToProcess = [...pendingInlineQueries];
|
|
29
|
+
pendingInlineQueries = [];
|
|
30
|
+
for (const inlineQuery of queriesToProcess) {
|
|
31
|
+
queriesInProcessing.set(inlineQuery.userId, inlineQuery);
|
|
32
|
+
for (const inlineQueryAction of this.inlineQueries) {
|
|
33
|
+
this.initializeInlineQueryContext(ctx, inlineQuery.query, inlineQuery.queryId, inlineQueryAction, inlineQuery.abortController.signal, inlineQuery.traceId);
|
|
34
|
+
await this.executeAction(inlineQueryAction, ctx, (error, ctx) => {
|
|
35
|
+
if (error.name == 'AbortError') {
|
|
36
|
+
ctx.logger.logWithTraceId(`Aborting query ${inlineQuery.queryId} (${inlineQuery.query}) successful.`);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
ctx.logger.errorWithTraceId(error, ctx);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
queriesInProcessing.delete(inlineQuery.userId);
|
|
44
|
+
}
|
|
45
|
+
this.api.flushResponses();
|
|
46
|
+
}, period, false, this.botName);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
initializeInlineQueryContext(ctx, queryText, queryId, action, abortSignal, traceId) {
|
|
50
|
+
ctx.queryText = queryText;
|
|
51
|
+
ctx.queryId = queryId;
|
|
52
|
+
ctx.botName = this.botName;
|
|
53
|
+
ctx.action = action;
|
|
54
|
+
ctx.traceId = traceId;
|
|
55
|
+
ctx.abortSignal = abortSignal;
|
|
56
|
+
ctx.isInitialized = true;
|
|
57
|
+
ctx.queryResults = [];
|
|
58
|
+
ctx.matchResults = [];
|
|
59
|
+
ctx.logger = this.logger.createScope(this.botName, traceId, 'Unknown');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ScheduledAction } from '../../entities/actions/scheduledAction';
|
|
2
|
+
import { IActionState } from '../../types/actionState';
|
|
3
|
+
import { ILogger } from '../../types/logger';
|
|
4
|
+
import { IScheduler } from '../../types/scheduler';
|
|
5
|
+
import { IStorageClient } from '../../types/storage';
|
|
6
|
+
import { Seconds } from '../../types/timeValues';
|
|
7
|
+
import { TelegramApiService } from '../telegramApi';
|
|
8
|
+
import { BaseActionProcessor } from './baseProcessor';
|
|
9
|
+
export declare class ScheduledActionProcessor extends BaseActionProcessor {
|
|
10
|
+
private readonly chats;
|
|
11
|
+
private scheduled;
|
|
12
|
+
constructor(botName: string, chats: Record<string, number>, storage: IStorageClient, scheduler: IScheduler, logger: ILogger);
|
|
13
|
+
initialize(api: TelegramApiService, scheduled: ScheduledAction<IActionState>[], period: Seconds): void;
|
|
14
|
+
private runScheduled;
|
|
15
|
+
private initializeChatContext;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=scheduledActionProcessor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduledActionProcessor.d.ts","sourceRoot":"","sources":["../../../services/actionProcessors/scheduledActionProcessor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAC;AAIzE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAgB,MAAM,wBAAwB,CAAC;AAE/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,qBAAa,wBAAyB,SAAQ,mBAAmB;IAC7D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyB;IAE/C,OAAO,CAAC,SAAS,CAAmC;gBAGhD,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7B,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,OAAO;IAMnB,UAAU,CACN,GAAG,EAAE,kBAAkB,EACvB,SAAS,EAAE,eAAe,CAAC,YAAY,CAAC,EAAE,EAC1C,MAAM,EAAE,OAAO;YAgDL,YAAY;IA0B1B,OAAO,CAAC,qBAAqB;CAmBhC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import moment from 'moment';
|
|
2
|
+
import { ChatInfo } from '../../dtos/chatInfo';
|
|
3
|
+
import { ChatContextInternal } from '../../entities/context/chatContext';
|
|
4
|
+
import { secondsToMilliseconds } from '../../helpers/timeConvertions';
|
|
5
|
+
import { createTrace } from '../../helpers/traceFactory';
|
|
6
|
+
import { BaseActionProcessor } from './baseProcessor';
|
|
7
|
+
export class ScheduledActionProcessor extends BaseActionProcessor {
|
|
8
|
+
chats;
|
|
9
|
+
scheduled;
|
|
10
|
+
constructor(botName, chats, storage, scheduler, logger) {
|
|
11
|
+
super(botName, storage, scheduler, logger);
|
|
12
|
+
this.chats = chats;
|
|
13
|
+
}
|
|
14
|
+
initialize(api, scheduled, period) {
|
|
15
|
+
this.initializeDependencies(api);
|
|
16
|
+
this.scheduled = scheduled;
|
|
17
|
+
if (this.scheduled.length > 0) {
|
|
18
|
+
const now = moment();
|
|
19
|
+
if (now.minute() == 0 && now.second() == 0) {
|
|
20
|
+
this.scheduler.createTask('ScheduledProcessing', async () => {
|
|
21
|
+
await this.runScheduled();
|
|
22
|
+
}, secondsToMilliseconds(period), true, this.botName);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
let nextExecutionTime = now.clone().startOf('hour');
|
|
26
|
+
if (now.minute() > 0 || now.second() > 0) {
|
|
27
|
+
nextExecutionTime = nextExecutionTime.add(1, 'hour');
|
|
28
|
+
}
|
|
29
|
+
const delay = nextExecutionTime.diff(now);
|
|
30
|
+
this.scheduler.createOnetimeTask('ScheduledProcessing_OneTime', () => {
|
|
31
|
+
this.scheduler.createTask('ScheduledProcessing', () => {
|
|
32
|
+
void this.runScheduled();
|
|
33
|
+
}, secondsToMilliseconds(period), true, this.botName);
|
|
34
|
+
}, delay, this.botName);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async runScheduled() {
|
|
38
|
+
const ctx = new ChatContextInternal(this.storage, this.scheduler);
|
|
39
|
+
for (const [chatName, chatId] of Object.entries(this.chats)) {
|
|
40
|
+
for (const scheduledAction of this.scheduled) {
|
|
41
|
+
this.initializeChatContext(ctx, scheduledAction, new ChatInfo(chatId, chatName, []), createTrace(scheduledAction, this.botName, `${scheduledAction.key}-${chatId}`));
|
|
42
|
+
await this.executeAction(scheduledAction, ctx);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
this.api.flushResponses();
|
|
46
|
+
}
|
|
47
|
+
initializeChatContext(ctx, action, chatInfo, traceId) {
|
|
48
|
+
ctx.responses = [];
|
|
49
|
+
ctx.isInitialized = true;
|
|
50
|
+
ctx.botName = this.botName;
|
|
51
|
+
ctx.action = action;
|
|
52
|
+
ctx.chatInfo = chatInfo;
|
|
53
|
+
ctx.traceId = traceId;
|
|
54
|
+
ctx.logger = this.logger.createScope(this.botName, traceId, chatInfo.name);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IStorageClient } from '../types/storage';
|
|
2
|
+
import { IActionState } from '../types/actionState';
|
|
3
|
+
import { IActionWithState, ActionKey } from '../types/action';
|
|
4
|
+
export declare class JsonFileStorage implements IStorageClient {
|
|
5
|
+
private readonly filePaths;
|
|
6
|
+
private readonly locks;
|
|
7
|
+
private readonly cache;
|
|
8
|
+
private readonly storagePath;
|
|
9
|
+
private readonly botName;
|
|
10
|
+
constructor(botName: string, actions: IActionWithState<IActionState>[], path?: string);
|
|
11
|
+
private backfillEmptyActionStates;
|
|
12
|
+
private lock;
|
|
13
|
+
private tryGetFromCache;
|
|
14
|
+
private loadFromFile;
|
|
15
|
+
private updateCacheAndSaveToFile;
|
|
16
|
+
load<TActionState extends IActionState>(key: ActionKey): Promise<Record<number, TActionState | undefined>>;
|
|
17
|
+
saveMetadata(actions: IActionWithState<IActionState>[]): Promise<void>;
|
|
18
|
+
getActionState<TActionState extends IActionState>(action: IActionWithState<TActionState>, chatId: number): Promise<TActionState | (TActionState & undefined)>;
|
|
19
|
+
saveActionExecutionResult<TActionState extends IActionState>(action: IActionWithState<TActionState>, chatId: number, state: TActionState): Promise<void>;
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
updateStateFor<TActionState extends IActionState>(action: IActionWithState<TActionState>, chatId: number, update: (state: TActionState) => Promise<void> | void): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=jsonFileStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonFileStorage.d.ts","sourceRoot":"","sources":["../../services/jsonFileStorage.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAO9D,qBAAa,eAAgB,YAAW,cAAc;IAClD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAC1D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmC;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4C;IAClE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAG7B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,gBAAgB,CAAC,YAAY,CAAC,EAAE,EACzC,IAAI,CAAC,EAAE,MAAM;IAqBjB,OAAO,CAAC,yBAAyB;YAanB,IAAI;IAYlB,OAAO,CAAC,eAAe;YAIT,YAAY;YA6BZ,wBAAwB;IAehC,IAAI,CAAC,YAAY,SAAS,YAAY,EAAE,GAAG,EAAE,SAAS;IAStD,YAAY,CAAC,OAAO,EAAE,gBAAgB,CAAC,YAAY,CAAC,EAAE;IAQtD,cAAc,CAAC,YAAY,SAAS,YAAY,EAClD,MAAM,EAAE,gBAAgB,CAAC,YAAY,CAAC,EACtC,MAAM,EAAE,MAAM;IAWZ,yBAAyB,CAAC,YAAY,SAAS,YAAY,EAC7D,MAAM,EAAE,gBAAgB,CAAC,YAAY,CAAC,EACtC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY;IAcjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,cAAc,CAAC,YAAY,SAAS,YAAY,EAClD,MAAM,EAAE,gBAAgB,CAAC,YAAY,CAAC,EACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;CAkB5D"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
2
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
3
|
+
import { Sema as Semaphore } from 'async-sema';
|
|
4
|
+
import { getOrSetIfNotExists } from '../helpers/mapUtils';
|
|
5
|
+
function buildPath(storagePath, botName, actionKey) {
|
|
6
|
+
return `${storagePath}/${botName}/${actionKey.replaceAll(':', '/')}.json`;
|
|
7
|
+
}
|
|
8
|
+
export class JsonFileStorage {
|
|
9
|
+
filePaths = new Map();
|
|
10
|
+
locks = new Map();
|
|
11
|
+
cache;
|
|
12
|
+
storagePath;
|
|
13
|
+
botName;
|
|
14
|
+
constructor(botName, actions, path) {
|
|
15
|
+
this.cache = new Map();
|
|
16
|
+
this.botName = botName;
|
|
17
|
+
this.storagePath = path ?? 'storage';
|
|
18
|
+
if (!existsSync(`${this.storagePath}/${this.botName}/`)) {
|
|
19
|
+
mkdirSync(`${this.storagePath}/${this.botName}/`, {
|
|
20
|
+
recursive: true
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
for (const action of actions) {
|
|
24
|
+
this.locks.set(action.key, new Semaphore(1));
|
|
25
|
+
this.filePaths.set(action.key, buildPath(this.storagePath, this.botName, action.key));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
backfillEmptyActionStates(action, data) {
|
|
29
|
+
for (const [stringKey, value] of Object.entries(data)) {
|
|
30
|
+
if (value)
|
|
31
|
+
continue;
|
|
32
|
+
data[Number.parseInt(stringKey)] = action.stateConstructor();
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
async lock(key, action) {
|
|
37
|
+
const lock = getOrSetIfNotExists(this.locks, key, new Semaphore(1));
|
|
38
|
+
await lock.acquire();
|
|
39
|
+
try {
|
|
40
|
+
return await action();
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
lock.release();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
tryGetFromCache(key) {
|
|
47
|
+
return this.cache.get(key);
|
|
48
|
+
}
|
|
49
|
+
async loadFromFile(key) {
|
|
50
|
+
const targetPath = getOrSetIfNotExists(this.filePaths, key, buildPath(this.storagePath, this.botName, key));
|
|
51
|
+
const fileContent = await readFile(targetPath, {
|
|
52
|
+
encoding: 'utf-8',
|
|
53
|
+
flag: 'a+'
|
|
54
|
+
});
|
|
55
|
+
if (fileContent) {
|
|
56
|
+
const data = JSON.parse(fileContent);
|
|
57
|
+
this.cache.set(key, data);
|
|
58
|
+
}
|
|
59
|
+
return (this.cache.get(key) ?? {});
|
|
60
|
+
}
|
|
61
|
+
async updateCacheAndSaveToFile(data, key) {
|
|
62
|
+
this.cache.set(key, data);
|
|
63
|
+
const targetPath = getOrSetIfNotExists(this.filePaths, key, buildPath(this.storagePath, this.botName, key));
|
|
64
|
+
await writeFile(targetPath, JSON.stringify(data), { flag: 'w+' });
|
|
65
|
+
}
|
|
66
|
+
async load(key) {
|
|
67
|
+
return (this.tryGetFromCache(key) ??
|
|
68
|
+
(await this.lock(key, async () => {
|
|
69
|
+
return await this.loadFromFile(key);
|
|
70
|
+
})));
|
|
71
|
+
}
|
|
72
|
+
async saveMetadata(actions) {
|
|
73
|
+
const targetPath = `${this.storagePath}/${this.botName}/Metadata-${this.botName}.json`;
|
|
74
|
+
await writeFile(targetPath, JSON.stringify(actions), {
|
|
75
|
+
flag: 'w+'
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
async getActionState(action, chatId) {
|
|
79
|
+
const value = this.tryGetFromCache(action.key) ??
|
|
80
|
+
(await this.lock(action.key, async () => {
|
|
81
|
+
return await this.loadFromFile(action.key);
|
|
82
|
+
}));
|
|
83
|
+
return Object.assign(action.stateConstructor(), value[chatId]);
|
|
84
|
+
}
|
|
85
|
+
async saveActionExecutionResult(action, chatId, state) {
|
|
86
|
+
await this.lock(action.key, async () => {
|
|
87
|
+
const data = this.tryGetFromCache(action.key) ??
|
|
88
|
+
(await this.loadFromFile(action.key));
|
|
89
|
+
data[chatId] = state;
|
|
90
|
+
if (this.backfillEmptyActionStates(action, data))
|
|
91
|
+
await this.updateCacheAndSaveToFile(data, action.key);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async close() {
|
|
95
|
+
for (const lock of this.locks.values()) {
|
|
96
|
+
await lock.acquire();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async updateStateFor(action, chatId, update) {
|
|
100
|
+
await this.lock(action.key, async () => {
|
|
101
|
+
const data = this.tryGetFromCache(action.key) ??
|
|
102
|
+
(await this.loadFromFile(action.key));
|
|
103
|
+
const state = Object.assign(action.stateConstructor(), data[chatId]);
|
|
104
|
+
await update(state);
|
|
105
|
+
if (this.backfillEmptyActionStates(action, data))
|
|
106
|
+
await this.updateCacheAndSaveToFile(data, action.key);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ILogger, IScopedLogger } from '../types/logger';
|
|
2
|
+
import { TraceId } from '../types/trace';
|
|
3
|
+
export declare class JsonLogger implements ILogger {
|
|
4
|
+
private serializeError;
|
|
5
|
+
private getCircularReplacer;
|
|
6
|
+
createScope(botName: string, traceId: TraceId, chatName: string): IScopedLogger;
|
|
7
|
+
logObjectWithTraceId(botName: string, traceId: TraceId, chatName: string, data: unknown): void;
|
|
8
|
+
logWithTraceId(botName: string, traceId: TraceId, chatName: string, text: string): void;
|
|
9
|
+
errorWithTraceId(botName: string, traceId: TraceId, chatName: string, errorObj: unknown, extraData?: unknown): void;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=jsonLogger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonLogger.d.ts","sourceRoot":"","sources":["../../services/jsonLogger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,qBAAa,UAAW,YAAW,OAAO;IACtC,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,mBAAmB;IAc3B,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAiBtD,aAAa;IAGtB,oBAAoB,CAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO;IAoBjB,cAAc,CACV,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM;IAOhB,gBAAgB,CACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,EACjB,SAAS,CAAC,EAAE,OAAO;CAe1B"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export class JsonLogger {
|
|
2
|
+
serializeError(error) {
|
|
3
|
+
if (error instanceof Error) {
|
|
4
|
+
const plainObject = {
|
|
5
|
+
name: error.name,
|
|
6
|
+
message: error.message,
|
|
7
|
+
stack: error.stack
|
|
8
|
+
};
|
|
9
|
+
for (const [key, value] of Object.entries(error)) {
|
|
10
|
+
plainObject[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return JSON.stringify(plainObject);
|
|
13
|
+
}
|
|
14
|
+
return JSON.stringify({ error });
|
|
15
|
+
}
|
|
16
|
+
getCircularReplacer() {
|
|
17
|
+
const cache = new Set();
|
|
18
|
+
return (_, value) => {
|
|
19
|
+
if (typeof value === 'object' && value !== null) {
|
|
20
|
+
if (cache.has(value)) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
cache.add(value);
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
createScope(botName, traceId, chatName) {
|
|
29
|
+
return {
|
|
30
|
+
logObjectWithTraceId: (data) => {
|
|
31
|
+
this.logObjectWithTraceId(botName, traceId, chatName, data);
|
|
32
|
+
},
|
|
33
|
+
logWithTraceId: (text) => {
|
|
34
|
+
this.logWithTraceId(botName, traceId, chatName, text);
|
|
35
|
+
},
|
|
36
|
+
errorWithTraceId: (errorObj, extraData) => {
|
|
37
|
+
this.errorWithTraceId(botName, traceId, chatName, errorObj, extraData);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
logObjectWithTraceId(botName, traceId, chatName, data) {
|
|
42
|
+
const enrichedData = typeof data == 'object'
|
|
43
|
+
? {
|
|
44
|
+
...data,
|
|
45
|
+
botName,
|
|
46
|
+
traceId,
|
|
47
|
+
chatName
|
|
48
|
+
}
|
|
49
|
+
: {
|
|
50
|
+
botName,
|
|
51
|
+
traceId,
|
|
52
|
+
chatName,
|
|
53
|
+
data
|
|
54
|
+
};
|
|
55
|
+
console.log(enrichedData);
|
|
56
|
+
}
|
|
57
|
+
logWithTraceId(botName, traceId, chatName, text) {
|
|
58
|
+
console.log(`{"botName":"${botName}","traceId":"${traceId}","chatName":"${chatName}","text":"${text}"}`);
|
|
59
|
+
}
|
|
60
|
+
errorWithTraceId(botName, traceId, chatName, errorObj, extraData) {
|
|
61
|
+
const dataString = extraData
|
|
62
|
+
? `,"extraData":${JSON.stringify(extraData, this.getCircularReplacer())}`
|
|
63
|
+
: '';
|
|
64
|
+
console.error(`{"botName":"${botName}","traceId":"${traceId}","chatName":"${chatName}","error":${this.serializeError(errorObj)}${dataString}}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TaskRecord } from '../entities/taskRecord';
|
|
2
|
+
import { ILogger } from '../types/logger';
|
|
3
|
+
import { IScheduler } from '../types/scheduler';
|
|
4
|
+
import { Milliseconds } from '../types/timeValues';
|
|
5
|
+
export declare class NodeTimeoutScheduler implements IScheduler {
|
|
6
|
+
private readonly logger;
|
|
7
|
+
readonly activeTasks: TaskRecord[];
|
|
8
|
+
constructor(logger: ILogger);
|
|
9
|
+
stopAll(): void;
|
|
10
|
+
createTask(name: string, action: () => unknown, interval: Milliseconds, executeRightAway: boolean, ownerName: string): void;
|
|
11
|
+
createOnetimeTask(name: string, action: () => unknown, delay: Milliseconds, ownerName: string): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=nodeTimeoutScheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodeTimeoutScheduler.d.ts","sourceRoot":"","sources":["../../services/nodeTimeoutScheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,qBAAa,oBAAqB,YAAW,UAAU;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,QAAQ,CAAC,WAAW,EAAE,UAAU,EAAE,CAAM;gBAE5B,MAAM,EAAE,OAAO;IAI3B,OAAO;IAMP,UAAU,CACN,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,OAAO,EACrB,QAAQ,EAAE,YAAY,EACtB,gBAAgB,EAAE,OAAO,EACzB,SAAS,EAAE,MAAM;IAmBrB,iBAAiB,CACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,OAAO,EACrB,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM;CAoBxB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { TaskRecord } from '../entities/taskRecord';
|
|
2
|
+
import { createTrace } from '../helpers/traceFactory';
|
|
3
|
+
export class NodeTimeoutScheduler {
|
|
4
|
+
logger;
|
|
5
|
+
activeTasks = [];
|
|
6
|
+
constructor(logger) {
|
|
7
|
+
this.logger = logger;
|
|
8
|
+
}
|
|
9
|
+
stopAll() {
|
|
10
|
+
for (const task of this.activeTasks) {
|
|
11
|
+
clearInterval(task.taskId);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
createTask(name, action, interval, executeRightAway, ownerName) {
|
|
15
|
+
const taskId = setInterval(action, interval);
|
|
16
|
+
const task = new TaskRecord(name, taskId, interval);
|
|
17
|
+
if (executeRightAway) {
|
|
18
|
+
setImmediate(action);
|
|
19
|
+
}
|
|
20
|
+
this.logger.logWithTraceId(ownerName, createTrace(this, ownerName, name), 'System', `Created task ${name}, that will run every ${interval}ms.`);
|
|
21
|
+
this.activeTasks.push(task);
|
|
22
|
+
}
|
|
23
|
+
createOnetimeTask(name, action, delay, ownerName) {
|
|
24
|
+
const actionWrapper = () => {
|
|
25
|
+
this.logger.logWithTraceId(ownerName, createTrace(this, ownerName, name), 'System', `Executing delayed oneshot ${name}`);
|
|
26
|
+
action();
|
|
27
|
+
};
|
|
28
|
+
setTimeout(actionWrapper, delay);
|
|
29
|
+
this.logger.logWithTraceId(ownerName, createTrace(this, ownerName, name), 'System', `Created oneshot task ${name}, that will run in ${delay}ms.`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type QueueItem = {
|
|
2
|
+
priority: number;
|
|
3
|
+
callback: () => Promise<void>;
|
|
4
|
+
};
|
|
5
|
+
export declare class ResponseProcessingQueue {
|
|
6
|
+
rateLimiter: () => Promise<void>;
|
|
7
|
+
items: QueueItem[];
|
|
8
|
+
isFlushing: boolean;
|
|
9
|
+
enqueue(item: QueueItem): void;
|
|
10
|
+
flushReadyItems(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=responseProcessingQueue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"responseProcessingQueue.d.ts","sourceRoot":"","sources":["../../services/responseProcessingQueue.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GAAG;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC,CAAC;AAQF,qBAAa,uBAAuB;IAChC,WAAW,sBAAwD;IACnE,KAAK,EAAE,SAAS,EAAE,CAAM;IACxB,UAAU,UAAS;IAEnB,OAAO,CAAC,IAAI,EAAE,SAAS;IAmBjB,eAAe;CAkBxB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { RateLimit } from 'async-sema';
|
|
2
|
+
function notEmpty(arr) {
|
|
3
|
+
return arr.length > 0;
|
|
4
|
+
}
|
|
5
|
+
const TELEGRAM_RATELIMIT_DELAY = 35;
|
|
6
|
+
export class ResponseProcessingQueue {
|
|
7
|
+
rateLimiter = RateLimit(1, { timeUnit: TELEGRAM_RATELIMIT_DELAY });
|
|
8
|
+
items = [];
|
|
9
|
+
isFlushing = false;
|
|
10
|
+
enqueue(item) {
|
|
11
|
+
if (this.items.length === 0 ||
|
|
12
|
+
item.priority >= this.items[this.items.length - 1].priority) {
|
|
13
|
+
this.items.push(item);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
let insertIndex = this.items.length;
|
|
17
|
+
while (insertIndex > 0 &&
|
|
18
|
+
this.items[insertIndex - 1].priority > item.priority) {
|
|
19
|
+
insertIndex--;
|
|
20
|
+
}
|
|
21
|
+
this.items.splice(insertIndex, 0, item);
|
|
22
|
+
}
|
|
23
|
+
async flushReadyItems() {
|
|
24
|
+
if (this.isFlushing)
|
|
25
|
+
return;
|
|
26
|
+
this.isFlushing = true;
|
|
27
|
+
while (notEmpty(this.items)) {
|
|
28
|
+
if (Date.now() >= this.items[0].priority) {
|
|
29
|
+
await this.rateLimiter();
|
|
30
|
+
const [item] = this.items;
|
|
31
|
+
this.items.shift();
|
|
32
|
+
await item.callback();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
this.isFlushing = false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IStorageClient } from '../types/storage';
|
|
2
|
+
import { BotResponse } from '../types/response';
|
|
3
|
+
import { ILogger } from '../types/logger';
|
|
4
|
+
import { IReplyCapture } from '../types/capture';
|
|
5
|
+
import { TraceId } from '../types/trace';
|
|
6
|
+
import { ChatInfo } from '../dtos/chatInfo';
|
|
7
|
+
import { TelegramApiClient } from '../types/externalAliases';
|
|
8
|
+
export declare const TELEGRAM_ERROR_QUOTE_INVALID = "QUOTE_TEXT_INVALID";
|
|
9
|
+
export declare class TelegramApiService {
|
|
10
|
+
private readonly queue;
|
|
11
|
+
private readonly telegram;
|
|
12
|
+
private readonly storage;
|
|
13
|
+
private readonly logger;
|
|
14
|
+
private readonly captureRegistrationCallback;
|
|
15
|
+
private readonly botName;
|
|
16
|
+
constructor(botName: string, telegram: TelegramApiClient, storage: IStorageClient, logger: ILogger, captureRegistrationCallback: (capture: IReplyCapture, parentMessageId: number, chatInfo: ChatInfo, traceId: TraceId) => void);
|
|
17
|
+
enqueueBatchedResponses(responses: BotResponse[]): void;
|
|
18
|
+
flushResponses(): void;
|
|
19
|
+
private pinIfShould;
|
|
20
|
+
private processResponse;
|
|
21
|
+
private sendApiRequest;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=telegramApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegramApi.d.ts","sourceRoot":"","sources":["../../services/telegramApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAkB,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAmB,MAAM,0BAA0B,CAAC;AAE9E,eAAO,MAAM,4BAA4B,uBAAuB,CAAC;AAEjE,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAKlC;IAEV,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAG7B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,OAAO,EACf,2BAA2B,EAAE,CACzB,OAAO,EAAE,aAAa,EACtB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,KACf,IAAI;IASb,uBAAuB,CAAC,SAAS,EAAE,WAAW,EAAE;IAwDhD,cAAc;YAIA,WAAW;YAqBX,eAAe;YAiBf,cAAc;CA6F/B"}
|