From 787c0c092f43a48ec425f1bd0b5fa720efddf8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20H=C3=BCttemann?= Date: Fri, 18 Aug 2023 15:30:53 +0200 Subject: [PATCH] Add Message implementation --- src/app.ts | 5 +- src/handlers/messages.ts | 127 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/handlers/messages.ts diff --git a/src/app.ts b/src/app.ts index 2661191..107ee64 100644 --- a/src/app.ts +++ b/src/app.ts @@ -4,6 +4,7 @@ import lineByLine from 'n-readlines' import 'reflect-metadata' import { handle as handleRoom } from './handlers/rooms' import { handle as handleUser } from './handlers/users' +import { handle as handleMessage } from './handlers/messages' import log from './helpers/logger' import { initStorage } from './helpers/storage' import { whoami } from './helpers/synapse' @@ -27,7 +28,7 @@ async function loadRcExport(entity: Entity) { break case Entity.Messages: - log.debug(`Message: ${item.name}`) + await handleMessage(item) break default: @@ -44,6 +45,8 @@ async function main() { await loadRcExport(Entity.Users) log.info('Parsing rooms') await loadRcExport(Entity.Rooms) + log.info('Parsing messages') + await loadRcExport(Entity.Messages) log.info('Done.') } catch (error) { log.error(`Encountered an error while booting up: ${error}`, error) diff --git a/src/handlers/messages.ts b/src/handlers/messages.ts new file mode 100644 index 0000000..f6e99d6 --- /dev/null +++ b/src/handlers/messages.ts @@ -0,0 +1,127 @@ +import { Entity, entities } from '../Entities' +import { IdMapping } from '../entity/IdMapping' +import log from '../helpers/logger' +import { getMessageId, getRoomId, getUserId, save } from '../helpers/storage' +import { axios, formatUserSessionOptions } from '../helpers/synapse' + +const applicationServiceToken = process.env.AS_TOKEN || '' +if (!applicationServiceToken) { + const message = 'No AS_TOKEN found in .env.' + log.error(message) + throw new Error(message) +} + +export type RcMessage = { + _id: string + rid: string // The unique id for the room + msg: string // The content of the message. + tmid?: string + ts: { + $date: string + } + mentions?: string[] + u: { + _id: string + username?: string + name?: string + } + md?: any // The message's content in a markdown format. + pinned?: boolean + drid?: string // The direct room id (if belongs to a direct room). + attachments?: any[] // An array of attachment objects, available only when the message has at least one attachment. + reactions?: object // Object containing reaction information associated with the message. +} + +export type MatrixMessage = { + body: string + msgtype: 'm.text' + type: 'm.room.message' + 'm.relates_to'?: { + rel_type: 'm.thread' + event_id: string + is_falling_back: true + 'm.in_reply_to': { + event_id: string + } + } +} + +export function mapMessage(rcMessage: RcMessage): MatrixMessage { + return { + body: rcMessage.msg, + msgtype: 'm.text', + type: 'm.room.message', + } +} + +export async function createMapping( + rcId: string, + matrixId: string +): Promise { + const messageMapping = new IdMapping() + messageMapping.rcId = rcId + messageMapping.matrixId = matrixId + messageMapping.type = entities[Entity.Messages].mappingType + + await save(messageMapping) + log.debug('Mapping added:', messageMapping) +} + +export async function createMessage( + matrixMessage: MatrixMessage, + room_id: string, + user_id: string, + ts: number, + transactionId: string +): Promise { + return ( + await axios.put( + `/_matrix/client/v3/rooms/${room_id}/send/m.room.message/${transactionId}?user_id=${user_id}&ts=${ts}`, + matrixMessage, + formatUserSessionOptions(applicationServiceToken) + ) + ).data.event_id +} + +export async function handle(rcMessage: RcMessage): Promise { + const room_id = (await getRoomId(rcMessage.rid)) || '' + if (!room_id) { + log.info( + `Could not find room ${rcMessage.rid} for message ${rcMessage._id}, skipping.` + ) + return + } + + const user_id = (await getUserId(rcMessage.u._id)) || '' + if (!user_id) { + log.info( + `Could not find author ${rcMessage.u.username} for message ${rcMessage._id}, skipping.` + ) + return + } + + const matrixMessage = mapMessage(rcMessage) + + const ts = new Date(rcMessage.ts.$date).valueOf() + if (rcMessage.tmid) { + const event_id = (await getMessageId(rcMessage.tmid)) || '' + matrixMessage['m.relates_to'] = { + rel_type: 'm.thread', + event_id, + is_falling_back: true, + 'm.in_reply_to': { + event_id, + }, + } + } + + const event_id = await createMessage( + matrixMessage, + room_id, + user_id, + ts, + rcMessage._id + ) + + createMapping(rcMessage._id, event_id) +}