chz-telegram-bot 0.5.5 → 0.6.8
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/README.md +41 -31
- package/dist/entities/actions/commandAction.d.ts.map +1 -1
- package/dist/entities/actions/commandAction.js +11 -1
- package/dist/entities/actions/inlineQueryAction.d.ts.map +1 -1
- package/dist/entities/actions/inlineQueryAction.js +9 -1
- package/dist/entities/actions/replyCaptureAction.d.ts.map +1 -1
- package/dist/entities/actions/replyCaptureAction.js +9 -1
- package/dist/entities/actions/scheduledAction.d.ts.map +1 -1
- package/dist/entities/actions/scheduledAction.js +24 -4
- package/dist/entities/botInstance.d.ts +3 -4
- package/dist/entities/botInstance.d.ts.map +1 -1
- package/dist/entities/botInstance.js +13 -11
- package/dist/entities/context/baseContext.d.ts +4 -4
- package/dist/entities/context/baseContext.d.ts.map +1 -1
- package/dist/entities/context/baseContext.js +3 -2
- package/dist/eslint.config.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/main.d.ts +0 -3
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +1 -2
- package/dist/services/actionProcessingService.d.ts +4 -4
- package/dist/services/actionProcessingService.d.ts.map +1 -1
- package/dist/services/actionProcessingService.js +10 -10
- package/dist/services/actionProcessors/baseProcessor.d.ts +3 -3
- package/dist/services/actionProcessors/baseProcessor.d.ts.map +1 -1
- package/dist/services/actionProcessors/baseProcessor.js +9 -5
- package/dist/services/actionProcessors/commandActionProcessor.d.ts +2 -3
- package/dist/services/actionProcessors/commandActionProcessor.d.ts.map +1 -1
- package/dist/services/actionProcessors/commandActionProcessor.js +32 -18
- package/dist/services/actionProcessors/inlineQueryActionProcessor.d.ts.map +1 -1
- package/dist/services/actionProcessors/inlineQueryActionProcessor.js +16 -8
- package/dist/services/actionProcessors/scheduledActionProcessor.d.ts +2 -2
- package/dist/services/actionProcessors/scheduledActionProcessor.d.ts.map +1 -1
- package/dist/services/actionProcessors/scheduledActionProcessor.js +3 -4
- package/dist/services/jsonFileStorage.d.ts +3 -1
- package/dist/services/jsonFileStorage.d.ts.map +1 -1
- package/dist/services/jsonFileStorage.js +26 -2
- package/dist/services/nodeTimeoutScheduler.d.ts +3 -3
- package/dist/services/nodeTimeoutScheduler.d.ts.map +1 -1
- package/dist/services/nodeTimeoutScheduler.js +27 -8
- package/dist/services/telegramApi.d.ts +4 -4
- package/dist/services/telegramApi.d.ts.map +1 -1
- package/dist/services/telegramApi.js +39 -9
- package/dist/types/events.d.ts +193 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +69 -0
- package/dist/types/logger.d.ts +0 -12
- package/dist/types/logger.d.ts.map +1 -1
- package/dist/types/logger.js +1 -1
- package/entities/actions/commandAction.ts +11 -3
- package/entities/actions/inlineQueryAction.ts +9 -1
- package/entities/actions/replyCaptureAction.ts +9 -3
- package/entities/actions/scheduledAction.ts +31 -10
- package/entities/botInstance.ts +18 -25
- package/entities/context/baseContext.ts +9 -4
- package/index.ts +1 -1
- package/main.ts +1 -10
- package/package.json +1 -1
- package/services/actionProcessingService.ts +11 -15
- package/services/actionProcessors/baseProcessor.ts +9 -9
- package/services/actionProcessors/commandActionProcessor.ts +35 -46
- package/services/actionProcessors/inlineQueryActionProcessor.ts +24 -20
- package/services/actionProcessors/scheduledActionProcessor.ts +5 -10
- package/services/jsonFileStorage.ts +27 -1
- package/services/nodeTimeoutScheduler.ts +22 -22
- package/services/telegramApi.ts +53 -23
- package/types/events.ts +285 -0
- package/dist/services/jsonLogger.d.ts +0 -11
- package/dist/services/jsonLogger.d.ts.map +0 -1
- package/dist/services/jsonLogger.js +0 -66
- package/services/jsonLogger.ts +0 -112
- package/types/logger.ts +0 -39
|
@@ -5,12 +5,14 @@ import { IStorageClient } from '../types/storage';
|
|
|
5
5
|
import { IActionState } from '../types/actionState';
|
|
6
6
|
import { IActionWithState, ActionKey } from '../types/action';
|
|
7
7
|
import { getOrSetIfNotExists } from '../helpers/mapUtils';
|
|
8
|
+
import { BotEventType, TypedEventEmitter } from '../types/events';
|
|
8
9
|
|
|
9
10
|
function buildPath(storagePath: string, botName: string, actionKey: string) {
|
|
10
11
|
return `${storagePath}/${botName}/${actionKey.replaceAll(':', '/')}.json`;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export class JsonFileStorage implements IStorageClient {
|
|
15
|
+
private readonly eventEmitter: TypedEventEmitter;
|
|
14
16
|
private readonly filePaths = new Map<ActionKey, string>();
|
|
15
17
|
private readonly locks = new Map<ActionKey, Semaphore>();
|
|
16
18
|
private readonly cache: Map<string, Record<number, IActionState>>;
|
|
@@ -20,8 +22,10 @@ export class JsonFileStorage implements IStorageClient {
|
|
|
20
22
|
constructor(
|
|
21
23
|
botName: string,
|
|
22
24
|
actions: IActionWithState<IActionState>[],
|
|
25
|
+
eventEmitter: TypedEventEmitter,
|
|
23
26
|
path?: string
|
|
24
27
|
) {
|
|
28
|
+
this.eventEmitter = eventEmitter;
|
|
25
29
|
this.cache = new Map<string, Record<number, IActionState>>();
|
|
26
30
|
this.botName = botName;
|
|
27
31
|
this.storagePath = path ?? 'storage';
|
|
@@ -57,12 +61,15 @@ export class JsonFileStorage implements IStorageClient {
|
|
|
57
61
|
private async lock<TType>(key: ActionKey, action: () => Promise<TType>) {
|
|
58
62
|
const lock = getOrSetIfNotExists(this.locks, key, new Semaphore(1));
|
|
59
63
|
|
|
64
|
+
this.eventEmitter.emit(BotEventType.storageLockAcquiring, key);
|
|
60
65
|
await lock.acquire();
|
|
66
|
+
this.eventEmitter.emit(BotEventType.storageLockAcquired, key);
|
|
61
67
|
|
|
62
68
|
try {
|
|
63
69
|
return await action();
|
|
64
70
|
} finally {
|
|
65
71
|
lock.release();
|
|
72
|
+
this.eventEmitter.emit(BotEventType.storageLockReleased, key);
|
|
66
73
|
}
|
|
67
74
|
}
|
|
68
75
|
|
|
@@ -103,6 +110,10 @@ export class JsonFileStorage implements IStorageClient {
|
|
|
103
110
|
data: Record<number, TActionState>,
|
|
104
111
|
key: ActionKey
|
|
105
112
|
) {
|
|
113
|
+
this.eventEmitter.emit(BotEventType.storageStateSaving, {
|
|
114
|
+
data,
|
|
115
|
+
key
|
|
116
|
+
});
|
|
106
117
|
this.cache.set(key, data);
|
|
107
118
|
|
|
108
119
|
const targetPath = getOrSetIfNotExists(
|
|
@@ -112,6 +123,10 @@ export class JsonFileStorage implements IStorageClient {
|
|
|
112
123
|
);
|
|
113
124
|
|
|
114
125
|
await writeFile(targetPath, JSON.stringify(data), { flag: 'w+' });
|
|
126
|
+
this.eventEmitter.emit(BotEventType.storageStateSaved, {
|
|
127
|
+
data,
|
|
128
|
+
key
|
|
129
|
+
});
|
|
115
130
|
}
|
|
116
131
|
|
|
117
132
|
async load<TActionState extends IActionState>(key: ActionKey) {
|
|
@@ -135,13 +150,24 @@ export class JsonFileStorage implements IStorageClient {
|
|
|
135
150
|
action: IActionWithState<TActionState>,
|
|
136
151
|
chatId: number
|
|
137
152
|
) {
|
|
153
|
+
this.eventEmitter.emit(BotEventType.storageStateLoading, {
|
|
154
|
+
action,
|
|
155
|
+
chatId
|
|
156
|
+
});
|
|
138
157
|
const value =
|
|
139
158
|
this.tryGetFromCache<TActionState>(action.key) ??
|
|
140
159
|
(await this.lock(action.key, async () => {
|
|
141
160
|
return await this.loadFromFile<TActionState>(action.key);
|
|
142
161
|
}));
|
|
143
162
|
|
|
144
|
-
|
|
163
|
+
const result = Object.assign(action.stateConstructor(), value[chatId]);
|
|
164
|
+
|
|
165
|
+
this.eventEmitter.emit(BotEventType.storageStateLoaded, {
|
|
166
|
+
action,
|
|
167
|
+
chatId,
|
|
168
|
+
state: result
|
|
169
|
+
});
|
|
170
|
+
return result;
|
|
145
171
|
}
|
|
146
172
|
|
|
147
173
|
async saveActionExecutionResult<TActionState extends IActionState>(
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { TaskRecord } from '../entities/taskRecord';
|
|
2
|
-
import {
|
|
3
|
-
import { ILogger } from '../types/logger';
|
|
2
|
+
import { BotEventType, TypedEventEmitter } from '../types/events';
|
|
4
3
|
import { IScheduler } from '../types/scheduler';
|
|
5
4
|
import { Milliseconds } from '../types/timeValues';
|
|
6
5
|
|
|
7
6
|
export class NodeTimeoutScheduler implements IScheduler {
|
|
8
|
-
private readonly logger!: ILogger;
|
|
9
7
|
readonly activeTasks: TaskRecord[] = [];
|
|
10
8
|
|
|
11
|
-
constructor(
|
|
12
|
-
this.logger = logger;
|
|
13
|
-
}
|
|
9
|
+
constructor(readonly eventEmitter: TypedEventEmitter) {}
|
|
14
10
|
|
|
15
11
|
stopAll() {
|
|
16
12
|
for (const task of this.activeTasks) {
|
|
@@ -25,19 +21,25 @@ export class NodeTimeoutScheduler implements IScheduler {
|
|
|
25
21
|
executeRightAway: boolean,
|
|
26
22
|
ownerName: string
|
|
27
23
|
) {
|
|
28
|
-
const taskId = setInterval(
|
|
24
|
+
const taskId = setInterval(() => {
|
|
25
|
+
action();
|
|
26
|
+
this.eventEmitter.emit(BotEventType.taskRun, {
|
|
27
|
+
name,
|
|
28
|
+
ownerName,
|
|
29
|
+
interval
|
|
30
|
+
});
|
|
31
|
+
}, interval);
|
|
29
32
|
const task = new TaskRecord(name, taskId, interval);
|
|
30
33
|
|
|
31
34
|
if (executeRightAway) {
|
|
32
35
|
setImmediate(action);
|
|
33
36
|
}
|
|
34
37
|
|
|
35
|
-
this.
|
|
38
|
+
this.eventEmitter.emit(BotEventType.taskCreated, {
|
|
39
|
+
name,
|
|
36
40
|
ownerName,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
`Created task ${name}, that will run every ${interval}ms.`
|
|
40
|
-
);
|
|
41
|
+
interval
|
|
42
|
+
});
|
|
41
43
|
|
|
42
44
|
this.activeTasks.push(task);
|
|
43
45
|
}
|
|
@@ -49,21 +51,19 @@ export class NodeTimeoutScheduler implements IScheduler {
|
|
|
49
51
|
ownerName: string
|
|
50
52
|
) {
|
|
51
53
|
const actionWrapper = () => {
|
|
52
|
-
this.
|
|
54
|
+
this.eventEmitter.emit(BotEventType.taskRun, {
|
|
55
|
+
name,
|
|
53
56
|
ownerName,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
`Executing delayed oneshot ${name}`
|
|
57
|
-
);
|
|
57
|
+
delay
|
|
58
|
+
});
|
|
58
59
|
action();
|
|
59
60
|
};
|
|
60
61
|
setTimeout(actionWrapper, delay);
|
|
61
62
|
|
|
62
|
-
this.
|
|
63
|
+
this.eventEmitter.emit(BotEventType.taskCreated, {
|
|
64
|
+
name,
|
|
63
65
|
ownerName,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
`Created oneshot task ${name}, that will run in ${delay}ms.`
|
|
67
|
-
);
|
|
66
|
+
delay
|
|
67
|
+
});
|
|
68
68
|
}
|
|
69
69
|
}
|
package/services/telegramApi.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { IStorageClient } from '../types/storage';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
BotResponse,
|
|
4
|
+
BotResponseTypes,
|
|
5
|
+
IReplyResponse
|
|
6
|
+
} from '../types/response';
|
|
4
7
|
import { QueueItem, ResponseProcessingQueue } from './responseProcessingQueue';
|
|
5
8
|
import { IReplyCapture } from '../types/capture';
|
|
6
9
|
import { IActionWithState } from '../types/action';
|
|
@@ -8,6 +11,7 @@ import { IActionState } from '../types/actionState';
|
|
|
8
11
|
import { TraceId } from '../types/trace';
|
|
9
12
|
import { ChatInfo } from '../dtos/chatInfo';
|
|
10
13
|
import { TelegramApiClient, TelegramMessage } from '../types/externalAliases';
|
|
14
|
+
import { BotEventType, TypedEventEmitter } from '../types/events';
|
|
11
15
|
|
|
12
16
|
export const TELEGRAM_ERROR_QUOTE_INVALID = 'QUOTE_TEXT_INVALID';
|
|
13
17
|
|
|
@@ -15,7 +19,7 @@ export class TelegramApiService {
|
|
|
15
19
|
private readonly queue = new ResponseProcessingQueue();
|
|
16
20
|
private readonly telegram: TelegramApiClient;
|
|
17
21
|
private readonly storage: IStorageClient;
|
|
18
|
-
private readonly
|
|
22
|
+
private readonly eventEmitter: TypedEventEmitter;
|
|
19
23
|
private readonly captureRegistrationCallback: (
|
|
20
24
|
capture: IReplyCapture,
|
|
21
25
|
parentMessageId: number,
|
|
@@ -25,22 +29,35 @@ export class TelegramApiService {
|
|
|
25
29
|
|
|
26
30
|
private readonly botName: string;
|
|
27
31
|
|
|
32
|
+
private readonly methodMap: Record<
|
|
33
|
+
'pin' | keyof typeof BotResponseTypes,
|
|
34
|
+
string | null
|
|
35
|
+
> = {
|
|
36
|
+
inlineQuery: 'answerInlineQuery',
|
|
37
|
+
text: 'sendMessage',
|
|
38
|
+
react: 'setMessageReaction',
|
|
39
|
+
unpin: 'unpinChatMessage',
|
|
40
|
+
pin: 'pinChatMessage',
|
|
41
|
+
image: 'sendPhoto',
|
|
42
|
+
video: 'sendVideo',
|
|
43
|
+
delay: null
|
|
44
|
+
};
|
|
45
|
+
|
|
28
46
|
constructor(
|
|
29
47
|
botName: string,
|
|
30
48
|
telegram: TelegramApiClient,
|
|
31
49
|
storage: IStorageClient,
|
|
32
|
-
|
|
50
|
+
eventEmitter: TypedEventEmitter,
|
|
33
51
|
captureRegistrationCallback: (
|
|
34
52
|
capture: IReplyCapture,
|
|
35
53
|
parentMessageId: number,
|
|
36
|
-
chatInfo: ChatInfo
|
|
37
|
-
traceId: TraceId
|
|
54
|
+
chatInfo: ChatInfo
|
|
38
55
|
) => void
|
|
39
56
|
) {
|
|
40
57
|
this.telegram = telegram;
|
|
41
58
|
this.botName = botName;
|
|
42
59
|
this.storage = storage;
|
|
43
|
-
this.
|
|
60
|
+
this.eventEmitter = eventEmitter;
|
|
44
61
|
this.captureRegistrationCallback = captureRegistrationCallback;
|
|
45
62
|
}
|
|
46
63
|
|
|
@@ -54,14 +71,6 @@ export class TelegramApiService {
|
|
|
54
71
|
|
|
55
72
|
const queueItem: QueueItem = {
|
|
56
73
|
callback: async () => {
|
|
57
|
-
const scopedLogger = this.logger.createScope(
|
|
58
|
-
this.botName,
|
|
59
|
-
response.traceId,
|
|
60
|
-
'chatInfo' in response
|
|
61
|
-
? response.chatInfo.name
|
|
62
|
-
: 'Unknown'
|
|
63
|
-
);
|
|
64
|
-
|
|
65
74
|
try {
|
|
66
75
|
await this.processResponse(response);
|
|
67
76
|
} catch (error) {
|
|
@@ -75,23 +84,27 @@ export class TelegramApiService {
|
|
|
75
84
|
TELEGRAM_ERROR_QUOTE_INVALID
|
|
76
85
|
)
|
|
77
86
|
) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
this.eventEmitter.emit(BotEventType.error, {
|
|
88
|
+
error: new Error(
|
|
89
|
+
'Quote error recieved, retrying without quote'
|
|
90
|
+
)
|
|
91
|
+
});
|
|
92
|
+
|
|
81
93
|
try {
|
|
82
94
|
await this.processResponse(response, true);
|
|
83
95
|
} catch (error) {
|
|
84
|
-
|
|
85
|
-
error
|
|
86
|
-
|
|
87
|
-
);
|
|
96
|
+
this.eventEmitter.emit(BotEventType.error, {
|
|
97
|
+
error: error as Error
|
|
98
|
+
});
|
|
88
99
|
}
|
|
89
100
|
|
|
90
101
|
return;
|
|
91
102
|
}
|
|
92
103
|
}
|
|
93
104
|
|
|
94
|
-
|
|
105
|
+
this.eventEmitter.emit(BotEventType.error, {
|
|
106
|
+
error: error as Error
|
|
107
|
+
});
|
|
95
108
|
}
|
|
96
109
|
},
|
|
97
110
|
priority: response.createdAt + offset
|
|
@@ -109,11 +122,19 @@ export class TelegramApiService {
|
|
|
109
122
|
message: TelegramMessage
|
|
110
123
|
) {
|
|
111
124
|
if (response.shouldPin) {
|
|
125
|
+
this.eventEmitter.emit(BotEventType.apiRequestSending, {
|
|
126
|
+
response: null,
|
|
127
|
+
telegramMethod: this.methodMap['pin']
|
|
128
|
+
});
|
|
112
129
|
await this.telegram.pinChatMessage(
|
|
113
130
|
response.chatInfo.id,
|
|
114
131
|
message.message_id,
|
|
115
132
|
{ disable_notification: true }
|
|
116
133
|
);
|
|
134
|
+
this.eventEmitter.emit(BotEventType.apiRequestSent, {
|
|
135
|
+
response: null,
|
|
136
|
+
telegramMethod: this.methodMap['pin']
|
|
137
|
+
});
|
|
117
138
|
|
|
118
139
|
await this.storage.updateStateFor(
|
|
119
140
|
response.action as IActionWithState<IActionState>,
|
|
@@ -127,6 +148,10 @@ export class TelegramApiService {
|
|
|
127
148
|
|
|
128
149
|
private async processResponse(response: BotResponse, ignoreQuote = false) {
|
|
129
150
|
const sentMessage = await this.sendApiRequest(response, ignoreQuote);
|
|
151
|
+
this.eventEmitter.emit(BotEventType.apiRequestSent, {
|
|
152
|
+
response,
|
|
153
|
+
telegramMethod: this.methodMap[response.kind]
|
|
154
|
+
});
|
|
130
155
|
|
|
131
156
|
if (sentMessage && 'content' in response) {
|
|
132
157
|
await this.pinIfShould(response, sentMessage);
|
|
@@ -146,6 +171,11 @@ export class TelegramApiService {
|
|
|
146
171
|
response: BotResponse,
|
|
147
172
|
ignoreQuote: boolean
|
|
148
173
|
): Promise<TelegramMessage | null> {
|
|
174
|
+
this.eventEmitter.emit(BotEventType.apiRequestSending, {
|
|
175
|
+
response,
|
|
176
|
+
telegramMethod: this.methodMap[response.kind]
|
|
177
|
+
});
|
|
178
|
+
|
|
149
179
|
switch (response.kind) {
|
|
150
180
|
case 'text':
|
|
151
181
|
return await this.telegram.sendMessage(
|
package/types/events.ts
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { ChatInfo } from '../dtos/chatInfo';
|
|
2
|
+
import { IncomingMessage } from '../dtos/incomingMessage';
|
|
3
|
+
import { IncomingInlineQuery } from '../dtos/incomingQuery';
|
|
4
|
+
import { CommandAction } from '../entities/actions/commandAction';
|
|
5
|
+
import { ChatContext } from '../entities/context/chatContext';
|
|
6
|
+
import { InlineQueryContext } from '../entities/context/inlineQueryContext';
|
|
7
|
+
import { MessageContext } from '../entities/context/messageContext';
|
|
8
|
+
import { ReplyContext } from '../entities/context/replyContext';
|
|
9
|
+
import { ActionKey, IAction, IActionWithState } from './action';
|
|
10
|
+
import { IActionState } from './actionState';
|
|
11
|
+
import { BotInfo } from './externalAliases';
|
|
12
|
+
import { BotResponse } from './response';
|
|
13
|
+
import { Milliseconds } from './timeValues';
|
|
14
|
+
|
|
15
|
+
export const BotEventType = {
|
|
16
|
+
error: 'error.generic',
|
|
17
|
+
|
|
18
|
+
messageRecieved: 'message.recieved',
|
|
19
|
+
messageProcessingStarted: 'message.processingStarted',
|
|
20
|
+
messageProcessingFinished: 'message.processingFinished',
|
|
21
|
+
beforeActionsExecuting: 'message.beforeActionsExecuting',
|
|
22
|
+
|
|
23
|
+
commandActionExecuting: 'command.actionExecuting',
|
|
24
|
+
commandActionExecuted: 'command.actionExecuted',
|
|
25
|
+
commandActionCaptureStarted: 'command.captionStarted',
|
|
26
|
+
commandActionCaptureAborted: 'command.captionAborted',
|
|
27
|
+
|
|
28
|
+
replyActionExecuting: 'reply.actionExecuting',
|
|
29
|
+
replyActionExecuted: 'reply.actionExecuted',
|
|
30
|
+
|
|
31
|
+
inlineActionExecuting: 'inline.actionExecuting',
|
|
32
|
+
inlineActionExecuted: 'inline.actionExecuted',
|
|
33
|
+
inlineProcessingStarted: 'inline.processingStarted',
|
|
34
|
+
inlineProcessingAborting: 'inline.processingAborting',
|
|
35
|
+
inlineProcessingAborted: 'inline.processingAborted',
|
|
36
|
+
|
|
37
|
+
scheduledActionExecuting: 'scheduled.actionExecuting',
|
|
38
|
+
scheduledActionExecuted: 'scheduled.actionExecuted',
|
|
39
|
+
scheduledActionCacheValueReturned: 'scheduled.cachedValueReturned',
|
|
40
|
+
scheduledActionCacheValueCreating: 'scheduled.cachedValueCreating',
|
|
41
|
+
|
|
42
|
+
apiRequestSending: 'api.requestSending',
|
|
43
|
+
apiRequestSent: 'api.requestSent',
|
|
44
|
+
|
|
45
|
+
storageLockAcquiring: 'storage.lockAcquiring',
|
|
46
|
+
storageLockAcquired: 'storage.lockAcquired',
|
|
47
|
+
storageLockReleased: 'storage.lockReleased',
|
|
48
|
+
storageStateSaving: 'storage.stateSaving',
|
|
49
|
+
storageStateSaved: 'storage.stateSaved',
|
|
50
|
+
storageStateLoading: 'storage.stateLoading',
|
|
51
|
+
storageStateLoaded: 'storage.stateLoaded',
|
|
52
|
+
|
|
53
|
+
taskCreated: 'task.created',
|
|
54
|
+
taskRun: 'task.run',
|
|
55
|
+
|
|
56
|
+
botStarting: 'bot.starting',
|
|
57
|
+
botStopping: 'bot.stopping'
|
|
58
|
+
} as const;
|
|
59
|
+
|
|
60
|
+
type BotEventTypeKeys = (typeof BotEventType)[keyof typeof BotEventType];
|
|
61
|
+
// Exhaustiveness validation
|
|
62
|
+
const _checkBotEventMapExhaustive: Record<BotEventTypeKeys, unknown> =
|
|
63
|
+
null as unknown as BotEventMap;
|
|
64
|
+
|
|
65
|
+
export type BotEventMap = {
|
|
66
|
+
[BotEventType.error]: {
|
|
67
|
+
error: Error;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
[BotEventType.messageRecieved]: {
|
|
71
|
+
botInfo: BotInfo;
|
|
72
|
+
message: IncomingMessage;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
[BotEventType.messageProcessingStarted]: {
|
|
76
|
+
botInfo: BotInfo;
|
|
77
|
+
message: IncomingMessage;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
[BotEventType.messageProcessingFinished]: {
|
|
81
|
+
botInfo: BotInfo;
|
|
82
|
+
message: IncomingMessage;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
[BotEventType.beforeActionsExecuting]: {
|
|
86
|
+
botInfo: BotInfo;
|
|
87
|
+
message: IncomingMessage;
|
|
88
|
+
commands: Set<CommandAction<IActionState>>;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
[BotEventType.commandActionExecuting]: {
|
|
92
|
+
action: IActionWithState<IActionState>;
|
|
93
|
+
ctx: MessageContext<IActionState>;
|
|
94
|
+
state: IActionState;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
[BotEventType.commandActionExecuted]: {
|
|
98
|
+
action: IActionWithState<IActionState>;
|
|
99
|
+
ctx: MessageContext<IActionState>;
|
|
100
|
+
state: IActionState;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
[BotEventType.commandActionCaptureStarted]: {
|
|
104
|
+
parentMessageId: number;
|
|
105
|
+
chatInfo: ChatInfo;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
[BotEventType.commandActionCaptureAborted]: {
|
|
109
|
+
parentMessageId: number;
|
|
110
|
+
chatInfo: ChatInfo;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
[BotEventType.replyActionExecuting]: {
|
|
114
|
+
action: IAction;
|
|
115
|
+
ctx: ReplyContext<IActionState>;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
[BotEventType.replyActionExecuted]: {
|
|
119
|
+
action: IAction;
|
|
120
|
+
ctx: ReplyContext<IActionState>;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
[BotEventType.inlineActionExecuting]: {
|
|
124
|
+
action: IAction;
|
|
125
|
+
ctx: InlineQueryContext;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
[BotEventType.inlineActionExecuted]: {
|
|
129
|
+
action: IAction;
|
|
130
|
+
ctx: InlineQueryContext;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
[BotEventType.inlineProcessingStarted]: {
|
|
134
|
+
query: IncomingInlineQuery;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
[BotEventType.inlineProcessingAborting]: {
|
|
138
|
+
abortedQuery: IncomingInlineQuery;
|
|
139
|
+
newQuery: IncomingInlineQuery;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
[BotEventType.inlineProcessingAborted]: {
|
|
143
|
+
abortedQuery: IncomingInlineQuery;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
[BotEventType.scheduledActionExecuting]: {
|
|
147
|
+
action: IAction;
|
|
148
|
+
ctx: ChatContext<IActionState>;
|
|
149
|
+
state: IActionState;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
[BotEventType.scheduledActionExecuted]: {
|
|
153
|
+
action: IAction;
|
|
154
|
+
ctx: ChatContext<IActionState>;
|
|
155
|
+
state: IActionState;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
[BotEventType.scheduledActionCacheValueCreating]: {
|
|
159
|
+
action: IAction;
|
|
160
|
+
ctx: ChatContext<IActionState>;
|
|
161
|
+
key: string;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
[BotEventType.scheduledActionCacheValueReturned]: {
|
|
165
|
+
action: IAction;
|
|
166
|
+
ctx: ChatContext<IActionState>;
|
|
167
|
+
key: string;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
[BotEventType.apiRequestSending]: {
|
|
171
|
+
response: BotResponse | null;
|
|
172
|
+
telegramMethod: string | null;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
[BotEventType.apiRequestSent]: {
|
|
176
|
+
response: BotResponse | null;
|
|
177
|
+
telegramMethod: string | null;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
[BotEventType.storageLockAcquiring]: ActionKey;
|
|
181
|
+
[BotEventType.storageLockAcquired]: ActionKey;
|
|
182
|
+
[BotEventType.storageLockReleased]: ActionKey;
|
|
183
|
+
[BotEventType.storageStateSaved]: {
|
|
184
|
+
key: ActionKey;
|
|
185
|
+
data: Record<number, unknown>;
|
|
186
|
+
};
|
|
187
|
+
[BotEventType.storageStateSaving]: {
|
|
188
|
+
key: ActionKey;
|
|
189
|
+
data: Record<number, unknown>;
|
|
190
|
+
};
|
|
191
|
+
[BotEventType.storageStateLoading]: {
|
|
192
|
+
action: IActionWithState<IActionState>;
|
|
193
|
+
chatId: number;
|
|
194
|
+
};
|
|
195
|
+
[BotEventType.storageStateLoaded]: {
|
|
196
|
+
action: IActionWithState<IActionState>;
|
|
197
|
+
chatId: number;
|
|
198
|
+
state: IActionState;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
[BotEventType.taskCreated]: {
|
|
202
|
+
name: string;
|
|
203
|
+
ownerName: string;
|
|
204
|
+
delay?: Milliseconds;
|
|
205
|
+
interval?: Milliseconds;
|
|
206
|
+
};
|
|
207
|
+
[BotEventType.taskRun]: {
|
|
208
|
+
name: string;
|
|
209
|
+
ownerName: string;
|
|
210
|
+
delay?: Milliseconds;
|
|
211
|
+
interval?: Milliseconds;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
[BotEventType.botStarting]: {
|
|
215
|
+
botName: string;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
[BotEventType.botStopping]: {
|
|
219
|
+
botName: string;
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
type ListenerArgs<K extends keyof BotEventMap> =
|
|
224
|
+
BotEventMap[K] extends undefined ? [] : [BotEventMap[K]];
|
|
225
|
+
|
|
226
|
+
export type Listener<K extends keyof BotEventMap> = (
|
|
227
|
+
timestamp: number,
|
|
228
|
+
...args: ListenerArgs<K>
|
|
229
|
+
) => void;
|
|
230
|
+
|
|
231
|
+
export type EachListener = (
|
|
232
|
+
event: BotEventTypeKeys,
|
|
233
|
+
timestamp: number,
|
|
234
|
+
data: unknown
|
|
235
|
+
) => void;
|
|
236
|
+
|
|
237
|
+
export class TypedEventEmitter {
|
|
238
|
+
private readonly listeners = new Map<
|
|
239
|
+
keyof BotEventMap | '*',
|
|
240
|
+
Set<Listener<keyof BotEventMap> | EachListener>
|
|
241
|
+
>();
|
|
242
|
+
|
|
243
|
+
on<K extends keyof BotEventMap>(event: K, fn: Listener<K>) {
|
|
244
|
+
const set = this.listeners.get(event) ?? new Set();
|
|
245
|
+
set.add(fn as Listener<keyof BotEventMap>);
|
|
246
|
+
this.listeners.set(event, set);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
onEach(fn: EachListener) {
|
|
250
|
+
const event = '*';
|
|
251
|
+
const set = this.listeners.get(event) ?? new Set();
|
|
252
|
+
set.add(fn);
|
|
253
|
+
this.listeners.set(event, set);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
emit<K extends keyof BotEventMap>(
|
|
257
|
+
event: K,
|
|
258
|
+
...args: ListenerArgs<K>
|
|
259
|
+
): void {
|
|
260
|
+
const timestamp = Date.now();
|
|
261
|
+
const specific = this.listeners.get(event);
|
|
262
|
+
if (specific) {
|
|
263
|
+
for (const fn of specific) {
|
|
264
|
+
(fn as Listener<K>)(timestamp, ...args);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const anySet = this.listeners.get('*');
|
|
269
|
+
if (anySet) {
|
|
270
|
+
for (const fn of anySet) {
|
|
271
|
+
(
|
|
272
|
+
fn as unknown as (
|
|
273
|
+
e: K,
|
|
274
|
+
t: number,
|
|
275
|
+
...a: ListenerArgs<K>
|
|
276
|
+
) => void
|
|
277
|
+
)(event, timestamp, ...args);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
events(): (keyof BotEventMap | '*')[] {
|
|
283
|
+
return [...this.listeners.keys()];
|
|
284
|
+
}
|
|
285
|
+
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { ILogger, IScopedLogger } from '../types/logger';
|
|
2
|
-
import { TraceId } from '../types/trace';
|
|
3
|
-
export declare class JsonLogger implements ILogger {
|
|
4
|
-
private serializeError;
|
|
5
|
-
private getCircularReplacer;
|
|
6
|
-
createScope(botName: string, traceId: TraceId, chatName: string): IScopedLogger;
|
|
7
|
-
logObjectWithTraceId(botName: string, traceId: TraceId, chatName: string, data: unknown): void;
|
|
8
|
-
logWithTraceId(botName: string, traceId: TraceId, chatName: string, text: string): void;
|
|
9
|
-
errorWithTraceId(botName: string, traceId: TraceId, chatName: string, errorObj: unknown, extraData?: unknown): void;
|
|
10
|
-
}
|
|
11
|
-
//# sourceMappingURL=jsonLogger.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jsonLogger.d.ts","sourceRoot":"","sources":["../../services/jsonLogger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,qBAAa,UAAW,YAAW,OAAO;IACtC,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,mBAAmB;IAc3B,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAiBtD,aAAa;IAGtB,oBAAoB,CAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO;IAoBjB,cAAc,CACV,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM;IAOhB,gBAAgB,CACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,EACjB,SAAS,CAAC,EAAE,OAAO;CAe1B"}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
export class JsonLogger {
|
|
2
|
-
serializeError(error) {
|
|
3
|
-
if (error instanceof Error) {
|
|
4
|
-
const plainObject = {
|
|
5
|
-
name: error.name,
|
|
6
|
-
message: error.message,
|
|
7
|
-
stack: error.stack
|
|
8
|
-
};
|
|
9
|
-
for (const [key, value] of Object.entries(error)) {
|
|
10
|
-
plainObject[key] = value;
|
|
11
|
-
}
|
|
12
|
-
return JSON.stringify(plainObject);
|
|
13
|
-
}
|
|
14
|
-
return JSON.stringify({ error });
|
|
15
|
-
}
|
|
16
|
-
getCircularReplacer() {
|
|
17
|
-
const cache = new Set();
|
|
18
|
-
return (_, value) => {
|
|
19
|
-
if (typeof value === 'object' && value !== null) {
|
|
20
|
-
if (cache.has(value)) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
cache.add(value);
|
|
24
|
-
}
|
|
25
|
-
return value;
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
createScope(botName, traceId, chatName) {
|
|
29
|
-
return {
|
|
30
|
-
logObjectWithTraceId: (data) => {
|
|
31
|
-
this.logObjectWithTraceId(botName, traceId, chatName, data);
|
|
32
|
-
},
|
|
33
|
-
logWithTraceId: (text) => {
|
|
34
|
-
this.logWithTraceId(botName, traceId, chatName, text);
|
|
35
|
-
},
|
|
36
|
-
errorWithTraceId: (errorObj, extraData) => {
|
|
37
|
-
this.errorWithTraceId(botName, traceId, chatName, errorObj, extraData);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
logObjectWithTraceId(botName, traceId, chatName, data) {
|
|
42
|
-
const enrichedData = typeof data == 'object'
|
|
43
|
-
? {
|
|
44
|
-
...data,
|
|
45
|
-
botName,
|
|
46
|
-
traceId,
|
|
47
|
-
chatName
|
|
48
|
-
}
|
|
49
|
-
: {
|
|
50
|
-
botName,
|
|
51
|
-
traceId,
|
|
52
|
-
chatName,
|
|
53
|
-
data
|
|
54
|
-
};
|
|
55
|
-
console.log(enrichedData);
|
|
56
|
-
}
|
|
57
|
-
logWithTraceId(botName, traceId, chatName, text) {
|
|
58
|
-
console.log(`{"botName":"${botName}","traceId":"${traceId}","chatName":"${chatName}","text":"${text}"}`);
|
|
59
|
-
}
|
|
60
|
-
errorWithTraceId(botName, traceId, chatName, errorObj, extraData) {
|
|
61
|
-
const dataString = extraData
|
|
62
|
-
? `,"extraData":${JSON.stringify(extraData, this.getCircularReplacer())}`
|
|
63
|
-
: '';
|
|
64
|
-
console.error(`{"botName":"${botName}","traceId":"${traceId}","chatName":"${chatName}","error":${this.serializeError(errorObj)}${dataString}}`);
|
|
65
|
-
}
|
|
66
|
-
}
|