chz-telegram-bot 0.3.11 → 0.3.13
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/dtos/commandTriggerCheckResult.d.ts +15 -4
- package/dist/dtos/commandTriggerCheckResult.d.ts.map +1 -1
- package/dist/dtos/commandTriggerCheckResult.js +17 -7
- package/dist/dtos/cooldownInfo.d.ts +7 -0
- package/dist/dtos/cooldownInfo.d.ts.map +1 -0
- package/dist/dtos/cooldownInfo.js +12 -0
- package/dist/entities/actions/commandAction.d.ts +8 -3
- package/dist/entities/actions/commandAction.d.ts.map +1 -1
- package/dist/entities/actions/commandAction.js +51 -26
- package/dist/entities/actions/replyCaptureAction.d.ts.map +1 -1
- package/dist/entities/actions/replyCaptureAction.js +5 -5
- package/dist/entities/context/messageContext.d.ts +6 -1
- package/dist/entities/context/messageContext.d.ts.map +1 -1
- package/dist/entities/context/messageContext.js +7 -0
- package/dist/entities/context/replyContext.d.ts +3 -1
- package/dist/entities/context/replyContext.d.ts.map +1 -1
- package/dist/entities/context/replyContext.js +2 -0
- package/dist/helpers/builders/commandActionBuilder.d.ts +8 -0
- package/dist/helpers/builders/commandActionBuilder.d.ts.map +1 -1
- package/dist/helpers/builders/commandActionBuilder.js +17 -1
- package/dist/services/actionProcessingService.d.ts.map +1 -1
- package/dist/services/actionProcessingService.js +1 -1
- package/dist/services/actionProcessors/commandActionProcessor.d.ts +3 -1
- package/dist/services/actionProcessors/commandActionProcessor.d.ts.map +1 -1
- package/dist/services/actionProcessors/commandActionProcessor.js +8 -3
- package/dtos/commandTriggerCheckResult.ts +22 -7
- package/dtos/cooldownInfo.ts +5 -0
- package/entities/actions/commandAction.ts +90 -39
- package/entities/actions/replyCaptureAction.ts +10 -5
- package/entities/context/messageContext.ts +11 -1
- package/entities/context/replyContext.ts +3 -1
- package/helpers/builders/commandActionBuilder.ts +22 -1
- package/package.json +1 -1
- package/services/actionProcessingService.ts +2 -1
- package/services/actionProcessors/commandActionProcessor.ts +10 -3
|
@@ -1,11 +1,22 @@
|
|
|
1
|
+
declare const _SkipTriggerReasonsObject: {
|
|
2
|
+
readonly UserIdMissing: "UserIdMissing";
|
|
3
|
+
readonly UserForbidden: "UserForbidden";
|
|
4
|
+
readonly OnCooldown: "OnCooldown";
|
|
5
|
+
readonly CustomConditionNotMet: "CustomConditionNotMet";
|
|
6
|
+
readonly TriggerNotSatisfied: "TriggerNotSatisfied";
|
|
7
|
+
readonly Other: "Other";
|
|
8
|
+
};
|
|
9
|
+
export type SkipTriggerReasons = keyof typeof _SkipTriggerReasonsObject;
|
|
1
10
|
export declare class CommandTriggerCheckResult {
|
|
2
|
-
static
|
|
3
|
-
static
|
|
4
|
-
static
|
|
11
|
+
static DontTriggerAndSkipCooldown(reason: SkipTriggerReasons): CommandTriggerCheckResult;
|
|
12
|
+
static DoNotTrigger(reason: SkipTriggerReasons): CommandTriggerCheckResult;
|
|
13
|
+
static Trigger(): CommandTriggerCheckResult;
|
|
5
14
|
readonly shouldExecute: boolean;
|
|
6
15
|
readonly matchResults: RegExpExecArray[];
|
|
7
16
|
readonly skipCooldown: boolean;
|
|
8
|
-
|
|
17
|
+
readonly reason: SkipTriggerReasons | undefined;
|
|
18
|
+
constructor(shouldExecute: boolean, matchResults: RegExpExecArray[], skipCooldown: boolean, reason?: SkipTriggerReasons);
|
|
9
19
|
mergeWith(other: CommandTriggerCheckResult): CommandTriggerCheckResult;
|
|
10
20
|
}
|
|
21
|
+
export {};
|
|
11
22
|
//# sourceMappingURL=commandTriggerCheckResult.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commandTriggerCheckResult.d.ts","sourceRoot":"","sources":["../../dtos/commandTriggerCheckResult.ts"],"names":[],"mappings":"AAAA,qBAAa,yBAAyB;IAClC,MAAM,
|
|
1
|
+
{"version":3,"file":"commandTriggerCheckResult.d.ts","sourceRoot":"","sources":["../../dtos/commandTriggerCheckResult.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,yBAAyB;;;;;;;CAOrB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,MAAM,OAAO,yBAAyB,CAAC;AAExE,qBAAa,yBAAyB;IAClC,MAAM,CAAC,0BAA0B,CAAC,MAAM,EAAE,kBAAkB;IAG5D,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,kBAAkB;IAG9C,MAAM,CAAC,OAAO;IAId,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,eAAe,EAAE,CAAC;IACzC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,kBAAkB,GAAG,SAAS,CAAC;gBAG5C,aAAa,EAAE,OAAO,EACtB,YAAY,EAAE,eAAe,EAAE,EAC/B,YAAY,EAAE,OAAO,EACrB,MAAM,CAAC,EAAE,kBAAkB;IAQ/B,SAAS,CAAC,KAAK,EAAE,yBAAyB;CAQ7C"}
|
|
@@ -1,26 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CommandTriggerCheckResult = void 0;
|
|
4
|
+
const _SkipTriggerReasonsObject = {
|
|
5
|
+
UserIdMissing: 'UserIdMissing',
|
|
6
|
+
UserForbidden: 'UserForbidden',
|
|
7
|
+
OnCooldown: 'OnCooldown',
|
|
8
|
+
CustomConditionNotMet: 'CustomConditionNotMet',
|
|
9
|
+
TriggerNotSatisfied: 'TriggerNotSatisfied',
|
|
10
|
+
Other: 'Other'
|
|
11
|
+
};
|
|
4
12
|
class CommandTriggerCheckResult {
|
|
5
|
-
static
|
|
6
|
-
return new CommandTriggerCheckResult(false, [], true);
|
|
13
|
+
static DontTriggerAndSkipCooldown(reason) {
|
|
14
|
+
return new CommandTriggerCheckResult(false, [], true, reason);
|
|
7
15
|
}
|
|
8
|
-
static
|
|
9
|
-
return new CommandTriggerCheckResult(false, [], false);
|
|
16
|
+
static DoNotTrigger(reason) {
|
|
17
|
+
return new CommandTriggerCheckResult(false, [], false, reason);
|
|
10
18
|
}
|
|
11
|
-
static
|
|
19
|
+
static Trigger() {
|
|
12
20
|
return new CommandTriggerCheckResult(true, [], false);
|
|
13
21
|
}
|
|
14
22
|
shouldExecute;
|
|
15
23
|
matchResults;
|
|
16
24
|
skipCooldown;
|
|
17
|
-
|
|
25
|
+
reason;
|
|
26
|
+
constructor(shouldExecute, matchResults, skipCooldown, reason) {
|
|
18
27
|
this.shouldExecute = shouldExecute;
|
|
19
28
|
this.matchResults = matchResults;
|
|
20
29
|
this.skipCooldown = skipCooldown;
|
|
30
|
+
this.reason = reason;
|
|
21
31
|
}
|
|
22
32
|
mergeWith(other) {
|
|
23
|
-
return new CommandTriggerCheckResult(this.shouldExecute || other.shouldExecute, this.matchResults.concat(other.matchResults), this.skipCooldown || other.skipCooldown);
|
|
33
|
+
return new CommandTriggerCheckResult(this.shouldExecute || other.shouldExecute, this.matchResults.concat(other.matchResults), this.skipCooldown || other.skipCooldown, other.reason);
|
|
24
34
|
}
|
|
25
35
|
}
|
|
26
36
|
exports.CommandTriggerCheckResult = CommandTriggerCheckResult;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cooldownInfo.d.ts","sourceRoot":"","sources":["../../dtos/cooldownInfo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,qBAAa,YAAY;IACF,OAAO,EAAE,OAAO;IAAS,OAAO,EAAE,MAAM,GAAG,SAAS;gBAApD,OAAO,EAAE,OAAO,EAAS,OAAO,EAAE,MAAM,GAAG,SAAS;CAC1E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CooldownInfo = void 0;
|
|
4
|
+
class CooldownInfo {
|
|
5
|
+
seconds;
|
|
6
|
+
message;
|
|
7
|
+
constructor(seconds, message) {
|
|
8
|
+
this.seconds = seconds;
|
|
9
|
+
this.message = message;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.CooldownInfo = CooldownInfo;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { CommandHandler } from '../../types/handlers';
|
|
2
2
|
import { CommandCondition } from '../../types/commandCondition';
|
|
3
|
-
import { Seconds } from '../../types/timeValues';
|
|
4
3
|
import { IActionState } from '../../types/actionState';
|
|
5
4
|
import { IActionWithState, ActionKey } from '../../types/action';
|
|
6
5
|
import { MessageContext } from '../context/messageContext';
|
|
7
6
|
import { CommandTrigger } from '../../types/commandTrigger';
|
|
7
|
+
import { Sema as Semaphore } from 'async-sema';
|
|
8
|
+
import { CooldownInfo } from '../../dtos/cooldownInfo';
|
|
9
|
+
import { Seconds } from '../../types/timeValues';
|
|
8
10
|
export declare class CommandAction<TActionState extends IActionState> implements IActionWithState<TActionState> {
|
|
11
|
+
readonly ratelimitSemaphores: Map<number, Semaphore>;
|
|
9
12
|
readonly triggers: CommandTrigger[];
|
|
10
13
|
readonly handler: CommandHandler<TActionState>;
|
|
11
14
|
readonly name: string;
|
|
12
|
-
readonly
|
|
15
|
+
readonly cooldownInfo: CooldownInfo;
|
|
13
16
|
readonly active: boolean;
|
|
14
17
|
readonly chatsBlacklist: number[];
|
|
15
18
|
readonly allowedUsers: number[];
|
|
@@ -17,7 +20,9 @@ export declare class CommandAction<TActionState extends IActionState> implements
|
|
|
17
20
|
readonly stateConstructor: () => TActionState;
|
|
18
21
|
readonly key: ActionKey;
|
|
19
22
|
readonly readmeFactory: (botName: string) => string;
|
|
20
|
-
|
|
23
|
+
readonly maxAllowedSimultaniousExecutions: number;
|
|
24
|
+
lastCustomCooldown: Seconds | undefined;
|
|
25
|
+
constructor(trigger: CommandTrigger | CommandTrigger[], handler: CommandHandler<TActionState>, name: string, active: boolean, cooldownInfo: CooldownInfo, chatsBlacklist: number[], allowedUsers: number[], maxAllowedSimultaniousExecutions: number, condition: CommandCondition<TActionState>, stateConstructor: () => TActionState, readmeFactory: (botName: string) => string);
|
|
21
26
|
exec(ctx: MessageContext<TActionState>): Promise<import("../../types/response").BotResponse[]>;
|
|
22
27
|
private checkIfShouldBeExecuted;
|
|
23
28
|
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;
|
|
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;AAGhE,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;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAGvD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,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,YAAY,EAAE,YAAY,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;IAElD,kBAAkB,EAAE,OAAO,GAAG,SAAS,CAAC;gBAGpC,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE,EAC1C,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,EACrC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO,EACf,YAAY,EAAE,YAAY,EAC1B,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;IA8E5C,OAAO,CAAC,uBAAuB;IAsC/B,OAAO,CAAC,YAAY;CAuCvB"}
|
|
@@ -10,11 +10,16 @@ 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");
|
|
15
|
+
const textMessage_1 = require("../../dtos/responses/textMessage");
|
|
16
|
+
const replyInfo_1 = require("../../dtos/replyInfo");
|
|
13
17
|
class CommandAction {
|
|
18
|
+
ratelimitSemaphores = new Map();
|
|
14
19
|
triggers;
|
|
15
20
|
handler;
|
|
16
21
|
name;
|
|
17
|
-
|
|
22
|
+
cooldownInfo;
|
|
18
23
|
active;
|
|
19
24
|
chatsBlacklist;
|
|
20
25
|
allowedUsers;
|
|
@@ -22,17 +27,21 @@ class CommandAction {
|
|
|
22
27
|
stateConstructor;
|
|
23
28
|
key;
|
|
24
29
|
readmeFactory;
|
|
25
|
-
|
|
30
|
+
maxAllowedSimultaniousExecutions;
|
|
31
|
+
lastCustomCooldown;
|
|
32
|
+
constructor(trigger, handler, name, active, cooldownInfo, chatsBlacklist, allowedUsers, maxAllowedSimultaniousExecutions, condition, stateConstructor, readmeFactory) {
|
|
26
33
|
this.triggers = (0, toArray_1.toArray)(trigger);
|
|
27
34
|
this.handler = handler;
|
|
28
35
|
this.name = name;
|
|
29
|
-
this.
|
|
36
|
+
this.cooldownInfo = cooldownInfo;
|
|
30
37
|
this.active = active;
|
|
31
38
|
this.chatsBlacklist = chatsBlacklist;
|
|
32
39
|
this.allowedUsers = allowedUsers;
|
|
33
40
|
this.condition = condition;
|
|
34
41
|
this.stateConstructor = stateConstructor;
|
|
35
42
|
this.readmeFactory = readmeFactory;
|
|
43
|
+
this.maxAllowedSimultaniousExecutions =
|
|
44
|
+
maxAllowedSimultaniousExecutions;
|
|
36
45
|
this.key = `command:${this.name.replace('.', '-')}`;
|
|
37
46
|
}
|
|
38
47
|
async exec(ctx) {
|
|
@@ -40,48 +49,64 @@ class CommandAction {
|
|
|
40
49
|
throw new Error(`Context for ${this.key} is not initialized or already consumed`);
|
|
41
50
|
if (!this.active || this.chatsBlacklist.includes(ctx.chatInfo.id))
|
|
42
51
|
return noop_1.Noop.NoResponse;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
let lock;
|
|
53
|
+
if (this.maxAllowedSimultaniousExecutions != 0) {
|
|
54
|
+
lock = (0, mapUtils_1.getOrSetIfNotExists)(this.ratelimitSemaphores, ctx.chatInfo.id, new async_sema_1.Sema(this.maxAllowedSimultaniousExecutions));
|
|
55
|
+
await lock.acquire();
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const state = await ctx.storage.getActionState(this, ctx.chatInfo.id);
|
|
59
|
+
const { shouldExecute, matchResults, skipCooldown, reason } = this.triggers
|
|
60
|
+
.map((x) => this.checkIfShouldBeExecuted(ctx, x, state))
|
|
61
|
+
.reduce((acc, curr) => acc.mergeWith(curr), commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger('Other'));
|
|
62
|
+
if (!shouldExecute) {
|
|
63
|
+
if (reason == 'OnCooldown' && this.cooldownInfo.message)
|
|
64
|
+
return [
|
|
65
|
+
new textMessage_1.TextMessage(this.cooldownInfo.message, ctx.chatInfo, ctx.traceId, this, new replyInfo_1.ReplyInfo(ctx.messageId))
|
|
66
|
+
];
|
|
67
|
+
return noop_1.Noop.NoResponse;
|
|
68
|
+
}
|
|
69
|
+
ctx.logger.logWithTraceId(` - Executing [${this.name}] in ${ctx.chatInfo.id}`);
|
|
70
|
+
ctx.matchResults = matchResults;
|
|
71
|
+
await this.handler(ctx, state);
|
|
72
|
+
if (skipCooldown) {
|
|
73
|
+
ctx.startCooldown = false;
|
|
74
|
+
}
|
|
75
|
+
if (ctx.startCooldown) {
|
|
76
|
+
this.lastCustomCooldown = ctx.customCooldown;
|
|
77
|
+
state.lastExecutedDate = (0, moment_1.default)().valueOf();
|
|
78
|
+
}
|
|
79
|
+
await ctx.storage.saveActionExecutionResult(this, ctx.chatInfo.id, state);
|
|
80
|
+
return ctx.responses;
|
|
54
81
|
}
|
|
55
|
-
|
|
56
|
-
|
|
82
|
+
finally {
|
|
83
|
+
lock?.release();
|
|
57
84
|
}
|
|
58
|
-
await ctx.storage.saveActionExecutionResult(this, ctx.chatInfo.id, state);
|
|
59
|
-
return ctx.responses;
|
|
60
85
|
}
|
|
61
86
|
checkIfShouldBeExecuted(ctx, trigger, state) {
|
|
62
87
|
if (!ctx.fromUserId)
|
|
63
|
-
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DontTriggerAndSkipCooldown;
|
|
88
|
+
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DontTriggerAndSkipCooldown('UserIdMissing');
|
|
64
89
|
const isUserAllowed = this.allowedUsers.length == 0 ||
|
|
65
90
|
this.allowedUsers.includes(ctx.fromUserId);
|
|
66
91
|
if (!isUserAllowed)
|
|
67
|
-
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DontTriggerAndSkipCooldown;
|
|
92
|
+
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DontTriggerAndSkipCooldown('UserForbidden');
|
|
68
93
|
const lastExecutedDate = (0, moment_1.default)(state.lastExecutedDate);
|
|
69
|
-
const cooldownInMilliseconds = (0, timeConvertions_1.secondsToMilliseconds)(this.
|
|
94
|
+
const cooldownInMilliseconds = (0, timeConvertions_1.secondsToMilliseconds)(this.lastCustomCooldown ?? this.cooldownInfo.seconds);
|
|
70
95
|
const onCooldown = (0, moment_1.default)().diff(lastExecutedDate) < cooldownInMilliseconds;
|
|
71
96
|
if (onCooldown)
|
|
72
|
-
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger;
|
|
97
|
+
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger('OnCooldown');
|
|
73
98
|
const isCustomConditionMet = this.condition(ctx, state);
|
|
74
99
|
if (!isCustomConditionMet)
|
|
75
|
-
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DontTriggerAndSkipCooldown;
|
|
100
|
+
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DontTriggerAndSkipCooldown('CustomConditionNotMet');
|
|
76
101
|
return this.checkTrigger(ctx, trigger);
|
|
77
102
|
}
|
|
78
103
|
checkTrigger(ctx, trigger) {
|
|
79
104
|
if (trigger == messageTypes_1.MessageType.Any || trigger == ctx.messageType)
|
|
80
|
-
return commandTriggerCheckResult_1.CommandTriggerCheckResult.Trigger;
|
|
105
|
+
return commandTriggerCheckResult_1.CommandTriggerCheckResult.Trigger();
|
|
81
106
|
if (typeof trigger == 'string')
|
|
82
107
|
return ctx.messageText.toLowerCase() == trigger.toLowerCase()
|
|
83
|
-
? commandTriggerCheckResult_1.CommandTriggerCheckResult.Trigger
|
|
84
|
-
: commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger;
|
|
108
|
+
? commandTriggerCheckResult_1.CommandTriggerCheckResult.Trigger()
|
|
109
|
+
: commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger('TriggerNotSatisfied');
|
|
85
110
|
const matchResults = [];
|
|
86
111
|
trigger.lastIndex = 0;
|
|
87
112
|
const execResult = trigger.exec(ctx.messageText);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replyCaptureAction.d.ts","sourceRoot":"","sources":["../../../entities/actions/replyCaptureAction.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,qBAAa,kBAAkB,CAAC,kBAAkB,SAAS,YAAY,CACnE,YAAW,OAAO;IAElB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,CACd,YAAY,EAAE,YAAY,CAAC,kBAAkB,CAAC,KAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;gBAGtC,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,EAClD,OAAO,EAAE,CACL,YAAY,EAAE,YAAY,CAAC,kBAAkB,CAAC,KAC7C,OAAO,CAAC,IAAI,CAAC,EAClB,QAAQ,EAAE,cAAc,EAAE,EAC1B,eAAe,EAAE,eAAe;IAY9B,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,kBAAkB,CAAC;IAyBhD,OAAO,CAAC,uBAAuB;
|
|
1
|
+
{"version":3,"file":"replyCaptureAction.d.ts","sourceRoot":"","sources":["../../../entities/actions/replyCaptureAction.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,qBAAa,kBAAkB,CAAC,kBAAkB,SAAS,YAAY,CACnE,YAAW,OAAO;IAElB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,CACd,YAAY,EAAE,YAAY,CAAC,kBAAkB,CAAC,KAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;gBAGtC,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,EAClD,OAAO,EAAE,CACL,YAAY,EAAE,YAAY,CAAC,kBAAkB,CAAC,KAC7C,OAAO,CAAC,IAAI,CAAC,EAClB,QAAQ,EAAE,cAAc,EAAE,EAC1B,eAAe,EAAE,eAAe;IAY9B,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,kBAAkB,CAAC;IAyBhD,OAAO,CAAC,uBAAuB;CA+ClC"}
|
|
@@ -23,7 +23,7 @@ class ReplyCaptureAction {
|
|
|
23
23
|
throw new Error(`Context for ${this.key} is not initialized or already consumed`);
|
|
24
24
|
const { shouldExecute, matchResults } = this.triggers
|
|
25
25
|
.map((x) => this.checkIfShouldBeExecuted(ctx, x))
|
|
26
|
-
.reduce((acc, curr) => acc.mergeWith(curr), commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger);
|
|
26
|
+
.reduce((acc, curr) => acc.mergeWith(curr), commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger('Other'));
|
|
27
27
|
if (!shouldExecute)
|
|
28
28
|
return noop_1.Noop.NoResponse;
|
|
29
29
|
ctx.logger.logWithTraceId(` - Executing [${this.key}] in ${ctx.chatInfo.id}`);
|
|
@@ -33,14 +33,14 @@ class ReplyCaptureAction {
|
|
|
33
33
|
}
|
|
34
34
|
checkIfShouldBeExecuted(ctx, trigger) {
|
|
35
35
|
if (ctx.replyMessageId != this.parentMessageId)
|
|
36
|
-
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger;
|
|
36
|
+
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger('TriggerNotSatisfied');
|
|
37
37
|
if (trigger == ctx.messageType)
|
|
38
|
-
return commandTriggerCheckResult_1.CommandTriggerCheckResult.Trigger;
|
|
38
|
+
return commandTriggerCheckResult_1.CommandTriggerCheckResult.Trigger();
|
|
39
39
|
if (typeof trigger == 'string')
|
|
40
40
|
if (ctx.messageText.toLowerCase() == trigger.toLowerCase())
|
|
41
|
-
return commandTriggerCheckResult_1.CommandTriggerCheckResult.Trigger;
|
|
41
|
+
return commandTriggerCheckResult_1.CommandTriggerCheckResult.Trigger();
|
|
42
42
|
else
|
|
43
|
-
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger;
|
|
43
|
+
return commandTriggerCheckResult_1.CommandTriggerCheckResult.DoNotTrigger('TriggerNotSatisfied');
|
|
44
44
|
const matchResults = [];
|
|
45
45
|
trigger.lastIndex = 0;
|
|
46
46
|
const execResult = trigger.exec(ctx.messageText);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { TelegramEmoji } from 'telegraf/types';
|
|
1
|
+
import { TelegramEmoji, UserFromGetMe } from 'telegraf/types';
|
|
2
2
|
import { IActionState } from '../../types/actionState';
|
|
3
3
|
import { ChatContext } from './chatContext';
|
|
4
4
|
import { MessageSendingOptions, TextMessageSendingOptions } from '../../types/messageSendingOptions';
|
|
5
5
|
import { MessageTypeValue, TelegrafContextMessage } from '../../types/messageTypes';
|
|
6
6
|
import { CommandAction } from '../actions/commandAction';
|
|
7
|
+
import { Seconds } from '../../types/timeValues';
|
|
7
8
|
/**
|
|
8
9
|
* Context of action executed in chat, in response to a message
|
|
9
10
|
*/
|
|
@@ -24,10 +25,14 @@ export declare class MessageContext<TActionState extends IActionState> extends C
|
|
|
24
25
|
messageType: MessageTypeValue;
|
|
25
26
|
/** Message object recieved from Telegram */
|
|
26
27
|
messageUpdateObject: TelegrafContextMessage;
|
|
28
|
+
/** Bot info from Telegram */
|
|
29
|
+
botInfo: UserFromGetMe;
|
|
30
|
+
customCooldown: Seconds | undefined;
|
|
27
31
|
private getQuotePart;
|
|
28
32
|
private replyWithText;
|
|
29
33
|
private replyWithImage;
|
|
30
34
|
private replyWithVideo;
|
|
35
|
+
startCustomCooldown(customCooldown: Seconds): void;
|
|
31
36
|
/**
|
|
32
37
|
* Collection of actions that can be done as a reply to a message that triggered this action
|
|
33
38
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messageContext.d.ts","sourceRoot":"","sources":["../../../entities/context/messageContext.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"messageContext.d.ts","sourceRoot":"","sources":["../../../entities/context/messageContext.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAKvD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EACH,qBAAqB,EACrB,yBAAyB,EAC5B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACH,gBAAgB,EAChB,sBAAsB,EACzB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD;;GAEG;AACH,qBAAa,cAAc,CACvB,YAAY,SAAS,YAAY,CACnC,SAAQ,WAAW,CAAC,YAAY,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IAC5D,kDAAkD;IAClD,SAAS,EAAG,MAAM,CAAC;IACnB,oDAAoD;IACpD,WAAW,EAAG,MAAM,CAAC;IACrB,4HAA4H;IAC5H,YAAY,EAAE,gBAAgB,EAAE,CAAM;IACtC,mEAAmE;IACnE,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,kGAAkG;IAClG,aAAa,EAAE,OAAO,CAAQ;IAC9B,qEAAqE;IACrE,YAAY,EAAG,MAAM,CAAC;IACtB,qCAAqC;IACrC,WAAW,EAAG,gBAAgB,CAAC;IAC/B,4CAA4C;IAC5C,mBAAmB,EAAG,sBAAsB,CAAC;IAC7C,6BAA6B;IAC7B,OAAO,EAAG,aAAa,CAAC;IAExB,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC;IAEpC,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,aAAa;IAqBrB,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,cAAc;IAqBtB,mBAAmB,CAAC,cAAc,EAAE,OAAO;IAK3C;;OAEG;IACH,KAAK;QACD;;;WAGG;;YAEC;;;;;eAKG;6BAEO,MAAM,UACJ,MAAM,YACJ,yBAAyB;YAEvC;;;;;eAKG;8BAEO,MAAM,UACJ,MAAM,YACJ,qBAAqB;YAGnC;;;;;eAKG;8BAEO,MAAM,UACJ,MAAM,YACJ,qBAAqB;;QAIvC;;;;;WAKG;yBACc,MAAM,YAAY,yBAAyB;QAE5D;;;;;WAKG;0BACe,MAAM,YAAY,qBAAqB;QAGzD;;;;;WAKG;0BACe,MAAM,YAAY,qBAAqB;QAGzD;;;;WAIG;8BACmB,aAAa;MAWrC;CACL"}
|
|
@@ -28,6 +28,9 @@ class MessageContext extends chatContext_1.ChatContext {
|
|
|
28
28
|
messageType;
|
|
29
29
|
/** Message object recieved from Telegram */
|
|
30
30
|
messageUpdateObject;
|
|
31
|
+
/** Bot info from Telegram */
|
|
32
|
+
botInfo;
|
|
33
|
+
customCooldown;
|
|
31
34
|
getQuotePart(quote) {
|
|
32
35
|
return typeof quote == 'boolean'
|
|
33
36
|
? this.matchResults.length != 0
|
|
@@ -53,6 +56,10 @@ class MessageContext extends chatContext_1.ChatContext {
|
|
|
53
56
|
this.responses.push(response);
|
|
54
57
|
return this.createCaptureController(response);
|
|
55
58
|
}
|
|
59
|
+
startCustomCooldown(customCooldown) {
|
|
60
|
+
this.startCooldown = true;
|
|
61
|
+
this.customCooldown = customCooldown;
|
|
62
|
+
}
|
|
56
63
|
/**
|
|
57
64
|
* Collection of actions that can be done as a reply to a message that triggered this action
|
|
58
65
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TelegramEmoji } from 'telegraf/types';
|
|
1
|
+
import { TelegramEmoji, UserFromGetMe } from 'telegraf/types';
|
|
2
2
|
import { IActionState } from '../../types/actionState';
|
|
3
3
|
import { TextMessageSendingOptions, MessageSendingOptions } from '../../types/messageSendingOptions';
|
|
4
4
|
import { MessageTypeValue, TelegrafContextMessage } from '../../types/messageTypes';
|
|
@@ -21,6 +21,8 @@ export declare class ReplyContext<TParentActionState extends IActionState> exten
|
|
|
21
21
|
fromUserName: string;
|
|
22
22
|
/** Message object recieved from Telegram */
|
|
23
23
|
messageUpdateObject: TelegrafContextMessage;
|
|
24
|
+
/** Bot info from Telegram */
|
|
25
|
+
botInfo: UserFromGetMe;
|
|
24
26
|
isInitialized: boolean;
|
|
25
27
|
private getQuotePart;
|
|
26
28
|
private replyWithText;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replyContext.d.ts","sourceRoot":"","sources":["../../../entities/context/replyContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"replyContext.d.ts","sourceRoot":"","sources":["../../../entities/context/replyContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAM9D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EACH,yBAAyB,EACzB,qBAAqB,EACxB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACH,gBAAgB,EAChB,sBAAsB,EACzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,qBAAa,YAAY,CACrB,kBAAkB,SAAS,YAAY,CACzC,SAAQ,WAAW,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;IACzD,4HAA4H;IAC5H,YAAY,EAAG,eAAe,EAAE,CAAC;IACjC,kDAAkD;IAClD,cAAc,EAAG,MAAM,GAAG,SAAS,CAAC;IACpC,kDAAkD;IAClD,SAAS,EAAG,MAAM,CAAC;IACnB,qCAAqC;IACrC,WAAW,EAAG,gBAAgB,CAAC;IAC/B,oDAAoD;IACpD,WAAW,EAAG,MAAM,CAAC;IACrB,mEAAmE;IACnE,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,qEAAqE;IACrE,YAAY,EAAG,MAAM,CAAC;IACtB,4CAA4C;IAC5C,mBAAmB,EAAG,sBAAsB,CAAC;IAC7C,6BAA6B;IAC7B,OAAO,EAAG,aAAa,CAAC;IAExB,aAAa,UAAS;IAEtB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,cAAc;IAmBtB;;OAEG;IACH,WAAW;IAIX;;OAEG;IACH,KAAK;QACD;;;WAGG;;YAEC;;;;;eAKG;6BAEO,MAAM,UACJ,MAAM,YACJ,yBAAyB;YAIvC;;;;;eAKG;8BAEO,MAAM,UACJ,MAAM,YACJ,qBAAqB;YAKnC;;;;;eAKG;8BAEO,MAAM,UACJ,MAAM,YACJ,qBAAqB;;QAMvC;;;;;WAKG;yBACc,MAAM,YAAY,yBAAyB;QAG5D;;;;;WAKG;0BACe,MAAM,YAAY,qBAAqB;QAIzD;;;;;WAKG;0BACe,MAAM,YAAY,qBAAqB;QAIzD;;;;WAIG;8BACmB,aAAa;MAWrC;CACL"}
|
|
@@ -25,6 +25,8 @@ class ReplyContext extends baseContext_1.BaseContext {
|
|
|
25
25
|
fromUserName;
|
|
26
26
|
/** Message object recieved from Telegram */
|
|
27
27
|
messageUpdateObject;
|
|
28
|
+
/** Bot info from Telegram */
|
|
29
|
+
botInfo;
|
|
28
30
|
isInitialized = false;
|
|
29
31
|
getQuotePart(quote) {
|
|
30
32
|
return typeof quote == 'boolean'
|
|
@@ -19,6 +19,8 @@ export declare class CommandActionBuilderWithState<TActionState extends IActionS
|
|
|
19
19
|
stateConstructor: () => TActionState;
|
|
20
20
|
handler: CommandHandler<TActionState>;
|
|
21
21
|
condition: CommandCondition<TActionState>;
|
|
22
|
+
maxAllowedSimultaniousExecutions: number;
|
|
23
|
+
cooldownMessage: string | undefined;
|
|
22
24
|
/**
|
|
23
25
|
* Builder for `CommandAction` with state represented by `TActionState`
|
|
24
26
|
* @param name Action name, will be used for logging and storage
|
|
@@ -47,10 +49,16 @@ export declare class CommandActionBuilderWithState<TActionState extends IActionS
|
|
|
47
49
|
withHelp(readmeFactory: (botName: string) => string): this;
|
|
48
50
|
/** If called during building, action is marked as disabled and never checked. */
|
|
49
51
|
disabled(): this;
|
|
52
|
+
/** Sets maximum number of simultaniously executing handlers for this command per chat. 0 is treated as unlimited. */
|
|
53
|
+
ratelimit(maxAllowedSimultaniousExecutions: number): this;
|
|
50
54
|
/** Sets action cooldown.
|
|
51
55
|
* @param seconds Cooldown in seconds.
|
|
52
56
|
*/
|
|
53
57
|
cooldown(seconds: Seconds): this;
|
|
58
|
+
/** Sets action cooldown message.
|
|
59
|
+
* @param message Message that will be sent if action is on cooldown.
|
|
60
|
+
*/
|
|
61
|
+
withCooldownMessage(message: string): this;
|
|
54
62
|
/**
|
|
55
63
|
* Adds a chat to ignore list for this action.
|
|
56
64
|
* @param chatId Chat id to ignore.
|
|
@@ -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;
|
|
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;AAG5D;;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;IAC7C,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IAEpC;;;;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;;OAEG;IACH,mBAAmB,CAAC,OAAO,EAAE,MAAM;IAMnC;;;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"}
|
|
@@ -5,6 +5,7 @@ const commandAction_1 = require("../../entities/actions/commandAction");
|
|
|
5
5
|
const actionStateBase_1 = require("../../entities/states/actionStateBase");
|
|
6
6
|
const toArray_1 = require("../toArray");
|
|
7
7
|
const noop_1 = require("../noop");
|
|
8
|
+
const cooldownInfo_1 = require("../../dtos/cooldownInfo");
|
|
8
9
|
/**
|
|
9
10
|
* Builder for `CommandAction` with state represented by `TActionState`
|
|
10
11
|
*/
|
|
@@ -19,6 +20,8 @@ class CommandActionBuilderWithState {
|
|
|
19
20
|
stateConstructor;
|
|
20
21
|
handler = noop_1.Noop.call;
|
|
21
22
|
condition = noop_1.Noop.true;
|
|
23
|
+
maxAllowedSimultaniousExecutions = 0;
|
|
24
|
+
cooldownMessage;
|
|
22
25
|
/**
|
|
23
26
|
* Builder for `CommandAction` with state represented by `TActionState`
|
|
24
27
|
* @param name Action name, will be used for logging and storage
|
|
@@ -68,6 +71,12 @@ class CommandActionBuilderWithState {
|
|
|
68
71
|
this.active = false;
|
|
69
72
|
return this;
|
|
70
73
|
}
|
|
74
|
+
/** Sets maximum number of simultaniously executing handlers for this command per chat. 0 is treated as unlimited. */
|
|
75
|
+
ratelimit(maxAllowedSimultaniousExecutions) {
|
|
76
|
+
this.maxAllowedSimultaniousExecutions =
|
|
77
|
+
maxAllowedSimultaniousExecutions;
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
71
80
|
/** Sets action cooldown.
|
|
72
81
|
* @param seconds Cooldown in seconds.
|
|
73
82
|
*/
|
|
@@ -75,6 +84,13 @@ class CommandActionBuilderWithState {
|
|
|
75
84
|
this.cooldownSeconds = seconds;
|
|
76
85
|
return this;
|
|
77
86
|
}
|
|
87
|
+
/** Sets action cooldown message.
|
|
88
|
+
* @param message Message that will be sent if action is on cooldown.
|
|
89
|
+
*/
|
|
90
|
+
withCooldownMessage(message) {
|
|
91
|
+
this.cooldownMessage = message;
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
78
94
|
/**
|
|
79
95
|
* Adds a chat to ignore list for this action.
|
|
80
96
|
* @param chatId Chat id to ignore.
|
|
@@ -85,7 +101,7 @@ class CommandActionBuilderWithState {
|
|
|
85
101
|
}
|
|
86
102
|
/** Builds action */
|
|
87
103
|
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 : (_) => '');
|
|
104
|
+
return new commandAction_1.CommandAction(this.trigger, this.handler, this.name, this.active, new cooldownInfo_1.CooldownInfo(this.cooldownSeconds, this.cooldownMessage), this.blacklist, this.allowedUsers, this.maxAllowedSimultaniousExecutions, this.condition, this.stateConstructor, this.readmeFactory != null ? this.readmeFactory : (_) => '');
|
|
89
105
|
}
|
|
90
106
|
}
|
|
91
107
|
exports.CommandActionBuilderWithState = CommandActionBuilderWithState;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actionProcessingService.d.ts","sourceRoot":"","sources":["../../services/actionProcessingService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAuB,MAAM,qBAAqB,CAAC;AAEnE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAMtE,qBAAa,uBAAuB;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IAEjC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAyB;IAC1D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA2B;IAC9D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA6B;IAElE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAY;gBAGxB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7B,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,OAAO;IA4Bb,UAAU,CACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QACL,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;QACxC,SAAS,EAAE,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC;QAC3C,aAAa,EAAE,iBAAiB,EAAE,CAAC;KACtC,EACD,eAAe,CAAC,EAAE,OAAO,EACzB,gCAAgC,CAAC,EAAE,OAAO;
|
|
1
|
+
{"version":3,"file":"actionProcessingService.d.ts","sourceRoot":"","sources":["../../services/actionProcessingService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAuB,MAAM,qBAAqB,CAAC;AAEnE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAMtE,qBAAa,uBAAuB;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IAEjC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAyB;IAC1D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA2B;IAC9D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA6B;IAElE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAY;gBAGxB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7B,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,OAAO;IA4Bb,UAAU,CACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QACL,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;QACxC,SAAS,EAAE,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC;QAC3C,aAAa,EAAE,iBAAiB,EAAE,CAAC;KACtC,EACD,eAAe,CAAC,EAAE,OAAO,EACzB,gCAAgC,CAAC,EAAE,OAAO;IA2D9C,IAAI,CAAC,IAAI,EAAE,MAAM;CAGpB"}
|
|
@@ -38,7 +38,7 @@ class ActionProcessingService {
|
|
|
38
38
|
...actions.commands
|
|
39
39
|
]
|
|
40
40
|
: [];
|
|
41
|
-
this.commandProcessor.initialize(api, this.telegraf, commandActions, verboseLoggingForIncomingMessage ?? false);
|
|
41
|
+
this.commandProcessor.initialize(api, this.telegraf, commandActions, verboseLoggingForIncomingMessage ?? false, botInfo);
|
|
42
42
|
this.inlineQueryProcessor.initialize(api, this.telegraf, actions.inlineQueries, 300);
|
|
43
43
|
this.scheduledProcessor.initialize(api, actions.scheduled, scheduledPeriod ?? (0, timeConvertions_1.hoursToSeconds)(1));
|
|
44
44
|
void this.storage.saveMetadata([
|
|
@@ -6,10 +6,12 @@ import { IReplyCapture } from '../../types/capture';
|
|
|
6
6
|
import { TraceId } from '../../types/trace';
|
|
7
7
|
import { ChatInfo } from '../../dtos/chatInfo';
|
|
8
8
|
import { BaseActionProcessor } from './baseProcessor';
|
|
9
|
+
import { UserFromGetMe } from 'telegraf/types';
|
|
9
10
|
export declare class CommandActionProcessor extends BaseActionProcessor {
|
|
10
11
|
private readonly replyCaptures;
|
|
12
|
+
private botInfo;
|
|
11
13
|
private commands;
|
|
12
|
-
initialize(api: TelegramApiService, telegraf: Telegraf, commands: CommandAction<IActionState>[], verboseLoggingForIncomingMessage: boolean): void;
|
|
14
|
+
initialize(api: TelegramApiService, telegraf: Telegraf, commands: CommandAction<IActionState>[], verboseLoggingForIncomingMessage: boolean, botInfo: UserFromGetMe): void;
|
|
13
15
|
captureRegistrationCallback(capture: IReplyCapture, parentMessageId: number, chatInfo: ChatInfo, traceId: TraceId): void;
|
|
14
16
|
private processMessage;
|
|
15
17
|
private initializeReplyCaptureContext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commandActionProcessor.d.ts","sourceRoot":"","sources":["../../../services/actionProcessors/commandActionProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAIrE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAM/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"commandActionProcessor.d.ts","sourceRoot":"","sources":["../../../services/actionProcessors/commandActionProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAIrE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAM/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,qBAAa,sBAAuB,SAAQ,mBAAmB;IAC3D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0C;IACxE,OAAO,CAAC,OAAO,CAAiB;IAEhC,OAAO,CAAC,QAAQ,CAKd;IAEF,UAAU,CACN,GAAG,EAAE,kBAAkB,EACvB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,EAAE,EACvC,gCAAgC,EAAE,OAAO,EACzC,OAAO,EAAE,aAAa;IA0D1B,2BAA2B,CACvB,OAAO,EAAE,aAAa,EACtB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO;YA+BN,cAAc;IAiC5B,OAAO,CAAC,6BAA6B;IA8BrC,OAAO,CAAC,wBAAwB;CAgCnC"}
|
|
@@ -10,11 +10,13 @@ const objectFromEntries_1 = require("../../helpers/objectFromEntries");
|
|
|
10
10
|
const baseProcessor_1 = require("./baseProcessor");
|
|
11
11
|
class CommandActionProcessor extends baseProcessor_1.BaseActionProcessor {
|
|
12
12
|
replyCaptures = [];
|
|
13
|
+
botInfo;
|
|
13
14
|
commands = (0, objectFromEntries_1.typeSafeObjectFromEntries)(Object.values(messageTypes_1.MessageType).map((x) => [
|
|
14
15
|
x,
|
|
15
16
|
[]
|
|
16
17
|
]));
|
|
17
|
-
initialize(api, telegraf, commands, verboseLoggingForIncomingMessage) {
|
|
18
|
+
initialize(api, telegraf, commands, verboseLoggingForIncomingMessage, botInfo) {
|
|
19
|
+
this.botInfo = botInfo;
|
|
18
20
|
this.initializeDependencies(api);
|
|
19
21
|
for (const msgType of Object.values(messageTypes_1.MessageType)) {
|
|
20
22
|
if (msgType == messageTypes_1.MessageType.Text) {
|
|
@@ -30,7 +32,7 @@ class CommandActionProcessor extends baseProcessor_1.BaseActionProcessor {
|
|
|
30
32
|
cmd.triggers.includes(messageTypes_1.MessageType.Any));
|
|
31
33
|
}
|
|
32
34
|
if (commands.length > 0) {
|
|
33
|
-
telegraf.on('message',
|
|
35
|
+
telegraf.on('message', (ctx) => {
|
|
34
36
|
const msg = new incomingMessage_1.IncomingMessage(ctx.update.message, this.botName);
|
|
35
37
|
const logger = this.logger.createScope(this.botName, msg.traceId, msg.chatInfo.name);
|
|
36
38
|
if (verboseLoggingForIncomingMessage) {
|
|
@@ -39,7 +41,7 @@ class CommandActionProcessor extends baseProcessor_1.BaseActionProcessor {
|
|
|
39
41
|
else {
|
|
40
42
|
logger.logWithTraceId(`${msg.from?.first_name ?? 'Unknown'} (${msg.from?.id ?? 'Unknown'}): ${msg.text || `<non-text message: ${msg.type}>`}`);
|
|
41
43
|
}
|
|
42
|
-
|
|
44
|
+
void this.processMessage(msg);
|
|
43
45
|
});
|
|
44
46
|
}
|
|
45
47
|
}
|
|
@@ -87,6 +89,7 @@ class CommandActionProcessor extends baseProcessor_1.BaseActionProcessor {
|
|
|
87
89
|
ctx.action = action;
|
|
88
90
|
ctx.chatInfo = message.chatInfo;
|
|
89
91
|
ctx.traceId = message.traceId;
|
|
92
|
+
ctx.botInfo = this.botInfo;
|
|
90
93
|
ctx.isInitialized = true;
|
|
91
94
|
ctx.matchResults = [];
|
|
92
95
|
ctx.logger = this.logger.createScope(this.botName, message.traceId, message.chatInfo.name);
|
|
@@ -108,6 +111,8 @@ class CommandActionProcessor extends baseProcessor_1.BaseActionProcessor {
|
|
|
108
111
|
ctx.action = action;
|
|
109
112
|
ctx.chatInfo = message.chatInfo;
|
|
110
113
|
ctx.traceId = message.traceId;
|
|
114
|
+
ctx.botInfo = this.botInfo;
|
|
115
|
+
ctx.customCooldown = undefined;
|
|
111
116
|
ctx.logger = this.logger.createScope(this.botName, message.traceId, message.chatInfo.name);
|
|
112
117
|
}
|
|
113
118
|
}
|
|
@@ -1,33 +1,48 @@
|
|
|
1
|
+
const _SkipTriggerReasonsObject = {
|
|
2
|
+
UserIdMissing: 'UserIdMissing',
|
|
3
|
+
UserForbidden: 'UserForbidden',
|
|
4
|
+
OnCooldown: 'OnCooldown',
|
|
5
|
+
CustomConditionNotMet: 'CustomConditionNotMet',
|
|
6
|
+
TriggerNotSatisfied: 'TriggerNotSatisfied',
|
|
7
|
+
Other: 'Other'
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
export type SkipTriggerReasons = keyof typeof _SkipTriggerReasonsObject;
|
|
11
|
+
|
|
1
12
|
export class CommandTriggerCheckResult {
|
|
2
|
-
static
|
|
3
|
-
return new CommandTriggerCheckResult(false, [], true);
|
|
13
|
+
static DontTriggerAndSkipCooldown(reason: SkipTriggerReasons) {
|
|
14
|
+
return new CommandTriggerCheckResult(false, [], true, reason);
|
|
4
15
|
}
|
|
5
|
-
static
|
|
6
|
-
return new CommandTriggerCheckResult(false, [], false);
|
|
16
|
+
static DoNotTrigger(reason: SkipTriggerReasons) {
|
|
17
|
+
return new CommandTriggerCheckResult(false, [], false, reason);
|
|
7
18
|
}
|
|
8
|
-
static
|
|
19
|
+
static Trigger() {
|
|
9
20
|
return new CommandTriggerCheckResult(true, [], false);
|
|
10
21
|
}
|
|
11
22
|
|
|
12
23
|
readonly shouldExecute: boolean;
|
|
13
24
|
readonly matchResults: RegExpExecArray[];
|
|
14
25
|
readonly skipCooldown: boolean;
|
|
26
|
+
readonly reason: SkipTriggerReasons | undefined;
|
|
15
27
|
|
|
16
28
|
constructor(
|
|
17
29
|
shouldExecute: boolean,
|
|
18
30
|
matchResults: RegExpExecArray[],
|
|
19
|
-
skipCooldown: boolean
|
|
31
|
+
skipCooldown: boolean,
|
|
32
|
+
reason?: SkipTriggerReasons
|
|
20
33
|
) {
|
|
21
34
|
this.shouldExecute = shouldExecute;
|
|
22
35
|
this.matchResults = matchResults;
|
|
23
36
|
this.skipCooldown = skipCooldown;
|
|
37
|
+
this.reason = reason;
|
|
24
38
|
}
|
|
25
39
|
|
|
26
40
|
mergeWith(other: CommandTriggerCheckResult) {
|
|
27
41
|
return new CommandTriggerCheckResult(
|
|
28
42
|
this.shouldExecute || other.shouldExecute,
|
|
29
43
|
this.matchResults.concat(other.matchResults),
|
|
30
|
-
this.skipCooldown || other.skipCooldown
|
|
44
|
+
this.skipCooldown || other.skipCooldown,
|
|
45
|
+
other.reason
|
|
31
46
|
);
|
|
32
47
|
}
|
|
33
48
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import moment from 'moment';
|
|
2
2
|
import { CommandHandler } from '../../types/handlers';
|
|
3
3
|
import { CommandCondition } from '../../types/commandCondition';
|
|
4
|
-
import { Seconds } from '../../types/timeValues';
|
|
5
4
|
import { secondsToMilliseconds } from '../../helpers/timeConvertions';
|
|
6
5
|
import { toArray } from '../../helpers/toArray';
|
|
7
6
|
import { IActionState } from '../../types/actionState';
|
|
@@ -11,14 +10,22 @@ import { MessageContext } from '../context/messageContext';
|
|
|
11
10
|
import { CommandTrigger } from '../../types/commandTrigger';
|
|
12
11
|
import { Noop } from '../../helpers/noop';
|
|
13
12
|
import { MessageType } from '../../types/messageTypes';
|
|
13
|
+
import { Sema as Semaphore } from 'async-sema';
|
|
14
|
+
import { getOrSetIfNotExists } from '../../helpers/mapUtils';
|
|
15
|
+
import { CooldownInfo } from '../../dtos/cooldownInfo';
|
|
16
|
+
import { TextMessage } from '../../dtos/responses/textMessage';
|
|
17
|
+
import { ReplyInfo } from '../../dtos/replyInfo';
|
|
18
|
+
import { Seconds } from '../../types/timeValues';
|
|
14
19
|
|
|
15
20
|
export class CommandAction<TActionState extends IActionState>
|
|
16
21
|
implements IActionWithState<TActionState>
|
|
17
22
|
{
|
|
23
|
+
readonly ratelimitSemaphores = new Map<number, Semaphore>();
|
|
24
|
+
|
|
18
25
|
readonly triggers: CommandTrigger[];
|
|
19
26
|
readonly handler: CommandHandler<TActionState>;
|
|
20
27
|
readonly name: string;
|
|
21
|
-
readonly
|
|
28
|
+
readonly cooldownInfo: CooldownInfo;
|
|
22
29
|
readonly active: boolean;
|
|
23
30
|
readonly chatsBlacklist: number[];
|
|
24
31
|
readonly allowedUsers: number[];
|
|
@@ -26,15 +33,19 @@ export class CommandAction<TActionState extends IActionState>
|
|
|
26
33
|
readonly stateConstructor: () => TActionState;
|
|
27
34
|
readonly key: ActionKey;
|
|
28
35
|
readonly readmeFactory: (botName: string) => string;
|
|
36
|
+
readonly maxAllowedSimultaniousExecutions: number;
|
|
37
|
+
|
|
38
|
+
lastCustomCooldown: Seconds | undefined;
|
|
29
39
|
|
|
30
40
|
constructor(
|
|
31
41
|
trigger: CommandTrigger | CommandTrigger[],
|
|
32
42
|
handler: CommandHandler<TActionState>,
|
|
33
43
|
name: string,
|
|
34
44
|
active: boolean,
|
|
35
|
-
|
|
45
|
+
cooldownInfo: CooldownInfo,
|
|
36
46
|
chatsBlacklist: number[],
|
|
37
47
|
allowedUsers: number[],
|
|
48
|
+
maxAllowedSimultaniousExecutions: number,
|
|
38
49
|
condition: CommandCondition<TActionState>,
|
|
39
50
|
stateConstructor: () => TActionState,
|
|
40
51
|
readmeFactory: (botName: string) => string
|
|
@@ -42,13 +53,15 @@ export class CommandAction<TActionState extends IActionState>
|
|
|
42
53
|
this.triggers = toArray(trigger);
|
|
43
54
|
this.handler = handler;
|
|
44
55
|
this.name = name;
|
|
45
|
-
this.
|
|
56
|
+
this.cooldownInfo = cooldownInfo;
|
|
46
57
|
this.active = active;
|
|
47
58
|
this.chatsBlacklist = chatsBlacklist;
|
|
48
59
|
this.allowedUsers = allowedUsers;
|
|
49
60
|
this.condition = condition;
|
|
50
61
|
this.stateConstructor = stateConstructor;
|
|
51
62
|
this.readmeFactory = readmeFactory;
|
|
63
|
+
this.maxAllowedSimultaniousExecutions =
|
|
64
|
+
maxAllowedSimultaniousExecutions;
|
|
52
65
|
|
|
53
66
|
this.key = `command:${this.name.replace('.', '-')}` as ActionKey;
|
|
54
67
|
}
|
|
@@ -62,42 +75,73 @@ export class CommandAction<TActionState extends IActionState>
|
|
|
62
75
|
if (!this.active || this.chatsBlacklist.includes(ctx.chatInfo.id))
|
|
63
76
|
return Noop.NoResponse;
|
|
64
77
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
78
|
+
let lock: Semaphore | undefined;
|
|
79
|
+
if (this.maxAllowedSimultaniousExecutions != 0) {
|
|
80
|
+
lock = getOrSetIfNotExists(
|
|
81
|
+
this.ratelimitSemaphores,
|
|
82
|
+
ctx.chatInfo.id,
|
|
83
|
+
new Semaphore(this.maxAllowedSimultaniousExecutions)
|
|
84
|
+
);
|
|
69
85
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
86
|
+
await lock.acquire();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const state = await ctx.storage.getActionState<TActionState>(
|
|
91
|
+
this,
|
|
92
|
+
ctx.chatInfo.id
|
|
75
93
|
);
|
|
76
94
|
|
|
77
|
-
|
|
95
|
+
const { shouldExecute, matchResults, skipCooldown, reason } =
|
|
96
|
+
this.triggers
|
|
97
|
+
.map((x) => this.checkIfShouldBeExecuted(ctx, x, state))
|
|
98
|
+
.reduce(
|
|
99
|
+
(acc, curr) => acc.mergeWith(curr),
|
|
100
|
+
CommandTriggerCheckResult.DoNotTrigger('Other')
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
if (!shouldExecute) {
|
|
104
|
+
if (reason == 'OnCooldown' && this.cooldownInfo.message)
|
|
105
|
+
return [
|
|
106
|
+
new TextMessage(
|
|
107
|
+
this.cooldownInfo.message,
|
|
108
|
+
ctx.chatInfo,
|
|
109
|
+
ctx.traceId,
|
|
110
|
+
this,
|
|
111
|
+
new ReplyInfo(ctx.messageId)
|
|
112
|
+
)
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
return Noop.NoResponse;
|
|
116
|
+
}
|
|
78
117
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
118
|
+
ctx.logger.logWithTraceId(
|
|
119
|
+
` - Executing [${this.name}] in ${ctx.chatInfo.id}`
|
|
120
|
+
);
|
|
121
|
+
ctx.matchResults = matchResults;
|
|
83
122
|
|
|
84
|
-
|
|
123
|
+
await this.handler(ctx, state);
|
|
85
124
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
125
|
+
if (skipCooldown) {
|
|
126
|
+
ctx.startCooldown = false;
|
|
127
|
+
}
|
|
89
128
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
129
|
+
if (ctx.startCooldown) {
|
|
130
|
+
this.lastCustomCooldown = ctx.customCooldown;
|
|
93
131
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
ctx.chatInfo.id,
|
|
97
|
-
state
|
|
98
|
-
);
|
|
132
|
+
state.lastExecutedDate = moment().valueOf();
|
|
133
|
+
}
|
|
99
134
|
|
|
100
|
-
|
|
135
|
+
await ctx.storage.saveActionExecutionResult(
|
|
136
|
+
this,
|
|
137
|
+
ctx.chatInfo.id,
|
|
138
|
+
state
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
return ctx.responses;
|
|
142
|
+
} finally {
|
|
143
|
+
lock?.release();
|
|
144
|
+
}
|
|
101
145
|
}
|
|
102
146
|
|
|
103
147
|
private checkIfShouldBeExecuted(
|
|
@@ -106,27 +150,34 @@ export class CommandAction<TActionState extends IActionState>
|
|
|
106
150
|
state: TActionState
|
|
107
151
|
) {
|
|
108
152
|
if (!ctx.fromUserId)
|
|
109
|
-
return CommandTriggerCheckResult.DontTriggerAndSkipCooldown
|
|
153
|
+
return CommandTriggerCheckResult.DontTriggerAndSkipCooldown(
|
|
154
|
+
'UserIdMissing'
|
|
155
|
+
);
|
|
110
156
|
|
|
111
157
|
const isUserAllowed =
|
|
112
158
|
this.allowedUsers.length == 0 ||
|
|
113
159
|
this.allowedUsers.includes(ctx.fromUserId);
|
|
114
160
|
|
|
115
161
|
if (!isUserAllowed)
|
|
116
|
-
return CommandTriggerCheckResult.DontTriggerAndSkipCooldown
|
|
162
|
+
return CommandTriggerCheckResult.DontTriggerAndSkipCooldown(
|
|
163
|
+
'UserForbidden'
|
|
164
|
+
);
|
|
117
165
|
|
|
118
166
|
const lastExecutedDate = moment(state.lastExecutedDate);
|
|
119
167
|
const cooldownInMilliseconds = secondsToMilliseconds(
|
|
120
|
-
this.
|
|
168
|
+
this.lastCustomCooldown ?? this.cooldownInfo.seconds
|
|
121
169
|
);
|
|
122
170
|
const onCooldown =
|
|
123
171
|
moment().diff(lastExecutedDate) < cooldownInMilliseconds;
|
|
124
172
|
|
|
125
|
-
if (onCooldown)
|
|
173
|
+
if (onCooldown)
|
|
174
|
+
return CommandTriggerCheckResult.DoNotTrigger('OnCooldown');
|
|
126
175
|
|
|
127
176
|
const isCustomConditionMet = this.condition(ctx, state);
|
|
128
177
|
if (!isCustomConditionMet)
|
|
129
|
-
return CommandTriggerCheckResult.DontTriggerAndSkipCooldown
|
|
178
|
+
return CommandTriggerCheckResult.DontTriggerAndSkipCooldown(
|
|
179
|
+
'CustomConditionNotMet'
|
|
180
|
+
);
|
|
130
181
|
|
|
131
182
|
return this.checkTrigger(ctx, trigger);
|
|
132
183
|
}
|
|
@@ -136,12 +187,12 @@ export class CommandAction<TActionState extends IActionState>
|
|
|
136
187
|
trigger: CommandTrigger
|
|
137
188
|
) {
|
|
138
189
|
if (trigger == MessageType.Any || trigger == ctx.messageType)
|
|
139
|
-
return CommandTriggerCheckResult.Trigger;
|
|
190
|
+
return CommandTriggerCheckResult.Trigger();
|
|
140
191
|
|
|
141
192
|
if (typeof trigger == 'string')
|
|
142
193
|
return ctx.messageText.toLowerCase() == trigger.toLowerCase()
|
|
143
|
-
? CommandTriggerCheckResult.Trigger
|
|
144
|
-
: CommandTriggerCheckResult.DoNotTrigger;
|
|
194
|
+
? CommandTriggerCheckResult.Trigger()
|
|
195
|
+
: CommandTriggerCheckResult.DoNotTrigger('TriggerNotSatisfied');
|
|
145
196
|
|
|
146
197
|
const matchResults: RegExpExecArray[] = [];
|
|
147
198
|
|
|
@@ -45,7 +45,7 @@ export class ReplyCaptureAction<TParentActionState extends IActionState>
|
|
|
45
45
|
.map((x) => this.checkIfShouldBeExecuted(ctx, x))
|
|
46
46
|
.reduce(
|
|
47
47
|
(acc, curr) => acc.mergeWith(curr),
|
|
48
|
-
CommandTriggerCheckResult.DoNotTrigger
|
|
48
|
+
CommandTriggerCheckResult.DoNotTrigger('Other')
|
|
49
49
|
);
|
|
50
50
|
|
|
51
51
|
if (!shouldExecute) return Noop.NoResponse;
|
|
@@ -65,15 +65,20 @@ export class ReplyCaptureAction<TParentActionState extends IActionState>
|
|
|
65
65
|
trigger: CommandTrigger
|
|
66
66
|
) {
|
|
67
67
|
if (ctx.replyMessageId != this.parentMessageId)
|
|
68
|
-
return CommandTriggerCheckResult.DoNotTrigger
|
|
68
|
+
return CommandTriggerCheckResult.DoNotTrigger(
|
|
69
|
+
'TriggerNotSatisfied'
|
|
70
|
+
);
|
|
69
71
|
|
|
70
72
|
if (trigger == ctx.messageType)
|
|
71
|
-
return CommandTriggerCheckResult.Trigger;
|
|
73
|
+
return CommandTriggerCheckResult.Trigger();
|
|
72
74
|
|
|
73
75
|
if (typeof trigger == 'string')
|
|
74
76
|
if (ctx.messageText.toLowerCase() == trigger.toLowerCase())
|
|
75
|
-
return CommandTriggerCheckResult.Trigger;
|
|
76
|
-
else
|
|
77
|
+
return CommandTriggerCheckResult.Trigger();
|
|
78
|
+
else
|
|
79
|
+
return CommandTriggerCheckResult.DoNotTrigger(
|
|
80
|
+
'TriggerNotSatisfied'
|
|
81
|
+
);
|
|
77
82
|
|
|
78
83
|
const matchResults: RegExpExecArray[] = [];
|
|
79
84
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolve } from 'path';
|
|
2
|
-
import { TelegramEmoji } from 'telegraf/types';
|
|
2
|
+
import { TelegramEmoji, UserFromGetMe } from 'telegraf/types';
|
|
3
3
|
import { IActionState } from '../../types/actionState';
|
|
4
4
|
import { ImageMessage } from '../../dtos/responses/imageMessage';
|
|
5
5
|
import { Reaction } from '../../dtos/responses/reaction';
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from '../../types/messageTypes';
|
|
17
17
|
import { ReplyInfo } from '../../dtos/replyInfo';
|
|
18
18
|
import { CommandAction } from '../actions/commandAction';
|
|
19
|
+
import { Seconds } from '../../types/timeValues';
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Context of action executed in chat, in response to a message
|
|
@@ -39,6 +40,10 @@ export class MessageContext<
|
|
|
39
40
|
messageType!: MessageTypeValue;
|
|
40
41
|
/** Message object recieved from Telegram */
|
|
41
42
|
messageUpdateObject!: TelegrafContextMessage;
|
|
43
|
+
/** Bot info from Telegram */
|
|
44
|
+
botInfo!: UserFromGetMe;
|
|
45
|
+
|
|
46
|
+
customCooldown: Seconds | undefined;
|
|
42
47
|
|
|
43
48
|
private getQuotePart(quote: boolean | string) {
|
|
44
49
|
return typeof quote == 'boolean'
|
|
@@ -111,6 +116,11 @@ export class MessageContext<
|
|
|
111
116
|
return this.createCaptureController(response);
|
|
112
117
|
}
|
|
113
118
|
|
|
119
|
+
startCustomCooldown(customCooldown: Seconds) {
|
|
120
|
+
this.startCooldown = true;
|
|
121
|
+
this.customCooldown = customCooldown;
|
|
122
|
+
}
|
|
123
|
+
|
|
114
124
|
/**
|
|
115
125
|
* Collection of actions that can be done as a reply to a message that triggered this action
|
|
116
126
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TelegramEmoji } from 'telegraf/types';
|
|
1
|
+
import { TelegramEmoji, UserFromGetMe } from 'telegraf/types';
|
|
2
2
|
import { ReplyInfo } from '../../dtos/replyInfo';
|
|
3
3
|
import { ImageMessage } from '../../dtos/responses/imageMessage';
|
|
4
4
|
import { Reaction } from '../../dtos/responses/reaction';
|
|
@@ -36,6 +36,8 @@ export class ReplyContext<
|
|
|
36
36
|
fromUserName!: string;
|
|
37
37
|
/** Message object recieved from Telegram */
|
|
38
38
|
messageUpdateObject!: TelegrafContextMessage;
|
|
39
|
+
/** Bot info from Telegram */
|
|
40
|
+
botInfo!: UserFromGetMe;
|
|
39
41
|
|
|
40
42
|
isInitialized = false;
|
|
41
43
|
|
|
@@ -7,6 +7,7 @@ import { IActionState } from '../../types/actionState';
|
|
|
7
7
|
import { toArray } from '../toArray';
|
|
8
8
|
import { Noop } from '../noop';
|
|
9
9
|
import { CommandTrigger } from '../../types/commandTrigger';
|
|
10
|
+
import { CooldownInfo } from '../../dtos/cooldownInfo';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Builder for `CommandAction` with state represented by `TActionState`
|
|
@@ -23,6 +24,8 @@ export class CommandActionBuilderWithState<TActionState extends IActionState> {
|
|
|
23
24
|
stateConstructor: () => TActionState;
|
|
24
25
|
handler: CommandHandler<TActionState> = Noop.call;
|
|
25
26
|
condition: CommandCondition<TActionState> = Noop.true;
|
|
27
|
+
maxAllowedSimultaniousExecutions: number = 0;
|
|
28
|
+
cooldownMessage: string | undefined;
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
31
|
* Builder for `CommandAction` with state represented by `TActionState`
|
|
@@ -86,6 +89,14 @@ export class CommandActionBuilderWithState<TActionState extends IActionState> {
|
|
|
86
89
|
return this;
|
|
87
90
|
}
|
|
88
91
|
|
|
92
|
+
/** Sets maximum number of simultaniously executing handlers for this command per chat. 0 is treated as unlimited. */
|
|
93
|
+
ratelimit(maxAllowedSimultaniousExecutions: number) {
|
|
94
|
+
this.maxAllowedSimultaniousExecutions =
|
|
95
|
+
maxAllowedSimultaniousExecutions;
|
|
96
|
+
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
|
|
89
100
|
/** Sets action cooldown.
|
|
90
101
|
* @param seconds Cooldown in seconds.
|
|
91
102
|
*/
|
|
@@ -95,6 +106,15 @@ export class CommandActionBuilderWithState<TActionState extends IActionState> {
|
|
|
95
106
|
return this;
|
|
96
107
|
}
|
|
97
108
|
|
|
109
|
+
/** Sets action cooldown message.
|
|
110
|
+
* @param message Message that will be sent if action is on cooldown.
|
|
111
|
+
*/
|
|
112
|
+
withCooldownMessage(message: string) {
|
|
113
|
+
this.cooldownMessage = message;
|
|
114
|
+
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
|
|
98
118
|
/**
|
|
99
119
|
* Adds a chat to ignore list for this action.
|
|
100
120
|
* @param chatId Chat id to ignore.
|
|
@@ -112,9 +132,10 @@ export class CommandActionBuilderWithState<TActionState extends IActionState> {
|
|
|
112
132
|
this.handler,
|
|
113
133
|
this.name,
|
|
114
134
|
this.active,
|
|
115
|
-
this.cooldownSeconds,
|
|
135
|
+
new CooldownInfo(this.cooldownSeconds, this.cooldownMessage),
|
|
116
136
|
this.blacklist,
|
|
117
137
|
this.allowedUsers,
|
|
138
|
+
this.maxAllowedSimultaniousExecutions,
|
|
118
139
|
this.condition,
|
|
119
140
|
this.stateConstructor,
|
|
120
141
|
this.readmeFactory != null ? this.readmeFactory : (_) => ''
|
package/package.json
CHANGED
|
@@ -15,9 +15,11 @@ import {
|
|
|
15
15
|
} from '../../types/messageTypes';
|
|
16
16
|
import { typeSafeObjectFromEntries } from '../../helpers/objectFromEntries';
|
|
17
17
|
import { BaseActionProcessor } from './baseProcessor';
|
|
18
|
+
import { UserFromGetMe } from 'telegraf/types';
|
|
18
19
|
|
|
19
20
|
export class CommandActionProcessor extends BaseActionProcessor {
|
|
20
21
|
private readonly replyCaptures: ReplyCaptureAction<IActionState>[] = [];
|
|
22
|
+
private botInfo!: UserFromGetMe;
|
|
21
23
|
|
|
22
24
|
private commands = typeSafeObjectFromEntries(
|
|
23
25
|
Object.values(MessageType).map((x) => [
|
|
@@ -30,8 +32,10 @@ export class CommandActionProcessor extends BaseActionProcessor {
|
|
|
30
32
|
api: TelegramApiService,
|
|
31
33
|
telegraf: Telegraf,
|
|
32
34
|
commands: CommandAction<IActionState>[],
|
|
33
|
-
verboseLoggingForIncomingMessage: boolean
|
|
35
|
+
verboseLoggingForIncomingMessage: boolean,
|
|
36
|
+
botInfo: UserFromGetMe
|
|
34
37
|
) {
|
|
38
|
+
this.botInfo = botInfo;
|
|
35
39
|
this.initializeDependencies(api);
|
|
36
40
|
|
|
37
41
|
for (const msgType of Object.values(MessageType)) {
|
|
@@ -60,7 +64,7 @@ export class CommandActionProcessor extends BaseActionProcessor {
|
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
if (commands.length > 0) {
|
|
63
|
-
telegraf.on('message',
|
|
67
|
+
telegraf.on('message', (ctx) => {
|
|
64
68
|
const msg = new IncomingMessage(
|
|
65
69
|
ctx.update.message,
|
|
66
70
|
this.botName
|
|
@@ -82,7 +86,7 @@ export class CommandActionProcessor extends BaseActionProcessor {
|
|
|
82
86
|
);
|
|
83
87
|
}
|
|
84
88
|
|
|
85
|
-
|
|
89
|
+
void this.processMessage(msg);
|
|
86
90
|
});
|
|
87
91
|
}
|
|
88
92
|
}
|
|
@@ -173,6 +177,7 @@ export class CommandActionProcessor extends BaseActionProcessor {
|
|
|
173
177
|
ctx.action = action;
|
|
174
178
|
ctx.chatInfo = message.chatInfo;
|
|
175
179
|
ctx.traceId = message.traceId;
|
|
180
|
+
ctx.botInfo = this.botInfo;
|
|
176
181
|
|
|
177
182
|
ctx.isInitialized = true;
|
|
178
183
|
ctx.matchResults = [];
|
|
@@ -207,6 +212,8 @@ export class CommandActionProcessor extends BaseActionProcessor {
|
|
|
207
212
|
ctx.action = action;
|
|
208
213
|
ctx.chatInfo = message.chatInfo;
|
|
209
214
|
ctx.traceId = message.traceId;
|
|
215
|
+
ctx.botInfo = this.botInfo;
|
|
216
|
+
ctx.customCooldown = undefined;
|
|
210
217
|
|
|
211
218
|
ctx.logger = this.logger.createScope(
|
|
212
219
|
this.botName,
|