From 757b120e422c08e6d4c374a6cf77da1d85002ab1 Mon Sep 17 00:00:00 2001 From: Martin Dimitrov Date: Sun, 27 Oct 2024 07:40:25 -0700 Subject: [PATCH] refactor to have 3 promises race instead of timeouts --- .../functions/buzzer-activated.js | 98 +++++++++++++------ 1 file changed, 67 insertions(+), 31 deletions(-) diff --git a/packages/doorman-client/functions/buzzer-activated.js b/packages/doorman-client/functions/buzzer-activated.js index 970f692..e4f3108 100644 --- a/packages/doorman-client/functions/buzzer-activated.js +++ b/packages/doorman-client/functions/buzzer-activated.js @@ -13,7 +13,7 @@ async function getConfig(context, buzzer) { function notifyDiscord(context, msg, u, optionalJsonStr) { return fetch(context.DOORMAN_URL + - `/api/door/notify?discordUser=${u}&msg=${encodeURIComponent(msg)}&json=${encodeURIComponent(optionalJsonStr)}` + `/api/door/notify?discordUser=${u}&msg=${encodeURIComponent(msg)}&json=${encodeURIComponent(optionalJsonStr)}`, ).catch(err => console.log(err)) } @@ -42,8 +42,6 @@ function dialFallbackTwiml(twiml, config) { } exports.handler = async function(context, event, callback) { - let twiml = new Twilio.twiml.VoiceResponse(); - let config = event.config; // get by api or parse it out from query @@ -59,45 +57,83 @@ exports.handler = async function(context, event, callback) { // reject the call if this is not configured if (!config || !config.door) { + let twiml = new Twilio.twiml.VoiceResponse(); twiml.reject(); callback(null, twiml); return; } - // TODO: await on this? // let users know someone is currently buzzing, and allow unlock by discord user let msg = `🔔 Someone is dialing right now @ Door "${config.door}" [Click to unlock](${context.DOORMAN_URL}/api/door/auth?door=${config.door}&key=`; - let discordNotifs = Promise.all(config.discordUsers.map((u) => + + // TODO: should we await for one delivery? + Promise.race(config.discordUsers.map((u) => notifyDiscord(context, msg + u + ')', u) )); - // poll Doorman, to see if we should unlock - const interval = setInterval(() => { - fetch(context.DOORMAN_URL + `/api/door/status?door=${config.door}`) - .then(async res => { - if (res.status === 200) { - clearInterval(interval); - // put this before awaiting notify - // so it would be appended above any dial Verb from fallback - doorOpenTwiml(twiml, config); + let discordLock = false; - const body = await res.json(); - await notifyAllDiscord(context, config, `🔓 Doorman buzzed someone up @ Door "${config.door}"`, JSON.stringify(body.fingerprint)); - callback(null, twiml); - } - }) - .catch(err => console.log(err)); - }, 500); + const unlockPromise = new Promise((resolve, reject) => { + const interval = setInterval(() => { + fetch(context.DOORMAN_URL + `/api/door/status?door=${config.door}`) + .then(async res => { + if (res.status === 200) { + clearInterval(interval); + const body = await res.json(); + const twiml = new Twilio.twiml.VoiceResponse(); + doorOpenTwiml(twiml, config); + if (!discordLock) { + console.log( + "UnlockPromise: I was the fastest, so I will attempt to notify discord users before resolving with unlock" + ); + discordLock = true; + await notifyAllDiscord(context, config, `🔓 Doorman buzzed someone up @ Door "${config.door}"`, JSON.stringify(body.fingerprint)); + resolve(twiml); + } else { + console.log( + "UnlockPromise: dropping out of the race, graceful fallback is already notifiying discord users" + ); + } + } + }).catch(err => console.log(err)); + }, 500) + }); - // redirect to call after 6s - setTimeout(async () => { - dialFallbackTwiml(twiml, config); - await notifyAllDiscord( - context, - config, - `📞 Somebody buzzed the door and it dialed through to fallback phone numbers @ Door "${config.door}"` - ); + const gracefulFallbackPromise = new Promise((resolve, reject) => { + setTimeout(async () => { + const twiml = new Twilio.twiml.VoiceResponse(); + dialFallbackTwiml(twiml, config); - callback(null, twiml); - }, 6000); + if (!discordLock) { + console.log( + "GracefulFallbackPromise: I was the fastest, so I will attempt to notify discord users before resolving with a call" + ); + discordLock = true; + await notifyAllDiscord( + context, + config, + `📞 Somebody buzzed the door and it dialed through to fallback phone numbers @ Door "${config.door}"` + ); + resolve(twiml); + } else { + console.log( + "GracefulFallbackPromise: dropping out of the race, unlock is already notifying discord users" + ); + } + }, 6000); + }); + + const ungracefulFallbackPromise = new Promise((resolve, reject) => { + setTimeout(async () => { + const twiml = new Twilio.twiml.VoiceResponse(); + dialFallbackTwiml(twiml, config); + console.error( + "UngracefulFallbackPromise: Cutting it too close to timeout! Skipping notifying users and calling fallback" + ); + resolve(twiml); + }, 8000); + }); + + const twiml = await Promise.race([unlockPromise, gracefulFallbackPromise, ungracefulFallbackPromise]); + callback(null, twiml); };