chz-telegram-bot 0.0.2 → 0.0.3

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.
Files changed (105) hide show
  1. package/dist/entities/actions/commandAction.d.ts +22 -0
  2. package/dist/entities/actions/commandAction.d.ts.map +1 -0
  3. package/dist/entities/actions/commandAction.js +2 -3
  4. package/dist/entities/actions/scheduledAction.d.ts +24 -0
  5. package/dist/entities/actions/scheduledAction.d.ts.map +1 -0
  6. package/dist/entities/actions/scheduledAction.js +2 -3
  7. package/dist/entities/bot.d.ts +27 -0
  8. package/dist/entities/bot.d.ts.map +1 -0
  9. package/dist/entities/bot.js +14 -10
  10. package/dist/entities/cachedStateFactory.d.ts +7 -0
  11. package/dist/entities/cachedStateFactory.d.ts.map +1 -0
  12. package/dist/entities/commandTriggerCheckResult.d.ts +10 -0
  13. package/dist/entities/commandTriggerCheckResult.d.ts.map +1 -0
  14. package/dist/entities/context/chatContext.d.ts +15 -0
  15. package/dist/entities/context/chatContext.d.ts.map +1 -0
  16. package/dist/entities/context/chatContext.js +2 -1
  17. package/dist/entities/context/messageContext.d.ts +22 -0
  18. package/dist/entities/context/messageContext.d.ts.map +1 -0
  19. package/dist/entities/context/messageContext.js +3 -4
  20. package/dist/entities/incomingMessage.d.ts +16 -0
  21. package/dist/entities/incomingMessage.d.ts.map +1 -0
  22. package/dist/entities/incomingMessage.js +2 -5
  23. package/dist/entities/responses/imageMessage.d.ts +10 -0
  24. package/dist/entities/responses/imageMessage.d.ts.map +1 -0
  25. package/dist/entities/responses/reaction.d.ts +9 -0
  26. package/dist/entities/responses/reaction.d.ts.map +1 -0
  27. package/dist/entities/responses/textMessage.d.ts +9 -0
  28. package/dist/entities/responses/textMessage.d.ts.map +1 -0
  29. package/dist/entities/responses/videoMessage.d.ts +10 -0
  30. package/dist/entities/responses/videoMessage.d.ts.map +1 -0
  31. package/dist/entities/states/actionStateBase.d.ts +5 -0
  32. package/dist/entities/states/actionStateBase.d.ts.map +1 -0
  33. package/dist/entities/taskRecord.d.ts +8 -0
  34. package/dist/entities/taskRecord.d.ts.map +1 -0
  35. package/dist/entities/transactionResult.d.ts +7 -0
  36. package/dist/entities/transactionResult.d.ts.map +1 -0
  37. package/dist/helpers/builders/commandActionBuilder.d.ts +30 -0
  38. package/dist/helpers/builders/commandActionBuilder.d.ts.map +1 -0
  39. package/dist/helpers/builders/scheduledActionBuilder.d.ts +20 -0
  40. package/dist/helpers/builders/scheduledActionBuilder.d.ts.map +1 -0
  41. package/dist/helpers/noop.d.ts +7 -0
  42. package/dist/helpers/noop.d.ts.map +1 -0
  43. package/dist/helpers/reverseMap.d.ts +2 -0
  44. package/dist/helpers/reverseMap.d.ts.map +1 -0
  45. package/dist/helpers/timeConvertions.d.ts +5 -0
  46. package/dist/helpers/timeConvertions.d.ts.map +1 -0
  47. package/dist/helpers/toArray.d.ts +2 -0
  48. package/dist/helpers/toArray.d.ts.map +1 -0
  49. package/dist/index.d.ts +15 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +19 -17
  52. package/dist/main.d.ts +8 -0
  53. package/dist/main.d.ts.map +1 -0
  54. package/dist/main.js +10 -6
  55. package/dist/services/jsonFileStorage.d.ts +23 -0
  56. package/dist/services/jsonFileStorage.d.ts.map +1 -0
  57. package/dist/services/{storage.js → jsonFileStorage.js} +13 -11
  58. package/dist/services/logger.d.ts +7 -0
  59. package/dist/services/logger.d.ts.map +1 -0
  60. package/dist/services/taskScheduler.d.ts +11 -0
  61. package/dist/services/taskScheduler.d.ts.map +1 -0
  62. package/dist/services/telegramApi.d.ts +27 -0
  63. package/dist/services/telegramApi.d.ts.map +1 -0
  64. package/dist/services/telegramApi.js +4 -3
  65. package/dist/types/actionState.d.ts +4 -0
  66. package/dist/types/actionState.d.ts.map +1 -0
  67. package/dist/types/actionWithState.d.ts +6 -0
  68. package/dist/types/actionWithState.d.ts.map +1 -0
  69. package/dist/types/cachedValueAccessor.d.ts +2 -0
  70. package/dist/types/cachedValueAccessor.d.ts.map +1 -0
  71. package/dist/types/commandCondition.d.ts +4 -0
  72. package/dist/types/commandCondition.d.ts.map +1 -0
  73. package/dist/types/daysOfTheWeek.d.ts +10 -0
  74. package/dist/types/daysOfTheWeek.d.ts.map +1 -0
  75. package/dist/types/handlers.d.ts +7 -0
  76. package/dist/types/handlers.d.ts.map +1 -0
  77. package/dist/types/replyMessage.d.ts +7 -0
  78. package/dist/types/replyMessage.d.ts.map +1 -0
  79. package/dist/types/storage.d.ts +12 -0
  80. package/dist/types/storage.d.ts.map +1 -0
  81. package/dist/types/timeValues.d.ts +11 -0
  82. package/dist/types/timeValues.d.ts.map +1 -0
  83. package/entities/actions/commandAction.ts +4 -5
  84. package/entities/actions/scheduledAction.ts +2 -3
  85. package/entities/bot.ts +39 -24
  86. package/entities/context/chatContext.ts +5 -1
  87. package/entities/context/messageContext.ts +10 -6
  88. package/entities/incomingMessage.ts +2 -2
  89. package/index.ts +28 -3
  90. package/main.ts +12 -8
  91. package/package.json +1 -2
  92. package/services/{storage.ts → jsonFileStorage.ts} +20 -14
  93. package/services/telegramApi.ts +8 -2
  94. package/tsconfig.json +2 -2
  95. package/types/storage.ts +19 -0
  96. package/dist/entities/states/potuzhnoState.js +0 -13
  97. package/dist/helpers/escapeMarkdown.js +0 -17
  98. package/dist/helpers/getWeek.js +0 -12
  99. package/dist/helpers/randomInt.js +0 -8
  100. package/entities/states/potuzhnoState.ts +0 -5
  101. package/helpers/escapeMarkdown.ts +0 -12
  102. package/helpers/getWeek.ts +0 -8
  103. package/helpers/randomInt.ts +0 -7
  104. package/types/scheduledItem.ts +0 -6
  105. /package/dist/types/{scheduledItem.js → storage.js} +0 -0
package/dist/main.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import BotInstance from './entities/bot.js';
2
+ import CommandAction from './entities/actions/commandAction.js';
3
+ import IActionState from './types/actionState.js';
4
+ import ScheduledAction from './entities/actions/scheduledAction.js';
5
+ declare function startBot(name: string, tokenFilePath: string, commands: CommandAction<IActionState>[], scheduled: ScheduledAction[], chats: Map<string, number>, storagePath?: string): Promise<BotInstance>;
6
+ declare function stopBots(reason: string): Promise<void>;
7
+ export { startBot, stopBots };
8
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../main.ts"],"names":[],"mappings":"AACA,OAAO,WAAW,MAAM,mBAAmB,CAAC;AAG5C,OAAO,aAAa,MAAM,qCAAqC,CAAC;AAChE,OAAO,YAAY,MAAM,wBAAwB,CAAC;AAClD,OAAO,eAAe,MAAM,uCAAuC,CAAC;AAQpE,iBAAe,QAAQ,CACnB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,EAAE,EACvC,SAAS,EAAE,eAAe,EAAE,EAC5B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1B,WAAW,CAAC,EAAE,MAAM,wBAcvB;AAED,iBAAe,QAAQ,CAAC,MAAM,EAAE,MAAM,iBASrC;AAED,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC"}
package/dist/main.js CHANGED
@@ -8,15 +8,21 @@ exports.stopBots = stopBots;
8
8
  const promises_1 = require("fs/promises");
9
9
  const bot_js_1 = __importDefault(require("./entities/bot.js"));
10
10
  const taskScheduler_js_1 = __importDefault(require("./services/taskScheduler.js"));
11
- const storage_js_1 = __importDefault(require("./services/storage.js"));
12
11
  const logger_js_1 = __importDefault(require("./services/logger.js"));
13
12
  const bots = [];
14
13
  function log(text) {
15
14
  logger_js_1.default.logWithTraceId('ALL BOTS', 'System:Bot', 'System', text);
16
15
  }
17
- async function startBot(name, tokenFile, commands, scheduled, chats) {
18
- const token = await (0, promises_1.readFile)(tokenFile, 'utf8');
19
- const bot = new bot_js_1.default(name, token, commands, scheduled, chats);
16
+ async function startBot(name, tokenFilePath, commands, scheduled, chats, storagePath) {
17
+ const token = await (0, promises_1.readFile)(tokenFilePath, 'utf8');
18
+ const bot = new bot_js_1.default({
19
+ name,
20
+ token,
21
+ commands,
22
+ scheduled,
23
+ chats,
24
+ storagePath
25
+ });
20
26
  bots.push(bot);
21
27
  return bot;
22
28
  }
@@ -24,10 +30,8 @@ async function stopBots(reason) {
24
30
  log(`Recieved termination code: ${reason}`);
25
31
  taskScheduler_js_1.default.stopAll();
26
32
  log('Acquiring storage semaphore...');
27
- await storage_js_1.default.semaphoreInstance.acquire();
28
33
  log('Stopping bots...');
29
34
  for (const bot of bots) {
30
35
  bot.stop(reason);
31
36
  }
32
- process.exit(0);
33
37
  }
@@ -0,0 +1,23 @@
1
+ import TransactionResult from '../entities/transactionResult';
2
+ import ActionStateBase from '../entities/states/actionStateBase';
3
+ import IActionState from '../types/actionState';
4
+ import IActionWithState from '../types/actionWithState';
5
+ import { Sema as Semaphore } from 'async-sema';
6
+ import { IStorageClient } from '../types/storage';
7
+ export default class JsonFileStorage implements IStorageClient {
8
+ semaphore: Semaphore;
9
+ private cache;
10
+ private storagePath;
11
+ private botName;
12
+ constructor(botName: string, path: string | undefined);
13
+ private lock;
14
+ private loadInternal;
15
+ private save;
16
+ private buidPathFromKey;
17
+ load(key: string): Promise<Record<number, ActionStateBase>>;
18
+ saveMetadata(actions: IActionWithState[], botName: string): Promise<void>;
19
+ getActionState<TActionState extends IActionState>(entity: IActionWithState, chatId: number): Promise<TActionState>;
20
+ saveActionExecutionResult(action: IActionWithState, chatId: number, transactionResult: TransactionResult): Promise<void>;
21
+ close(): 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":"AAEA,OAAO,iBAAiB,MAAM,+BAA+B,CAAC;AAE9D,OAAO,eAAe,MAAM,oCAAoC,CAAC;AACjE,OAAO,YAAY,MAAM,sBAAsB,CAAC;AAChD,OAAO,gBAAgB,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,CAAC,OAAO,OAAO,eAAgB,YAAW,cAAc;IAC1D,SAAS,YAAoB;IAC7B,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS;YAMvC,IAAI;YAUJ,YAAY;YAmBZ,IAAI;IAalB,OAAO,CAAC,eAAe;IAOjB,IAAI,CAAC,GAAG,EAAE,MAAM;IAMhB,YAAY,CAAC,OAAO,EAAE,gBAAgB,EAAE,EAAE,OAAO,EAAE,MAAM;IAUzD,cAAc,CAAC,YAAY,SAAS,YAAY,EAClD,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,MAAM;IASZ,yBAAyB,CAC3B,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,MAAM,EACd,iBAAiB,EAAE,iBAAiB;IAYlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
@@ -4,20 +4,20 @@ const fs_1 = require("fs");
4
4
  const path_1 = require("path");
5
5
  const promises_1 = require("fs/promises");
6
6
  const async_sema_1 = require("async-sema");
7
- class Storage {
8
- get semaphoreInstance() {
9
- return Storage.semaphore;
10
- }
11
- constructor() {
7
+ class JsonFileStorage {
8
+ constructor(botName, path) {
9
+ this.semaphore = new async_sema_1.Sema(1);
12
10
  this.cache = new Map();
11
+ this.botName = botName;
12
+ this.storagePath = path ?? 'storage';
13
13
  }
14
14
  async lock(action) {
15
- await this.semaphoreInstance.acquire();
15
+ await this.semaphore.acquire();
16
16
  try {
17
17
  return await action();
18
18
  }
19
19
  finally {
20
- this.semaphoreInstance.release();
20
+ this.semaphore.release();
21
21
  }
22
22
  }
23
23
  async loadInternal(key) {
@@ -44,7 +44,7 @@ class Storage {
44
44
  await (0, promises_1.writeFile)(targetPath, JSON.stringify(data), { flag: 'w+' });
45
45
  }
46
46
  buidPathFromKey(key) {
47
- return 'storage/' + key.replaceAll(':', '/') + '.json';
47
+ return `${this.storagePath}/${this.botName}/${key.replaceAll(':', '/')}.json`;
48
48
  }
49
49
  async load(key) {
50
50
  return await this.lock(async () => {
@@ -65,7 +65,7 @@ class Storage {
65
65
  return data[chatId] ?? entity.stateConstructor();
66
66
  });
67
67
  }
68
- async commitTransactionForAction(action, chatId, transactionResult) {
68
+ async saveActionExecutionResult(action, chatId, transactionResult) {
69
69
  await this.lock(async () => {
70
70
  const data = await this.loadInternal(action.key);
71
71
  if (transactionResult.shouldUpdate) {
@@ -74,6 +74,8 @@ class Storage {
74
74
  }
75
75
  });
76
76
  }
77
+ async close() {
78
+ await this.semaphore.acquire();
79
+ }
77
80
  }
78
- Storage.semaphore = new async_sema_1.Sema(1);
79
- exports.default = new Storage();
81
+ exports.default = JsonFileStorage;
@@ -0,0 +1,7 @@
1
+ declare class Logger {
2
+ logWithTraceId(botName: string, traceId: string | number, chatName: string, text: string): void;
3
+ errorWithTraceId<TData>(botName: string, traceId: string | number, chatName: string, errorObj: string | Error, extraData?: TData | undefined): void;
4
+ }
5
+ declare const _default: Logger;
6
+ export default _default;
7
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../services/logger.ts"],"names":[],"mappings":"AAAA,cAAM,MAAM;IACR,cAAc,CACV,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM;IAKhB,gBAAgB,CAAC,KAAK,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAAG,KAAK,EACxB,SAAS,CAAC,EAAE,KAAK,GAAG,SAAS;CAYpC;;AAED,wBAA4B"}
@@ -0,0 +1,11 @@
1
+ import TaskRecord from '../entities/taskRecord';
2
+ import { Milliseconds } from '../types/timeValues';
3
+ declare class TaskScheduler {
4
+ activeTasks: TaskRecord[];
5
+ stopAll(): void;
6
+ createTask(name: string, action: () => void, interval: Milliseconds, executeRightAway: boolean, ownerName: string): void;
7
+ createOnetimeTask(name: string, action: () => void, delay: Milliseconds, ownerName: string): void;
8
+ }
9
+ declare const _default: TaskScheduler;
10
+ export default _default;
11
+ //# sourceMappingURL=taskScheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taskScheduler.d.ts","sourceRoot":"","sources":["../../services/taskScheduler.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,wBAAwB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAW,MAAM,qBAAqB,CAAC;AAG5D,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,wBAAmC"}
@@ -0,0 +1,27 @@
1
+ import MessageContext from '../entities/context/messageContext';
2
+ import ChatContext from '../entities/context/chatContext';
3
+ import { Telegraf } from 'telegraf';
4
+ import IReplyMessage from '../types/replyMessage';
5
+ import IncomingMessage from '../entities/incomingMessage';
6
+ import Reaction from '../entities/responses/reaction';
7
+ import { IStorageClient } from '../types/storage';
8
+ export default class TelegramApiService {
9
+ botName: string;
10
+ telegraf: Telegraf;
11
+ chats: Map<number, string>;
12
+ messageQueue: Array<IReplyMessage<unknown> | Reaction>;
13
+ storage: IStorageClient;
14
+ constructor(botName: string, telegraf: Telegraf, storage: IStorageClient, chats: Map<string, number>);
15
+ private dequeueResponse;
16
+ private processResponse;
17
+ private enqueueResponse;
18
+ private enqueueReaction;
19
+ private getInteractions;
20
+ createContextForMessage(incomingMessage: IncomingMessage): MessageContext<import("../types/actionState").default>;
21
+ createContextForChat(chatId: number, scheduledName: string): ChatContext;
22
+ }
23
+ export interface IBotApiInteractions {
24
+ respond: <TType>(response: IReplyMessage<TType>) => void;
25
+ react: (reaction: Reaction) => void;
26
+ }
27
+ //# sourceMappingURL=telegramApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegramApi.d.ts","sourceRoot":"","sources":["../../services/telegramApi.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,oCAAoC,CAAC;AAChE,OAAO,WAAW,MAAM,iCAAiC,CAAC;AAM1D,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,aAAa,MAAM,uBAAuB,CAAC;AAClD,OAAO,eAAe,MAAM,6BAA6B,CAAC;AAE1D,OAAO,QAAQ,MAAM,gCAAgC,CAAC;AAGtD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,CAAC,OAAO,OAAO,kBAAkB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,YAAY,EAAE,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAM;IAC5D,OAAO,EAAE,cAAc,CAAC;gBAGpB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;YAkBhB,eAAe;YAkBf,eAAe;IAgE7B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAOvB,uBAAuB,CAAC,eAAe,EAAE,eAAe;IAoBxD,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM;CAU7D;AAED,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;IACzD,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;CACvC"}
@@ -12,11 +12,12 @@ const taskScheduler_1 = __importDefault(require("./taskScheduler"));
12
12
  const logger_1 = __importDefault(require("./logger"));
13
13
  const reverseMap_1 = require("../helpers/reverseMap");
14
14
  class TelegramApiService {
15
- constructor(botName, telegraf, chats) {
15
+ constructor(botName, telegraf, storage, chats) {
16
16
  this.messageQueue = [];
17
17
  this.telegraf = telegraf;
18
18
  this.botName = botName;
19
19
  this.chats = (0, reverseMap_1.reverseMap)(chats);
20
+ this.storage = storage;
20
21
  taskScheduler_1.default.createTask('MessageSending', () => {
21
22
  this.dequeueResponse();
22
23
  }, 100, false, this.botName);
@@ -85,10 +86,10 @@ class TelegramApiService {
85
86
  const lastName = incomingMessage.from?.last_name
86
87
  ? ` ${incomingMessage.from?.last_name}`
87
88
  : '';
88
- return new messageContext_1.default(this.botName, this.getInteractions(), incomingMessage.chat.id, incomingMessage.chatName, incomingMessage.message_id, incomingMessage.text, incomingMessage.from?.id, incomingMessage.traceId, firstName + lastName);
89
+ return new messageContext_1.default(this.botName, this.getInteractions(), incomingMessage.chat.id, incomingMessage.chatName, incomingMessage.message_id, incomingMessage.text, incomingMessage.from?.id, incomingMessage.traceId, firstName + lastName, this.storage);
89
90
  }
90
91
  createContextForChat(chatId, scheduledName) {
91
- return new chatContext_1.default(this.botName, this.getInteractions(), chatId, this.chats.get(chatId), `Scheduled:${scheduledName}:${chatId}`);
92
+ return new chatContext_1.default(this.botName, this.getInteractions(), chatId, this.chats.get(chatId), `Scheduled:${scheduledName}:${chatId}`, this.storage);
92
93
  }
93
94
  }
94
95
  exports.default = TelegramApiService;
@@ -0,0 +1,4 @@
1
+ export default interface IActionState {
2
+ lastExecutedDate: number;
3
+ }
4
+ //# sourceMappingURL=actionState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actionState.d.ts","sourceRoot":"","sources":["../../types/actionState.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,WAAW,YAAY;IACjC,gBAAgB,EAAE,MAAM,CAAC;CAC5B"}
@@ -0,0 +1,6 @@
1
+ import IActionState from './actionState';
2
+ export default interface IActionWithState {
3
+ key: string;
4
+ stateConstructor: () => IActionState;
5
+ }
6
+ //# sourceMappingURL=actionWithState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actionWithState.d.ts","sourceRoot":"","sources":["../../types/actionWithState.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAC;AAEzC,MAAM,CAAC,OAAO,WAAW,gBAAgB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,EAAE,MAAM,YAAY,CAAC;CACxC"}
@@ -0,0 +1,2 @@
1
+ export type CachedValueAccessor = <TResult>(key: string) => Promise<TResult>;
2
+ //# sourceMappingURL=cachedValueAccessor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cachedValueAccessor.d.ts","sourceRoot":"","sources":["../../types/cachedValueAccessor.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import MessageContext from '../entities/context/messageContext';
2
+ import IActionState from './actionState';
3
+ export type CommandCondition<TActionState extends IActionState> = (ctx: MessageContext<TActionState>) => Promise<boolean>;
4
+ //# sourceMappingURL=commandCondition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commandCondition.d.ts","sourceRoot":"","sources":["../../types/commandCondition.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,oCAAoC,CAAC;AAChE,OAAO,YAAY,MAAM,eAAe,CAAC;AAEzC,MAAM,MAAM,gBAAgB,CAAC,YAAY,SAAS,YAAY,IAAI,CAC9D,GAAG,EAAE,cAAc,CAAC,YAAY,CAAC,KAChC,OAAO,CAAC,OAAO,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ export declare enum Day {
2
+ Sunday = 0,
3
+ Monday = 1,
4
+ Tuesday = 2,
5
+ Wednesday = 3,
6
+ Thursday = 4,
7
+ Friday = 5,
8
+ Saturday = 6
9
+ }
10
+ //# sourceMappingURL=daysOfTheWeek.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daysOfTheWeek.d.ts","sourceRoot":"","sources":["../../types/daysOfTheWeek.ts"],"names":[],"mappings":"AAAA,oBAAY,GAAG;IACX,MAAM,IAAI;IACV,MAAM,IAAI;IACV,OAAO,IAAI;IACX,SAAS,IAAI;IACb,QAAQ,IAAI;IACZ,MAAM,IAAI;IACV,QAAQ,IAAI;CACf"}
@@ -0,0 +1,7 @@
1
+ import ChatContext from '../entities/context/chatContext';
2
+ import MessageContext from '../entities/context/messageContext';
3
+ import IActionState from './actionState';
4
+ import { CachedValueAccessor } from './cachedValueAccessor';
5
+ export type CommandHandler<TActionState extends IActionState> = (ctx: MessageContext<TActionState>, state: TActionState) => Promise<void>;
6
+ export type ScheduledHandler = (ctx: ChatContext, getCached: CachedValueAccessor) => Promise<void>;
7
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../types/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,iCAAiC,CAAC;AAC1D,OAAO,cAAc,MAAM,oCAAoC,CAAC;AAChE,OAAO,YAAY,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,MAAM,cAAc,CAAC,YAAY,SAAS,YAAY,IAAI,CAC5D,GAAG,EAAE,cAAc,CAAC,YAAY,CAAC,EACjC,KAAK,EAAE,YAAY,KAClB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,MAAM,gBAAgB,GAAG,CAC3B,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,mBAAmB,KAC7B,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export default interface IReplyMessage<TType> {
2
+ content: TType;
3
+ chatId: number;
4
+ replyId: number | undefined;
5
+ traceId: number | string;
6
+ }
7
+ //# sourceMappingURL=replyMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replyMessage.d.ts","sourceRoot":"","sources":["../../types/replyMessage.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,WAAW,aAAa,CAAC,KAAK;IACxC,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B"}
@@ -0,0 +1,12 @@
1
+ import ActionStateBase from '../entities/states/actionStateBase';
2
+ import TransactionResult from '../entities/transactionResult';
3
+ import IActionState from './actionState';
4
+ import IActionWithState from './actionWithState';
5
+ export interface IStorageClient {
6
+ close(): Promise<void>;
7
+ load(key: string): Promise<Record<number, ActionStateBase>>;
8
+ saveMetadata(actions: IActionWithState[], botName: string): Promise<void>;
9
+ getActionState<TActionState extends IActionState>(entity: IActionWithState, chatId: number): Promise<TActionState>;
10
+ saveActionExecutionResult(action: IActionWithState, chatId: number, transactionResult: TransactionResult): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../types/storage.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,oCAAoC,CAAC;AACjE,OAAO,iBAAiB,MAAM,+BAA+B,CAAC;AAC9D,OAAO,YAAY,MAAM,eAAe,CAAC;AACzC,OAAO,gBAAgB,MAAM,mBAAmB,CAAC;AAEjD,MAAM,WAAW,cAAc;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;IAC5D,YAAY,CAAC,OAAO,EAAE,gBAAgB,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,cAAc,CAAC,YAAY,SAAS,YAAY,EAC5C,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,CAAC,CAAC;IACzB,yBAAyB,CACrB,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,MAAM,EACd,iBAAiB,EAAE,iBAAiB,GACrC,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB"}
@@ -0,0 +1,11 @@
1
+ export type Milliseconds = number & {
2
+ __brand: 'ms';
3
+ };
4
+ export type Seconds = number & {
5
+ __brand: 's';
6
+ };
7
+ export type Hours = number & {
8
+ __brand: 'h';
9
+ };
10
+ export type HoursOfDay = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23;
11
+ //# sourceMappingURL=timeValues.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeValues.d.ts","sourceRoot":"","sources":["../../types/timeValues.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC;AACtD,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC;AAChD,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC;AAE9C,MAAM,MAAM,UAAU,GAChB,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,CAAC"}
@@ -1,5 +1,4 @@
1
- import storage from '../../services/storage';
2
- import TransactionResult from '../transactionResult';
1
+ import ActionExecutionResult from '../transactionResult';
3
2
  import moment from 'moment';
4
3
  import logger from '../../services/logger';
5
4
  import MessageContext from '../context/messageContext';
@@ -57,7 +56,7 @@ export default class CommandAction<TActionState extends IActionState>
57
56
 
58
57
  if (!isConditionMet) return;
59
58
 
60
- const state = await storage.getActionState<TActionState>(
59
+ const state = await ctx.storage.getActionState<TActionState>(
61
60
  this,
62
61
  ctx.chatId
63
62
  );
@@ -91,10 +90,10 @@ export default class CommandAction<TActionState extends IActionState>
91
90
 
92
91
  ctx.updateActions.forEach((action) => action(state));
93
92
 
94
- await storage.commitTransactionForAction(
93
+ await ctx.storage.saveActionExecutionResult(
95
94
  this,
96
95
  ctx.chatId,
97
- new TransactionResult(state, ctx.startCooldown && shouldTrigger)
96
+ new ActionExecutionResult(state, ctx.startCooldown && shouldTrigger)
98
97
  );
99
98
  }
100
99
 
@@ -1,4 +1,3 @@
1
- import storage from '../../services/storage';
2
1
  import TransactionResult from '../transactionResult';
3
2
  import moment from 'moment';
4
3
  import logger from '../../services/logger';
@@ -47,7 +46,7 @@ export default class ScheduledAction implements IActionWithState {
47
46
  async exec(ctx: ChatContext) {
48
47
  if (!this.active || !this.chatsWhitelist.includes(ctx.chatId)) return;
49
48
 
50
- const state = await storage.getActionState(this, ctx.chatId);
49
+ const state = await ctx.storage.getActionState(this, ctx.chatId);
51
50
  const isAllowedToTrigger = this.shouldTrigger(state);
52
51
 
53
52
  if (isAllowedToTrigger) {
@@ -64,7 +63,7 @@ export default class ScheduledAction implements IActionWithState {
64
63
 
65
64
  state.lastExecutedDate = moment().valueOf();
66
65
 
67
- await storage.commitTransactionForAction(
66
+ await ctx.storage.saveActionExecutionResult(
68
67
  this,
69
68
  ctx.chatId,
70
69
  new TransactionResult(state, isAllowedToTrigger)
package/entities/bot.ts CHANGED
@@ -11,28 +11,32 @@ import {
11
11
  secondsToMilliseconds
12
12
  } from '../helpers/timeConvertions';
13
13
  import { Hours, Seconds } from '../types/timeValues';
14
- import storage from '../services/storage';
14
+ import JsonFileStorage from '../services/jsonFileStorage';
15
+ import { IStorageClient } from '../types/storage';
15
16
 
16
17
  export default class Bot {
17
18
  name: string;
18
- api: TelegramApiService;
19
- telegraf: Telegraf;
20
- commands: CommandAction<IActionState>[];
21
- scheduled: ScheduledAction[];
22
- chats: Map<string, number>;
23
- messageQueue: IncomingMessage[] = [];
24
-
25
- constructor(
26
- name: string,
27
- token: string,
28
- commands: CommandAction<IActionState>[],
29
- scheduled: ScheduledAction[],
30
- chats: Map<string, number>
31
- ) {
32
- this.name = name;
33
- this.commands = commands;
34
- this.scheduled = scheduled;
35
- this.chats = chats;
19
+ private api: TelegramApiService;
20
+ private telegraf: Telegraf;
21
+ private commands: CommandAction<IActionState>[];
22
+ private scheduled: ScheduledAction[];
23
+ private chats: Map<string, number>;
24
+ private messageQueue: IncomingMessage[] = [];
25
+ storage: IStorageClient;
26
+
27
+ constructor(options: {
28
+ name: string;
29
+ token: string;
30
+ commands: CommandAction<IActionState>[];
31
+ scheduled: ScheduledAction[];
32
+ chats: Map<string, number>;
33
+ storageClient?: IStorageClient;
34
+ storagePath?: string;
35
+ }) {
36
+ this.name = options.name;
37
+ this.commands = options.commands;
38
+ this.scheduled = options.scheduled;
39
+ this.chats = options.chats;
36
40
 
37
41
  logger.logWithTraceId(
38
42
  this.name,
@@ -40,9 +44,16 @@ export default class Bot {
40
44
  'System',
41
45
  'Starting bot...'
42
46
  );
43
- this.telegraf = new Telegraf(token);
44
-
45
- this.api = new TelegramApiService(this.name, this.telegraf, this.chats);
47
+ this.telegraf = new Telegraf(options.token);
48
+ this.storage =
49
+ options.storageClient ??
50
+ new JsonFileStorage(options.name, options.storagePath);
51
+ this.api = new TelegramApiService(
52
+ this.name,
53
+ this.telegraf,
54
+ this.storage,
55
+ this.chats
56
+ );
46
57
 
47
58
  this.telegraf.on('message', async (ctx) => {
48
59
  const msg = new IncomingMessage(ctx.update.message);
@@ -86,10 +97,13 @@ export default class Bot {
86
97
  this.name
87
98
  );
88
99
 
89
- storage.saveMetadata([...this.commands, ...this.scheduled], this.name);
100
+ this.storage.saveMetadata(
101
+ [...this.commands, ...this.scheduled],
102
+ this.name
103
+ );
90
104
  }
91
105
 
92
- stop(code: string) {
106
+ async stop(code: string) {
93
107
  logger.logWithTraceId(
94
108
  this.name,
95
109
  `System:Bot-${this.name}-Stop`,
@@ -97,6 +111,7 @@ export default class Bot {
97
111
  'Stopping bot...'
98
112
  );
99
113
 
114
+ await this.storage.close();
100
115
  this.telegraf.stop(code);
101
116
  }
102
117
 
@@ -3,6 +3,7 @@ import TextMessage from '../responses/textMessage';
3
3
  import VideoMessage from '../responses/videoMessage';
4
4
  import { resolve } from 'path';
5
5
  import { IBotApiInteractions } from '../../services/telegramApi';
6
+ import { IStorageClient } from '../../types/storage';
6
7
 
7
8
  export default class ChatContext {
8
9
  botName: string;
@@ -10,19 +11,22 @@ export default class ChatContext {
10
11
  chatId: number;
11
12
  chatName: string;
12
13
  traceId: number | string;
14
+ storage: IStorageClient;
13
15
 
14
16
  constructor(
15
17
  botName: string,
16
18
  interactions: IBotApiInteractions,
17
19
  chatId: number,
18
20
  chatName: string,
19
- traceId: number | string
21
+ traceId: number | string,
22
+ storage: IStorageClient
20
23
  ) {
21
24
  this.botName = botName;
22
25
  this.interactions = interactions;
23
26
  this.chatId = chatId;
24
27
  this.chatName = chatName;
25
28
  this.traceId = traceId;
29
+ this.storage = storage;
26
30
  }
27
31
 
28
32
  sendTextToChat(text: string) {
@@ -3,12 +3,13 @@ import ImageMessage from '../responses/imageMessage';
3
3
  import TextMessage from '../responses/textMessage';
4
4
  import VideoMessage from '../responses/videoMessage';
5
5
  import ChatContext from './chatContext';
6
- import storage from '../../services/storage';
6
+ import storage from '../../services/jsonFileStorage';
7
7
  import { resolve } from 'path';
8
8
  import IActionState from '../../types/actionState';
9
9
  import { IBotApiInteractions } from '../../services/telegramApi';
10
10
  import { TelegramEmoji } from 'telegraf/types';
11
11
  import Reaction from '../responses/reaction';
12
+ import { IStorageClient } from '../../types/storage';
12
13
 
13
14
  export default class MessageContext<
14
15
  TActionState extends IActionState
@@ -30,9 +31,10 @@ export default class MessageContext<
30
31
  messageText: string,
31
32
  fromUserId: number | undefined,
32
33
  traceId: number | string,
33
- fromUserName: string
34
+ fromUserName: string,
35
+ storage: IStorageClient
34
36
  ) {
35
- super(botName, interactions, chatId, chatName, traceId);
37
+ super(botName, interactions, chatId, chatName, traceId, storage);
36
38
 
37
39
  this.messageId = messageId;
38
40
  this.messageText = messageText;
@@ -44,9 +46,11 @@ export default class MessageContext<
44
46
  commandName: string
45
47
  ): Promise<TAnotherActionState> {
46
48
  return (
47
- ((await storage.load(`command:${commandName.replace('.', '-')}`))[
48
- this.chatId
49
- ] as TAnotherActionState) ?? new ActionStateBase()
49
+ ((
50
+ await this.storage.load(
51
+ `command:${commandName.replace('.', '-')}`
52
+ )
53
+ )[this.chatId] as TAnotherActionState) ?? new ActionStateBase()
50
54
  );
51
55
  }
52
56
 
@@ -1,5 +1,5 @@
1
1
  import { Chat, User } from 'telegraf/types';
2
- import randomInteger from '../helpers/randomInt';
2
+ import { randomInt } from 'crypto';
3
3
 
4
4
  export default class IncomingMessage {
5
5
  message_id: number;
@@ -7,7 +7,7 @@ export default class IncomingMessage {
7
7
  from: User | undefined;
8
8
  text: string;
9
9
  chatName: string;
10
- traceId = randomInteger(10000, 99999);
10
+ traceId = randomInt(10000, 99999);
11
11
 
12
12
  constructor(ctxMessage: {
13
13
  message_id: number;
package/index.ts CHANGED
@@ -1,3 +1,28 @@
1
- export { startBot, stopBots } from './main';
2
- export * from './helpers/builders/commandActionBuilder';
3
- export * from './helpers/builders/scheduledActionBuilder';
1
+ import { startBot, stopBots } from './main';
2
+ import { CommandActionBuilder } from './helpers/builders/commandActionBuilder';
3
+ import { CommandActionBuilderWithState } from './helpers/builders/commandActionBuilder';
4
+ import ScheduledActionBuilder from './helpers/builders/scheduledActionBuilder';
5
+ import {
6
+ hoursToMilliseconds,
7
+ hoursToSeconds,
8
+ secondsToMilliseconds
9
+ } from './helpers/timeConvertions';
10
+ import Noop from './helpers/noop';
11
+ import { IStorageClient } from './types/storage';
12
+
13
+ const helpers = {
14
+ hoursToMilliseconds,
15
+ hoursToSeconds,
16
+ secondsToMilliseconds,
17
+ Noop
18
+ };
19
+
20
+ export {
21
+ startBot,
22
+ stopBots,
23
+ CommandActionBuilder,
24
+ CommandActionBuilderWithState,
25
+ ScheduledActionBuilder,
26
+ IStorageClient as IStorage,
27
+ helpers
28
+ };