mirror of
https://github.com/matrix-org/mjolnir.git
synced 2024-10-01 01:36:06 -04:00
postgres db
This commit is contained in:
parent
efb4cebbd1
commit
f383a1c416
@ -50,6 +50,7 @@
|
||||
"matrix-appservice-bridge": "^5.0.0",
|
||||
"nedb": "^1.8.0",
|
||||
"parse-duration": "^1.0.2",
|
||||
"pg": "^8.8.0",
|
||||
"shell-quote": "^1.7.3",
|
||||
"yaml": "^2.1.1"
|
||||
},
|
||||
|
@ -16,20 +16,23 @@
|
||||
*/
|
||||
|
||||
import { randomUUID } from "crypto";
|
||||
import { AppServiceRegistration, Bridge, Cli, Request, WeakEvent, BridgeContext, MatrixUser, UserBridgeStore, RemoteUser } from "matrix-appservice-bridge";
|
||||
import { AppServiceRegistration, Bridge, Cli, Request, WeakEvent, BridgeContext, MatrixUser } from "matrix-appservice-bridge";
|
||||
import { MatrixClient } from "matrix-bot-sdk";
|
||||
// needed by appservice irc, though it looks completely dead.
|
||||
import * as Datastore from "nedb";
|
||||
import { MjolnirManager } from ".//MjolnirManager";
|
||||
import { DataStore, PgDataStore } from ".//datastore";
|
||||
import { Api } from "./Api";
|
||||
// ts-node src/appservice/AppService.ts -r -u "http://localhost:9000" # remember to add the registration to homeserver.yaml! you probably want host.docker.internal as the hostname of the appservice if using mx-tester
|
||||
// ts-node src/appservice/AppService -p 9000 # to start.
|
||||
|
||||
export class MjolnirAppService {
|
||||
|
||||
public readonly dataStore: DataStore;
|
||||
public readonly bridge: Bridge;
|
||||
public readonly mjolnirManager: MjolnirManager = new MjolnirManager();
|
||||
|
||||
public constructor() {
|
||||
this.dataStore = new PgDataStore("foo bar baz");
|
||||
new Api("http://localhost:8081", this).start(9001);
|
||||
this.bridge = new Bridge({
|
||||
homeserverUrl: "http://localhost:8081",
|
||||
@ -39,40 +42,56 @@ export class MjolnirAppService {
|
||||
onUserQuery: this.onUserQuery.bind(this),
|
||||
onEvent: this.onEvent.bind(this),
|
||||
},
|
||||
userStore: new UserBridgeStore(new Datastore()),
|
||||
suppressEcho: false,
|
||||
});
|
||||
}
|
||||
|
||||
public async provisionNewMjolnir(requestingUserId: string): Promise<[string, string]> {
|
||||
// FIXME: we need to restrict who can do it (special list? ban remote users?)
|
||||
const issuedMjolnirs = await this.bridge.getUserStore()!.getRemoteUsersFromMatrixId(requestingUserId);
|
||||
if (issuedMjolnirs.length === 0) {
|
||||
public async initStoredMjolnirs(): Promise<void> {
|
||||
for (var mjolnirRecord of await this.dataStore.list()) {
|
||||
const [_mjolnirUserId, mjolnirClient] = await this.makeMatrixClient(mjolnirRecord.localPart);
|
||||
await this.mjolnirManager.makeInstance(
|
||||
mjolnirRecord.owner,
|
||||
mjolnirRecord.managementRoom,
|
||||
mjolnirClient,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async makeMatrixClient(localPart: string): Promise<[string, MatrixClient]> {
|
||||
// Now we need to make one of the transparent mjolnirs and add it to the monitor.
|
||||
const mjIntent = await this.bridge.getIntentFromLocalpart(`mjolnir_${randomUUID()}`);
|
||||
const mjIntent = await this.bridge.getIntentFromLocalpart(localPart);
|
||||
await mjIntent.ensureRegistered();
|
||||
// we're only doing this because it's complaining about missing profiles.
|
||||
// actually the user id wasn't even right, so this might not be necessary anymore.
|
||||
await mjIntent.ensureProfile('Mjolnir');
|
||||
return [mjIntent.userId, mjIntent.matrixClient];
|
||||
}
|
||||
|
||||
const managementRoomId = (await mjIntent.createRoom({
|
||||
createAsClient: true,
|
||||
options: {
|
||||
preset: 'private_chat',
|
||||
invite: [requestingUserId],
|
||||
name: `${requestingUserId}'s mjolnir`
|
||||
}
|
||||
})).room_id;
|
||||
public async provisionNewMjolnir(requestingUserId: string): Promise<[string, string]> {
|
||||
// FIXME: we need to restrict who can do it (special list? ban remote users?)
|
||||
const provisionedMjolnirs = await this.dataStore.lookupByOwner(requestingUserId);
|
||||
if (provisionedMjolnirs.length === 0) {
|
||||
const mjolnirLocalPart = `mjolnir_${randomUUID()}`;
|
||||
const [mjolnirUserId, mjolnirClient] = await this.makeMatrixClient(mjolnirLocalPart);
|
||||
|
||||
await this.mjolnirManager.createNew(requestingUserId, managementRoomId, mjIntent.matrixClient);
|
||||
// Technically the mjolnir is a remote user, but also not because it's matrix-matrix.
|
||||
//const mjAsRemote = new RemoteUser(mjIntent.userId)
|
||||
//const bridgeStore = this.bridge.getUserStore()!;
|
||||
//bridgeStore.setRemoteUser()
|
||||
await this.bridge.getUserStore()!.linkUsers(new MatrixUser(requestingUserId), new RemoteUser(mjIntent.userId));
|
||||
return [mjIntent.userId, managementRoomId];
|
||||
const managementRoomId = await mjolnirClient.createRoom({
|
||||
preset: 'private_chat',
|
||||
invite: [requestingUserId],
|
||||
name: `${requestingUserId}'s mjolnir`
|
||||
});
|
||||
|
||||
const mjolnir = await this.mjolnirManager.makeInstance(requestingUserId, managementRoomId, mjolnirClient);
|
||||
await mjolnir.createFirstList(requestingUserId, "list");
|
||||
|
||||
await this.dataStore.store({
|
||||
localPart: mjolnirLocalPart,
|
||||
owner: requestingUserId,
|
||||
managementRoom: managementRoomId,
|
||||
});
|
||||
|
||||
return [mjolnirUserId, managementRoomId];
|
||||
} else {
|
||||
throw new Error(`User: ${requestingUserId} has already provisioned ${issuedMjolnirs.length} mjolnirs.`);
|
||||
throw new Error(`User: ${requestingUserId} has already provisioned ${provisionedMjolnirs.length} mjolnirs.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,14 +14,10 @@ export class MjolnirManager {
|
||||
return config;
|
||||
}
|
||||
|
||||
public async createNew(requestingUserId: string, managementRoomId: string, client: MatrixClient) {
|
||||
// FIXME: We should be creating the intent here and generating the id surely?
|
||||
// rather than externally...
|
||||
// FIXME: We need to verify that we haven't stored a mjolnir already if we aren't doing the above.
|
||||
|
||||
public async makeInstance(requestingUserId: string, managementRoomId: string, client: MatrixClient): Promise<ManagedMjolnir> {
|
||||
const managedMjolnir = new ManagedMjolnir(await Mjolnir.setupMjolnirFromConfig(client, this.getDefaultMjolnirConfig(managementRoomId)));
|
||||
await managedMjolnir.createFirstList(requestingUserId, 'list')
|
||||
this.mjolnirs.set(await client.getUserId(), managedMjolnir);
|
||||
return managedMjolnir;
|
||||
}
|
||||
|
||||
public onEvent(request: Request<WeakEvent>, context: BridgeContext) {
|
||||
|
66
src/appservice/datastore.ts
Normal file
66
src/appservice/datastore.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { Client } from "pg";
|
||||
|
||||
export interface MjolnirRecord {
|
||||
localPart: string,
|
||||
owner: string,
|
||||
managementRoom: string,
|
||||
}
|
||||
|
||||
export interface DataStore {
|
||||
init(): Promise<void>;
|
||||
|
||||
list(): Promise<MjolnirRecord[]>;
|
||||
|
||||
store(mjolnirRecord: MjolnirRecord): Promise<void>;
|
||||
|
||||
lookupByOwner(owner: string): Promise<MjolnirRecord[]>;
|
||||
|
||||
lookupByMxid(mxid: string): Promise<MjolnirRecord[]>;
|
||||
}
|
||||
|
||||
export class PgDataStore implements DataStore {
|
||||
private pgClient: Client;
|
||||
|
||||
constructor(connectionString: string) {
|
||||
this.pgClient = new Client({ connectionString: connectionString });
|
||||
}
|
||||
|
||||
public async init(): Promise<void> {
|
||||
await this.pgClient.connect();
|
||||
}
|
||||
|
||||
public async list(): Promise<MjolnirRecord[]> {
|
||||
const result = await this.pgClient.query<MjolnirRecord>("SELECT mxid, owner, managementRoom FROM mjolnir");
|
||||
|
||||
if (!result.rowCount) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return result.rows;
|
||||
}
|
||||
|
||||
public async store(mjolnirRecord: MjolnirRecord): Promise<void> {
|
||||
await this.pgClient.query(
|
||||
"INSERT INTO mjolnir (mxid, owner, managementRoom) VALUES ($1, $2, $3)",
|
||||
[mjolnirRecord.mxid, mjolnirRecord.owner, mjolnirRecord.managementRoom],
|
||||
);
|
||||
}
|
||||
|
||||
public async lookupByOwner(owner: string): Promise<MjolnirRecord[]> {
|
||||
const result = await this.pgClient.query<MjolnirRecord>(
|
||||
"SELECT mxid, owner FROM mjolnir WHERE owner = $1",
|
||||
[owner],
|
||||
);
|
||||
|
||||
return result.rows;
|
||||
}
|
||||
|
||||
public async lookupByMxid(mxid: string): Promise<MjolnirRecord[]> {
|
||||
const result = await this.pgClient.query<MjolnirRecord>(
|
||||
"SELECT mxid, owner, managementRoom FROM mjolnir WHERE mxid = $1",
|
||||
[mxid],
|
||||
);
|
||||
|
||||
return result.rows;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user