123 lines
3.6 KiB
JavaScript
123 lines
3.6 KiB
JavaScript
const {
|
|
AutojoinRoomsMixin,
|
|
MatrixClient,
|
|
RustSdkCryptoStorageProvider,
|
|
SimpleFsStorageProvider,
|
|
} = require('matrix-bot-sdk');
|
|
const fastq = require('fastq');
|
|
|
|
const { appState, proposalEventIds } = require('./db');
|
|
|
|
const {
|
|
MATRIX_HOMESERVER_URL,
|
|
MATRIX_ACCESS_TOKEN,
|
|
BOT_STORAGE_PATH,
|
|
BOT_CRYPTO_STORAGE_PATH,
|
|
BOT_INSTANCE_ID,
|
|
ETH_NETWORK,
|
|
} = process.env;
|
|
|
|
const storageProvider = new SimpleFsStorageProvider(BOT_STORAGE_PATH);
|
|
const cryptoProvider = new RustSdkCryptoStorageProvider(BOT_CRYPTO_STORAGE_PATH);
|
|
let client;
|
|
let joinedRooms;
|
|
let targetRoomId;
|
|
|
|
const processOutboundQueue = async ({ type, ...args }) => {
|
|
if (!targetRoomId) return;
|
|
switch (type) {
|
|
case 'NewProposal': {
|
|
const { proposalIndex, text } = args;
|
|
try {
|
|
await proposalEventIds.get(Number(proposalIndex));
|
|
} catch (e) {
|
|
if (e.status === 404) {
|
|
console.log('sending to room', targetRoomId, { text });
|
|
const eventId = await client.sendText(targetRoomId, text);
|
|
await proposalEventIds.put(Number(proposalIndex), eventId);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
}
|
|
};
|
|
|
|
const outboundQueue = fastq(processOutboundQueue, 1);
|
|
outboundQueue.pause();
|
|
|
|
const start = async () => {
|
|
console.log('MATRIX_HOMESERVER_URL:', MATRIX_HOMESERVER_URL);
|
|
client = new MatrixClient(
|
|
MATRIX_HOMESERVER_URL,
|
|
MATRIX_ACCESS_TOKEN,
|
|
storageProvider,
|
|
cryptoProvider,
|
|
);
|
|
|
|
// Automatically join a room to which we are invited
|
|
AutojoinRoomsMixin.setupOnClient(client);
|
|
|
|
joinedRooms = await client.getJoinedRooms();
|
|
console.log('joined rooms:', joinedRooms);
|
|
|
|
try {
|
|
targetRoomId = await appState.get('targetRoomId');
|
|
} catch (e) {
|
|
// Leave targetRoomId uninitialized for now
|
|
}
|
|
|
|
async function handleCommand(roomId, event) {
|
|
// Don't handle unhelpful events (ones that aren't text messages, are redacted, or sent by us)
|
|
if (event.content?.msgtype !== 'm.text') return;
|
|
if (event.sender === await client.getUserId()) return;
|
|
|
|
const helloRegex = /^!hello\b/i;
|
|
const targetRegex = /^!target (.*)\b/i;
|
|
const proposalRegex = /\bprop(|osal) ([0-9]+)\b/i;
|
|
|
|
const { body } = event.content;
|
|
|
|
if (helloRegex.test(body)) {
|
|
console.log(`!hello roomId ${roomId}`);
|
|
await client.replyNotice(roomId, event, 'Hello world!');
|
|
} else if (targetRegex.test(body)) {
|
|
const [, instanceId] = targetRegex.exec(body);
|
|
console.log(`!target roomId ${roomId} instanceId ${instanceId}`);
|
|
if (instanceId === BOT_INSTANCE_ID) {
|
|
targetRoomId = roomId;
|
|
await appState.put('targetRoomId', targetRoomId);
|
|
await client.replyNotice(roomId, event, `Proposal events will be sent to this room for network ${ETH_NETWORK}`);
|
|
}
|
|
} else if (proposalRegex.test(body)) {
|
|
const [, , proposalIndexStr] = proposalRegex.exec(body);
|
|
const proposalIndex = parseInt(proposalIndexStr, 10);
|
|
console.log(`mention of proposal ${proposalIndex} in roomId ${roomId}`);
|
|
try {
|
|
const proposalEventId = await proposalEventIds.get(proposalIndex);
|
|
const proposalEventUri = `https://matrix.to/#/${roomId}/${proposalEventId}`;
|
|
await client.sendText(roomId, `Proposal ${proposalIndex}: ${proposalEventUri}`);
|
|
} catch (e) {
|
|
// Not found
|
|
}
|
|
}
|
|
}
|
|
|
|
// Before we start the bot, register our command handler
|
|
client.on('room.message', handleCommand);
|
|
|
|
client.start().then(() => {
|
|
console.log('Bot started!');
|
|
outboundQueue.resume();
|
|
});
|
|
};
|
|
|
|
const sendNewProposalEvent = (proposalIndex, text) => {
|
|
outboundQueue.push({ type: 'NewProposal', proposalIndex, text });
|
|
};
|
|
|
|
module.exports = {
|
|
start,
|
|
sendNewProposalEvent,
|
|
};
|