chz-telegram-bot 0.0.51 → 0.0.53

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 (100) hide show
  1. package/dist/dtos/commandTriggerCheckResult.d.ts +5 -5
  2. package/dist/dtos/commandTriggerCheckResult.d.ts.map +1 -1
  3. package/dist/dtos/commandTriggerCheckResult.js +3 -6
  4. package/dist/dtos/incomingMessage.d.ts +8 -7
  5. package/dist/dtos/incomingMessage.d.ts.map +1 -1
  6. package/dist/dtos/incomingMessage.js +3 -2
  7. package/dist/dtos/responses/delay.d.ts +3 -2
  8. package/dist/dtos/responses/delay.d.ts.map +1 -1
  9. package/dist/dtos/responses/imageMessage.d.ts +3 -2
  10. package/dist/dtos/responses/imageMessage.d.ts.map +1 -1
  11. package/dist/dtos/responses/reaction.d.ts +3 -2
  12. package/dist/dtos/responses/reaction.d.ts.map +1 -1
  13. package/dist/dtos/responses/textMessage.d.ts +3 -2
  14. package/dist/dtos/responses/textMessage.d.ts.map +1 -1
  15. package/dist/dtos/responses/unpin.d.ts +3 -2
  16. package/dist/dtos/responses/unpin.d.ts.map +1 -1
  17. package/dist/dtos/responses/videoMessage.d.ts +3 -2
  18. package/dist/dtos/responses/videoMessage.d.ts.map +1 -1
  19. package/dist/entities/actions/commandAction.d.ts +1 -0
  20. package/dist/entities/actions/commandAction.d.ts.map +1 -1
  21. package/dist/entities/actions/commandAction.js +38 -37
  22. package/dist/entities/actions/scheduledAction.d.ts +1 -1
  23. package/dist/entities/actions/scheduledAction.d.ts.map +1 -1
  24. package/dist/entities/actions/scheduledAction.js +12 -16
  25. package/dist/entities/botInstance.d.ts +11 -3
  26. package/dist/entities/botInstance.d.ts.map +1 -1
  27. package/dist/entities/botInstance.js +26 -18
  28. package/dist/entities/context/chatContext.d.ts +12 -11
  29. package/dist/entities/context/chatContext.d.ts.map +1 -1
  30. package/dist/entities/context/chatContext.js +5 -12
  31. package/dist/entities/context/messageContext.d.ts +4 -2
  32. package/dist/entities/context/messageContext.d.ts.map +1 -1
  33. package/dist/entities/context/messageContext.js +4 -4
  34. package/dist/helpers/noop.d.ts +4 -2
  35. package/dist/helpers/noop.d.ts.map +1 -1
  36. package/dist/helpers/noop.js +3 -2
  37. package/dist/helpers/traceFactory.d.ts +3 -0
  38. package/dist/helpers/traceFactory.d.ts.map +1 -0
  39. package/dist/helpers/traceFactory.js +6 -0
  40. package/dist/index.d.ts +4 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/main.d.ts +10 -2
  43. package/dist/main.d.ts.map +1 -1
  44. package/dist/main.js +6 -11
  45. package/dist/services/jsonFileStorage.d.ts +1 -2
  46. package/dist/services/jsonFileStorage.d.ts.map +1 -1
  47. package/dist/services/jsonFileStorage.js +3 -5
  48. package/dist/services/jsonLogger.d.ts +9 -0
  49. package/dist/services/jsonLogger.d.ts.map +1 -0
  50. package/dist/services/jsonLogger.js +28 -0
  51. package/dist/services/nodeTimeoutScheduler.d.ts +13 -0
  52. package/dist/services/nodeTimeoutScheduler.d.ts.map +1 -0
  53. package/dist/services/nodeTimeoutScheduler.js +34 -0
  54. package/dist/services/telegramApi.d.ts +7 -5
  55. package/dist/services/telegramApi.d.ts.map +1 -1
  56. package/dist/services/telegramApi.js +4 -4
  57. package/dist/types/commandCondition.d.ts +1 -1
  58. package/dist/types/commandCondition.d.ts.map +1 -1
  59. package/dist/types/logger.d.ts +7 -0
  60. package/dist/types/logger.d.ts.map +1 -0
  61. package/dist/types/logger.js +2 -0
  62. package/dist/types/response.d.ts +2 -1
  63. package/dist/types/response.d.ts.map +1 -1
  64. package/dist/types/scheduler.d.ts +7 -0
  65. package/dist/types/scheduler.d.ts.map +1 -0
  66. package/dist/types/scheduler.js +2 -0
  67. package/dist/types/storage.d.ts +1 -2
  68. package/dist/types/storage.d.ts.map +1 -1
  69. package/dist/types/trace.d.ts +2 -0
  70. package/dist/types/trace.d.ts.map +1 -0
  71. package/dist/types/trace.js +2 -0
  72. package/dtos/commandTriggerCheckResult.ts +10 -10
  73. package/dtos/incomingMessage.ts +17 -7
  74. package/dtos/responses/delay.ts +3 -2
  75. package/dtos/responses/imageMessage.ts +3 -2
  76. package/dtos/responses/reaction.ts +3 -2
  77. package/dtos/responses/textMessage.ts +3 -2
  78. package/dtos/responses/unpin.ts +3 -2
  79. package/dtos/responses/videoMessage.ts +3 -2
  80. package/entities/actions/commandAction.ts +48 -41
  81. package/entities/actions/scheduledAction.ts +28 -31
  82. package/entities/botInstance.ts +57 -34
  83. package/entities/context/chatContext.ts +22 -17
  84. package/entities/context/messageContext.ts +10 -6
  85. package/helpers/noop.ts +5 -2
  86. package/helpers/traceFactory.ts +9 -0
  87. package/index.ts +4 -1
  88. package/main.ts +16 -15
  89. package/package.json +1 -1
  90. package/services/jsonFileStorage.ts +4 -6
  91. package/services/{logger.ts → jsonLogger.ts} +7 -6
  92. package/services/{taskScheduler.ts → nodeTimeoutScheduler.ts} +15 -10
  93. package/services/telegramApi.ts +15 -8
  94. package/types/commandCondition.ts +1 -1
  95. package/types/logger.ts +26 -0
  96. package/types/response.ts +2 -1
  97. package/types/scheduler.ts +20 -0
  98. package/types/storage.ts +1 -2
  99. package/types/trace.ts +1 -0
  100. package/dtos/actionExecutionResult.ts +0 -11
@@ -10,22 +10,28 @@ import { TelegramApiService } from '../services/telegramApi';
10
10
  import { IActionState } from '../types/actionState';
11
11
  import { CommandAction } from './actions/commandAction';
12
12
  import { ScheduledAction } from './actions/scheduledAction';
13
- import { Logger } from '../services/logger';
14
- import { Scheduler } from '../services/taskScheduler';
13
+ import { JsonLogger } from '../services/jsonLogger';
15
14
  import { IncomingMessage } from '../dtos/incomingMessage';
16
15
  import moment from 'moment';
17
16
  import { ChatContext } from './context/chatContext';
18
17
  import { MessageContext } from './context/messageContext';
19
18
  import { ChatInfo } from '../dtos/chatInfo';
19
+ import { ILogger } from '../types/logger';
20
+ import { IScheduler } from '../types/scheduler';
21
+ import { NodeTimeoutScheduler } from '../services/nodeTimeoutScheduler';
22
+ import { createTrace } from '../helpers/traceFactory';
20
23
 
21
24
  export class BotInstance {
22
- readonly name: string;
23
25
  private readonly api: TelegramApiService;
26
+ private readonly storage: IStorageClient;
27
+ private readonly scheduler: IScheduler;
28
+ private readonly logger: ILogger;
29
+
30
+ readonly name: string;
24
31
  private readonly telegraf: Telegraf;
25
32
  private readonly commands: CommandAction<IActionState>[];
26
33
  private readonly scheduled: ScheduledAction<IActionState>[];
27
34
  private readonly chats: Record<string, number>;
28
- readonly storage: IStorageClient;
29
35
 
30
36
  constructor(options: {
31
37
  name: string;
@@ -33,10 +39,14 @@ export class BotInstance {
33
39
  commands: CommandAction<IActionState>[];
34
40
  scheduled: ScheduledAction<IActionState>[];
35
41
  chats: Record<string, number>;
36
- storageClient?: IStorageClient;
37
42
  storagePath?: string;
38
43
  scheduledPeriod?: Seconds;
39
44
  verboseLoggingForIncomingMessage?: boolean;
45
+ services?: {
46
+ storageClient?: IStorageClient;
47
+ logger?: ILogger;
48
+ scheduler?: IScheduler;
49
+ };
40
50
  }) {
41
51
  this.name = options.name;
42
52
  this.commands = options.commands;
@@ -44,21 +54,19 @@ export class BotInstance {
44
54
  this.chats = options.chats;
45
55
 
46
56
  const actions = [...this.commands, ...this.scheduled];
47
-
48
- Logger.logWithTraceId(
49
- this.name,
50
- `System:Bot-${this.name}-Start`,
51
- 'System',
52
- 'Starting bot...'
53
- );
54
57
  this.telegraf = new Telegraf(options.token);
58
+ this.logger = options.services?.logger ?? new JsonLogger();
59
+ this.scheduler =
60
+ options.services?.scheduler ??
61
+ new NodeTimeoutScheduler(this.logger);
55
62
  this.storage =
56
- options.storageClient ??
63
+ options.services?.storageClient ??
57
64
  new JsonFileStorage(options.name, actions, options.storagePath);
58
65
  this.api = new TelegramApiService(
59
66
  this.name,
60
67
  this.telegraf.telegram,
61
- this.storage
68
+ this.storage,
69
+ this.logger
62
70
  );
63
71
 
64
72
  this.initializeMessageProcessing(
@@ -70,6 +78,12 @@ export class BotInstance {
70
78
 
71
79
  this.storage.saveMetadata(actions, this.name);
72
80
 
81
+ this.logger.logWithTraceId(
82
+ this.name,
83
+ createTrace(this, this.name, 'Start'),
84
+ 'System',
85
+ 'Starting bot...'
86
+ );
73
87
  this.telegraf.launch();
74
88
  }
75
89
 
@@ -78,7 +92,7 @@ export class BotInstance {
78
92
  const now = moment();
79
93
 
80
94
  if (now.minute() == 0 && now.second() == 0) {
81
- Scheduler.createTask(
95
+ this.scheduler.createTask(
82
96
  'ScheduledProcessing',
83
97
  async () => {
84
98
  await this.runScheduled();
@@ -98,10 +112,10 @@ export class BotInstance {
98
112
 
99
113
  const delay = nextExecutionTime.diff(now);
100
114
 
101
- Scheduler.createOnetimeTask(
115
+ this.scheduler.createOnetimeTask(
102
116
  'ScheduledProcessing_OneTime',
103
117
  async () => {
104
- Scheduler.createTask(
118
+ this.scheduler.createTask(
105
119
  'ScheduledProcessing',
106
120
  async () => {
107
121
  await this.runScheduled();
@@ -121,7 +135,7 @@ export class BotInstance {
121
135
  ) {
122
136
  if (this.commands.length > 0) {
123
137
  this.telegraf.on('message', async (ctx) => {
124
- const msg = new IncomingMessage(ctx.update.message);
138
+ const msg = new IncomingMessage(ctx.update.message, this.name);
125
139
  const messageContent =
126
140
  msg.text || `<non-text message: ${msg.type}>`;
127
141
 
@@ -129,14 +143,14 @@ export class BotInstance {
129
143
  const messageFromId = msg.from?.id ?? 'Unknown';
130
144
 
131
145
  if (verboseLoggingForIncomingMessage) {
132
- Logger.logObjectWithTraceId(
146
+ this.logger.logObjectWithTraceId(
133
147
  this.name,
134
148
  msg.traceId,
135
149
  msg.chatInfo.name,
136
150
  ctx.update.message
137
151
  );
138
152
  } else {
139
- Logger.logWithTraceId(
153
+ this.logger.logWithTraceId(
140
154
  this.name,
141
155
  msg.traceId,
142
156
  msg.chatInfo.name,
@@ -150,19 +164,24 @@ export class BotInstance {
150
164
  }
151
165
 
152
166
  async stop(code: string) {
153
- Logger.logWithTraceId(
167
+ this.logger.logWithTraceId(
154
168
  this.name,
155
- `System:Bot-${this.name}-Stop`,
169
+ createTrace(this, this.name, 'Stop'),
156
170
  'System',
157
171
  'Stopping bot...'
158
172
  );
159
173
 
174
+ this.scheduler.stopAll();
160
175
  await this.storage.close();
161
176
  this.telegraf.stop(code);
162
177
  }
163
178
 
164
179
  private async runScheduled() {
165
- const ctx = new ChatContext<IActionState>();
180
+ const ctx = new ChatContext<IActionState>(
181
+ this.storage,
182
+ this.logger,
183
+ this.scheduler
184
+ );
166
185
 
167
186
  for (const [chatName, chatId] of Object.entries(this.chats)) {
168
187
  for (const scheduledAction of this.scheduled) {
@@ -170,15 +189,19 @@ export class BotInstance {
170
189
  this.name,
171
190
  scheduledAction,
172
191
  new ChatInfo(chatId, chatName),
173
- `Scheduled:${scheduledAction.key}:${chatId}`,
174
- this.storage
192
+ createTrace(
193
+ scheduledAction,
194
+ this.name,
195
+ `${scheduledAction.key}-${chatId}`
196
+ )
175
197
  );
176
198
 
177
199
  try {
178
200
  const responses = await scheduledAction.exec(ctx);
179
201
  this.api.enqueueBatchedResponses(responses);
202
+ ctx.isInitialized = false;
180
203
  } catch (error) {
181
- Logger.errorWithTraceId(
204
+ this.logger.errorWithTraceId(
182
205
  ctx.botName,
183
206
  ctx.traceId,
184
207
  chatName,
@@ -193,21 +216,21 @@ export class BotInstance {
193
216
  }
194
217
 
195
218
  private async processMessage(msg: IncomingMessage) {
196
- const ctx = new MessageContext<IActionState>();
219
+ const ctx = new MessageContext<IActionState>(
220
+ this.storage,
221
+ this.logger,
222
+ this.scheduler
223
+ );
197
224
 
198
225
  for (const commandAction of this.commands) {
199
- ctx.initializeMessageContext(
200
- this.name,
201
- commandAction,
202
- msg,
203
- this.storage
204
- );
226
+ ctx.initializeMessageContext(this.name, commandAction, msg);
205
227
 
206
228
  try {
207
229
  const responses = await commandAction.exec(ctx);
208
230
  this.api.enqueueBatchedResponses(responses);
231
+ ctx.isInitialized = false;
209
232
  } catch (error) {
210
- Logger.errorWithTraceId(
233
+ this.logger.errorWithTraceId(
211
234
  ctx.botName,
212
235
  ctx.traceId,
213
236
  ctx.chatInfo.name,
@@ -14,56 +14,61 @@ import { BotResponse } from '../../types/response';
14
14
  import { Milliseconds } from '../../types/timeValues';
15
15
  import { DelayResponse } from '../../dtos/responses/delay';
16
16
  import { ChatInfo } from '../../dtos/chatInfo';
17
+ import { ILogger } from '../../types/logger';
18
+ import { IScheduler } from '../../types/scheduler';
19
+ import { TraceId } from '../../types/trace';
17
20
 
18
21
  /**
19
22
  * Context of action executed in chat.
20
23
  */
21
24
  export class ChatContext<TActionState extends IActionState> {
22
25
  protected action!: IActionWithState<TActionState>;
23
- updateActions: Array<(state: TActionState) => void> = [];
26
+
27
+ /** Storage client instance for the bot executing this action. */
28
+ readonly storage!: IStorageClient;
29
+ /** Logger instance for the bot executing this action */
30
+ readonly logger!: ILogger;
31
+ /** Scheduler instance for the bot executing this action */
32
+ readonly scheduler!: IScheduler;
33
+
24
34
  /** Trace id of a action execution. */
25
- traceId!: number | string;
35
+ traceId!: TraceId;
26
36
  /** Name of a bot that executes this action. */
27
37
  botName!: string;
28
38
  /** Chat information. */
29
39
  chatInfo!: ChatInfo;
30
- /** Storage client instance for this bot. */
31
- storage!: IStorageClient;
32
40
  /** Ordered collection of responses to be processed */
33
41
  responses: BotResponse[] = [];
34
42
 
35
43
  isInitialized = false;
36
44
 
37
- constructor() {}
45
+ constructor(
46
+ storage: IStorageClient,
47
+ logger: ILogger,
48
+ scheduler: IScheduler
49
+ ) {
50
+ this.storage = storage;
51
+ this.logger = logger;
52
+ this.scheduler = scheduler;
53
+ }
38
54
 
39
55
  initializeChatContext(
40
56
  botName: string,
41
57
  action: IActionWithState<TActionState>,
42
58
  chatInfo: ChatInfo,
43
- traceId: number | string,
44
- storage: IStorageClient
59
+ traceId: TraceId
45
60
  ) {
46
61
  this.botName = botName;
47
62
  this.action = action;
48
63
  this.chatInfo = chatInfo;
49
64
  this.traceId = traceId;
50
- this.storage = storage;
51
65
 
52
- this.updateActions = [];
53
66
  this.isInitialized = true;
54
67
  this.responses = [];
55
68
 
56
69
  return this;
57
70
  }
58
71
 
59
- /**
60
- * Manually update the state of an action.
61
- * @param stateUpdateAction Function that will modify state.
62
- */
63
- updateState(stateUpdateAction: (state: TActionState) => void) {
64
- this.updateActions.push(stateUpdateAction);
65
- }
66
-
67
72
  /**
68
73
  * Sends text message to chat after action execution is finished.
69
74
  * If multiple responses are sent, they will be sent in the order they were added, with delay of at least 35ms as per Telegram rate-limit.
@@ -15,6 +15,8 @@ import {
15
15
  } from '../../types/messageSendingOptions';
16
16
  import { IActionWithState, ActionKey } from '../../types/actionWithState';
17
17
  import { MessageTypeValue } from '../../types/messageTypes';
18
+ import { ILogger } from '../../types/logger';
19
+ import { IScheduler } from '../../types/scheduler';
18
20
  /**
19
21
  * Context of action executed in chat, in response to a message
20
22
  */
@@ -36,15 +38,18 @@ export class MessageContext<
36
38
  /** Type of message being received */
37
39
  messageType!: MessageTypeValue;
38
40
 
39
- constructor() {
40
- super();
41
+ constructor(
42
+ storage: IStorageClient,
43
+ logger: ILogger,
44
+ scheduler: IScheduler
45
+ ) {
46
+ super(storage, logger, scheduler);
41
47
  }
42
48
 
43
49
  initializeMessageContext(
44
50
  botName: string,
45
51
  action: IActionWithState<TActionState>,
46
- message: IncomingMessage,
47
- storage: IStorageClient
52
+ message: IncomingMessage
48
53
  ) {
49
54
  this.messageId = message.message_id;
50
55
  this.messageText = message.text ?? '';
@@ -61,8 +66,7 @@ export class MessageContext<
61
66
  botName,
62
67
  action,
63
68
  message.chatInfo,
64
- message.traceId,
65
- storage
69
+ message.traceId
66
70
  );
67
71
  }
68
72
 
package/helpers/noop.ts CHANGED
@@ -1,9 +1,12 @@
1
+ import { BotResponse } from '../types/response';
2
+
1
3
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
4
  export class Noop {
3
- static async true<T1>(arg1: T1) {
5
+ static NoResponse: BotResponse[] = [];
6
+ static true<T1>(arg1: T1) {
4
7
  return true;
5
8
  }
6
- static async false<T1>(arg1: T1) {
9
+ static false<T1>(arg1: T1) {
7
10
  return false;
8
11
  }
9
12
  static async call<T1, T2>(arg1: T1, arg2: T2): Promise<void>;
@@ -0,0 +1,9 @@
1
+ import { TraceId } from '../types/trace';
2
+
3
+ export function createTrace<T extends object>(
4
+ traceOwner: T,
5
+ botName: string,
6
+ traceName: string
7
+ ): TraceId {
8
+ return `${traceOwner.constructor.name}:${botName}-${traceName}`;
9
+ }
package/index.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  export { startBot, stopBots } from './main';
2
2
  export { CommandActionBuilder } from './helpers/builders/commandActionBuilder';
3
3
  export { CommandActionBuilderWithState } from './helpers/builders/commandActionBuilder';
4
- export * from './helpers/builders/scheduledActionBuilder';
5
4
  export { IStorageClient } from './types/storage';
5
+ export { ILogger } from './types/logger';
6
+ export { IScheduler } from './types/scheduler';
7
+ export * from './helpers/builders/scheduledActionBuilder';
6
8
  export * from './types/actionState';
7
9
  export * from './entities/states/actionStateBase';
8
10
  export { Hours, Milliseconds, Seconds } from './types/timeValues';
9
11
  export { MessageType } from './types/messageTypes';
12
+ export { TraceId } from './types/trace';
package/main.ts CHANGED
@@ -1,19 +1,15 @@
1
1
  import { readFile } from 'fs/promises';
2
2
  import { IStorageClient } from './types/storage';
3
- import { Logger } from './services/logger';
4
3
  import { CommandAction } from './entities/actions/commandAction';
5
4
  import { ScheduledAction } from './entities/actions/scheduledAction';
6
5
  import { IActionState } from './types/actionState';
7
- import { Scheduler } from './services/taskScheduler';
8
6
  import { BotInstance } from './entities/botInstance';
9
7
  import { Seconds } from './types/timeValues';
8
+ import { IScheduler } from './types/scheduler';
9
+ import { ILogger } from './types/logger';
10
10
 
11
11
  const bots: BotInstance[] = [];
12
12
 
13
- function log(text: string) {
14
- Logger.logWithTraceId('ALL BOTS', 'System:Bot', 'System', text);
15
- }
16
-
17
13
  /**
18
14
  * Starts bot
19
15
  */
@@ -28,14 +24,20 @@ async function startBot(options: {
28
24
  scheduled: ScheduledAction<IActionState>[];
29
25
  /** Object containing chat name and chat id pairs. Used for logging and execution of scheduled action. */
30
26
  chats: Record<string, number>;
31
- /** Storage client for bot state storage. If not provided, default `JsonFileStorage` will be used. */
32
- storageClient?: IStorageClient;
33
27
  /** 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.*/
34
28
  storagePath?: string;
35
29
  /** Period of time between execution of scheduled actions. */
36
30
  scheduledPeriod?: Seconds;
37
31
  /** If true, telegram API objects will be logged instead of message content. */
38
32
  verboseLoggingForIncomingMessage?: boolean;
33
+ services?: {
34
+ /** Storage client for bot state storage. If not provided, default `JsonFileStorage` will be used. */
35
+ storageClient?: IStorageClient;
36
+ /** Logger client for bot logging. If not provided, default `JsonFileStorage` will be used. */
37
+ logger?: ILogger;
38
+ /** Scheduler client for bot scheduling. If not provided, default `NodeTimeoutScheduler` will be used. */
39
+ scheduler?: IScheduler;
40
+ };
39
41
  }) {
40
42
  const token = await readFile(options.tokenFilePath, 'utf8');
41
43
  const bot = new BotInstance({
@@ -44,11 +46,15 @@ async function startBot(options: {
44
46
  commands: options.commands,
45
47
  scheduled: options.scheduled,
46
48
  chats: options.chats,
47
- storageClient: options.storageClient,
48
49
  storagePath: options.storagePath,
49
50
  scheduledPeriod: options.scheduledPeriod,
50
51
  verboseLoggingForIncomingMessage:
51
- options.verboseLoggingForIncomingMessage
52
+ options.verboseLoggingForIncomingMessage,
53
+ services: {
54
+ storageClient: options.services?.storageClient,
55
+ logger: options.services?.logger,
56
+ scheduler: options.services?.scheduler
57
+ }
52
58
  });
53
59
  bots.push(bot);
54
60
 
@@ -59,11 +65,6 @@ async function startBot(options: {
59
65
  * Terminates all scheduled tasks, closes storage connections and stops all bots.
60
66
  */
61
67
  async function stopBots(reason: string) {
62
- log(`Recieved termination code: ${reason}`);
63
- Scheduler.stopAll();
64
- log('Acquiring storage semaphore...');
65
-
66
- log('Stopping bots...');
67
68
  for (const bot of bots) {
68
69
  await bot.stop(reason);
69
70
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chz-telegram-bot",
3
- "version": "0.0.51",
3
+ "version": "0.0.53",
4
4
  "type": "module",
5
5
  "dependencies": {
6
6
  "async-sema": "^3.1.1",
@@ -3,7 +3,6 @@ import { dirname } from 'path';
3
3
  import { mkdir, readFile, writeFile } from 'fs/promises';
4
4
  import { Sema as Semaphore } from 'async-sema';
5
5
  import { IStorageClient } from '../types/storage';
6
- import { ActionExecutionResult } from '../dtos/actionExecutionResult';
7
6
  import { IActionState } from '../types/actionState';
8
7
  import { IActionWithState, ActionKey } from '../types/actionWithState';
9
8
 
@@ -129,15 +128,14 @@ export class JsonFileStorage implements IStorageClient {
129
128
  async saveActionExecutionResult<TActionState extends IActionState>(
130
129
  action: IActionWithState<TActionState>,
131
130
  chatId: number,
132
- transactionResult: ActionExecutionResult<TActionState>
131
+ state: TActionState
133
132
  ) {
134
133
  await this.lock(action.key, async () => {
135
134
  const data = await this.loadInternal<TActionState>(action.key);
136
135
 
137
- if (transactionResult.shouldUpdate) {
138
- data[chatId] = transactionResult.data;
139
- await this.save(data, action.key);
140
- }
136
+ data[chatId] = state;
137
+
138
+ await this.save(data, action.key);
141
139
  });
142
140
  }
143
141
 
@@ -1,4 +1,7 @@
1
- class JsonLogger {
1
+ import { ILogger } from '../types/logger';
2
+ import { TraceId } from '../types/trace';
3
+
4
+ export class JsonLogger implements ILogger {
2
5
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
6
  private serializeError(error: any) {
4
7
  const plainObject: Record<string, unknown> = {};
@@ -10,7 +13,7 @@ class JsonLogger {
10
13
 
11
14
  logObjectWithTraceId(
12
15
  botName: string,
13
- traceId: string | number,
16
+ traceId: TraceId,
14
17
  chatName: string,
15
18
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
19
  data: any
@@ -23,7 +26,7 @@ class JsonLogger {
23
26
 
24
27
  logWithTraceId(
25
28
  botName: string,
26
- traceId: string | number,
29
+ traceId: TraceId,
27
30
  chatName: string,
28
31
  text: string
29
32
  ) {
@@ -34,7 +37,7 @@ class JsonLogger {
34
37
 
35
38
  errorWithTraceId<TData>(
36
39
  botName: string,
37
- traceId: string | number,
40
+ traceId: TraceId,
38
41
  chatName: string,
39
42
  errorObj: unknown,
40
43
  extraData?: TData | undefined
@@ -46,5 +49,3 @@ class JsonLogger {
46
49
  );
47
50
  }
48
51
  }
49
-
50
- export const Logger = new JsonLogger();
@@ -1,10 +1,17 @@
1
1
  import { TaskRecord } from '../entities/taskRecord';
2
+ import { createTrace } from '../helpers/traceFactory';
3
+ import { ILogger } from '../types/logger';
4
+ import { IScheduler } from '../types/scheduler';
2
5
  import { Milliseconds } from '../types/timeValues';
3
- import { Logger } from './logger';
4
6
 
5
- class TaskScheduler {
7
+ export class NodeTimeoutScheduler implements IScheduler {
8
+ private readonly logger!: ILogger;
6
9
  readonly activeTasks: TaskRecord[] = [];
7
10
 
11
+ constructor(logger: ILogger) {
12
+ this.logger = logger;
13
+ }
14
+
8
15
  stopAll() {
9
16
  this.activeTasks.forEach((task) => {
10
17
  clearInterval(task.taskId);
@@ -25,9 +32,9 @@ class TaskScheduler {
25
32
  setImmediate(action);
26
33
  }
27
34
 
28
- Logger.logWithTraceId(
35
+ this.logger.logWithTraceId(
29
36
  ownerName,
30
- `System:TaskScheduler-${ownerName}-${name}`,
37
+ createTrace(this, ownerName, name),
31
38
  'System',
32
39
  `Created task [${taskId}]${name}, that will run every ${interval}ms.`
33
40
  );
@@ -42,9 +49,9 @@ class TaskScheduler {
42
49
  ownerName: string
43
50
  ) {
44
51
  const actionWrapper = () => {
45
- Logger.logWithTraceId(
52
+ this.logger.logWithTraceId(
46
53
  ownerName,
47
- `System:TaskScheduler-${ownerName}-${name}`,
54
+ createTrace(this, ownerName, name),
48
55
  'System',
49
56
  `Executing delayed oneshot [${taskId}]${name}`
50
57
  );
@@ -52,13 +59,11 @@ class TaskScheduler {
52
59
  };
53
60
  const taskId = setTimeout(actionWrapper, delay);
54
61
 
55
- Logger.logWithTraceId(
62
+ this.logger.logWithTraceId(
56
63
  ownerName,
57
- `System:TaskScheduler-${ownerName}-${name}`,
64
+ createTrace(this, ownerName, name),
58
65
  'System',
59
66
  `Created oneshot task [${taskId}]${name}, that will run in ${delay}ms.`
60
67
  );
61
68
  }
62
69
  }
63
-
64
- export const Scheduler = new TaskScheduler();
@@ -1,25 +1,32 @@
1
1
  import { Message } from 'telegraf/types';
2
2
  import { IStorageClient } from '../types/storage';
3
- import { Logger } from './logger';
4
3
  import { BotResponse, IReplyMessage } from '../types/response';
5
4
  import { Telegram } from 'telegraf/typings/telegram';
6
5
  import { setTimeout } from 'timers/promises';
7
6
  import { Milliseconds } from '../types/timeValues';
7
+ import { ILogger } from '../types/logger';
8
8
 
9
9
  const TELEGRAM_RATELIMIT_DELAY = 35 as Milliseconds;
10
10
 
11
11
  export class TelegramApiService {
12
- isFlushing = false;
13
- readonly messageQueue: BotResponse[] = [];
12
+ private readonly telegram: Telegram;
13
+ private readonly storage: IStorageClient;
14
+ private readonly logger: ILogger;
14
15
 
15
- readonly botName: string;
16
- readonly telegram: Telegram;
17
- readonly storage: IStorageClient;
16
+ private readonly botName: string;
17
+ private readonly messageQueue: BotResponse[] = [];
18
+ isFlushing = false;
18
19
 
19
- constructor(botName: string, telegram: Telegram, storage: IStorageClient) {
20
+ constructor(
21
+ botName: string,
22
+ telegram: Telegram,
23
+ storage: IStorageClient,
24
+ logger: ILogger
25
+ ) {
20
26
  this.telegram = telegram;
21
27
  this.botName = botName;
22
28
  this.storage = storage;
29
+ this.logger = logger;
23
30
  }
24
31
 
25
32
  enqueueBatchedResponses(responses: BotResponse[]) {
@@ -42,7 +49,7 @@ export class TelegramApiService {
42
49
  await this.processResponse(message);
43
50
  await setTimeout(TELEGRAM_RATELIMIT_DELAY);
44
51
  } catch (error) {
45
- Logger.errorWithTraceId(
52
+ this.logger.errorWithTraceId(
46
53
  this.botName,
47
54
  message.traceId,
48
55
  message.chatInfo.name,
@@ -3,4 +3,4 @@ import { IActionState } from './actionState';
3
3
 
4
4
  export type CommandCondition<TActionState extends IActionState> = (
5
5
  ctx: MessageContext<TActionState>
6
- ) => Promise<boolean>;
6
+ ) => boolean;
@@ -0,0 +1,26 @@
1
+ import { TraceId } from './trace';
2
+
3
+ export interface ILogger {
4
+ logObjectWithTraceId(
5
+ botName: string,
6
+ traceId: TraceId,
7
+ chatName: string,
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ data: any
10
+ ): void;
11
+
12
+ logWithTraceId(
13
+ botName: string,
14
+ traceId: TraceId,
15
+ chatName: string,
16
+ text: string
17
+ ): void;
18
+
19
+ errorWithTraceId<TData>(
20
+ botName: string,
21
+ traceId: TraceId,
22
+ chatName: string,
23
+ errorObj: unknown,
24
+ extraData?: TData | undefined
25
+ ): void;
26
+ }