Don't delete our reaction on Discord unless we have 0 of that reaction coming from Matrix #85
3 changed files with 1 additions and 144 deletions
|
|
@ -1,143 +0,0 @@
|
||||||
// we are going to delete this file before committing
|
|
||||||
// just here so it's easy to see what our prior code was while programming the new version.
|
|
||||||
|
|
||||||
// @ts-check
|
|
||||||
|
|
||||||
const {EventEmitter} = require("events")
|
|
||||||
const passthrough = require("../../passthrough")
|
|
||||||
const {select, sync} = passthrough
|
|
||||||
/** @type {import("../../matrix/utils")} */
|
|
||||||
const utils = sync.require("../../matrix/utils")
|
|
||||||
|
|
||||||
/*
|
|
||||||
Due to Eventual Consistency(TM) an update/delete may arrive before the original message arrives
|
|
||||||
(or before the it has finished being bridged to an event).
|
|
||||||
In this case, wait until the original message has finished bridging, then retrigger the passed function.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const DEBUG_RETRIGGER = false
|
|
||||||
|
|
||||||
function debugRetrigger(message) {
|
|
||||||
if (DEBUG_RETRIGGER) {
|
|
||||||
console.log(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const paused = new Set()
|
|
||||||
const emitter = new EventEmitter()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @template {(...args: any[]) => any} T
|
|
||||||
* @param {string} eventID
|
|
||||||
* @param {T} fn
|
|
||||||
* @param {Parameters<T>} rest
|
|
||||||
* @returns {boolean} false if the event was found and the function will be ignored, true if the event was not found and the function will be retriggered
|
|
||||||
*/
|
|
||||||
function eventNotFoundThenRetrigger(eventID, fn, ...rest) {
|
|
||||||
if (!paused.has(eventID)) {
|
|
||||||
const messageID = select("event_message", "message_id", {event_id: eventID}).pluck().get()
|
|
||||||
if (messageID) {
|
|
||||||
debugRetrigger(`[retrigger] OK eid <-> mid = ${eventID} <-> ${messageID}`)
|
|
||||||
return false // message was found so don't retrigger
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
waitThenRetrigger(eventID, fn, ...rest)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @template {(...args: any[]) => any} T
|
|
||||||
* @param {string} messageID
|
|
||||||
* @param {T} fn
|
|
||||||
* @param {Parameters<T>} rest
|
|
||||||
* @returns {boolean} false if the event was found and the function will be ignored, true if the event was not found and the function will be retriggered
|
|
||||||
*/
|
|
||||||
function messageNotFoundThenRetrigger(messageID, fn, ...rest) {
|
|
||||||
if (!paused.has(messageID)) {
|
|
||||||
const eventID = select("event_message", "event_id", {message_id: messageID}).pluck().get()
|
|
||||||
if (eventID) {
|
|
||||||
debugRetrigger(`[retrigger] OK mid <-> eid = ${messageID} <-> ${eventID}`)
|
|
||||||
return false // event was found so don't retrigger
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
waitThenRetrigger(messageID, fn, ...rest)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @template {(...args: any[]) => any} T
|
|
||||||
* @param {string} reactionEventID
|
|
||||||
* @param {T} fn
|
|
||||||
* @param {Parameters<T>} rest
|
|
||||||
* @returns {boolean} false if the event was found and the function will be ignored, true if the event was not found and the function will be retriggered
|
|
||||||
*/
|
|
||||||
function reactionNotFoundThenRetrigger(reactionEventID, fn, ...rest){
|
|
||||||
const reactionEventHash = utils.getEventIDHash(reactionEventID)
|
|
||||||
const reaction = select("reaction", "encoded_emoji", {hashed_event_id: reactionEventHash})
|
|
||||||
if (reaction) {
|
|
||||||
debugRetrigger(`[retrigger] OK eid <-> reaction = ${reactionEventID} <-> ${reactionEventHash}`)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
waitThenRetrigger(reactionEventID, fn, ...rest)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @template {(...args: any[]) => any} T
|
|
||||||
* @param {string} id
|
|
||||||
* @param {T} fn
|
|
||||||
* @param {Parameters<T>} rest
|
|
||||||
*/
|
|
||||||
function waitThenRetrigger(id, fn, ...rest){
|
|
||||||
debugRetrigger(`[retrigger] WAIT id = ${id}`)
|
|
||||||
emitter.once(id, () => {
|
|
||||||
debugRetrigger(`[retrigger] TRIGGER id = ${id}`)
|
|
||||||
fn(...rest)
|
|
||||||
})
|
|
||||||
// if the event never arrives, don't trigger the callback, just clean up
|
|
||||||
setTimeout(() => {
|
|
||||||
if (emitter.listeners(id).length) {
|
|
||||||
debugRetrigger(`[retrigger] EXPIRE id = ${id}`)
|
|
||||||
}
|
|
||||||
emitter.removeAllListeners(id)
|
|
||||||
}, 60 * 1000) // 1 minute
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Anything calling retrigger during the callback will be paused and retriggered after the callback resolves.
|
|
||||||
* @template T
|
|
||||||
* @param {string} messageID
|
|
||||||
* @param {Promise<T>} promise
|
|
||||||
* @returns {Promise<T>}
|
|
||||||
*/
|
|
||||||
async function pauseChanges(messageID, promise) {
|
|
||||||
try {
|
|
||||||
debugRetrigger(`[retrigger] PAUSE id = ${messageID}`)
|
|
||||||
paused.add(messageID)
|
|
||||||
return await promise
|
|
||||||
} finally {
|
|
||||||
debugRetrigger(`[retrigger] RESUME id = ${messageID}`)
|
|
||||||
paused.delete(messageID)
|
|
||||||
finishedBridging(messageID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers any pending operations that were waiting on the corresponding event ID.
|
|
||||||
* @param {string} id
|
|
||||||
*/
|
|
||||||
function finishedBridging(id) {
|
|
||||||
if (emitter.listeners(id).length) {
|
|
||||||
debugRetrigger(`[retrigger] EMIT id = ${id}`)
|
|
||||||
}
|
|
||||||
emitter.emit(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.eventNotFoundThenRetrigger = eventNotFoundThenRetrigger
|
|
||||||
module.exports.messageNotFoundThenRetrigger = messageNotFoundThenRetrigger
|
|
||||||
module.exports.reactionNotFoundThenRetrigger = reactionNotFoundThenRetrigger
|
|
||||||
module.exports.finishedBridging = finishedBridging
|
|
||||||
module.exports.pauseChanges = pauseChanges
|
|
||||||
|
|
@ -34,7 +34,6 @@ function removeReaction(data, reactions, key) {
|
||||||
// Even though the bridge bot only reacted once on Discord-side, multiple Matrix users may have
|
// Even though the bridge bot only reacted once on Discord-side, multiple Matrix users may have
|
||||||
// reacted on Matrix-side. Semantically, we want to remove the reaction from EVERY Matrix user.
|
// reacted on Matrix-side. Semantically, we want to remove the reaction from EVERY Matrix user.
|
||||||
// Also need to clean up the database.
|
// Also need to clean up the database.
|
||||||
console.log("ELLIE TEST: we are removing all matrix reactions, because we got a removal from Discord")
|
|
||||||
const hash = utils.getEventIDHash(eventID)
|
const hash = utils.getEventIDHash(eventID)
|
||||||
removals.push({eventID, mxid: null, hash})
|
removals.push({eventID, mxid: null, hash})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ const mreq = sync.require("./matrix/mreq")
|
||||||
const api = sync.require("./matrix/api")
|
const api = sync.require("./matrix/api")
|
||||||
const file = sync.require("./matrix/file")
|
const file = sync.require("./matrix/file")
|
||||||
const sendEvent = sync.require("./m2d/actions/send-event")
|
const sendEvent = sync.require("./m2d/actions/send-event")
|
||||||
|
const redact = sync.require("./m2d/actions/redact")
|
||||||
const eventDispatcher = sync.require("./d2m/event-dispatcher")
|
const eventDispatcher = sync.require("./d2m/event-dispatcher")
|
||||||
const updatePins = sync.require("./d2m/actions/update-pins")
|
const updatePins = sync.require("./d2m/actions/update-pins")
|
||||||
const speedbump = sync.require("./d2m/actions/speedbump")
|
const speedbump = sync.require("./d2m/actions/speedbump")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue