chz-telegram-bot 0.3.7 → 0.3.9
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/botInstance.d.ts.map +1 -1
- package/dist/entities/botInstance.js +0 -1
- package/dist/entities/context/baseContext.d.ts +35 -0
- package/dist/entities/context/baseContext.d.ts.map +1 -0
- package/dist/entities/context/baseContext.js +32 -0
- package/dist/entities/context/chatContext.d.ts +4 -27
- package/dist/entities/context/chatContext.d.ts.map +1 -1
- package/dist/entities/context/chatContext.js +3 -19
- package/dist/entities/context/inlineQueryContext.d.ts +2 -15
- package/dist/entities/context/inlineQueryContext.d.ts.map +1 -1
- package/dist/entities/context/inlineQueryContext.js +3 -4
- package/dist/entities/context/messageContext.d.ts +2 -1
- package/dist/entities/context/messageContext.d.ts.map +1 -1
- package/dist/entities/context/replyContext.d.ts +2 -20
- package/dist/entities/context/replyContext.d.ts.map +1 -1
- package/dist/entities/context/replyContext.js +3 -5
- package/dist/services/actionProcessingService.d.ts.map +1 -1
- package/dist/services/actionProcessingService.js +4 -2
- package/dist/services/actionProcessors/baseProcessor.d.ts +20 -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 +2 -7
- package/dist/services/actionProcessors/commandActionProcessor.d.ts.map +1 -1
- package/dist/services/actionProcessors/commandActionProcessor.js +12 -27
- package/dist/services/actionProcessors/inlineQueryActionProcessor.d.ts +2 -7
- package/dist/services/actionProcessors/inlineQueryActionProcessor.d.ts.map +1 -1
- package/dist/services/actionProcessors/inlineQueryActionProcessor.js +6 -15
- package/dist/services/actionProcessors/scheduledActionProcessor.d.ts +2 -6
- package/dist/services/actionProcessors/scheduledActionProcessor.d.ts.map +1 -1
- package/dist/services/actionProcessors/scheduledActionProcessor.js +5 -14
- package/dist/services/jsonFileStorage.d.ts +5 -4
- package/dist/services/jsonFileStorage.d.ts.map +1 -1
- package/dist/services/jsonFileStorage.js +40 -29
- package/dist/types/action.d.ts +3 -0
- package/dist/types/action.d.ts.map +1 -1
- package/dist/types/storage.d.ts +1 -1
- package/dist/types/storage.d.ts.map +1 -1
- package/entities/botInstance.ts +0 -2
- package/entities/context/baseContext.ts +58 -0
- package/entities/context/chatContext.ts +8 -45
- package/entities/context/inlineQueryContext.ts +3 -20
- package/entities/context/messageContext.ts +2 -1
- package/entities/context/replyContext.ts +5 -25
- package/package.json +1 -1
- package/services/actionProcessingService.ts +9 -5
- package/services/actionProcessors/baseProcessor.ts +60 -0
- package/services/actionProcessors/commandActionProcessor.ts +19 -42
- package/services/actionProcessors/inlineQueryActionProcessor.ts +16 -32
- package/services/actionProcessors/scheduledActionProcessor.ts +7 -23
- package/services/jsonFileStorage.ts +57 -41
- package/types/action.ts +3 -0
- package/types/storage.ts +1 -2
|
@@ -5,13 +5,9 @@ import { IScheduler } from '../../types/scheduler';
|
|
|
5
5
|
import { IStorageClient } from '../../types/storage';
|
|
6
6
|
import { Seconds } from '../../types/timeValues';
|
|
7
7
|
import { TelegramApiService } from '../telegramApi';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
private readonly scheduler;
|
|
11
|
-
private readonly logger;
|
|
12
|
-
private readonly botName;
|
|
8
|
+
import { BaseActionProcessor } from './baseProcessor';
|
|
9
|
+
export declare class ScheduledActionProcessor extends BaseActionProcessor {
|
|
13
10
|
private readonly chats;
|
|
14
|
-
private api;
|
|
15
11
|
private scheduled;
|
|
16
12
|
constructor(botName: string, chats: Record<string, number>, storage: IStorageClient, scheduler: IScheduler, logger: ILogger);
|
|
17
13
|
initialize(api: TelegramApiService, scheduled: ScheduledAction<IActionState>[], period: Seconds): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduledActionProcessor.d.ts","sourceRoot":"","sources":["../../../services/actionProcessors/scheduledActionProcessor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAC;
|
|
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;IAuB1B,OAAO,CAAC,qBAAqB;CAmBhC"}
|
|
@@ -9,16 +9,14 @@ const chatInfo_1 = require("../../dtos/chatInfo");
|
|
|
9
9
|
const chatContext_1 = require("../../entities/context/chatContext");
|
|
10
10
|
const timeConvertions_1 = require("../../helpers/timeConvertions");
|
|
11
11
|
const traceFactory_1 = require("../../helpers/traceFactory");
|
|
12
|
-
|
|
12
|
+
const baseProcessor_1 = require("./baseProcessor");
|
|
13
|
+
class ScheduledActionProcessor extends baseProcessor_1.BaseActionProcessor {
|
|
13
14
|
constructor(botName, chats, storage, scheduler, logger) {
|
|
14
|
-
|
|
15
|
-
this.scheduler = scheduler;
|
|
16
|
-
this.logger = logger;
|
|
17
|
-
this.botName = botName;
|
|
15
|
+
super(botName, storage, scheduler, logger);
|
|
18
16
|
this.chats = chats;
|
|
19
17
|
}
|
|
20
18
|
initialize(api, scheduled, period) {
|
|
21
|
-
this.api
|
|
19
|
+
this.initializeDependencies(api, null);
|
|
22
20
|
this.scheduled = scheduled;
|
|
23
21
|
if (this.scheduled.length > 0) {
|
|
24
22
|
const now = (0, moment_1.default)();
|
|
@@ -45,14 +43,7 @@ class ScheduledActionProcessor {
|
|
|
45
43
|
for (const [chatName, chatId] of Object.entries(this.chats)) {
|
|
46
44
|
for (const scheduledAction of this.scheduled) {
|
|
47
45
|
this.initializeChatContext(ctx, scheduledAction, new chatInfo_1.ChatInfo(chatId, chatName), (0, traceFactory_1.createTrace)(scheduledAction, this.botName, `${scheduledAction.key}-${chatId}`));
|
|
48
|
-
|
|
49
|
-
const responses = await scheduledAction.exec(ctx);
|
|
50
|
-
this.api.enqueueBatchedResponses(responses);
|
|
51
|
-
ctx.isInitialized = false;
|
|
52
|
-
}
|
|
53
|
-
catch (error) {
|
|
54
|
-
ctx.logger.errorWithTraceId(error, ctx);
|
|
55
|
-
}
|
|
46
|
+
this.executeAction(scheduledAction, ctx);
|
|
56
47
|
}
|
|
57
48
|
}
|
|
58
49
|
this.api.flushResponses();
|
|
@@ -2,17 +2,18 @@ import { IStorageClient } from '../types/storage';
|
|
|
2
2
|
import { IActionState } from '../types/actionState';
|
|
3
3
|
import { IActionWithState, ActionKey } from '../types/action';
|
|
4
4
|
export declare class JsonFileStorage implements IStorageClient {
|
|
5
|
+
private readonly filePaths;
|
|
5
6
|
private readonly locks;
|
|
6
7
|
private readonly cache;
|
|
7
8
|
private readonly storagePath;
|
|
8
9
|
private readonly botName;
|
|
9
10
|
constructor(botName: string, actions: IActionWithState<IActionState>[], path?: string);
|
|
10
11
|
private lock;
|
|
11
|
-
private
|
|
12
|
-
private
|
|
13
|
-
private
|
|
12
|
+
private tryGetFromCache;
|
|
13
|
+
private loadFromFile;
|
|
14
|
+
private updateCacheAndSaveToFile;
|
|
14
15
|
load<TActionState extends IActionState>(key: ActionKey): Promise<Record<number, TActionState>>;
|
|
15
|
-
saveMetadata(actions: IActionWithState<IActionState>[]
|
|
16
|
+
saveMetadata(actions: IActionWithState<IActionState>[]): Promise<void>;
|
|
16
17
|
getActionState<TActionState extends IActionState>(action: IActionWithState<TActionState>, chatId: number): Promise<TActionState>;
|
|
17
18
|
saveActionExecutionResult<TActionState extends IActionState>(action: IActionWithState<TActionState>, chatId: number, state: TActionState): Promise<void>;
|
|
18
19
|
close(): Promise<void>;
|
|
@@ -1 +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;
|
|
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;AAM9D,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;YAqBH,IAAI;IAclB,OAAO,CAAC,eAAe;YAIT,YAAY;YAwBZ,wBAAwB;IAgBhC,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;IAajB,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;CAiBrD"}
|
|
@@ -4,8 +4,12 @@ exports.JsonFileStorage = void 0;
|
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const promises_1 = require("fs/promises");
|
|
6
6
|
const async_sema_1 = require("async-sema");
|
|
7
|
+
function buildPath(storagePath, botName, actionKey) {
|
|
8
|
+
return `${storagePath}/${botName}/${actionKey.replaceAll(':', '/')}.json`;
|
|
9
|
+
}
|
|
7
10
|
class JsonFileStorage {
|
|
8
11
|
constructor(botName, actions, path) {
|
|
12
|
+
this.filePaths = new Map();
|
|
9
13
|
this.locks = new Map();
|
|
10
14
|
this.cache = new Map();
|
|
11
15
|
this.botName = botName;
|
|
@@ -17,6 +21,7 @@ class JsonFileStorage {
|
|
|
17
21
|
}
|
|
18
22
|
for (const action of actions) {
|
|
19
23
|
this.locks.set(action.key, new async_sema_1.Sema(1));
|
|
24
|
+
this.filePaths.set(action.key, buildPath(this.storagePath, this.botName, action.key));
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
27
|
async lock(key, action) {
|
|
@@ -31,50 +36,55 @@ class JsonFileStorage {
|
|
|
31
36
|
lock.release();
|
|
32
37
|
}
|
|
33
38
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
tryGetFromCache(key) {
|
|
40
|
+
return this.cache.get(key);
|
|
41
|
+
}
|
|
42
|
+
async loadFromFile(key) {
|
|
43
|
+
if (!this.filePaths.has(key))
|
|
44
|
+
this.filePaths.set(key, buildPath(this.storagePath, this.botName, key));
|
|
45
|
+
const targetPath = this.filePaths.get(key);
|
|
46
|
+
const fileContent = await (0, promises_1.readFile)(targetPath, {
|
|
47
|
+
encoding: 'utf-8',
|
|
48
|
+
flag: 'a+'
|
|
49
|
+
});
|
|
50
|
+
if (fileContent) {
|
|
51
|
+
const data = JSON.parse(fileContent);
|
|
52
|
+
this.cache.set(key, data);
|
|
45
53
|
}
|
|
46
54
|
return (this.cache.get(key) ?? {});
|
|
47
55
|
}
|
|
48
|
-
async
|
|
56
|
+
async updateCacheAndSaveToFile(data, key) {
|
|
49
57
|
this.cache.set(key, data);
|
|
50
|
-
|
|
58
|
+
if (!this.filePaths.has(key))
|
|
59
|
+
this.filePaths.set(key, buildPath(this.storagePath, this.botName, key));
|
|
60
|
+
const targetPath = this.filePaths.get(key);
|
|
51
61
|
await (0, promises_1.writeFile)(targetPath, JSON.stringify(data), { flag: 'w+' });
|
|
52
62
|
}
|
|
53
|
-
buidPathFromKey(key) {
|
|
54
|
-
return `${this.storagePath}/${this.botName}/${key.replaceAll(':', '/')}.json`;
|
|
55
|
-
}
|
|
56
63
|
async load(key) {
|
|
57
|
-
return
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
return (this.tryGetFromCache(key) ??
|
|
65
|
+
(await this.lock(key, async () => {
|
|
66
|
+
return await this.loadFromFile(key);
|
|
67
|
+
})));
|
|
60
68
|
}
|
|
61
|
-
async saveMetadata(actions
|
|
62
|
-
const targetPath = this.
|
|
69
|
+
async saveMetadata(actions) {
|
|
70
|
+
const targetPath = `${this.storagePath}/${this.botName}/Metadata-${this.botName}.json`;
|
|
63
71
|
await (0, promises_1.writeFile)(targetPath, JSON.stringify(actions), {
|
|
64
72
|
flag: 'w+'
|
|
65
73
|
});
|
|
66
74
|
}
|
|
67
75
|
async getActionState(action, chatId) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
const value = this.tryGetFromCache(action.key) ??
|
|
77
|
+
(await this.lock(action.key, async () => {
|
|
78
|
+
return await this.loadFromFile(action.key);
|
|
79
|
+
}));
|
|
80
|
+
return Object.assign(action.stateConstructor(), value[chatId]);
|
|
72
81
|
}
|
|
73
82
|
async saveActionExecutionResult(action, chatId, state) {
|
|
74
83
|
return await this.lock(action.key, async () => {
|
|
75
|
-
const data =
|
|
84
|
+
const data = this.tryGetFromCache(action.key) ??
|
|
85
|
+
(await this.loadFromFile(action.key));
|
|
76
86
|
data[chatId] = state;
|
|
77
|
-
await this.
|
|
87
|
+
await this.updateCacheAndSaveToFile(data, action.key);
|
|
78
88
|
});
|
|
79
89
|
}
|
|
80
90
|
async close() {
|
|
@@ -84,10 +94,11 @@ class JsonFileStorage {
|
|
|
84
94
|
}
|
|
85
95
|
async updateStateFor(action, chatId, update) {
|
|
86
96
|
await this.lock(action.key, async () => {
|
|
87
|
-
const data =
|
|
97
|
+
const data = this.tryGetFromCache(action.key) ??
|
|
98
|
+
(await this.loadFromFile(action.key));
|
|
88
99
|
const state = Object.assign(action.stateConstructor(), data[chatId]);
|
|
89
100
|
await update(state);
|
|
90
|
-
await this.
|
|
101
|
+
await this.updateCacheAndSaveToFile(data, action.key);
|
|
91
102
|
});
|
|
92
103
|
}
|
|
93
104
|
}
|
package/dist/types/action.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { BaseContext } from '../entities/context/baseContext';
|
|
1
2
|
import { IActionState } from './actionState';
|
|
3
|
+
import { BotResponse } from './response';
|
|
2
4
|
export type ActionKey = string & {
|
|
3
5
|
__brand: 'actionKey';
|
|
4
6
|
};
|
|
@@ -7,5 +9,6 @@ export interface IActionWithState<TActionState extends IActionState> extends IAc
|
|
|
7
9
|
}
|
|
8
10
|
export interface IAction {
|
|
9
11
|
readonly key: ActionKey;
|
|
12
|
+
exec(ctx: BaseContext<IAction>): Promise<BotResponse[]>;
|
|
10
13
|
}
|
|
11
14
|
//# sourceMappingURL=action.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../types/action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../types/action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,gBAAgB,CAAC,YAAY,SAAS,YAAY,CAC/D,SAAQ,OAAO;IACf,QAAQ,CAAC,gBAAgB,EAAE,MAAM,YAAY,CAAC;CACjD;AAED,MAAM,WAAW,OAAO;IACpB,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CAC3D"}
|
package/dist/types/storage.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export interface IStorageClient {
|
|
|
4
4
|
updateStateFor<TActionState extends IActionState>(action: IActionWithState<TActionState>, chatId: number, update: (state: TActionState) => Promise<void>): Promise<void>;
|
|
5
5
|
close(): Promise<void>;
|
|
6
6
|
load<TActionState extends IActionState>(key: ActionKey): Promise<Record<number, TActionState>>;
|
|
7
|
-
saveMetadata<TActionState extends IActionState>(actions: IActionWithState<TActionState>[]
|
|
7
|
+
saveMetadata<TActionState extends IActionState>(actions: IActionWithState<TActionState>[]): Promise<void>;
|
|
8
8
|
getActionState<TActionState extends IActionState>(action: IActionWithState<TActionState>, chatId: number): Promise<TActionState>;
|
|
9
9
|
saveActionExecutionResult<TActionState extends IActionState>(action: IActionWithState<TActionState>, chatId: number, state: TActionState): Promise<void>;
|
|
10
10
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../types/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC3B,cAAc,CAAC,YAAY,SAAS,YAAY,EAC5C,MAAM,EAAE,gBAAgB,CAAC,YAAY,CAAC,EACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GAC/C,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,CAAC,YAAY,SAAS,YAAY,EAClC,GAAG,EAAE,SAAS,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACzC,YAAY,CAAC,YAAY,SAAS,YAAY,EAC1C,OAAO,EAAE,gBAAgB,CAAC,YAAY,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../types/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC3B,cAAc,CAAC,YAAY,SAAS,YAAY,EAC5C,MAAM,EAAE,gBAAgB,CAAC,YAAY,CAAC,EACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GAC/C,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,CAAC,YAAY,SAAS,YAAY,EAClC,GAAG,EAAE,SAAS,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACzC,YAAY,CAAC,YAAY,SAAS,YAAY,EAC1C,OAAO,EAAE,gBAAgB,CAAC,YAAY,CAAC,EAAE,GAC1C,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,CAAC,YAAY,SAAS,YAAY,EAC5C,MAAM,EAAE,gBAAgB,CAAC,YAAY,CAAC,EACtC,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,CAAC,CAAC;IACzB,yBAAyB,CAAC,YAAY,SAAS,YAAY,EACvD,MAAM,EAAE,gBAAgB,CAAC,YAAY,CAAC,EACtC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB"}
|
package/entities/botInstance.ts
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ChatInfo } from '../../dtos/chatInfo';
|
|
2
|
+
import { IAction, IActionWithState } from '../../types/action';
|
|
3
|
+
import { IActionState } from '../../types/actionState';
|
|
4
|
+
import { IScopedLogger } from '../../types/logger';
|
|
5
|
+
import { BotResponse } from '../../types/response';
|
|
6
|
+
import { IScheduler } from '../../types/scheduler';
|
|
7
|
+
import { IStorageClient } from '../../types/storage';
|
|
8
|
+
import { TraceId } from '../../types/trace';
|
|
9
|
+
|
|
10
|
+
export abstract class BaseContext<TAction extends IAction> {
|
|
11
|
+
isInitialized = false;
|
|
12
|
+
private _responses: BotResponse[] = [];
|
|
13
|
+
|
|
14
|
+
action!: TAction;
|
|
15
|
+
|
|
16
|
+
/** Storage client instance for the bot executing this action. */
|
|
17
|
+
readonly storage: IStorageClient;
|
|
18
|
+
/** Scheduler instance for the bot executing this action */
|
|
19
|
+
readonly scheduler: IScheduler;
|
|
20
|
+
logger!: IScopedLogger;
|
|
21
|
+
/** Trace id of a action execution. */
|
|
22
|
+
traceId!: TraceId;
|
|
23
|
+
/** Name of a bot that executes this action. */
|
|
24
|
+
botName!: string;
|
|
25
|
+
/** Chat information. */
|
|
26
|
+
chatInfo!: ChatInfo;
|
|
27
|
+
|
|
28
|
+
/** Ordered collection of responses to be processed */
|
|
29
|
+
public get responses(): BotResponse[] {
|
|
30
|
+
return this._responses;
|
|
31
|
+
}
|
|
32
|
+
public set responses(value: BotResponse[]) {
|
|
33
|
+
this._responses = value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
constructor(storage: IStorageClient, scheduler: IScheduler) {
|
|
37
|
+
this.storage = storage;
|
|
38
|
+
this.scheduler = scheduler;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Loads state of another action for current chat.
|
|
43
|
+
* @param action Action to load state of.
|
|
44
|
+
* @template TAnotherActionState - Type of a state that is used by another action.
|
|
45
|
+
*/
|
|
46
|
+
async loadStateOf<TAnotherActionState extends IActionState>(
|
|
47
|
+
action: IActionWithState<TAnotherActionState>
|
|
48
|
+
) {
|
|
49
|
+
const allStates = await this.storage.load(action.key);
|
|
50
|
+
const stateForChat = allStates[this.chatInfo.id];
|
|
51
|
+
|
|
52
|
+
if (!stateForChat) {
|
|
53
|
+
return Object.freeze(action.stateConstructor());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return Object.freeze(stateForChat as TAnotherActionState);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -10,44 +10,25 @@ import {
|
|
|
10
10
|
} from '../../types/messageSendingOptions';
|
|
11
11
|
import { IActionWithState } from '../../types/action';
|
|
12
12
|
import { IActionState } from '../../types/actionState';
|
|
13
|
-
import {
|
|
13
|
+
import { IReplyResponse } from '../../types/response';
|
|
14
14
|
import { Milliseconds } from '../../types/timeValues';
|
|
15
15
|
import { DelayResponse } from '../../dtos/responses/delay';
|
|
16
|
-
import { ChatInfo } from '../../dtos/chatInfo';
|
|
17
|
-
import { IScopedLogger } from '../../types/logger';
|
|
18
16
|
import { IScheduler } from '../../types/scheduler';
|
|
19
|
-
import { TraceId } from '../../types/trace';
|
|
20
17
|
import { ICaptureController } from '../../types/capture';
|
|
21
18
|
import { CommandTrigger } from '../../types/commandTrigger';
|
|
22
19
|
import { ReplyContext } from './replyContext';
|
|
20
|
+
import { BaseContext } from './baseContext';
|
|
21
|
+
import { ScheduledAction } from '../actions/scheduledAction';
|
|
23
22
|
|
|
24
23
|
/**
|
|
25
24
|
* Context of action executed in chat.
|
|
26
25
|
*/
|
|
27
|
-
export class ChatContext<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
readonly storage: IStorageClient;
|
|
32
|
-
/** Logger instance for the bot executing this action */
|
|
33
|
-
/** Scheduler instance for the bot executing this action */
|
|
34
|
-
readonly scheduler: IScheduler;
|
|
35
|
-
|
|
36
|
-
logger!: IScopedLogger;
|
|
37
|
-
/** Trace id of a action execution. */
|
|
38
|
-
traceId!: TraceId;
|
|
39
|
-
/** Name of a bot that executes this action. */
|
|
40
|
-
botName!: string;
|
|
41
|
-
/** Chat information. */
|
|
42
|
-
chatInfo!: ChatInfo;
|
|
43
|
-
/** Ordered collection of responses to be processed */
|
|
44
|
-
responses: BotResponse[] = [];
|
|
45
|
-
|
|
46
|
-
isInitialized = false;
|
|
47
|
-
|
|
26
|
+
export class ChatContext<
|
|
27
|
+
TActionState extends IActionState,
|
|
28
|
+
TAction extends IActionWithState<TActionState> = ScheduledAction<TActionState>
|
|
29
|
+
> extends BaseContext<TAction> {
|
|
48
30
|
constructor(storage: IStorageClient, scheduler: IScheduler) {
|
|
49
|
-
|
|
50
|
-
this.scheduler = scheduler;
|
|
31
|
+
super(storage, scheduler);
|
|
51
32
|
}
|
|
52
33
|
|
|
53
34
|
protected createCaptureController(
|
|
@@ -71,24 +52,6 @@ export class ChatContext<TActionState extends IActionState> {
|
|
|
71
52
|
};
|
|
72
53
|
}
|
|
73
54
|
|
|
74
|
-
/**
|
|
75
|
-
* Loads state of another action for current chat.
|
|
76
|
-
* @param action Action to load state of.
|
|
77
|
-
* @template TAnotherActionState - Type of a state that is used by another action.
|
|
78
|
-
*/
|
|
79
|
-
async loadStateOf<TAnotherActionState extends IActionState>(
|
|
80
|
-
action: IActionWithState<TAnotherActionState>
|
|
81
|
-
) {
|
|
82
|
-
const allStates = await this.storage.load(action.key);
|
|
83
|
-
const stateForChat = allStates[this.chatInfo.id];
|
|
84
|
-
|
|
85
|
-
if (!stateForChat) {
|
|
86
|
-
return Object.freeze(action.stateConstructor());
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return Object.freeze(stateForChat as TAnotherActionState);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
55
|
/**
|
|
93
56
|
* Collection of actions that send something to chat as a standalone message.
|
|
94
57
|
*/
|
|
@@ -1,27 +1,13 @@
|
|
|
1
1
|
import { InlineQueryResult } from 'telegraf/types';
|
|
2
|
-
import { IScopedLogger } from '../../types/logger';
|
|
3
2
|
import { BotResponse } from '../../types/response';
|
|
4
3
|
import { IScheduler } from '../../types/scheduler';
|
|
5
4
|
import { IStorageClient } from '../../types/storage';
|
|
6
|
-
import { TraceId } from '../../types/trace';
|
|
7
5
|
import { InlineQueryAction } from '../actions/inlineQueryAction';
|
|
8
6
|
import { InlineQueryResponse } from '../../dtos/responses/inlineQueryResponse';
|
|
7
|
+
import { BaseContext } from './baseContext';
|
|
9
8
|
|
|
10
|
-
export class InlineQueryContext {
|
|
11
|
-
action!: InlineQueryAction;
|
|
9
|
+
export class InlineQueryContext extends BaseContext<InlineQueryAction> {
|
|
12
10
|
queryResults: InlineQueryResult[] = [];
|
|
13
|
-
|
|
14
|
-
/** Storage client instance for the bot executing this action. */
|
|
15
|
-
readonly storage: IStorageClient;
|
|
16
|
-
/** Scheduler instance for the bot executing this action */
|
|
17
|
-
readonly scheduler: IScheduler;
|
|
18
|
-
|
|
19
|
-
/** Logger instance for the bot executing this action */
|
|
20
|
-
logger!: IScopedLogger;
|
|
21
|
-
/** Trace id of a action execution. */
|
|
22
|
-
traceId!: TraceId;
|
|
23
|
-
/** Name of a bot that executes this action. */
|
|
24
|
-
botName!: string;
|
|
25
11
|
/**
|
|
26
12
|
* Abort signal to be utilized in query handler.
|
|
27
13
|
* Signal will be aborted if new query comes from the same user.
|
|
@@ -46,11 +32,8 @@ export class InlineQueryContext {
|
|
|
46
32
|
/** Collection of Regexp match results on a message that triggered this action. Will be empty if trigger is not a Regexp. */
|
|
47
33
|
matchResults: RegExpMatchArray[] = [];
|
|
48
34
|
|
|
49
|
-
isInitialized = false;
|
|
50
|
-
|
|
51
35
|
constructor(storage: IStorageClient, scheduler: IScheduler) {
|
|
52
|
-
|
|
53
|
-
this.scheduler = scheduler;
|
|
36
|
+
super(storage, scheduler);
|
|
54
37
|
}
|
|
55
38
|
|
|
56
39
|
/**
|
|
@@ -17,13 +17,14 @@ import {
|
|
|
17
17
|
} from '../../types/messageTypes';
|
|
18
18
|
import { IScheduler } from '../../types/scheduler';
|
|
19
19
|
import { ReplyInfo } from '../../dtos/replyInfo';
|
|
20
|
+
import { CommandAction } from '../actions/commandAction';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Context of action executed in chat, in response to a message
|
|
23
24
|
*/
|
|
24
25
|
export class MessageContext<
|
|
25
26
|
TActionState extends IActionState
|
|
26
|
-
> extends ChatContext<TActionState
|
|
27
|
+
> extends ChatContext<TActionState, CommandAction<TActionState>> {
|
|
27
28
|
/** Id of a message that triggered this action. */
|
|
28
29
|
messageId!: number;
|
|
29
30
|
/** Text of a message that triggered this action. */
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { TelegramEmoji } from 'telegraf/types';
|
|
2
|
-
import { ChatInfo } from '../../dtos/chatInfo';
|
|
3
2
|
import { ReplyInfo } from '../../dtos/replyInfo';
|
|
4
3
|
import { ImageMessage } from '../../dtos/responses/imageMessage';
|
|
5
4
|
import { Reaction } from '../../dtos/responses/reaction';
|
|
6
5
|
import { TextMessage } from '../../dtos/responses/textMessage';
|
|
7
6
|
import { VideoMessage } from '../../dtos/responses/videoMessage';
|
|
8
7
|
import { IActionState } from '../../types/actionState';
|
|
9
|
-
import { IScopedLogger } from '../../types/logger';
|
|
10
8
|
import {
|
|
11
9
|
TextMessageSendingOptions,
|
|
12
10
|
MessageSendingOptions
|
|
@@ -15,32 +13,15 @@ import {
|
|
|
15
13
|
MessageTypeValue,
|
|
16
14
|
TelegrafContextMessage
|
|
17
15
|
} from '../../types/messageTypes';
|
|
18
|
-
import { BotResponse } from '../../types/response';
|
|
19
16
|
import { IScheduler } from '../../types/scheduler';
|
|
20
17
|
import { IStorageClient } from '../../types/storage';
|
|
21
|
-
import { TraceId } from '../../types/trace';
|
|
22
18
|
import { ReplyCaptureAction } from '../actions/replyCaptureAction';
|
|
23
19
|
import { resolve } from 'path';
|
|
20
|
+
import { BaseContext } from './baseContext';
|
|
24
21
|
|
|
25
|
-
export class ReplyContext<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/** Storage client instance for the bot executing this action. */
|
|
29
|
-
readonly storage: IStorageClient;
|
|
30
|
-
/** Scheduler instance for the bot executing this action */
|
|
31
|
-
readonly scheduler: IScheduler;
|
|
32
|
-
|
|
33
|
-
/** Trace id of a action execution. */
|
|
34
|
-
traceId!: TraceId;
|
|
35
|
-
/** Name of a bot that executes this action. */
|
|
36
|
-
botName!: string;
|
|
37
|
-
/** Logger instance for the bot executing this action */
|
|
38
|
-
logger!: IScopedLogger;
|
|
39
|
-
|
|
40
|
-
/** Ordered collection of responses to be processed */
|
|
41
|
-
responses: BotResponse[] = [];
|
|
42
|
-
/** Chat information. */
|
|
43
|
-
chatInfo!: ChatInfo;
|
|
22
|
+
export class ReplyContext<
|
|
23
|
+
TParentActionState extends IActionState
|
|
24
|
+
> extends BaseContext<ReplyCaptureAction<TParentActionState>> {
|
|
44
25
|
/** Collection of Regexp match results on a message that triggered this action. Will be empty if trigger is not a Regexp. */
|
|
45
26
|
matchResults!: RegExpExecArray[];
|
|
46
27
|
/** Id of a message that triggered this action. */
|
|
@@ -61,8 +42,7 @@ export class ReplyContext<TParentActionState extends IActionState> {
|
|
|
61
42
|
isInitialized = false;
|
|
62
43
|
|
|
63
44
|
constructor(storage: IStorageClient, scheduler: IScheduler) {
|
|
64
|
-
|
|
65
|
-
this.scheduler = scheduler;
|
|
45
|
+
super(storage, scheduler);
|
|
66
46
|
}
|
|
67
47
|
|
|
68
48
|
private getQuotePart(quote: boolean | string) {
|
package/package.json
CHANGED
|
@@ -85,10 +85,7 @@ export class ActionProcessingService {
|
|
|
85
85
|
);
|
|
86
86
|
|
|
87
87
|
const botInfo = await this.telegraf.telegram.getMe();
|
|
88
|
-
|
|
89
|
-
this.commandProcessor.initialize(
|
|
90
|
-
api,
|
|
91
|
-
this.telegraf,
|
|
88
|
+
const commandActions =
|
|
92
89
|
actions.commands.length > 0
|
|
93
90
|
? [
|
|
94
91
|
buildHelpCommand(
|
|
@@ -99,7 +96,12 @@ export class ActionProcessingService {
|
|
|
99
96
|
),
|
|
100
97
|
...actions.commands
|
|
101
98
|
]
|
|
102
|
-
: []
|
|
99
|
+
: [];
|
|
100
|
+
|
|
101
|
+
this.commandProcessor.initialize(
|
|
102
|
+
api,
|
|
103
|
+
this.telegraf,
|
|
104
|
+
commandActions,
|
|
103
105
|
verboseLoggingForIncomingMessage ?? false
|
|
104
106
|
);
|
|
105
107
|
this.inlineQueryProcessor.initialize(
|
|
@@ -114,6 +116,8 @@ export class ActionProcessingService {
|
|
|
114
116
|
scheduledPeriod ?? hoursToSeconds(1 as Hours)
|
|
115
117
|
);
|
|
116
118
|
|
|
119
|
+
this.storage.saveMetadata([...actions.scheduled, ...commandActions]);
|
|
120
|
+
|
|
117
121
|
this.telegraf.launch();
|
|
118
122
|
}
|
|
119
123
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Telegraf } from 'telegraf';
|
|
2
|
+
import { ILogger } from '../../types/logger';
|
|
3
|
+
import { IScheduler } from '../../types/scheduler';
|
|
4
|
+
import { IStorageClient } from '../../types/storage';
|
|
5
|
+
import { TelegramApiService } from '../telegramApi';
|
|
6
|
+
import { IAction } from '../../types/action';
|
|
7
|
+
import { BaseContext } from '../../entities/context/baseContext';
|
|
8
|
+
|
|
9
|
+
export abstract class BaseActionProcessor {
|
|
10
|
+
protected readonly storage: IStorageClient;
|
|
11
|
+
protected readonly scheduler: IScheduler;
|
|
12
|
+
protected readonly logger: ILogger;
|
|
13
|
+
|
|
14
|
+
protected readonly botName: string;
|
|
15
|
+
|
|
16
|
+
protected api!: TelegramApiService;
|
|
17
|
+
protected telegraf!: Telegraf;
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
botName: string,
|
|
21
|
+
storage: IStorageClient,
|
|
22
|
+
scheduler: IScheduler,
|
|
23
|
+
logger: ILogger
|
|
24
|
+
) {
|
|
25
|
+
this.storage = storage;
|
|
26
|
+
this.scheduler = scheduler;
|
|
27
|
+
this.logger = logger;
|
|
28
|
+
|
|
29
|
+
this.botName = botName;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private defaultErrorHandler<
|
|
33
|
+
TAction extends IAction,
|
|
34
|
+
TActionContext extends BaseContext<TAction>
|
|
35
|
+
>(error: Error, ctx: TActionContext) {
|
|
36
|
+
ctx.logger.errorWithTraceId(error, ctx);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
initializeDependencies(api: TelegramApiService, telegraf: Telegraf) {
|
|
40
|
+
this.api = api;
|
|
41
|
+
this.telegraf = telegraf;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async executeAction<
|
|
45
|
+
TAction extends IAction,
|
|
46
|
+
TActionContext extends BaseContext<TAction>
|
|
47
|
+
>(
|
|
48
|
+
action: TAction,
|
|
49
|
+
ctx: TActionContext,
|
|
50
|
+
errorHandler?: (error: Error, ctx: TActionContext) => void
|
|
51
|
+
) {
|
|
52
|
+
try {
|
|
53
|
+
const responses = await action.exec(ctx);
|
|
54
|
+
this.api.enqueueBatchedResponses(responses);
|
|
55
|
+
ctx.isInitialized = false;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
(errorHandler ?? this.defaultErrorHandler)(error as Error, ctx);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|