const sendError = async (event, roomId, e) => { e.response ? error = `Error(${e.response.status}): ${e.response.data.error}` : e.data ? error = `Error(${e.errcode}): ${e.data.error}` : error = `Error: ${e.syscall}, ${e.code}`; return matrixClient.sendHtmlNotice(roomId, '', error); }; const addReact = async (event, key) => { const roomId = event.event.room_id; return matrixClient.sendEvent(event.event.room_id, 'm.reaction', { 'm.relates_to': { rel_type: 'm.annotation', event_id: event.getId(), key, }, }).catch((e) => sendError(null, roomId, e)); }; const eventHandler = (args, roomId, command, event) => { const userInput = args.join(' '); const flaggedInput = userInput.substr(userInput.indexOf(' ') + 1); const address = args.slice(0, 1).join(' ').replace(/"/g, ''); args = []; switch (command) { case 'config': return; case 'help': case 'flood': case 'notify': args.push(roomId); break; case 'tip': case 'makeitrain': args.push(roomId, event, address, flaggedInput); break; case 'archive': case 'rearchive': args.push(roomId, userInput, !!~command.indexOf('re')); command = 'archive'; break; case 'post': case 'reply': case 'media': case 'mediareply': case 'random': case 'randomreply': case 'randommedia': case 'randommediareply': args.push(roomId, event, userInput, { isReply: !!~command.indexOf('reply'), hasMedia: !!~command.indexOf('media'), hasSubject: !!~command.indexOf('random'), }); command = 'post'; break; case 'proxy': case 'p': try { const url = new URL(userInput); const invidio = config.invidious.domains; const nitter = config.nitter.domains; command = invidio.redirect.includes(url.hostname) || invidio.original.includes(url.hostname) ? 'invidious' : nitter.redirect.includes(url.hostname) || nitter.original.includes(url.hostname) ? 'nitter' : 'proxy'; } catch (e) { sendError(event, roomId, e); } // fallthrough default: args.push(roomId, event, userInput); } registrar[command] && registrar[command].runQuery.apply(null, args); }; module.exports.sendError = sendError; module.exports.addReact = addReact; module.exports.eventHandler = eventHandler; module.exports.editNoticeHTML = (roomId, event, html, plain) => matrixClient.sendMessage(roomId, { body: ` * ${plain || html.replace(/<[^<]+?>/g, '')}`, formatted_body: ` * ${html}`, format: 'org.matrix.custom.html', msgtype: 'm.notice', 'm.new_content': { body: plain || html.replace(/<[^<]+?>/g, ''), formatted_body: html, format: 'org.matrix.custom.html', msgtype: 'm.notice', }, 'm.relates_to': { rel_type: 'm.replace', event_id: event.event_id, }, }); module.exports.handleReact = async (event) => { const roomId = event.event.room_id; const reaction = event.getContent()['m.relates_to']; if (!reaction) return; const metaEvent = await matrixClient.fetchRoomEvent(roomId, reaction.event_id); if (!metaEvent.content.meta || metaEvent.sender !== config.matrix.user) return; const args = metaEvent.content.meta.split(' '); isMeta = ['status', 'reblog', 'mention', 'redact', 'unreblog']; if (!isMeta.includes(args[0])) return; let command = []; args.shift().toLowerCase(); if (reaction.key === '🔁') command = 'copy'; if (reaction.key === '👏') command = 'clap'; if (reaction.key === '🗑️️') command = 'redact'; if (reaction.key === '🌧️') command = 'makeitrain'; eventHandler(args, roomId, command, event); }; module.exports.handleReply = async (event) => { const roomId = event.event.room_id; const reply = event.getContent()['m.relates_to']['m.in_reply_to']; if (!reply) return; const metaEvent = await matrixClient.fetchRoomEvent(roomId, reply.event_id); if (!metaEvent.content.meta || metaEvent.sender !== config.matrix.user) return; const args = metaEvent.content.meta.split(' '); args.push(event.event.content.formatted_body.trim().split('')[1]); isMeta = ['status', 'reblog', 'mention', 'redact', 'unreblog']; if (!isMeta.includes(args[0])) return; args.shift().toLowerCase(); command = 'reply'; eventHandler(args, roomId, command, event); }; module.exports.selfReact = async (event) => { if (event.getType() !== 'm.room.message') return; if (event.event.unsigned.age > 10000) return; const { meta } = event.getContent(); if (!meta) return; const type = meta.split(' ')[0]; if (type === 'redact' || type === 'unreblog') addReact(event, '🗑️️'); if (type === 'status' || type === 'reblog' || type === 'mention') { addReact(event, '🔁'); addReact(event, '👏'); if (config.fediverse.tipping === true) addReact(event, '🌧️'); } }; module.exports.retryPromise = async (argList, promiseFn) => { let err; for(var arg of argList) { try { return await promiseFn(arg); } catch(e) { err = e; } } throw err || new Error('retryPromise error'); };