Skip to content

Commit bd1cf64

Browse files
authored
Command prefix fixes (#699)
We have added a "command normaliser" to interface-manager that can cover all the edge cases for pinging the bot or prefixing a command. Fixes #678 Fixes #686 * Use interface-manager's command normaliser. There's still work to be done to make sure we can get ahold of the displyaname. * Fetch displayname for Draupnir for the command normaliser. * Update to [email protected] This gives us the new command normaliser
1 parent 5a0305f commit bd1cf64

File tree

9 files changed

+89
-76
lines changed

9 files changed

+89
-76
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"@gnuxie/typescript-result": "^1.0.0",
5353
"@sentry/node": "^7.17.2",
5454
"@sinclair/typebox": "0.34.13",
55-
"@the-draupnir-project/interface-manager": "3.0.0",
55+
"@the-draupnir-project/interface-manager": "4.0.0",
5656
"@the-draupnir-project/matrix-basic-types": "^0.2.0",
5757
"better-sqlite3": "^9.4.3",
5858
"body-parser": "^1.20.2",

src/Draupnir.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export class Draupnir implements Client, MatrixAdaptorContext {
126126
private constructor(
127127
public readonly client: MatrixSendClient,
128128
public readonly clientUserID: StringUserID,
129+
public clientDisplayName: string,
129130
public readonly clientPlatform: ClientPlatform,
130131
public readonly managementRoomDetail: ManagementRoomDetail,
131132
public readonly clientRooms: ClientRooms,
@@ -186,6 +187,7 @@ export class Draupnir implements Client, MatrixAdaptorContext {
186187
public static async makeDraupnirBot(
187188
client: MatrixSendClient,
188189
clientUserID: StringUserID,
190+
clientDisplayName: string,
189191
clientPlatform: ClientPlatform,
190192
managementRoomDetail: ManagementRoomDetail,
191193
clientRooms: ClientRooms,
@@ -240,6 +242,7 @@ export class Draupnir implements Client, MatrixAdaptorContext {
240242
const draupnir = new Draupnir(
241243
client,
242244
clientUserID,
245+
clientDisplayName,
243246
clientPlatform,
244247
managementRoomDetail,
245248
clientRooms,

src/appservice/bot/AppserviceBotCommandDispatcher.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99

1010
import {
1111
BasicInvocationInformation,
12-
CommandPrefixExtractor,
12+
CommandNormaliser,
1313
JSInterfaceCommandDispatcher,
14+
makeCommandNormaliser,
1415
MatrixInterfaceCommandDispatcher,
1516
StandardJSInterfaceCommandDispatcher,
1617
StandardMatrixInterfaceCommandDispatcher,
@@ -21,33 +22,27 @@ import {
2122
invocationInformationFromMatrixEventcontext,
2223
} from "../../commands/interface-manager/MPSMatrixInterfaceAdaptor";
2324
import { AppserviceAdaptorContext } from "./AppserviceBotPrerequisite";
24-
import { userLocalpart } from "@the-draupnir-project/matrix-basic-types";
2525
import { AppserviceBotCommands } from "./AppserviceBotCommandTable";
2626
import { AppserviceBotHelpCommand } from "./AppserviceBotHelp";
2727
import {
2828
AppserviceBotInterfaceAdaptor,
2929
AppserviceAdaptorContextToCommandContextTranslator,
3030
} from "./AppserviceBotInterfaceAdaptor";
3131

32-
function makePrefixExtractor(
32+
function makeAppserviceCommandNormaliser(
3333
appserviceContext: AppserviceAdaptorContext
34-
): CommandPrefixExtractor {
35-
const plainPrefixes = [
36-
"admin",
37-
userLocalpart(appserviceContext.clientUserID),
38-
appserviceContext.clientUserID,
39-
];
40-
const allPossiblePrefixes = [
41-
...plainPrefixes.map((p) => `!${p}`),
42-
...plainPrefixes.map((p) => `${p}:`),
43-
...plainPrefixes,
44-
];
45-
return (body) => {
46-
const isPrefixUsed = allPossiblePrefixes.find((p) =>
47-
body.toLowerCase().startsWith(p.toLowerCase())
48-
);
49-
return isPrefixUsed ? "admin" : undefined;
50-
};
34+
): CommandNormaliser {
35+
return makeCommandNormaliser(appserviceContext.clientUserID, {
36+
symbolPrefixes: ["!"],
37+
isAllowedOnlySymbolPrefixes: false,
38+
additionalPrefixes: ["admin"],
39+
getDisplayName: function (): string {
40+
// TODO: I don't nkow how we're going to do this yet but we'll
41+
// figure it out one day.
42+
return "admin";
43+
},
44+
normalisedPrefix: "admin",
45+
});
5146
}
5247

5348
export function makeAppserviceBotCommandDispatcher(
@@ -61,7 +56,7 @@ export function makeAppserviceBotCommandDispatcher(
6156
invocationInformationFromMatrixEventcontext,
6257
{
6358
...MPSCommandDispatcherCallbacks,
64-
prefixExtractor: makePrefixExtractor(appserviceContext),
59+
commandNormaliser: makeAppserviceCommandNormaliser(appserviceContext),
6560
}
6661
);
6762
}
@@ -75,7 +70,7 @@ export function makeAppserviceJSCommandDispatcher(
7570
appserviceContext,
7671
{
7772
...MPSCommandDispatcherCallbacks,
78-
prefixExtractor: makePrefixExtractor(appserviceContext),
73+
commandNormaliser: makeAppserviceCommandNormaliser(appserviceContext),
7974
},
8075
AppserviceAdaptorContextToCommandContextTranslator
8176
);

src/commands/DraupnirCommandDispatcher.ts

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
import {
1111
MatrixInterfaceCommandDispatcher,
1212
StandardMatrixInterfaceCommandDispatcher,
13-
CommandPrefixExtractor,
1413
JSInterfaceCommandDispatcher,
1514
BasicInvocationInformation,
1615
StandardJSInterfaceCommandDispatcher,
16+
CommandNormaliser,
17+
makeCommandNormaliser,
1718
} from "@the-draupnir-project/interface-manager";
1819
import { Draupnir } from "../Draupnir";
1920
import {
@@ -22,33 +23,29 @@ import {
2223
invocationInformationFromMatrixEventcontext,
2324
} from "./interface-manager/MPSMatrixInterfaceAdaptor";
2425
import { DraupnirHelpCommand } from "./Help";
25-
import { userLocalpart } from "@the-draupnir-project/matrix-basic-types";
26+
import { StringUserID } from "@the-draupnir-project/matrix-basic-types";
2627
import { DraupnirTopLevelCommands } from "./DraupnirCommandTable";
2728
import {
2829
DraupnirContextToCommandContextTranslator,
2930
DraupnirInterfaceAdaptor,
3031
} from "./DraupnirCommandPrerequisites";
3132
import "./DraupnirCommands";
33+
import { IConfig } from "../config";
3234

33-
function makePrefixExtractor(draupnir: Draupnir): CommandPrefixExtractor {
34-
const plainPrefixes = [
35-
"!draupnir",
36-
userLocalpart(draupnir.clientUserID),
37-
draupnir.clientUserID,
38-
...draupnir.config.commands.additionalPrefixes,
39-
];
40-
const allPossiblePrefixes = [
41-
...plainPrefixes.map((p) => `!${p}`),
42-
...plainPrefixes.map((p) => `${p}:`),
43-
...plainPrefixes,
44-
...(draupnir.config.commands.allowNoPrefix ? ["!"] : []),
45-
];
46-
return (body) => {
47-
const isPrefixUsed = allPossiblePrefixes.find((p) =>
48-
body.toLowerCase().startsWith(p.toLowerCase())
49-
);
50-
return isPrefixUsed ? "draupnir" : undefined;
51-
};
35+
export function makeDraupnirCommandNormaliser(
36+
clientUserID: StringUserID,
37+
displayNameIssuer: { clientDisplayName: string },
38+
config: IConfig
39+
): CommandNormaliser {
40+
return makeCommandNormaliser(clientUserID, {
41+
symbolPrefixes: ["!"],
42+
isAllowedOnlySymbolPrefixes: config.commands.allowNoPrefix,
43+
additionalPrefixes: ["draupnir", ...config.commands.additionalPrefixes],
44+
getDisplayName: function (): string {
45+
return displayNameIssuer.clientDisplayName;
46+
},
47+
normalisedPrefix: "draupnir",
48+
});
5249
}
5350

5451
export function makeDraupnirCommandDispatcher(
@@ -62,7 +59,11 @@ export function makeDraupnirCommandDispatcher(
6259
invocationInformationFromMatrixEventcontext,
6360
{
6461
...MPSCommandDispatcherCallbacks,
65-
prefixExtractor: makePrefixExtractor(draupnir),
62+
commandNormaliser: makeDraupnirCommandNormaliser(
63+
draupnir.clientUserID,
64+
draupnir,
65+
draupnir.config
66+
),
6667
}
6768
);
6869
}
@@ -76,7 +77,11 @@ export function makeDraupnirJSCommandDispatcher(
7677
draupnir,
7778
{
7879
...MPSCommandDispatcherCallbacks,
79-
prefixExtractor: makePrefixExtractor(draupnir),
80+
commandNormaliser: makeDraupnirCommandNormaliser(
81+
draupnir.clientUserID,
82+
draupnir,
83+
draupnir.config
84+
),
8085
},
8186
DraupnirContextToCommandContextTranslator
8287
);

src/commands/interface-manager/MPSMatrixInterfaceAdaptor.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ export const MPSCommandDispatcherCallbacks = {
180180
error.message
181181
);
182182
},
183+
commandNormaliser(body) {
184+
return body;
185+
},
183186
} satisfies CommandDispatcherCallbacks<BasicInvocationInformation>;
184187

185188
export const rendererFailedCB: MatrixInterfaceRendererFailedCB<

src/draupnirfactory/DraupnirFactory.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
ClientForUserID,
1616
RoomStateManagerFactory,
1717
joinedRoomsSafe,
18+
resultifyBotSDKRequestErrorWith404AsUndefined,
1819
} from "matrix-protection-suite-for-matrix-bot-sdk";
1920
import { IConfig } from "../config";
2021
import { makeProtectedRoomsSet } from "./DraupnirProtectedRoomsSet";
@@ -101,9 +102,19 @@ export class DraupnirFactory {
101102
managementRoomMembership.ok,
102103
managementRoomState.ok
103104
);
105+
const clientProfileResult = await client.getUserProfile(clientUserID).then(
106+
(value) => Ok(value),
107+
(error) => resultifyBotSDKRequestErrorWith404AsUndefined(error)
108+
);
109+
if (isError(clientProfileResult)) {
110+
return clientProfileResult.elaborate(
111+
"Unable to fetch Draupnir's profile information"
112+
);
113+
}
104114
return await Draupnir.makeDraupnirBot(
105115
client,
106116
clientUserID,
117+
clientProfileResult.ok?.displayname ?? clientUserID,
107118
clientPlatform,
108119
managementRoomDetail,
109120
clientRooms.ok,
@@ -136,11 +147,21 @@ export class DraupnirFactory {
136147
clientUserID,
137148
client
138149
);
150+
const clientProfileResult = await client.getUserProfile(clientUserID).then(
151+
(value) => Ok(value),
152+
(error) => resultifyBotSDKRequestErrorWith404AsUndefined(error)
153+
);
154+
if (isError(clientProfileResult)) {
155+
return clientProfileResult.elaborate(
156+
"Unable to fetch Draupnir's profile information"
157+
);
158+
}
139159
return Ok(
140160
new SafeModeDraupnir(
141161
cause,
142162
client,
143163
clientUserID,
164+
clientProfileResult.ok?.displayname ?? clientUserID,
144165
clientPlatform,
145166
managementRoom,
146167
clientRooms.ok,

src/safemode/DraupnirSafeMode.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export class SafeModeDraupnir implements MatrixAdaptorContext {
5959
public readonly cause: SafeModeCause,
6060
public readonly client: MatrixSendClient,
6161
public readonly clientUserID: StringUserID,
62+
public clientDisplayName: string,
6263
public readonly clientPlatform: ClientPlatform,
6364
public readonly managementRoom: MatrixRoomID,
6465
private readonly clientRooms: ClientRooms,

src/safemode/SafeModeCommandDispatcher.ts

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import {
66
BasicInvocationInformation,
7-
CommandPrefixExtractor,
87
JSInterfaceCommandDispatcher,
98
MatrixInterfaceCommandDispatcher,
109
StandardJSInterfaceCommandDispatcher,
@@ -16,35 +15,13 @@ import {
1615
MatrixEventContext,
1716
invocationInformationFromMatrixEventcontext,
1817
} from "../commands/interface-manager/MPSMatrixInterfaceAdaptor";
19-
import { userLocalpart } from "@the-draupnir-project/matrix-basic-types";
2018
import { SafeModeCommands } from "./commands/SafeModeCommands";
2119
import { SafeModeHelpCommand } from "./commands/HelpCommand";
2220
import {
2321
SafeModeContextToCommandContextTranslator,
2422
SafeModeInterfaceAdaptor,
2523
} from "./commands/SafeModeAdaptor";
26-
27-
function makePrefixExtractor(
28-
safeModeDraupnir: SafeModeDraupnir
29-
): CommandPrefixExtractor {
30-
const plainPrefixes = [
31-
"!draupnir",
32-
userLocalpart(safeModeDraupnir.clientUserID),
33-
safeModeDraupnir.clientUserID,
34-
];
35-
const allPossiblePrefixes = [
36-
...plainPrefixes.map((p) => `!${p}`),
37-
...plainPrefixes.map((p) => `${p}:`),
38-
...plainPrefixes,
39-
...(safeModeDraupnir.config.commands.allowNoPrefix ? ["!"] : []),
40-
];
41-
return (body) => {
42-
const isPrefixUsed = allPossiblePrefixes.find((p) =>
43-
body.toLowerCase().startsWith(p.toLowerCase())
44-
);
45-
return isPrefixUsed ? "draupnir" : undefined;
46-
};
47-
}
24+
import { makeDraupnirCommandNormaliser } from "../commands/DraupnirCommandDispatcher";
4825

4926
export function makeSafeModeCommandDispatcher(
5027
safeModeDraupnir: SafeModeDraupnir
@@ -57,7 +34,11 @@ export function makeSafeModeCommandDispatcher(
5734
invocationInformationFromMatrixEventcontext,
5835
{
5936
...MPSCommandDispatcherCallbacks,
60-
prefixExtractor: makePrefixExtractor(safeModeDraupnir),
37+
commandNormaliser: makeDraupnirCommandNormaliser(
38+
safeModeDraupnir.clientUserID,
39+
safeModeDraupnir,
40+
safeModeDraupnir.config
41+
),
6142
}
6243
);
6344
}
@@ -71,7 +52,11 @@ export function makeSafeModeJSDispatcher(
7152
safeModeDraupnir,
7253
{
7354
...MPSCommandDispatcherCallbacks,
74-
prefixExtractor: makePrefixExtractor(safeModeDraupnir),
55+
commandNormaliser: makeDraupnirCommandNormaliser(
56+
safeModeDraupnir.clientUserID,
57+
safeModeDraupnir,
58+
safeModeDraupnir.config
59+
),
7560
},
7661
SafeModeContextToCommandContextTranslator
7762
);

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,10 +311,10 @@
311311
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
312312
integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
313313

314-
"@the-draupnir-project/interface-manager@3.0.0":
315-
version "3.0.0"
316-
resolved "https://registry.yarnpkg.com/@the-draupnir-project/interface-manager/-/interface-manager-3.0.0.tgz#8aedad18be4f33a098e5dc2e74ed8590ca1aba68"
317-
integrity sha512-TRPBf+JqcwHS8ARp2FXQhIGcvBrXhUEB16oCKQAybUqMN6f9G7hKP0WQnT1A+IK9xWkG1eAtyUf2HX1LUzwLxg==
314+
"@the-draupnir-project/interface-manager@4.0.0":
315+
version "4.0.0"
316+
resolved "https://registry.yarnpkg.com/@the-draupnir-project/interface-manager/-/interface-manager-4.0.0.tgz#068f4d22ee1f4c964879b1a3f0a619bec1a655c6"
317+
integrity sha512-szatmeDnJgkeEBSwdvMRNum/CKVB15WVbN+0gIJQOsZZihQy6PZ4CGl9pLuV49E24kcFK9Z2our0Ut4N3oCAZA==
318318
dependencies:
319319
"@gnuxie/super-cool-stream" "^0.2.1"
320320
"@gnuxie/typescript-result" "^1.0.0"

0 commit comments

Comments
 (0)