chz-telegram-bot 0.0.23 → 0.0.25
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/entities/actions/scheduledAction.d.ts +1 -1
- package/dist/entities/actions/scheduledAction.d.ts.map +1 -1
- package/dist/entities/actions/scheduledAction.js +1 -0
- package/dist/entities/botInstance.d.ts +1 -1
- package/dist/entities/botInstance.d.ts.map +1 -1
- package/dist/entities/botInstance.js +30 -12
- package/dist/entities/context/chatContext.d.ts +37 -4
- package/dist/entities/context/chatContext.d.ts.map +1 -1
- package/dist/entities/context/chatContext.js +30 -0
- package/dist/entities/context/messageContext.d.ts +34 -3
- package/dist/entities/context/messageContext.d.ts.map +1 -1
- package/dist/entities/context/messageContext.js +29 -4
- package/dist/helpers/builders/commandActionBuilder.d.ts +38 -0
- package/dist/helpers/builders/commandActionBuilder.d.ts.map +1 -1
- package/dist/helpers/builders/commandActionBuilder.js +38 -0
- package/dist/helpers/builders/scheduledActionBuilder.d.ts +34 -0
- package/dist/helpers/builders/scheduledActionBuilder.d.ts.map +1 -1
- package/dist/helpers/builders/scheduledActionBuilder.js +34 -0
- package/dist/helpers/reverseRecord.d.ts +2 -0
- package/dist/helpers/reverseRecord.d.ts.map +1 -0
- package/dist/helpers/reverseRecord.js +6 -0
- package/dist/main.d.ts +14 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +7 -1
- package/dist/services/taskScheduler.d.ts.map +1 -1
- package/dist/services/taskScheduler.js +1 -2
- package/dist/services/telegramApi.d.ts +7 -4
- package/dist/services/telegramApi.d.ts.map +1 -1
- package/dist/services/telegramApi.js +8 -7
- package/dist/types/handlers.d.ts +12 -2
- package/dist/types/handlers.d.ts.map +1 -1
- package/entities/actions/scheduledAction.ts +2 -1
- package/entities/botInstance.ts +52 -17
- package/entities/context/chatContext.ts +42 -4
- package/entities/context/messageContext.ts +34 -8
- package/helpers/builders/commandActionBuilder.ts +38 -0
- package/helpers/builders/scheduledActionBuilder.ts +34 -0
- package/helpers/reverseRecord.ts +7 -0
- package/main.ts +15 -2
- package/package.json +1 -1
- package/services/taskScheduler.ts +2 -3
- package/services/telegramApi.ts +22 -14
- package/types/handlers.ts +6 -1
- package/helpers/reverseMap.ts +0 -3
|
@@ -5,7 +5,15 @@ const scheduledAction_1 = require("../../entities/actions/scheduledAction");
|
|
|
5
5
|
const cachedStateFactory_1 = require("../../entities/cachedStateFactory");
|
|
6
6
|
const actionStateBase_1 = require("../../entities/states/actionStateBase");
|
|
7
7
|
const noop_1 = require("../noop");
|
|
8
|
+
/**
|
|
9
|
+
* Builder for `ScheduledAction` with state represented by `TActionState`
|
|
10
|
+
*/
|
|
8
11
|
class ScheduledActionBuilderWithState {
|
|
12
|
+
/**
|
|
13
|
+
* Builder for `ScheduledAction` with state represented by `TActionState`
|
|
14
|
+
* @param name Action name, will be used for logging and storage
|
|
15
|
+
* @param stateConstructor Function that creates default state object
|
|
16
|
+
*/
|
|
9
17
|
constructor(name, stateConstructor) {
|
|
10
18
|
this.active = true;
|
|
11
19
|
this.time = 0;
|
|
@@ -15,32 +23,58 @@ class ScheduledActionBuilderWithState {
|
|
|
15
23
|
this.name = name;
|
|
16
24
|
this.stateConstructor = stateConstructor;
|
|
17
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Adds a chat to whitelist for this action.
|
|
28
|
+
* @param chatId Chat id to execute in.
|
|
29
|
+
*/
|
|
18
30
|
allowIn(chatId) {
|
|
19
31
|
this.whitelist.push(chatId);
|
|
20
32
|
return this;
|
|
21
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Defines time for scheduled item execution.
|
|
36
|
+
* @param time Time of day (0 - 23) to execute action.
|
|
37
|
+
*/
|
|
22
38
|
runAt(time) {
|
|
23
39
|
this.time = time;
|
|
24
40
|
return this;
|
|
25
41
|
}
|
|
42
|
+
/** Defines action logic itself, will be executed on timer.
|
|
43
|
+
* @param handler Callback that will be called on timer.
|
|
44
|
+
*/
|
|
26
45
|
do(handler) {
|
|
27
46
|
this.handler = handler;
|
|
28
47
|
return this;
|
|
29
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Defines process-wide cache, that is shared by all actions of this type (even in different bot instances).
|
|
51
|
+
* Can be used for fetch request de-duping, etc.
|
|
52
|
+
* @param key Key that will be used to retrieve value from cache.
|
|
53
|
+
* @param itemFactory Callback that will be executed once to create cached value.
|
|
54
|
+
* @param invalidationTimeoutInHours Timeout for cache invalidation.
|
|
55
|
+
*/
|
|
30
56
|
withSharedCache(key, itemFactory, invalidationTimeoutInHours = 20) {
|
|
31
57
|
this.cachedStateFactories.set(key, new cachedStateFactory_1.CachedStateFactory(itemFactory, invalidationTimeoutInHours));
|
|
32
58
|
return this;
|
|
33
59
|
}
|
|
60
|
+
/** If called during building, action is marked as disabled and never checked. */
|
|
34
61
|
disabled() {
|
|
35
62
|
this.active = false;
|
|
36
63
|
return this;
|
|
37
64
|
}
|
|
65
|
+
/** Builds action */
|
|
38
66
|
build() {
|
|
39
67
|
return new scheduledAction_1.ScheduledAction(this.name, this.handler, this.time, this.active, this.whitelist, this.cachedStateFactories, this.stateConstructor);
|
|
40
68
|
}
|
|
41
69
|
}
|
|
42
70
|
exports.ScheduledActionBuilderWithState = ScheduledActionBuilderWithState;
|
|
71
|
+
/**
|
|
72
|
+
* Builder for `ScheduledAction` with state represented by default state (containing only last execution date).
|
|
73
|
+
*/
|
|
43
74
|
class ScheduledActionBuilder extends ScheduledActionBuilderWithState {
|
|
75
|
+
/**
|
|
76
|
+
* Builder for `ScheduledAction` with state represented by default state (containing only last execution date).
|
|
77
|
+
*/
|
|
44
78
|
constructor(name) {
|
|
45
79
|
super(name, () => new actionStateBase_1.ActionStateBase());
|
|
46
80
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reverseRecord.d.ts","sourceRoot":"","sources":["../../helpers/reverseRecord.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,WAAW,EACtE,KAAK,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAId,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CACpB"}
|
package/dist/main.d.ts
CHANGED
|
@@ -3,15 +3,28 @@ import { CommandAction } from './entities/actions/commandAction';
|
|
|
3
3
|
import { ScheduledAction } from './entities/actions/scheduledAction';
|
|
4
4
|
import { IActionState } from './types/actionState';
|
|
5
5
|
import { BotInstance } from './entities/botInstance';
|
|
6
|
+
/**
|
|
7
|
+
* Starts bot
|
|
8
|
+
*/
|
|
6
9
|
declare function startBot(options: {
|
|
10
|
+
/** Bot name, used in logging */
|
|
7
11
|
name: string;
|
|
12
|
+
/** Path to file containing Telegram Bot token. */
|
|
8
13
|
tokenFilePath: string;
|
|
14
|
+
/** Collection of actions that will be executed as a response to message from used. Created using `CommandActionBuilder`.*/
|
|
9
15
|
commands: CommandAction<IActionState>[];
|
|
16
|
+
/** Collection of actions that will be executed on timer. Created using `ScheduledActionBuilder`.*/
|
|
10
17
|
scheduled: ScheduledAction<IActionState>[];
|
|
11
|
-
|
|
18
|
+
/** Object containing chat name and chat id pairs. Used for logging and execution of scheduled action. */
|
|
19
|
+
chats: Record<string, number>;
|
|
20
|
+
/** Storage client for bot state storage. If not provided, default `JsonFileStorage` will be used. */
|
|
12
21
|
storageClient?: IStorageClient;
|
|
22
|
+
/** Storage path for default `JsonFileStorage` client. Will be used only if `storageClient` is not provided. If not provided, default value of `./storage/` will be used.*/
|
|
13
23
|
storagePath?: string;
|
|
14
24
|
}): Promise<BotInstance>;
|
|
25
|
+
/**
|
|
26
|
+
* Terminates all scheduled tasks, closes storage connections and stops all bots.
|
|
27
|
+
*/
|
|
15
28
|
declare function stopBots(reason: string): Promise<void>;
|
|
16
29
|
export { startBot, stopBots };
|
|
17
30
|
//# sourceMappingURL=main.d.ts.map
|
package/dist/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAQrD,iBAAe,QAAQ,CAAC,OAAO,EAAE;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;IACxC,SAAS,EAAE,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC;IAC3C,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAQrD;;GAEG;AACH,iBAAe,QAAQ,CAAC,OAAO,EAAE;IAC7B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,aAAa,EAAE,MAAM,CAAC;IACtB,2HAA2H;IAC3H,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;IACxC,mGAAmG;IACnG,SAAS,EAAE,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC;IAC3C,yGAAyG;IACzG,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,qGAAqG;IACrG,aAAa,CAAC,EAAE,cAAc,CAAC;IAC/B,2KAA2K;IAC3K,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB,wBAcA;AAED;;GAEG;AACH,iBAAe,QAAQ,CAAC,MAAM,EAAE,MAAM,iBASrC;AAED,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC"}
|
package/dist/main.js
CHANGED
|
@@ -10,6 +10,9 @@ const bots = [];
|
|
|
10
10
|
function log(text) {
|
|
11
11
|
logger_1.Logger.logWithTraceId('ALL BOTS', 'System:Bot', 'System', text);
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Starts bot
|
|
15
|
+
*/
|
|
13
16
|
async function startBot(options) {
|
|
14
17
|
const token = await (0, promises_1.readFile)(options.tokenFilePath, 'utf8');
|
|
15
18
|
const bot = new botInstance_1.BotInstance({
|
|
@@ -24,12 +27,15 @@ async function startBot(options) {
|
|
|
24
27
|
bots.push(bot);
|
|
25
28
|
return bot;
|
|
26
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Terminates all scheduled tasks, closes storage connections and stops all bots.
|
|
32
|
+
*/
|
|
27
33
|
async function stopBots(reason) {
|
|
28
34
|
log(`Recieved termination code: ${reason}`);
|
|
29
35
|
taskScheduler_1.Scheduler.stopAll();
|
|
30
36
|
log('Acquiring storage semaphore...');
|
|
31
37
|
log('Stopping bots...');
|
|
32
38
|
for (const bot of bots) {
|
|
33
|
-
bot.stop(reason);
|
|
39
|
+
await bot.stop(reason);
|
|
34
40
|
}
|
|
35
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"taskScheduler.d.ts","sourceRoot":"","sources":["../../services/taskScheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"taskScheduler.d.ts","sourceRoot":"","sources":["../../services/taskScheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,cAAM,aAAa;IACf,WAAW,EAAE,UAAU,EAAE,CAAM;IAE/B,OAAO;IAMP,UAAU,CACN,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,IAAI,EAClB,QAAQ,EAAE,YAAY,EACtB,gBAAgB,EAAE,OAAO,EACzB,SAAS,EAAE,MAAM;IAoBrB,iBAAiB,CACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,IAAI,EAClB,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM;CAoBxB;AAED,eAAO,MAAM,SAAS,eAAsB,CAAC"}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Scheduler = void 0;
|
|
4
4
|
const taskRecord_1 = require("../entities/taskRecord");
|
|
5
|
-
const timeConvertions_1 = require("../helpers/timeConvertions");
|
|
6
5
|
const logger_1 = require("./logger");
|
|
7
6
|
class TaskScheduler {
|
|
8
7
|
constructor() {
|
|
@@ -18,7 +17,7 @@ class TaskScheduler {
|
|
|
18
17
|
const taskId = setInterval(action, interval);
|
|
19
18
|
const task = new taskRecord_1.TaskRecord(name, taskId, interval);
|
|
20
19
|
if (executeRightAway) {
|
|
21
|
-
|
|
20
|
+
setImmediate(action);
|
|
22
21
|
}
|
|
23
22
|
logger_1.Logger.logWithTraceId(ownerName, `System:TaskScheduler-${ownerName}-${name}`, 'System', `Created task [${taskId}]${name}, that will run every ${interval}ms.`);
|
|
24
23
|
this.activeTasks.push(task);
|
|
@@ -9,21 +9,24 @@ import { TextMessage } from '../entities/responses/textMessage';
|
|
|
9
9
|
import { VideoMessage } from '../entities/responses/videoMessage';
|
|
10
10
|
import { ImageMessage } from '../entities/responses/imageMessage';
|
|
11
11
|
import { Telegram } from 'telegraf/typings/telegram';
|
|
12
|
+
import { ScheduledAction } from '../entities/actions/scheduledAction';
|
|
13
|
+
import { IActionState } from '../types/actionState';
|
|
14
|
+
import { CommandAction } from '../entities/actions/commandAction';
|
|
12
15
|
export declare class TelegramApiService {
|
|
13
16
|
isFlushing: boolean;
|
|
14
17
|
messageQueue: Array<BotResponse>;
|
|
15
18
|
botName: string;
|
|
16
19
|
telegram: Telegram;
|
|
17
|
-
chats:
|
|
20
|
+
chats: Record<number, string>;
|
|
18
21
|
storage: IStorageClient;
|
|
19
|
-
constructor(botName: string, telegram: Telegram, storage: IStorageClient, chats:
|
|
22
|
+
constructor(botName: string, telegram: Telegram, storage: IStorageClient, chats: Record<string, number>);
|
|
20
23
|
flushResponses(): Promise<void>;
|
|
21
24
|
private pinIfShould;
|
|
22
25
|
private processResponse;
|
|
23
26
|
private enqueue;
|
|
24
27
|
private getInteractions;
|
|
25
|
-
createContextForMessage(incomingMessage: IncomingMessage,
|
|
26
|
-
createContextForChat(chatId: number,
|
|
28
|
+
createContextForMessage<TActionState extends IActionState>(incomingMessage: IncomingMessage, command: CommandAction<TActionState>): MessageContext<TActionState>;
|
|
29
|
+
createContextForChat<TActionState extends IActionState>(chatId: number, scheduledAction: ScheduledAction<TActionState>): ChatContext<TActionState>;
|
|
27
30
|
}
|
|
28
31
|
export interface IBotApiInteractions {
|
|
29
32
|
respond: (response: TextMessage | VideoMessage | ImageMessage) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telegramApi.d.ts","sourceRoot":"","sources":["../../services/telegramApi.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEpE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAiB,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"telegramApi.d.ts","sourceRoot":"","sources":["../../services/telegramApi.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEpE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAiB,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAElE,qBAAa,kBAAkB;IAC3B,UAAU,UAAS;IACnB,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,CAAM;IAEtC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,EAAE,cAAc,CAAC;gBAGpB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAQ3B,cAAc;YA2BN,WAAW;YAqBX,eAAe;IA2E7B,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,eAAe;IAQvB,uBAAuB,CAAC,YAAY,SAAS,YAAY,EACrD,eAAe,EAAE,eAAe,EAChC,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC;IAsBxC,oBAAoB,CAAC,YAAY,SAAS,YAAY,EAClD,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,eAAe,CAAC,YAAY,CAAC;CAYrD;AAED,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,CAAC,QAAQ,EAAE,WAAW,GAAG,YAAY,GAAG,YAAY,KAAK,IAAI,CAAC;IACvE,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,KAAK,EAAE,CAAC,YAAY,EAAE,aAAa,KAAK,IAAI,CAAC;CAChD"}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.TelegramApiService = void 0;
|
|
4
4
|
const chatContext_1 = require("../entities/context/chatContext");
|
|
5
5
|
const messageContext_1 = require("../entities/context/messageContext");
|
|
6
|
-
const
|
|
6
|
+
const reverseRecord_1 = require("../helpers/reverseRecord");
|
|
7
7
|
const logger_1 = require("./logger");
|
|
8
8
|
const promises_1 = require("timers/promises");
|
|
9
9
|
class TelegramApiService {
|
|
@@ -12,12 +12,13 @@ class TelegramApiService {
|
|
|
12
12
|
this.messageQueue = [];
|
|
13
13
|
this.telegram = telegram;
|
|
14
14
|
this.botName = botName;
|
|
15
|
-
this.chats = (0,
|
|
15
|
+
this.chats = (0, reverseRecord_1.reverseRecord)(chats);
|
|
16
16
|
this.storage = storage;
|
|
17
17
|
}
|
|
18
18
|
async flushResponses() {
|
|
19
19
|
if (this.isFlushing)
|
|
20
20
|
return;
|
|
21
|
+
this.isFlushing = true;
|
|
21
22
|
while (this.messageQueue.length) {
|
|
22
23
|
const message = this.messageQueue.pop();
|
|
23
24
|
if (!message)
|
|
@@ -27,7 +28,7 @@ class TelegramApiService {
|
|
|
27
28
|
await (0, promises_1.setTimeout)(100);
|
|
28
29
|
}
|
|
29
30
|
catch (error) {
|
|
30
|
-
logger_1.Logger.errorWithTraceId(this.botName, message.traceId, this.chats
|
|
31
|
+
logger_1.Logger.errorWithTraceId(this.botName, message.traceId, this.chats[message.chatId], error, message);
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
this.isFlushing = false;
|
|
@@ -92,15 +93,15 @@ class TelegramApiService {
|
|
|
92
93
|
unpin: (unpinMessage) => this.enqueue(unpinMessage)
|
|
93
94
|
};
|
|
94
95
|
}
|
|
95
|
-
createContextForMessage(incomingMessage,
|
|
96
|
+
createContextForMessage(incomingMessage, command) {
|
|
96
97
|
const firstName = incomingMessage.from?.first_name ?? 'Unknown user';
|
|
97
98
|
const lastName = incomingMessage.from?.last_name
|
|
98
99
|
? ` ${incomingMessage.from?.last_name}`
|
|
99
100
|
: '';
|
|
100
|
-
return new messageContext_1.MessageContext(this.botName,
|
|
101
|
+
return new messageContext_1.MessageContext(this.botName, command.key, this.getInteractions(), incomingMessage.chat.id, incomingMessage.chatName, incomingMessage.message_id, incomingMessage.text, incomingMessage.from?.id, incomingMessage.traceId, firstName + lastName, this.storage);
|
|
101
102
|
}
|
|
102
|
-
createContextForChat(chatId,
|
|
103
|
-
return new chatContext_1.ChatContext(this.botName,
|
|
103
|
+
createContextForChat(chatId, scheduledAction) {
|
|
104
|
+
return new chatContext_1.ChatContext(this.botName, scheduledAction.key, this.getInteractions(), chatId, this.chats[chatId], `Scheduled:${scheduledAction.key}:${chatId}`, this.storage);
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
107
|
exports.TelegramApiService = TelegramApiService;
|
package/dist/types/handlers.d.ts
CHANGED
|
@@ -2,6 +2,16 @@ import { ChatContext } from '../entities/context/chatContext';
|
|
|
2
2
|
import { MessageContext } from '../entities/context/messageContext';
|
|
3
3
|
import { IActionState } from './actionState';
|
|
4
4
|
import { CachedValueAccessor } from './cachedValueAccessor';
|
|
5
|
-
export type CommandHandler<TActionState extends IActionState> = (
|
|
6
|
-
|
|
5
|
+
export type CommandHandler<TActionState extends IActionState> = (
|
|
6
|
+
/** Context of action executed in chat, in response to a message. */
|
|
7
|
+
ctx: MessageContext<TActionState>,
|
|
8
|
+
/** State of an action being executed. */
|
|
9
|
+
state: TActionState) => Promise<void>;
|
|
10
|
+
export type ScheduledHandler<TActionState extends IActionState> = (
|
|
11
|
+
/** Context of action executed in chat. */
|
|
12
|
+
ctx: ChatContext<TActionState>,
|
|
13
|
+
/** Function that will attempt to get value from cache. If there is no value found, corresponding cached state factory will be called. */
|
|
14
|
+
getCached: CachedValueAccessor,
|
|
15
|
+
/** State of an action being executed. */
|
|
16
|
+
state: TActionState) => Promise<void>;
|
|
7
17
|
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../types/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,MAAM,cAAc,CAAC,YAAY,SAAS,YAAY,IAAI,
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../types/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,MAAM,cAAc,CAAC,YAAY,SAAS,YAAY,IAAI;AAC5D,oEAAoE;AACpE,GAAG,EAAE,cAAc,CAAC,YAAY,CAAC;AACjC,yCAAyC;AACzC,KAAK,EAAE,YAAY,KAClB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,MAAM,gBAAgB,CAAC,YAAY,SAAS,YAAY,IAAI;AAC9D,0CAA0C;AAC1C,GAAG,EAAE,WAAW,CAAC,YAAY,CAAC;AAC9B,yIAAyI;AACzI,SAAS,EAAE,mBAAmB;AAC9B,yCAAyC;AACzC,KAAK,EAAE,YAAY,KAClB,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -46,7 +46,7 @@ export class ScheduledAction<TActionState extends IActionState>
|
|
|
46
46
|
this.stateConstructor = stateConstructor;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
async exec(ctx: ChatContext) {
|
|
49
|
+
async exec(ctx: ChatContext<TActionState>) {
|
|
50
50
|
if (!this.active || !this.chatsWhitelist.includes(ctx.chatId)) return;
|
|
51
51
|
|
|
52
52
|
const state = await ctx.storage.getActionState<TActionState>(
|
|
@@ -72,6 +72,7 @@ export class ScheduledAction<TActionState extends IActionState>
|
|
|
72
72
|
|
|
73
73
|
state.lastExecutedDate = moment().valueOf();
|
|
74
74
|
|
|
75
|
+
ctx.updateActions.forEach((action) => action(state));
|
|
75
76
|
await ctx.storage.saveActionExecutionResult(
|
|
76
77
|
this,
|
|
77
78
|
ctx.chatId,
|
package/entities/botInstance.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Telegraf } from 'telegraf';
|
|
2
2
|
import { hoursToMilliseconds } from '../helpers/timeConvertions';
|
|
3
|
-
import { Hours } from '../types/timeValues';
|
|
3
|
+
import { Hours, Milliseconds } from '../types/timeValues';
|
|
4
4
|
import { IStorageClient } from '../types/storage';
|
|
5
5
|
import { JsonFileStorage } from '../services/jsonFileStorage';
|
|
6
6
|
import { TelegramApiService } from '../services/telegramApi';
|
|
@@ -10,6 +10,7 @@ import { ScheduledAction } from './actions/scheduledAction';
|
|
|
10
10
|
import { Logger } from '../services/logger';
|
|
11
11
|
import { Scheduler } from '../services/taskScheduler';
|
|
12
12
|
import { IncomingMessage } from './incomingMessage';
|
|
13
|
+
import moment from 'moment';
|
|
13
14
|
|
|
14
15
|
export class BotInstance {
|
|
15
16
|
name: string;
|
|
@@ -17,7 +18,7 @@ export class BotInstance {
|
|
|
17
18
|
private telegraf: Telegraf;
|
|
18
19
|
private commands: CommandAction<IActionState>[];
|
|
19
20
|
private scheduled: ScheduledAction<IActionState>[];
|
|
20
|
-
private chats:
|
|
21
|
+
private chats: Record<string, number>;
|
|
21
22
|
storage: IStorageClient;
|
|
22
23
|
|
|
23
24
|
constructor(options: {
|
|
@@ -25,7 +26,7 @@ export class BotInstance {
|
|
|
25
26
|
token: string;
|
|
26
27
|
commands: CommandAction<IActionState>[];
|
|
27
28
|
scheduled: ScheduledAction<IActionState>[];
|
|
28
|
-
chats:
|
|
29
|
+
chats: Record<string, number>;
|
|
29
30
|
storageClient?: IStorageClient;
|
|
30
31
|
storagePath?: string;
|
|
31
32
|
}) {
|
|
@@ -64,13 +65,44 @@ export class BotInstance {
|
|
|
64
65
|
|
|
65
66
|
private initializeScheduledProcessing() {
|
|
66
67
|
if (this.scheduled.length > 0) {
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
const now = moment();
|
|
69
|
+
|
|
70
|
+
let nextExecutionTime = now.clone().startOf('hour');
|
|
71
|
+
|
|
72
|
+
if (now.minute() == 0 && now.second() == 0) {
|
|
73
|
+
Scheduler.createTask(
|
|
74
|
+
'ScheduledProcessing',
|
|
75
|
+
async () => {
|
|
76
|
+
await this.runScheduled();
|
|
77
|
+
},
|
|
78
|
+
hoursToMilliseconds(1 as Hours),
|
|
79
|
+
true,
|
|
80
|
+
this.name
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (now.minute() > 0 || now.second() > 0) {
|
|
87
|
+
nextExecutionTime = nextExecutionTime.add(1, 'hour');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const delay = nextExecutionTime.diff(now);
|
|
91
|
+
|
|
92
|
+
Scheduler.createOnetimeTask(
|
|
93
|
+
'ScheduledProcessing_OneTime',
|
|
69
94
|
async () => {
|
|
70
|
-
|
|
95
|
+
Scheduler.createTask(
|
|
96
|
+
'ScheduledProcessing',
|
|
97
|
+
async () => {
|
|
98
|
+
await this.runScheduled();
|
|
99
|
+
},
|
|
100
|
+
hoursToMilliseconds(1 as Hours),
|
|
101
|
+
true,
|
|
102
|
+
this.name
|
|
103
|
+
);
|
|
71
104
|
},
|
|
72
|
-
|
|
73
|
-
true,
|
|
105
|
+
delay as Milliseconds,
|
|
74
106
|
this.name
|
|
75
107
|
);
|
|
76
108
|
}
|
|
@@ -111,12 +143,15 @@ export class BotInstance {
|
|
|
111
143
|
}
|
|
112
144
|
|
|
113
145
|
private async runScheduled() {
|
|
114
|
-
for (const [chatName, chatId] of this.chats
|
|
115
|
-
for (const
|
|
116
|
-
const ctx = this.api.createContextForChat(
|
|
146
|
+
for (const [chatName, chatId] of Object.entries(this.chats)) {
|
|
147
|
+
for (const scheduledAction of this.scheduled) {
|
|
148
|
+
const ctx = this.api.createContextForChat(
|
|
149
|
+
chatId,
|
|
150
|
+
scheduledAction
|
|
151
|
+
);
|
|
117
152
|
|
|
118
153
|
try {
|
|
119
|
-
await
|
|
154
|
+
await scheduledAction.exec(ctx);
|
|
120
155
|
} catch (error) {
|
|
121
156
|
Logger.errorWithTraceId(
|
|
122
157
|
ctx.botName,
|
|
@@ -129,15 +164,15 @@ export class BotInstance {
|
|
|
129
164
|
}
|
|
130
165
|
}
|
|
131
166
|
|
|
132
|
-
this.api.flushResponses();
|
|
167
|
+
await this.api.flushResponses();
|
|
133
168
|
}
|
|
134
169
|
|
|
135
170
|
private async processMessage(msg: IncomingMessage) {
|
|
136
|
-
for (const
|
|
137
|
-
const ctx = this.api.createContextForMessage(msg,
|
|
171
|
+
for (const commandAction of this.commands) {
|
|
172
|
+
const ctx = this.api.createContextForMessage(msg, commandAction);
|
|
138
173
|
|
|
139
174
|
try {
|
|
140
|
-
await
|
|
175
|
+
await commandAction.exec(ctx);
|
|
141
176
|
} catch (error) {
|
|
142
177
|
Logger.errorWithTraceId(
|
|
143
178
|
ctx.botName,
|
|
@@ -149,6 +184,6 @@ export class BotInstance {
|
|
|
149
184
|
}
|
|
150
185
|
}
|
|
151
186
|
|
|
152
|
-
this.api.flushResponses();
|
|
187
|
+
await this.api.flushResponses();
|
|
153
188
|
}
|
|
154
189
|
}
|
|
@@ -10,13 +10,22 @@ import {
|
|
|
10
10
|
TextMessageSendingOptions
|
|
11
11
|
} from '../../types/messageSendingOptions';
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Context of action executed in chat.
|
|
15
|
+
*/
|
|
16
|
+
export class ChatContext<TActionState> {
|
|
17
|
+
protected actionKey: string;
|
|
18
|
+
protected interactions: IBotApiInteractions;
|
|
19
|
+
updateActions: Array<(state: TActionState) => void> = [];
|
|
20
|
+
/** Trace id of a action execution. */
|
|
21
|
+
traceId: number | string;
|
|
22
|
+
/** Name of a bot that executes this action. */
|
|
14
23
|
botName: string;
|
|
15
|
-
|
|
16
|
-
interactions: IBotApiInteractions;
|
|
24
|
+
/** Id of a chat that action is executed in. */
|
|
17
25
|
chatId: number;
|
|
26
|
+
/** Name of a chat that action is executed in. */
|
|
18
27
|
chatName: string;
|
|
19
|
-
|
|
28
|
+
/** Storage client instance for this bot. */
|
|
20
29
|
storage: IStorageClient;
|
|
21
30
|
|
|
22
31
|
constructor(
|
|
@@ -37,6 +46,21 @@ export class ChatContext {
|
|
|
37
46
|
this.storage = storage;
|
|
38
47
|
}
|
|
39
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Manually update the state of an action.
|
|
51
|
+
* @param stateUpdateAction Function that will modify state.
|
|
52
|
+
*/
|
|
53
|
+
updateState(stateUpdateAction: (state: TActionState) => void) {
|
|
54
|
+
this.updateActions.push(
|
|
55
|
+
stateUpdateAction as (state: TActionState) => void
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Sends text message to chat.
|
|
61
|
+
* @param text Message contents.
|
|
62
|
+
* @param options Message sending option.
|
|
63
|
+
*/
|
|
40
64
|
sendTextToChat(text: string, options?: TextMessageSendingOptions) {
|
|
41
65
|
this.interactions.respond(
|
|
42
66
|
new TextMessage(
|
|
@@ -50,6 +74,11 @@ export class ChatContext {
|
|
|
50
74
|
);
|
|
51
75
|
}
|
|
52
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Sends image message to chat.
|
|
79
|
+
* @param name Message contents.
|
|
80
|
+
* @param options Message sending option.
|
|
81
|
+
*/
|
|
53
82
|
sendImageToChat(name: string, options?: MessageSendingOptions) {
|
|
54
83
|
const filePath = `./content/${name}.png`;
|
|
55
84
|
this.interactions.respond(
|
|
@@ -64,6 +93,11 @@ export class ChatContext {
|
|
|
64
93
|
);
|
|
65
94
|
}
|
|
66
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Sends video/gif message to chat.
|
|
98
|
+
* @param name Message contents.
|
|
99
|
+
* @param options Message sending option.
|
|
100
|
+
*/
|
|
67
101
|
sendVideoToChat(name: string, options?: MessageSendingOptions) {
|
|
68
102
|
const filePath = `./content/${name}.mp4`;
|
|
69
103
|
this.interactions.respond(
|
|
@@ -78,6 +112,10 @@ export class ChatContext {
|
|
|
78
112
|
);
|
|
79
113
|
}
|
|
80
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Unpins message.
|
|
117
|
+
* @param messageId Message id.
|
|
118
|
+
*/
|
|
81
119
|
unpinMessage(messageId: number) {
|
|
82
120
|
this.interactions.unpin(
|
|
83
121
|
new UnpinResponse(
|
|
@@ -14,15 +14,23 @@ import {
|
|
|
14
14
|
TextMessageSendingOptions
|
|
15
15
|
} from '../../types/messageSendingOptions';
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Context of action executed in chat, in response to a message
|
|
19
|
+
*/
|
|
17
20
|
export class MessageContext<
|
|
18
21
|
TActionState extends IActionState
|
|
19
|
-
> extends ChatContext {
|
|
22
|
+
> extends ChatContext<TActionState> {
|
|
23
|
+
/** Id of a message that triggered this action. */
|
|
20
24
|
messageId: number;
|
|
25
|
+
/** Text of a message that triggered this action. */
|
|
21
26
|
messageText: string;
|
|
27
|
+
/** Collection of Regexp match results on a message that triggered this action. Will be empty if trigger is not a Regexp. */
|
|
22
28
|
matchResults: RegExpMatchArray[] = [];
|
|
29
|
+
/** Id of a user that sent a message that triggered this action. */
|
|
23
30
|
fromUserId: number | undefined;
|
|
31
|
+
/** Indicates if cooldown should be started after action is executed. Set to `true` by default. */
|
|
24
32
|
startCooldown: boolean = true;
|
|
25
|
-
|
|
33
|
+
/** Name of a user that sent a message that triggered this action. */
|
|
26
34
|
fromUserName: string;
|
|
27
35
|
|
|
28
36
|
constructor(
|
|
@@ -54,6 +62,11 @@ export class MessageContext<
|
|
|
54
62
|
this.fromUserName = fromUserName;
|
|
55
63
|
}
|
|
56
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Loads state of another action. Changes to the loaded state will no affect actual state of other action.
|
|
67
|
+
* @param commandName Name of an action to load state of.
|
|
68
|
+
* @template TAnotherActionState - Type of a state that is used by another action.
|
|
69
|
+
*/
|
|
57
70
|
async loadStateOf<TAnotherActionState extends IActionState>(
|
|
58
71
|
commandName: string
|
|
59
72
|
): Promise<TAnotherActionState> {
|
|
@@ -66,12 +79,11 @@ export class MessageContext<
|
|
|
66
79
|
);
|
|
67
80
|
}
|
|
68
81
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Reply with text message to message that triggered this action.
|
|
84
|
+
* @param text Message contents.
|
|
85
|
+
* @param options Message sending option.
|
|
86
|
+
*/
|
|
75
87
|
replyWithText(text: string, options?: TextMessageSendingOptions) {
|
|
76
88
|
this.interactions.respond(
|
|
77
89
|
new TextMessage(
|
|
@@ -85,6 +97,11 @@ export class MessageContext<
|
|
|
85
97
|
);
|
|
86
98
|
}
|
|
87
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Reply with image message to message that triggered this action.
|
|
102
|
+
* @param text Message contents.
|
|
103
|
+
* @param options Message sending option.
|
|
104
|
+
*/
|
|
88
105
|
replyWithImage(name: string, options?: MessageSendingOptions) {
|
|
89
106
|
const filePath = `./content/${name}.png`;
|
|
90
107
|
this.interactions.respond(
|
|
@@ -99,6 +116,11 @@ export class MessageContext<
|
|
|
99
116
|
);
|
|
100
117
|
}
|
|
101
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Reply with video/gif message to message that triggered this action.
|
|
121
|
+
* @param text Message contents.
|
|
122
|
+
* @param options Message sending option.
|
|
123
|
+
*/
|
|
102
124
|
replyWithVideo(name: string, options?: MessageSendingOptions) {
|
|
103
125
|
const filePath = `./content/${name}.mp4`;
|
|
104
126
|
this.interactions.respond(
|
|
@@ -113,6 +135,10 @@ export class MessageContext<
|
|
|
113
135
|
);
|
|
114
136
|
}
|
|
115
137
|
|
|
138
|
+
/**
|
|
139
|
+
* React to the message that triggered this action.
|
|
140
|
+
* @param emoji Telegram emoji to react with.
|
|
141
|
+
*/
|
|
116
142
|
react(emoji: TelegramEmoji) {
|
|
117
143
|
this.interactions.react(
|
|
118
144
|
new Reaction(
|