chz-telegram-bot 0.3.11 → 0.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entities/actions/commandAction.d.ts +4 -1
- package/dist/entities/actions/commandAction.d.ts.map +1 -1
- package/dist/entities/actions/commandAction.js +32 -16
- package/dist/helpers/builders/commandActionBuilder.d.ts +3 -0
- package/dist/helpers/builders/commandActionBuilder.d.ts.map +1 -1
- package/dist/helpers/builders/commandActionBuilder.js +8 -1
- package/dist/services/actionProcessors/commandActionProcessor.js +2 -2
- package/entities/actions/commandAction.ts +50 -27
- package/helpers/builders/commandActionBuilder.ts +10 -0
- package/package.json +1 -1
- package/services/actionProcessors/commandActionProcessor.ts +2 -2
|
@@ -5,7 +5,9 @@ import { IActionState } from '../../types/actionState';
|
|
|
5
5
|
import { IActionWithState, ActionKey } from '../../types/action';
|
|
6
6
|
import { MessageContext } from '../context/messageContext';
|
|
7
7
|
import { CommandTrigger } from '../../types/commandTrigger';
|
|
8
|
+
import { Sema as Semaphore } from 'async-sema';
|
|
8
9
|
export declare class CommandAction<TActionState extends IActionState> implements IActionWithState<TActionState> {
|
|
10
|
+
readonly ratelimitSemaphores: Map<number, Semaphore>;
|
|
9
11
|
readonly triggers: CommandTrigger[];
|
|
10
12
|
readonly handler: CommandHandler<TActionState>;
|
|
11
13
|
readonly name: string;
|
|
@@ -17,7 +19,8 @@ export declare class CommandAction<TActionState extends IActionState> implements
|
|
|
17
19
|
readonly stateConstructor: () => TActionState;
|
|
18
20
|
readonly key: ActionKey;
|
|
19
21
|
readonly readmeFactory: (botName: string) => string;
|
|
20
|
-
|
|
22
|
+
readonly maxAllowedSimultaniousExecutions: number;
|
|
23
|
+
constructor(trigger: CommandTrigger | CommandTrigger[], handler: CommandHandler<TActionState>, name: string, active: boolean, cooldown: Seconds, chatsBlacklist: number[], allowedUsers: number[], maxAllowedSimultaniousExecutions: number, condition: CommandCondition<TActionState>, stateConstructor: () => TActionState, readmeFactory: (botName: string) => string);
|
|
21
24
|
exec(ctx: MessageContext<TActionState>): Promise<import("../../types/response").BotResponse[]>;
|
|
22
25
|
private checkIfShouldBeExecuted;
|
|
23
26
|
private checkTrigger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commandAction.d.ts","sourceRoot":"","sources":["../../../entities/actions/commandAction.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"commandAction.d.ts","sourceRoot":"","sources":["../../../entities/actions/commandAction.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAG5D,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,YAAY,CAAC;AAG/C,qBAAa,aAAa,CAAC,YAAY,SAAS,YAAY,CACxD,YAAW,gBAAgB,CAAC,YAAY,CAAC;IAEzC,QAAQ,CAAC,mBAAmB,yBAAgC;IAE5D,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;IACnD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,YAAY,CAAC;IAC9C,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IACpD,QAAQ,CAAC,gCAAgC,EAAE,MAAM,CAAC;gBAG9C,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE,EAC1C,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,EACrC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,OAAO,EACjB,cAAc,EAAE,MAAM,EAAE,EACxB,YAAY,EAAE,MAAM,EAAE,EACtB,gCAAgC,EAAE,MAAM,EACxC,SAAS,EAAE,gBAAgB,CAAC,YAAY,CAAC,EACzC,gBAAgB,EAAE,MAAM,YAAY,EACpC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM;IAkBxC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,YAAY,CAAC;IA8D5C,OAAO,CAAC,uBAAuB;IA+B/B,OAAO,CAAC,YAAY;CAuCvB"}
|
|
@@ -10,7 +10,10 @@ const toArray_1 = require("../../helpers/toArray");
|
|
|
10
10
|
const commandTriggerCheckResult_1 = require("../../dtos/commandTriggerCheckResult");
|
|
11
11
|
const noop_1 = require("../../helpers/noop");
|
|
12
12
|
const messageTypes_1 = require("../../types/messageTypes");
|
|
13
|
+
const async_sema_1 = require("async-sema");
|
|
14
|
+
const mapUtils_1 = require("../../helpers/mapUtils");
|
|
13
15
|
class CommandAction {
|
|
16
|
+
ratelimitSemaphores = new Map();
|
|
14
17
|
triggers;
|
|
15
18
|
handler;
|
|
16
19
|
name;
|
|
@@ -22,7 +25,8 @@ class CommandAction {
|
|
|
22
25
|
stateConstructor;
|
|
23
26
|
key;
|
|
24
27
|
readmeFactory;
|
|
25
|
-
|
|
28
|
+
maxAllowedSimultaniousExecutions;
|
|
29
|
+
constructor(trigger, handler, name, active, cooldown, chatsBlacklist, allowedUsers, maxAllowedSimultaniousExecutions, condition, stateConstructor, readmeFactory) {
|
|
26
30
|
this.triggers = (0, toArray_1.toArray)(trigger);
|
|
27
31
|
this.handler = handler;
|
|
28
32
|
this.name = name;
|
|
@@ -33,6 +37,8 @@ class CommandAction {
|
|
|
33
37
|
this.condition = condition;
|
|
34
38
|
this.stateConstructor = stateConstructor;
|
|
35
39
|
this.readmeFactory = readmeFactory;
|
|
40
|
+
this.maxAllowedSimultaniousExecutions =
|
|
41
|
+
maxAllowedSimultaniousExecutions;
|
|
36
42
|
this.key = `command:${this.name.replace('.', '-')}`;
|
|
37
43
|
}
|
|
38
44
|
async exec(ctx) {
|
|
@@ -40,23 +46,33 @@ class CommandAction {
|
|
|
40
46
|
throw new Error(`Context for ${this.key} is not initialized or already consumed`);
|
|
41
47
|
if (!this.active || this.chatsBlacklist.includes(ctx.chatInfo.id))
|
|
42
48
|
return noop_1.Noop.NoResponse;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
let lock;
|
|
50
|
+
if (this.maxAllowedSimultaniousExecutions != 0) {
|
|
51
|
+
lock = (0, mapUtils_1.getOrSetIfNotExists)(this.ratelimitSemaphores, ctx.chatInfo.id, new async_sema_1.Sema(this.maxAllowedSimultaniousExecutions));
|
|
52
|
+
await lock.acquire();
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const state = await ctx.storage.getActionState(this, ctx.chatInfo.id);
|
|
56
|
+
const { shouldExecute, matchResults, skipCooldown } = this.triggers
|
|
57
|
+
.map((x) => this.checkIfShouldBeExecuted(ctx, x, state))
|
|
58
|
+
.reduce((acc, curr) => acc.mergeWith(curr), commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger);
|
|
59
|
+
if (!shouldExecute)
|
|
60
|
+
return noop_1.Noop.NoResponse;
|
|
61
|
+
ctx.logger.logWithTraceId(` - Executing [${this.name}] in ${ctx.chatInfo.id}`);
|
|
62
|
+
ctx.matchResults = matchResults;
|
|
63
|
+
await this.handler(ctx, state);
|
|
64
|
+
if (skipCooldown) {
|
|
65
|
+
ctx.startCooldown = false;
|
|
66
|
+
}
|
|
67
|
+
if (ctx.startCooldown) {
|
|
68
|
+
state.lastExecutedDate = (0, moment_1.default)().valueOf();
|
|
69
|
+
}
|
|
70
|
+
await ctx.storage.saveActionExecutionResult(this, ctx.chatInfo.id, state);
|
|
71
|
+
return ctx.responses;
|
|
54
72
|
}
|
|
55
|
-
|
|
56
|
-
|
|
73
|
+
finally {
|
|
74
|
+
lock?.release();
|
|
57
75
|
}
|
|
58
|
-
await ctx.storage.saveActionExecutionResult(this, ctx.chatInfo.id, state);
|
|
59
|
-
return ctx.responses;
|
|
60
76
|
}
|
|
61
77
|
checkIfShouldBeExecuted(ctx, trigger, state) {
|
|
62
78
|
if (!ctx.fromUserId)
|
|
@@ -19,6 +19,7 @@ export declare class CommandActionBuilderWithState<TActionState extends IActionS
|
|
|
19
19
|
stateConstructor: () => TActionState;
|
|
20
20
|
handler: CommandHandler<TActionState>;
|
|
21
21
|
condition: CommandCondition<TActionState>;
|
|
22
|
+
maxAllowedSimultaniousExecutions: number;
|
|
22
23
|
/**
|
|
23
24
|
* Builder for `CommandAction` with state represented by `TActionState`
|
|
24
25
|
* @param name Action name, will be used for logging and storage
|
|
@@ -47,6 +48,8 @@ export declare class CommandActionBuilderWithState<TActionState extends IActionS
|
|
|
47
48
|
withHelp(readmeFactory: (botName: string) => string): this;
|
|
48
49
|
/** If called during building, action is marked as disabled and never checked. */
|
|
49
50
|
disabled(): this;
|
|
51
|
+
/** Sets maximum number of simultaniously executing handlers for this command per chat. 0 is treated as unlimited. */
|
|
52
|
+
ratelimit(maxAllowedSimultaniousExecutions: number): this;
|
|
50
53
|
/** Sets action cooldown.
|
|
51
54
|
* @param seconds Cooldown in seconds.
|
|
52
55
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commandActionBuilder.d.ts","sourceRoot":"","sources":["../../../helpers/builders/commandActionBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAGvD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D;;GAEG;AACH,qBAAa,6BAA6B,CAAC,YAAY,SAAS,YAAY;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE,CAAM;IAEhD,MAAM,UAAQ;IACd,aAAa,EAAE,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,CAAQ;IAC3D,eAAe,EAAE,OAAO,CAAgB;IACxC,SAAS,EAAE,MAAM,EAAE,CAAM;IACzB,YAAY,EAAE,MAAM,EAAE,CAAM;IAC5B,gBAAgB,EAAE,MAAM,YAAY,CAAC;IACrC,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,CAAa;IAClD,SAAS,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAa;
|
|
1
|
+
{"version":3,"file":"commandActionBuilder.d.ts","sourceRoot":"","sources":["../../../helpers/builders/commandActionBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAGvD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D;;GAEG;AACH,qBAAa,6BAA6B,CAAC,YAAY,SAAS,YAAY;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE,CAAM;IAEhD,MAAM,UAAQ;IACd,aAAa,EAAE,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,CAAQ;IAC3D,eAAe,EAAE,OAAO,CAAgB;IACxC,SAAS,EAAE,MAAM,EAAE,CAAM;IACzB,YAAY,EAAE,MAAM,EAAE,CAAM;IAC5B,gBAAgB,EAAE,MAAM,YAAY,CAAC;IACrC,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,CAAa;IAClD,SAAS,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAa;IACtD,gCAAgC,EAAE,MAAM,CAAK;IAE7C;;;;OAIG;gBACS,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,YAAY;IAK9D;;;;;OAKG;IACH,EAAE,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE;IAM7C;;OAEG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE;IAM1B;;OAEG;IACH,EAAE,CAAC,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC;IAMxC;;OAEG;IACH,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,YAAY,CAAC;IAM9C,QAAQ,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM;IAMnD,iFAAiF;IACjF,QAAQ;IAMR,qHAAqH;IACrH,SAAS,CAAC,gCAAgC,EAAE,MAAM;IAOlD;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO;IAMzB;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM;IAMzB,oBAAoB;IACpB,KAAK;CAeR;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,6BAA6B,CAAC,eAAe,CAAC;IACpF;;OAEG;gBACS,IAAI,EAAE,MAAM;CAG3B"}
|
|
@@ -19,6 +19,7 @@ class CommandActionBuilderWithState {
|
|
|
19
19
|
stateConstructor;
|
|
20
20
|
handler = noop_1.Noop.call;
|
|
21
21
|
condition = noop_1.Noop.true;
|
|
22
|
+
maxAllowedSimultaniousExecutions = 0;
|
|
22
23
|
/**
|
|
23
24
|
* Builder for `CommandAction` with state represented by `TActionState`
|
|
24
25
|
* @param name Action name, will be used for logging and storage
|
|
@@ -68,6 +69,12 @@ class CommandActionBuilderWithState {
|
|
|
68
69
|
this.active = false;
|
|
69
70
|
return this;
|
|
70
71
|
}
|
|
72
|
+
/** Sets maximum number of simultaniously executing handlers for this command per chat. 0 is treated as unlimited. */
|
|
73
|
+
ratelimit(maxAllowedSimultaniousExecutions) {
|
|
74
|
+
this.maxAllowedSimultaniousExecutions =
|
|
75
|
+
maxAllowedSimultaniousExecutions;
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
71
78
|
/** Sets action cooldown.
|
|
72
79
|
* @param seconds Cooldown in seconds.
|
|
73
80
|
*/
|
|
@@ -85,7 +92,7 @@ class CommandActionBuilderWithState {
|
|
|
85
92
|
}
|
|
86
93
|
/** Builds action */
|
|
87
94
|
build() {
|
|
88
|
-
return new commandAction_1.CommandAction(this.trigger, this.handler, this.name, this.active, this.cooldownSeconds, this.blacklist, this.allowedUsers, this.condition, this.stateConstructor, this.readmeFactory != null ? this.readmeFactory : (_) => '');
|
|
95
|
+
return new commandAction_1.CommandAction(this.trigger, this.handler, this.name, this.active, this.cooldownSeconds, this.blacklist, this.allowedUsers, this.maxAllowedSimultaniousExecutions, this.condition, this.stateConstructor, this.readmeFactory != null ? this.readmeFactory : (_) => '');
|
|
89
96
|
}
|
|
90
97
|
}
|
|
91
98
|
exports.CommandActionBuilderWithState = CommandActionBuilderWithState;
|
|
@@ -30,7 +30,7 @@ class CommandActionProcessor extends baseProcessor_1.BaseActionProcessor {
|
|
|
30
30
|
cmd.triggers.includes(messageTypes_1.MessageType.Any));
|
|
31
31
|
}
|
|
32
32
|
if (commands.length > 0) {
|
|
33
|
-
telegraf.on('message',
|
|
33
|
+
telegraf.on('message', (ctx) => {
|
|
34
34
|
const msg = new incomingMessage_1.IncomingMessage(ctx.update.message, this.botName);
|
|
35
35
|
const logger = this.logger.createScope(this.botName, msg.traceId, msg.chatInfo.name);
|
|
36
36
|
if (verboseLoggingForIncomingMessage) {
|
|
@@ -39,7 +39,7 @@ class CommandActionProcessor extends baseProcessor_1.BaseActionProcessor {
|
|
|
39
39
|
else {
|
|
40
40
|
logger.logWithTraceId(`${msg.from?.first_name ?? 'Unknown'} (${msg.from?.id ?? 'Unknown'}): ${msg.text || `<non-text message: ${msg.type}>`}`);
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
void this.processMessage(msg);
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -11,10 +11,14 @@ import { MessageContext } from '../context/messageContext';
|
|
|
11
11
|
import { CommandTrigger } from '../../types/commandTrigger';
|
|
12
12
|
import { Noop } from '../../helpers/noop';
|
|
13
13
|
import { MessageType } from '../../types/messageTypes';
|
|
14
|
+
import { Sema as Semaphore } from 'async-sema';
|
|
15
|
+
import { getOrSetIfNotExists } from '../../helpers/mapUtils';
|
|
14
16
|
|
|
15
17
|
export class CommandAction<TActionState extends IActionState>
|
|
16
18
|
implements IActionWithState<TActionState>
|
|
17
19
|
{
|
|
20
|
+
readonly ratelimitSemaphores = new Map<number, Semaphore>();
|
|
21
|
+
|
|
18
22
|
readonly triggers: CommandTrigger[];
|
|
19
23
|
readonly handler: CommandHandler<TActionState>;
|
|
20
24
|
readonly name: string;
|
|
@@ -26,6 +30,7 @@ export class CommandAction<TActionState extends IActionState>
|
|
|
26
30
|
readonly stateConstructor: () => TActionState;
|
|
27
31
|
readonly key: ActionKey;
|
|
28
32
|
readonly readmeFactory: (botName: string) => string;
|
|
33
|
+
readonly maxAllowedSimultaniousExecutions: number;
|
|
29
34
|
|
|
30
35
|
constructor(
|
|
31
36
|
trigger: CommandTrigger | CommandTrigger[],
|
|
@@ -35,6 +40,7 @@ export class CommandAction<TActionState extends IActionState>
|
|
|
35
40
|
cooldown: Seconds,
|
|
36
41
|
chatsBlacklist: number[],
|
|
37
42
|
allowedUsers: number[],
|
|
43
|
+
maxAllowedSimultaniousExecutions: number,
|
|
38
44
|
condition: CommandCondition<TActionState>,
|
|
39
45
|
stateConstructor: () => TActionState,
|
|
40
46
|
readmeFactory: (botName: string) => string
|
|
@@ -49,6 +55,8 @@ export class CommandAction<TActionState extends IActionState>
|
|
|
49
55
|
this.condition = condition;
|
|
50
56
|
this.stateConstructor = stateConstructor;
|
|
51
57
|
this.readmeFactory = readmeFactory;
|
|
58
|
+
this.maxAllowedSimultaniousExecutions =
|
|
59
|
+
maxAllowedSimultaniousExecutions;
|
|
52
60
|
|
|
53
61
|
this.key = `command:${this.name.replace('.', '-')}` as ActionKey;
|
|
54
62
|
}
|
|
@@ -62,42 +70,57 @@ export class CommandAction<TActionState extends IActionState>
|
|
|
62
70
|
if (!this.active || this.chatsBlacklist.includes(ctx.chatInfo.id))
|
|
63
71
|
return Noop.NoResponse;
|
|
64
72
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
let lock: Semaphore | undefined;
|
|
74
|
+
if (this.maxAllowedSimultaniousExecutions != 0) {
|
|
75
|
+
lock = getOrSetIfNotExists(
|
|
76
|
+
this.ratelimitSemaphores,
|
|
77
|
+
ctx.chatInfo.id,
|
|
78
|
+
new Semaphore(this.maxAllowedSimultaniousExecutions)
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
await lock.acquire();
|
|
82
|
+
}
|
|
69
83
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
CommandTriggerCheckResult.DoNotTrigger
|
|
84
|
+
try {
|
|
85
|
+
const state = await ctx.storage.getActionState<TActionState>(
|
|
86
|
+
this,
|
|
87
|
+
ctx.chatInfo.id
|
|
75
88
|
);
|
|
76
89
|
|
|
77
|
-
|
|
90
|
+
const { shouldExecute, matchResults, skipCooldown } = this.triggers
|
|
91
|
+
.map((x) => this.checkIfShouldBeExecuted(ctx, x, state))
|
|
92
|
+
.reduce(
|
|
93
|
+
(acc, curr) => acc.mergeWith(curr),
|
|
94
|
+
CommandTriggerCheckResult.DoNotTrigger
|
|
95
|
+
);
|
|
78
96
|
|
|
79
|
-
|
|
80
|
-
` - Executing [${this.name}] in ${ctx.chatInfo.id}`
|
|
81
|
-
);
|
|
82
|
-
ctx.matchResults = matchResults;
|
|
97
|
+
if (!shouldExecute) return Noop.NoResponse;
|
|
83
98
|
|
|
84
|
-
|
|
99
|
+
ctx.logger.logWithTraceId(
|
|
100
|
+
` - Executing [${this.name}] in ${ctx.chatInfo.id}`
|
|
101
|
+
);
|
|
102
|
+
ctx.matchResults = matchResults;
|
|
85
103
|
|
|
86
|
-
|
|
87
|
-
ctx.startCooldown = false;
|
|
88
|
-
}
|
|
104
|
+
await this.handler(ctx, state);
|
|
89
105
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
106
|
+
if (skipCooldown) {
|
|
107
|
+
ctx.startCooldown = false;
|
|
108
|
+
}
|
|
93
109
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
state
|
|
98
|
-
);
|
|
110
|
+
if (ctx.startCooldown) {
|
|
111
|
+
state.lastExecutedDate = moment().valueOf();
|
|
112
|
+
}
|
|
99
113
|
|
|
100
|
-
|
|
114
|
+
await ctx.storage.saveActionExecutionResult(
|
|
115
|
+
this,
|
|
116
|
+
ctx.chatInfo.id,
|
|
117
|
+
state
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
return ctx.responses;
|
|
121
|
+
} finally {
|
|
122
|
+
lock?.release();
|
|
123
|
+
}
|
|
101
124
|
}
|
|
102
125
|
|
|
103
126
|
private checkIfShouldBeExecuted(
|
|
@@ -23,6 +23,7 @@ export class CommandActionBuilderWithState<TActionState extends IActionState> {
|
|
|
23
23
|
stateConstructor: () => TActionState;
|
|
24
24
|
handler: CommandHandler<TActionState> = Noop.call;
|
|
25
25
|
condition: CommandCondition<TActionState> = Noop.true;
|
|
26
|
+
maxAllowedSimultaniousExecutions: number = 0;
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Builder for `CommandAction` with state represented by `TActionState`
|
|
@@ -86,6 +87,14 @@ export class CommandActionBuilderWithState<TActionState extends IActionState> {
|
|
|
86
87
|
return this;
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
/** Sets maximum number of simultaniously executing handlers for this command per chat. 0 is treated as unlimited. */
|
|
91
|
+
ratelimit(maxAllowedSimultaniousExecutions: number) {
|
|
92
|
+
this.maxAllowedSimultaniousExecutions =
|
|
93
|
+
maxAllowedSimultaniousExecutions;
|
|
94
|
+
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
|
|
89
98
|
/** Sets action cooldown.
|
|
90
99
|
* @param seconds Cooldown in seconds.
|
|
91
100
|
*/
|
|
@@ -115,6 +124,7 @@ export class CommandActionBuilderWithState<TActionState extends IActionState> {
|
|
|
115
124
|
this.cooldownSeconds,
|
|
116
125
|
this.blacklist,
|
|
117
126
|
this.allowedUsers,
|
|
127
|
+
this.maxAllowedSimultaniousExecutions,
|
|
118
128
|
this.condition,
|
|
119
129
|
this.stateConstructor,
|
|
120
130
|
this.readmeFactory != null ? this.readmeFactory : (_) => ''
|
package/package.json
CHANGED
|
@@ -60,7 +60,7 @@ export class CommandActionProcessor extends BaseActionProcessor {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
if (commands.length > 0) {
|
|
63
|
-
telegraf.on('message',
|
|
63
|
+
telegraf.on('message', (ctx) => {
|
|
64
64
|
const msg = new IncomingMessage(
|
|
65
65
|
ctx.update.message,
|
|
66
66
|
this.botName
|
|
@@ -82,7 +82,7 @@ export class CommandActionProcessor extends BaseActionProcessor {
|
|
|
82
82
|
);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
void this.processMessage(msg);
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
}
|