chz-telegram-bot 0.0.1
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/build.ps1 +34 -0
- package/bun.lock +506 -0
- package/dist/entities/actions/commandAction.js +79 -0
- package/dist/entities/actions/scheduledAction.js +65 -0
- package/dist/entities/bot.js +75 -0
- package/dist/entities/cachedStateFactory.js +9 -0
- package/dist/entities/commandTriggerCheckResult.js +22 -0
- package/dist/entities/context/chatContext.js +30 -0
- package/dist/entities/context/messageContext.js +46 -0
- package/dist/entities/incomingMessage.js +20 -0
- package/dist/entities/responses/imageMessage.js +11 -0
- package/dist/entities/responses/reaction.js +11 -0
- package/dist/entities/responses/textMessage.js +11 -0
- package/dist/entities/responses/videoMessage.js +11 -0
- package/dist/entities/states/actionStateBase.js +8 -0
- package/dist/entities/states/potuzhnoState.js +13 -0
- package/dist/entities/taskRecord.js +10 -0
- package/dist/entities/transactionResult.js +9 -0
- package/dist/helpers/builders/commandActionBuilder.js +61 -0
- package/dist/helpers/builders/scheduledActionBuilder.js +42 -0
- package/dist/helpers/escapeMarkdown.js +17 -0
- package/dist/helpers/getWeek.js +12 -0
- package/dist/helpers/noop.js +13 -0
- package/dist/helpers/randomInt.js +8 -0
- package/dist/helpers/reverseMap.js +6 -0
- package/dist/helpers/timeConvertions.js +14 -0
- package/dist/helpers/toArray.js +6 -0
- package/dist/index.js +33 -0
- package/dist/services/logger.js +17 -0
- package/dist/services/storage.js +79 -0
- package/dist/services/taskScheduler.js +37 -0
- package/dist/services/telegramApi.js +94 -0
- package/dist/types/actionState.js +2 -0
- package/dist/types/actionWithState.js +2 -0
- package/dist/types/cachedValueAccessor.js +2 -0
- package/dist/types/commandCondition.js +2 -0
- package/dist/types/daysOfTheWeek.js +13 -0
- package/dist/types/handlers.js +2 -0
- package/dist/types/replyMessage.js +2 -0
- package/dist/types/scheduledItem.js +2 -0
- package/dist/types/timeValues.js +2 -0
- package/entities/actions/commandAction.ts +143 -0
- package/entities/actions/scheduledAction.ts +121 -0
- package/entities/bot.ts +143 -0
- package/entities/cachedStateFactory.ts +14 -0
- package/entities/commandTriggerCheckResult.ts +30 -0
- package/entities/context/chatContext.ts +57 -0
- package/entities/context/messageContext.ts +94 -0
- package/entities/incomingMessage.ts +27 -0
- package/entities/responses/imageMessage.ts +21 -0
- package/entities/responses/reaction.ts +20 -0
- package/entities/responses/textMessage.ts +20 -0
- package/entities/responses/videoMessage.ts +21 -0
- package/entities/states/actionStateBase.ts +5 -0
- package/entities/states/potuzhnoState.ts +5 -0
- package/entities/taskRecord.ts +13 -0
- package/entities/transactionResult.ts +11 -0
- package/eslint.config.js +10 -0
- package/helpers/builders/commandActionBuilder.ts +88 -0
- package/helpers/builders/scheduledActionBuilder.ts +67 -0
- package/helpers/escapeMarkdown.ts +12 -0
- package/helpers/getWeek.ts +8 -0
- package/helpers/noop.ts +13 -0
- package/helpers/randomInt.ts +7 -0
- package/helpers/reverseMap.ts +3 -0
- package/helpers/timeConvertions.ts +13 -0
- package/helpers/toArray.ts +3 -0
- package/index.ts +47 -0
- package/package.json +30 -0
- package/services/logger.ts +30 -0
- package/services/storage.ts +111 -0
- package/services/taskScheduler.ts +66 -0
- package/services/telegramApi.ts +172 -0
- package/tsconfig.json +110 -0
- package/types/actionState.ts +3 -0
- package/types/actionWithState.ts +6 -0
- package/types/cachedValueAccessor.ts +1 -0
- package/types/commandCondition.ts +6 -0
- package/types/daysOfTheWeek.ts +9 -0
- package/types/handlers.ts +14 -0
- package/types/replyMessage.ts +6 -0
- package/types/scheduledItem.ts +6 -0
- package/types/timeValues.ts +29 -0
package/entities/bot.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Telegraf } from 'telegraf';
|
|
2
|
+
import TelegramApiService from '../services/telegramApi';
|
|
3
|
+
import IncomingMessage from './incomingMessage';
|
|
4
|
+
import taskScheduler from '../services/taskScheduler';
|
|
5
|
+
import logger from '../services/logger';
|
|
6
|
+
import CommandAction from './actions/commandAction';
|
|
7
|
+
import ScheduledAction from './actions/scheduledAction';
|
|
8
|
+
import IActionState from '../types/actionState';
|
|
9
|
+
import {
|
|
10
|
+
hoursToMilliseconds,
|
|
11
|
+
secondsToMilliseconds
|
|
12
|
+
} from '../helpers/timeConvertions';
|
|
13
|
+
import { Hours, Seconds } from '../types/timeValues';
|
|
14
|
+
import storage from '../services/storage';
|
|
15
|
+
|
|
16
|
+
export default class Bot {
|
|
17
|
+
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;
|
|
36
|
+
|
|
37
|
+
logger.logWithTraceId(
|
|
38
|
+
this.name,
|
|
39
|
+
`System:Bot-${this.name}-Start`,
|
|
40
|
+
'System',
|
|
41
|
+
'Starting bot...'
|
|
42
|
+
);
|
|
43
|
+
this.telegraf = new Telegraf(token);
|
|
44
|
+
|
|
45
|
+
this.api = new TelegramApiService(this.name, this.telegraf, this.chats);
|
|
46
|
+
|
|
47
|
+
this.telegraf.on('message', async (ctx) => {
|
|
48
|
+
const msg = new IncomingMessage(ctx.update.message);
|
|
49
|
+
const messageContent = msg.text || '<non-text message>';
|
|
50
|
+
|
|
51
|
+
const messageFromName = msg.from?.first_name ?? 'Unknown';
|
|
52
|
+
const messageFromId = msg.from?.id ?? 'Unknown';
|
|
53
|
+
logger.logWithTraceId(
|
|
54
|
+
this.name,
|
|
55
|
+
msg.traceId,
|
|
56
|
+
msg.chatName,
|
|
57
|
+
`${messageFromName} (${messageFromId}): ${messageContent}`
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (msg.text) {
|
|
61
|
+
this.messageQueue.push(msg);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
this.telegraf.launch();
|
|
66
|
+
|
|
67
|
+
taskScheduler.createTask(
|
|
68
|
+
'MessageProcessing',
|
|
69
|
+
async () => {
|
|
70
|
+
while (this.messageQueue.length > 0) {
|
|
71
|
+
await this.processMessages();
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
secondsToMilliseconds(0.3 as Seconds),
|
|
75
|
+
false,
|
|
76
|
+
this.name
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
taskScheduler.createTask(
|
|
80
|
+
'ScheduledProcessing',
|
|
81
|
+
async () => {
|
|
82
|
+
await this.runScheduled();
|
|
83
|
+
},
|
|
84
|
+
hoursToMilliseconds(0.5 as Hours),
|
|
85
|
+
true,
|
|
86
|
+
this.name
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
storage.saveMetadata([...this.commands, ...this.scheduled], this.name);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
stop(code: string) {
|
|
93
|
+
logger.logWithTraceId(
|
|
94
|
+
this.name,
|
|
95
|
+
`System:Bot-${this.name}-Stop`,
|
|
96
|
+
'System',
|
|
97
|
+
'Stopping bot...'
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
this.telegraf.stop(code);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private async runScheduled() {
|
|
104
|
+
for (const [chatName, chatId] of this.chats.entries()) {
|
|
105
|
+
for (const trig of this.scheduled) {
|
|
106
|
+
const ctx = this.api.createContextForChat(chatId, trig.name);
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
await trig.exec(ctx);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.dir(error);
|
|
112
|
+
logger.errorWithTraceId(
|
|
113
|
+
ctx.botName,
|
|
114
|
+
ctx.traceId,
|
|
115
|
+
chatName,
|
|
116
|
+
error as string | Error,
|
|
117
|
+
ctx
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private async processMessages() {
|
|
125
|
+
const msg = this.messageQueue.pop()!;
|
|
126
|
+
|
|
127
|
+
for (const cmd of this.commands) {
|
|
128
|
+
const ctx = this.api.createContextForMessage(msg);
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
await cmd.exec(ctx);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
logger.errorWithTraceId(
|
|
134
|
+
ctx.botName,
|
|
135
|
+
ctx.traceId,
|
|
136
|
+
ctx.chatName,
|
|
137
|
+
error as string | Error,
|
|
138
|
+
ctx
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Hours } from '../types/timeValues';
|
|
2
|
+
|
|
3
|
+
export default class CachedStateFactory {
|
|
4
|
+
getValue: () => Promise<unknown>;
|
|
5
|
+
invalidationTimeoutInHours: Hours;
|
|
6
|
+
|
|
7
|
+
constructor(
|
|
8
|
+
itemFactory: () => Promise<unknown>,
|
|
9
|
+
invalidationTimeout: Hours
|
|
10
|
+
) {
|
|
11
|
+
this.getValue = itemFactory;
|
|
12
|
+
this.invalidationTimeoutInHours = invalidationTimeout;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export default class CommandTriggerCheckResult {
|
|
2
|
+
static get DontTriggerAndSkipCooldown() {
|
|
3
|
+
return new CommandTriggerCheckResult(false, [], true);
|
|
4
|
+
}
|
|
5
|
+
static get DoNotTrigger() {
|
|
6
|
+
return new CommandTriggerCheckResult(false, [], false);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
shouldTrigger: boolean;
|
|
10
|
+
matchResults: RegExpExecArray[];
|
|
11
|
+
skipCooldown: boolean;
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
shouldTrigger: boolean,
|
|
15
|
+
matchResults: RegExpExecArray[],
|
|
16
|
+
skipCooldown: boolean
|
|
17
|
+
) {
|
|
18
|
+
this.shouldTrigger = shouldTrigger;
|
|
19
|
+
this.matchResults = matchResults;
|
|
20
|
+
this.skipCooldown = skipCooldown;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
mergeWith(other: CommandTriggerCheckResult) {
|
|
24
|
+
this.shouldTrigger = this.shouldTrigger || other.shouldTrigger;
|
|
25
|
+
this.matchResults = this.matchResults.concat(other.matchResults);
|
|
26
|
+
this.skipCooldown = this.skipCooldown || other.skipCooldown;
|
|
27
|
+
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import ImageMessage from '../responses/imageMessage';
|
|
2
|
+
import TextMessage from '../responses/textMessage';
|
|
3
|
+
import VideoMessage from '../responses/videoMessage';
|
|
4
|
+
import { resolve } from 'path';
|
|
5
|
+
import { IBotApiInteractions } from '../../services/telegramApi';
|
|
6
|
+
|
|
7
|
+
export default class ChatContext {
|
|
8
|
+
botName: string;
|
|
9
|
+
interactions: IBotApiInteractions;
|
|
10
|
+
chatId: number;
|
|
11
|
+
chatName: string;
|
|
12
|
+
traceId: number | string;
|
|
13
|
+
|
|
14
|
+
constructor(
|
|
15
|
+
botName: string,
|
|
16
|
+
interactions: IBotApiInteractions,
|
|
17
|
+
chatId: number,
|
|
18
|
+
chatName: string,
|
|
19
|
+
traceId: number | string
|
|
20
|
+
) {
|
|
21
|
+
this.botName = botName;
|
|
22
|
+
this.interactions = interactions;
|
|
23
|
+
this.chatId = chatId;
|
|
24
|
+
this.chatName = chatName;
|
|
25
|
+
this.traceId = traceId;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
sendTextToChat(text: string) {
|
|
29
|
+
this.interactions.respond(
|
|
30
|
+
new TextMessage(text, this.chatId, undefined, this.traceId)
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
sendImageToChat(name: string) {
|
|
35
|
+
const filePath = `./content/${name}.png`;
|
|
36
|
+
this.interactions.respond(
|
|
37
|
+
new ImageMessage(
|
|
38
|
+
{ source: resolve(filePath) },
|
|
39
|
+
this.chatId,
|
|
40
|
+
undefined,
|
|
41
|
+
this.traceId
|
|
42
|
+
)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
sendVideoToChat(name: string) {
|
|
47
|
+
const filePath = `./content/${name}.mp4`;
|
|
48
|
+
this.interactions.respond(
|
|
49
|
+
new VideoMessage(
|
|
50
|
+
{ source: resolve(filePath) },
|
|
51
|
+
this.chatId,
|
|
52
|
+
undefined,
|
|
53
|
+
this.traceId
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import ActionStateBase from '../states/actionStateBase';
|
|
2
|
+
import ImageMessage from '../responses/imageMessage';
|
|
3
|
+
import TextMessage from '../responses/textMessage';
|
|
4
|
+
import VideoMessage from '../responses/videoMessage';
|
|
5
|
+
import ChatContext from './chatContext';
|
|
6
|
+
import storage from '../../services/storage';
|
|
7
|
+
import { resolve } from 'path';
|
|
8
|
+
import IActionState from '../../types/actionState';
|
|
9
|
+
import { IBotApiInteractions } from '../../services/telegramApi';
|
|
10
|
+
import { TelegramEmoji } from 'telegraf/types';
|
|
11
|
+
import Reaction from '../responses/reaction';
|
|
12
|
+
|
|
13
|
+
export default class MessageContext<
|
|
14
|
+
TActionState extends IActionState
|
|
15
|
+
> extends ChatContext {
|
|
16
|
+
messageId: number;
|
|
17
|
+
messageText: string;
|
|
18
|
+
matchResults: RegExpMatchArray[] = [];
|
|
19
|
+
fromUserId: number | undefined;
|
|
20
|
+
startCooldown: boolean = true;
|
|
21
|
+
updateActions: Array<(state: TActionState) => void> = [];
|
|
22
|
+
fromUserName: string;
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
botName: string,
|
|
26
|
+
interactions: IBotApiInteractions,
|
|
27
|
+
chatId: number,
|
|
28
|
+
chatName: string,
|
|
29
|
+
messageId: number,
|
|
30
|
+
messageText: string,
|
|
31
|
+
fromUserId: number | undefined,
|
|
32
|
+
traceId: number | string,
|
|
33
|
+
fromUserName: string
|
|
34
|
+
) {
|
|
35
|
+
super(botName, interactions, chatId, chatName, traceId);
|
|
36
|
+
|
|
37
|
+
this.messageId = messageId;
|
|
38
|
+
this.messageText = messageText;
|
|
39
|
+
this.fromUserId = fromUserId;
|
|
40
|
+
this.fromUserName = fromUserName;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async loadStateOf<TAnotherActionState extends IActionState>(
|
|
44
|
+
commandName: string
|
|
45
|
+
): Promise<TAnotherActionState> {
|
|
46
|
+
return (
|
|
47
|
+
((await storage.load(`command:${commandName.replace('.', '-')}`))[
|
|
48
|
+
this.chatId
|
|
49
|
+
] as TAnotherActionState) ?? new ActionStateBase()
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
updateState(stateUpdateAction: (state: TActionState) => void) {
|
|
54
|
+
this.updateActions.push(
|
|
55
|
+
stateUpdateAction as (state: TActionState) => void
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
replyWithText(text: string) {
|
|
60
|
+
this.interactions.respond(
|
|
61
|
+
new TextMessage(text, this.chatId, this.messageId, this.traceId)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
replyWithImage(name: string) {
|
|
66
|
+
const filePath = `./content/${name}.png`;
|
|
67
|
+
this.interactions.respond(
|
|
68
|
+
new ImageMessage(
|
|
69
|
+
{ source: resolve(filePath) },
|
|
70
|
+
this.chatId,
|
|
71
|
+
this.messageId,
|
|
72
|
+
this.traceId
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
replyWithVideo(name: string) {
|
|
78
|
+
const filePath = `./content/${name}.mp4`;
|
|
79
|
+
this.interactions.respond(
|
|
80
|
+
new VideoMessage(
|
|
81
|
+
{ source: resolve(filePath) },
|
|
82
|
+
this.chatId,
|
|
83
|
+
this.messageId,
|
|
84
|
+
this.traceId
|
|
85
|
+
)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
react(emoji: TelegramEmoji) {
|
|
90
|
+
this.interactions.react(
|
|
91
|
+
new Reaction(this.traceId, this.chatId, this.messageId, emoji)
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Chat, User } from 'telegraf/types';
|
|
2
|
+
import randomInteger from '../helpers/randomInt';
|
|
3
|
+
|
|
4
|
+
export default class IncomingMessage {
|
|
5
|
+
message_id: number;
|
|
6
|
+
chat: Chat;
|
|
7
|
+
from: User | undefined;
|
|
8
|
+
text: string;
|
|
9
|
+
chatName: string;
|
|
10
|
+
traceId = randomInteger(10000, 99999);
|
|
11
|
+
|
|
12
|
+
constructor(ctxMessage: {
|
|
13
|
+
message_id: number;
|
|
14
|
+
chat: Chat;
|
|
15
|
+
from?: User;
|
|
16
|
+
text?: string;
|
|
17
|
+
}) {
|
|
18
|
+
this.message_id = ctxMessage.message_id;
|
|
19
|
+
this.chat = ctxMessage.chat;
|
|
20
|
+
this.from = ctxMessage.from;
|
|
21
|
+
this.text = ctxMessage.text || '';
|
|
22
|
+
this.chatName =
|
|
23
|
+
'title' in ctxMessage.chat
|
|
24
|
+
? ctxMessage.chat.title + ' ' + ctxMessage.chat.id
|
|
25
|
+
: 'DM';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { InputFile } from 'telegraf/types';
|
|
2
|
+
import IReplyMessage from '../../types/replyMessage';
|
|
3
|
+
|
|
4
|
+
export default class ImageMessage implements IReplyMessage<InputFile> {
|
|
5
|
+
content: InputFile;
|
|
6
|
+
chatId: number;
|
|
7
|
+
replyId: number | undefined;
|
|
8
|
+
traceId: string | number;
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
image: InputFile,
|
|
12
|
+
chatId: number,
|
|
13
|
+
replyId: number | undefined,
|
|
14
|
+
traceId: number | string
|
|
15
|
+
) {
|
|
16
|
+
this.content = image;
|
|
17
|
+
this.chatId = chatId;
|
|
18
|
+
this.replyId = replyId;
|
|
19
|
+
this.traceId = traceId;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { TelegramEmoji } from 'telegraf/types';
|
|
2
|
+
|
|
3
|
+
export default class Reaction {
|
|
4
|
+
chatId: number;
|
|
5
|
+
messageId: number;
|
|
6
|
+
traceId: number | string;
|
|
7
|
+
emoji: TelegramEmoji;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
traceId: number | string,
|
|
11
|
+
chatId: number,
|
|
12
|
+
messageId: number,
|
|
13
|
+
emoji: TelegramEmoji
|
|
14
|
+
) {
|
|
15
|
+
this.chatId = chatId;
|
|
16
|
+
this.messageId = messageId;
|
|
17
|
+
this.emoji = emoji;
|
|
18
|
+
this.traceId = traceId;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import IReplyMessage from '../../types/replyMessage';
|
|
2
|
+
|
|
3
|
+
export default class TextMessage implements IReplyMessage<string> {
|
|
4
|
+
content: string;
|
|
5
|
+
chatId: number;
|
|
6
|
+
replyId: number | undefined;
|
|
7
|
+
traceId: string | number;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
text: string,
|
|
11
|
+
chatId: number,
|
|
12
|
+
replyId: number | undefined,
|
|
13
|
+
traceId: string | number
|
|
14
|
+
) {
|
|
15
|
+
this.content = text;
|
|
16
|
+
this.chatId = chatId;
|
|
17
|
+
this.replyId = replyId;
|
|
18
|
+
this.traceId = traceId;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { InputFile } from 'telegraf/types';
|
|
2
|
+
import IReplyMessage from '../../types/replyMessage';
|
|
3
|
+
|
|
4
|
+
export default class VideoMessage implements IReplyMessage<InputFile> {
|
|
5
|
+
content: InputFile;
|
|
6
|
+
chatId: number;
|
|
7
|
+
replyId: number | undefined;
|
|
8
|
+
traceId: string | number;
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
video: InputFile,
|
|
12
|
+
chatId: number,
|
|
13
|
+
replyId: number | undefined,
|
|
14
|
+
traceId: number | string
|
|
15
|
+
) {
|
|
16
|
+
this.content = video;
|
|
17
|
+
this.chatId = chatId;
|
|
18
|
+
this.replyId = replyId;
|
|
19
|
+
this.traceId = traceId;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Milliseconds } from '../types/timeValues';
|
|
2
|
+
|
|
3
|
+
export default class TaskRecord {
|
|
4
|
+
name: string;
|
|
5
|
+
taskId: NodeJS.Timeout;
|
|
6
|
+
interval: Milliseconds;
|
|
7
|
+
|
|
8
|
+
constructor(name: string, taskId: NodeJS.Timeout, interval: Milliseconds) {
|
|
9
|
+
this.name = name;
|
|
10
|
+
this.taskId = taskId;
|
|
11
|
+
this.interval = interval;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import IActionState from '../types/actionState';
|
|
2
|
+
|
|
3
|
+
export default class TransactionResult {
|
|
4
|
+
data: IActionState;
|
|
5
|
+
shouldUpdate: boolean;
|
|
6
|
+
|
|
7
|
+
constructor(data: IActionState, shouldUpdate: boolean) {
|
|
8
|
+
this.data = data;
|
|
9
|
+
this.shouldUpdate = shouldUpdate;
|
|
10
|
+
}
|
|
11
|
+
}
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import CommandAction from '../../entities/actions/commandAction';
|
|
2
|
+
import ActionStateBase from '../../entities/states/actionStateBase';
|
|
3
|
+
import toArray from '../toArray';
|
|
4
|
+
import IActionState from '../../types/actionState';
|
|
5
|
+
import { CommandHandler } from '../../types/handlers';
|
|
6
|
+
import { CommandCondition } from '../../types/commandCondition';
|
|
7
|
+
import { Seconds } from '../../types/timeValues';
|
|
8
|
+
import Noop from '../noop';
|
|
9
|
+
|
|
10
|
+
export class CommandActionBuilderWithState<TActionState extends IActionState> {
|
|
11
|
+
name: string;
|
|
12
|
+
trigger: string | RegExp | Array<string> | Array<RegExp> = [];
|
|
13
|
+
|
|
14
|
+
active = true;
|
|
15
|
+
cooldownSeconds: Seconds = 0 as Seconds;
|
|
16
|
+
blacklist: number[] = [];
|
|
17
|
+
allowedUsers: number[] = [];
|
|
18
|
+
stateConstructor: () => TActionState;
|
|
19
|
+
handler: CommandHandler<TActionState> = Noop.call;
|
|
20
|
+
condition: CommandCondition<TActionState> = Noop.true;
|
|
21
|
+
|
|
22
|
+
constructor(name: string, stateConstructor: () => TActionState) {
|
|
23
|
+
this.name = name;
|
|
24
|
+
this.stateConstructor = stateConstructor;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
on(trigger: string | RegExp | Array<string> | Array<RegExp>) {
|
|
28
|
+
this.trigger = trigger;
|
|
29
|
+
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
from(id: number | Array<number>) {
|
|
34
|
+
this.allowedUsers = toArray(id);
|
|
35
|
+
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
do(handler: CommandHandler<TActionState>) {
|
|
40
|
+
this.handler = handler;
|
|
41
|
+
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
when(condition: CommandCondition<TActionState>) {
|
|
46
|
+
this.condition = condition;
|
|
47
|
+
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
disabled() {
|
|
52
|
+
this.active = false;
|
|
53
|
+
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
cooldown(seconds: Seconds) {
|
|
58
|
+
this.cooldownSeconds = seconds;
|
|
59
|
+
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
ignoreChat(chatId: number) {
|
|
64
|
+
this.blacklist.push(chatId);
|
|
65
|
+
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
build() {
|
|
70
|
+
return new CommandAction(
|
|
71
|
+
this.trigger,
|
|
72
|
+
this.handler,
|
|
73
|
+
this.name,
|
|
74
|
+
this.active,
|
|
75
|
+
this.cooldownSeconds,
|
|
76
|
+
this.blacklist,
|
|
77
|
+
this.allowedUsers,
|
|
78
|
+
this.condition,
|
|
79
|
+
this.stateConstructor
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export class CommandActionBuilder extends CommandActionBuilderWithState<ActionStateBase> {
|
|
85
|
+
constructor(name: string) {
|
|
86
|
+
super(name, () => new ActionStateBase());
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import ScheduledAction from '../../entities/actions/scheduledAction';
|
|
2
|
+
import CachedStateFactory from '../../entities/cachedStateFactory';
|
|
3
|
+
import { ScheduledHandler } from '../../types/handlers';
|
|
4
|
+
import { Hours, HoursOfDay } from '../../types/timeValues';
|
|
5
|
+
import Noop from '../noop';
|
|
6
|
+
|
|
7
|
+
export default class ScheduledActionBuilder {
|
|
8
|
+
active = true;
|
|
9
|
+
time: HoursOfDay = 0;
|
|
10
|
+
cachedStateFactories = new Map<string, CachedStateFactory>();
|
|
11
|
+
whitelist: number[] = [];
|
|
12
|
+
handler: ScheduledHandler = Noop.call;
|
|
13
|
+
|
|
14
|
+
name: string;
|
|
15
|
+
|
|
16
|
+
constructor(name: string) {
|
|
17
|
+
this.name = name;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
allowIn(chatId: number) {
|
|
21
|
+
this.whitelist.push(chatId);
|
|
22
|
+
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
runAt(time: HoursOfDay) {
|
|
27
|
+
this.time = time;
|
|
28
|
+
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
do(handler: ScheduledHandler) {
|
|
33
|
+
this.handler = handler;
|
|
34
|
+
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
withSharedCache(
|
|
39
|
+
key: string,
|
|
40
|
+
itemFactory: () => Promise<unknown>,
|
|
41
|
+
invalidationTimeoutInHours: Hours = 20 as Hours
|
|
42
|
+
) {
|
|
43
|
+
this.cachedStateFactories.set(
|
|
44
|
+
key,
|
|
45
|
+
new CachedStateFactory(itemFactory, invalidationTimeoutInHours)
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
disabled() {
|
|
52
|
+
this.active = false;
|
|
53
|
+
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
build() {
|
|
58
|
+
return new ScheduledAction(
|
|
59
|
+
this.name,
|
|
60
|
+
this.handler,
|
|
61
|
+
this.time,
|
|
62
|
+
this.active,
|
|
63
|
+
this.whitelist,
|
|
64
|
+
this.cachedStateFactories
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import escape from 'markdown-escape';
|
|
2
|
+
|
|
3
|
+
export default function escapeMarkdown(text: string) {
|
|
4
|
+
return escape(text)
|
|
5
|
+
.replaceAll(/\./g, '\\.')
|
|
6
|
+
.replaceAll(/-/g, '\\-')
|
|
7
|
+
.replaceAll(/\+/g, '\\+')
|
|
8
|
+
.replaceAll(/\{/g, '\\{')
|
|
9
|
+
.replaceAll(/!/g, '\\!')
|
|
10
|
+
.replaceAll(/\|/g, '\\|')
|
|
11
|
+
.replaceAll(/\}/g, '\\}');
|
|
12
|
+
}
|