Skip to content

Commit

Permalink
Merge branch 'matrix' of github.com:austinhuang0131/bolt into austinh…
Browse files Browse the repository at this point in the history
…uang0131-matrix

Signed-off-by: Jersey <[email protected]>
  • Loading branch information
williamhorning committed Mar 26, 2024
2 parents 20f2e6a + b67ea7c commit fe91041
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 116 deletions.
8 changes: 5 additions & 3 deletions packages/bolt-matrix/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ export {
AppServiceRegistration,
Bridge,
Intent,
MatrixUser,
Request,
type ClientEncryptionSession,
type WeakEvent
} from 'npm:[email protected]';
export {
Bolt,
BoltPlugin,
type BoltBridgeMessageArgs,
type BoltMessage
bolt_plugin,
type bridge_platform,
type message
} from '../bolt/mod.ts';
export { Buffer } from 'node:buffer';
61 changes: 38 additions & 23 deletions packages/bolt-matrix/events.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { BoltMessage, Intent, Request, WeakEvent } from './deps.ts';
import MatrixPlugin from './mod.ts';
import { message, Intent, Request, WeakEvent } from './deps.ts';
import { matrix_plugin } from './mod.ts';

export async function onEvent(this: MatrixPlugin, request: Request<WeakEvent>) {
export async function onEvent(
this: matrix_plugin,
request: Request<WeakEvent>
) {
const event = request.getData();
const bot = this.bot.getBot();
const intent = this.bot.getIntent();
Expand All @@ -16,52 +19,64 @@ export async function onEvent(this: MatrixPlugin, request: Request<WeakEvent>) {
this.emit('debug', `Failed to join room ${event.room_id}: ${e}`);
}
}
if (event.type === 'm.room.message' && !event['m.new_content']) {
this.emit('messageCreate', await messageToCore(event, intent));
if (event.type === 'm.room.message' && !event.content['m.new_content']) {
this.emit(
'create_message',
await messageToCore(event, intent, this.config.homeserverUrl)
);
}
if (event.type === 'm.room.message' && event['m.new_content']) {
this.emit('messageUpdate', await messageToCore(event, intent));
if (event.type === 'm.room.message' && event.content['m.new_content']) {
this.emit(
'edit_message',
await messageToCore(event, intent, this.config.homeserverUrl)
);
}
if (event.type === 'm.room.redaction') {
this.emit('messageDelete', {
this.emit('delete_message', {
id: event.redacts as string,
platform: { name: 'bolt-matrix', message: event },
channel: event.room_id,
timestamp: event.origin_server_ts
timestamp: Temporal.Instant.fromEpochMilliseconds(event.origin_server_ts)
});
}
}

export async function messageToCore(
event: WeakEvent,
intent: Intent
): Promise<BoltMessage<WeakEvent>> {
intent: Intent,
homeserverUrl: string
): Promise<message<WeakEvent>> {
const sender = await intent.getProfileInfo(event.sender);
return {
author: {
username: sender.displayname || event.sender,
rawname: event.sender,
id: event.sender,
profile: sender.avatar_url
profile: `${sender.avatar_url?.replace(
'mxc://',
`${homeserverUrl}/_matrix/media/v3/thumbnail/`
)}?width=96&height=96&method=scale`
},
channel: event.room_id,
id: event.event_id,
timestamp: event.origin_server_ts,
content: event.content.body as string,
reply: async (msg: BoltMessage<unknown>) => {
id:
event.content['m.relates_to']?.rel_type == 'm.replace'
? event.content['m.relates_to'].event_id
: event.event_id,
timestamp: Temporal.Instant.fromEpochMilliseconds(event.origin_server_ts),
content: (event.content['m.new_content']?.body ||
event.content.body) as string,
reply: async (msg: message<unknown>) => {
await intent.sendMessage(event.room_id, coreToMessage(msg));
},
platform: { name: 'bolt-matrix', message: event }
};
}

export function coreToMessage(msg: BoltMessage<unknown>) {
export function coreToMessage(msg: message<unknown>) {
return {
content: {
body: msg.content
? msg.content
: "*this bridge doesn't support anything except text at the moment*",
msgtype: 'm.text'
}
body: msg.content
? msg.content
: "*this bridge doesn't support anything except text at the moment*",
msgtype: 'm.text'
};
}
188 changes: 98 additions & 90 deletions packages/bolt-matrix/mod.ts
Original file line number Diff line number Diff line change
@@ -1,131 +1,139 @@
import {
AppServiceRegistration,
Bolt,
BoltBridgeMessageArgs,
BoltMessage,
BoltPlugin,
Bridge,
ClientEncryptionSession,
existsSync
Buffer,
MatrixUser,
existsSync,
bolt_plugin,
message,
bridge_platform
} from './deps.ts';
import { coreToMessage, onEvent } from './events.ts';

type MatrixConfig = {
accessToken: string;
appserviceUrl: string;
homeserverUrl: string;
domain: string;
port?: number;
reg_path: string;
};

export default class MatrixPlugin extends BoltPlugin {
export class matrix_plugin extends bolt_plugin<MatrixConfig> {
bot: Bridge;
config: MatrixConfig;
name = 'bolt-revolt';
version = '0.5.4';
bolt?: Bolt;
constructor(config: MatrixConfig) {
super();
this.config = config;
name = 'bolt-matrix';
version = '0.5.6';
support = ['0.5.5'];

constructor(bolt: Bolt, config: MatrixConfig) {
super(bolt, config);
this.bot = new Bridge({
homeserverUrl: this.config.homeserverUrl,
domain: this.config.domain,
registration: this.config.reg_path,
bridgeEncryption: {
homeserverUrl: config.homeserverUrl,
store: {
getStoredSession: async (userId: string) => {
return JSON.parse(
(await this.bolt?.redis?.get(`mtx-session-${userId}`)) || 'null'
);
},
setStoredSession: async (session: ClientEncryptionSession) => {
await this.bolt?.redis?.set(
`mtx-session-${session.userId}`,
JSON.stringify(session)
);
},
async updateSyncToken() {}
}
},
controller: {
onEvent: onEvent.bind(this)
},
roomStore: './db/roomStore.db',
userStore: './db/userStore.db',
userActivityStore: './db/userActivityStore.db'
});
}
async start(bolt: Bolt) {
this.bolt = bolt;
if (!existsSync(this.config.reg_path)) {
const reg = new AppServiceRegistration(this.config.homeserverUrl);
const reg = new AppServiceRegistration(this.config.appserviceUrl);
reg.setAppServiceToken(AppServiceRegistration.generateToken());
reg.setHomeserverToken(AppServiceRegistration.generateToken());
reg.setId(
'b4d15f02f7e406db25563c1a74ac78863dc4fbcc5595db8d835f6ee6ffef1448'
);
reg.setId(AppServiceRegistration.generateToken());
reg.setProtocols(['bolt']);
reg.setRateLimited(false);
reg.setSenderLocalpart('boltbot');
reg.addRegexPattern('users', '@bolt_*', true);
reg.setSenderLocalpart('bot.bolt');
reg.addRegexPattern('users', `@bolt-.+_.+:${this.config.domain}`, true);
reg.outputAsYaml(this.config.reg_path);
}
await this.bot.run(this.config.port || 8081);
this.bot.run(this.config.port || 8081);
}
bridgeSupport = { text: true };

// deno-lint-ignore require-await
async createSenddata(channelId: string) {
async create_bridge(channelId: string) {
return channelId;
}
async bridgeMessage(data: BoltBridgeMessageArgs) {
const intent = this.bot.getIntent(
`${data.data.platform.name}_${
'author' in data.data ? data.data.author.id : 'deletion'
}`
);
const room = data.data.bridgePlatform.senddata as string;
switch (data.type) {
case 'create':
case 'update': {
const message = coreToMessage(
data.data as unknown as BoltMessage<unknown>
);
let editinfo = {};
if (data.type === 'update') {
editinfo = {
'm.new_content': message,
'm.relates_to': {
rel_type: 'm.replace',
event_id: data.data.id
}
};

is_bridged(_msg: message<unknown>) {
// TODO: implement this
return true;
}

async create_message(
msg: message<unknown>,
platform: bridge_platform,
edit = false
) {
const room = platform.senddata as string;
const name = `@${platform.plugin}_${msg.author.id}:${this.config.domain}`;
const intent = this.bot.getIntent(name);
// check for profile
await intent.ensureProfile(msg.author.username);
const store = this.bot.getUserStore();
let storeUser = await store?.getMatrixUser(name);
if (!storeUser) {
storeUser = new MatrixUser(name);
}
if (storeUser?.get('avatar') != msg.author.profile) {
storeUser?.set('avatar', msg.author.profile);
const b = await (await fetch(msg.author.profile || '')).blob();
const newMxc = await intent.uploadContent(
Buffer.from(await b.arrayBuffer()),
{ type: b.type }
);
await intent.ensureProfile(msg.author.username, newMxc);
await store?.setMatrixUser(storeUser);
}
// now to our message
const message = coreToMessage(msg);
let editinfo = {};
if (edit) {
editinfo = {
'm.new_content': message,
'm.relates_to': {
rel_type: 'm.replace',
event_id: msg.id
}
const result = await intent.sendMessage(room, {
...message,
...editinfo
});
return {
channel: room,
id: result.event_id,
plugin: 'bolt-matrix',
senddata: room
};
}
case 'delete': {
await intent.sendEvent(room, 'm.room.redaction', {
content: {
reason: 'bridge message deletion'
},
redacts: data.data.id
});
return {
channel: room,
id: data.data.id,
plugin: 'bolt-matrix',
senddata: room
};
}
};
}
const result = await intent.sendMessage(room, {
...message,
...editinfo
});
return {
channel: room,
id: result.event_id,
plugin: 'bolt-matrix',
senddata: room
};
}

async edit_message(
msg: message<unknown>,
platform: bridge_platform & { id: string }
) {
return await this.create_message(msg, platform, true);
}

async delete_message(
_msg: message<unknown>,
platform: bridge_platform & { id: string }
) {
const room = platform.senddata as string;
const intent = this.bot.getIntent();
await intent.botSdkIntent.underlyingClient.redactEvent(
room,
platform.id,
'bridge message deletion'
);
return {
channel: room,
id: platform.id,
plugin: 'bolt-matrix',
senddata: room
};
}
}

0 comments on commit fe91041

Please sign in to comment.