From 573d3a063abbe4f4207a879212e26cc37b3bdca6 Mon Sep 17 00:00:00 2001 From: Martin Dimitrov Date: Sun, 27 Oct 2024 06:46:51 -0700 Subject: [PATCH] reduce to 1 lambda for buzzer --- .../functions/buzzer-activated.js | 99 +++++++++++++------ .../functions/call-residents.js | 23 ----- .../doorman-client/functions/door-open.js | 18 ---- packages/doorman-client/functions/text-me.js | 36 ------- 4 files changed, 70 insertions(+), 106 deletions(-) delete mode 100644 packages/doorman-client/functions/call-residents.js delete mode 100644 packages/doorman-client/functions/door-open.js delete mode 100644 packages/doorman-client/functions/text-me.js diff --git a/packages/doorman-client/functions/buzzer-activated.js b/packages/doorman-client/functions/buzzer-activated.js index d3d4145..970f692 100644 --- a/packages/doorman-client/functions/buzzer-activated.js +++ b/packages/doorman-client/functions/buzzer-activated.js @@ -1,20 +1,61 @@ /** - * Simple call box routine - * - * This function is meant for the apartment building callbox - * It gives the user a couple of seconds to produce the password - * Then dials all the residents to grant manual entry + * Doorman entrypoint */ const fetch = require('node-fetch'); -exports.handler = async function(context, event, callback) { - let twiml = new Twilio.twiml.VoiceResponse(); - - let config = await fetch(context.DOORMAN_URL + `/api/door/info?buzzer=${event.From}`) +async function getConfig(context, buzzer) { + return await fetch(context.DOORMAN_URL + `/api/door/info?buzzer=${buzzer}`) .then(res => res.json()) .catch(err => { return undefined; }); +} + +function notifyDiscord(context, msg, u, optionalJsonStr) { + return fetch(context.DOORMAN_URL + + `/api/door/notify?discordUser=${u}&msg=${encodeURIComponent(msg)}&json=${encodeURIComponent(optionalJsonStr)}` + ).catch(err => console.log(err)) +} + +function notifyAllDiscord(context, config, msg, optionalJsonStr) { + return Promise.all(config.discordUsers.map((u) => + notifyDiscord(context, msg, u, optionalJsonStr) + )); +} + +function doorOpenTwiml(twiml, config) { + twiml.play('https://buzzer-2439-prod.twil.io/buzzing_up_boosted.mp3'); + twiml.play({ digits: config.pressKey }); // configured in doorman what button to click and passed into this function + twiml.pause({ length: 1 }); + twiml.hangup(); +} + +function dialFallbackTwiml(twiml, config) { + let dial = twiml.dial({ + timeLimit: 20, + timeout: 20 + }); + + config.fallbackNumbers.forEach(number => { + dial.number(number); + }); +} + +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 + if (!config) { + config = await getConfig(context, event.From); + } else { + try { + config = JSON.parse(config); + } catch(e) { + config = await getConfig(context, event.From); + } + } // reject the call if this is not configured if (!config || !config.door) { @@ -23,31 +64,25 @@ exports.handler = async function(context, event, callback) { return; } - let configQuery = `config=${encodeURIComponent(JSON.stringify(config))}`; - - // let user know someone is currently buzzing, and allow unlock by discord user + // 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=`; - config.discordUsers.forEach((u) => { - // unlock me by discord userid - fetch(context.DOORMAN_URL + `/api/door/notify?discordUser=${u}&msg=${encodeURIComponent(msg + u + ')')}`); - }); + let discordNotifs = Promise.all(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 => { - // handle the case where doorman is explictly rejecting the buzzer - if (res.status === 410) { - clearInterval(interval); - twiml.redirect(`/text-me?method=doorman-time-lock&${configQuery}`); - callback(null, twiml); - } - - // we got the successful unlock - else if (res.status === 200) { + 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); + const body = await res.json(); - twiml.redirect(`/door-open?fingerprint=${encodeURIComponent(JSON.stringify(body.fingerprint))}&${configQuery}`); + await notifyAllDiscord(context, config, `🔓 Doorman buzzed someone up @ Door "${config.door}"`, JSON.stringify(body.fingerprint)); callback(null, twiml); } }) @@ -55,8 +90,14 @@ exports.handler = async function(context, event, callback) { }, 500); // redirect to call after 6s - setTimeout(() => { - twiml.redirect(`/call-residents?${configQuery}`); + setTimeout(async () => { + dialFallbackTwiml(twiml, config); + await notifyAllDiscord( + context, + config, + `📞 Somebody buzzed the door and it dialed through to fallback phone numbers @ Door "${config.door}"` + ); + callback(null, twiml); }, 6000); -}; \ No newline at end of file +}; diff --git a/packages/doorman-client/functions/call-residents.js b/packages/doorman-client/functions/call-residents.js deleted file mode 100644 index f1f4752..0000000 --- a/packages/doorman-client/functions/call-residents.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Fallback behavior, if the code is wrong or unspecified, then we should dial the fallback numbers - */ -exports.handler = function(context, event, callback) { - let twiml = new Twilio.twiml.VoiceResponse(); - - let config = JSON.parse(event.config); - console.log(config); - let configQuery = `config=${encodeURIComponent(JSON.stringify(config))}`; - - // If no valid answer after timeout, dial all residents until someone picks up - let dial = twiml.dial({ - action: `/text-me?Method=call&${configQuery}`, - timeLimit: 20, - timeout: 20 - }); - - config.fallbackNumbers.forEach(number => { - dial.number(number); - }); - - return callback(null, twiml); -} \ No newline at end of file diff --git a/packages/doorman-client/functions/door-open.js b/packages/doorman-client/functions/door-open.js deleted file mode 100644 index 7075f74..0000000 --- a/packages/doorman-client/functions/door-open.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Automatically open the door -*/ -exports.handler = function(context, event, callback) { - let twiml = new Twilio.twiml.VoiceResponse(); - - let config = JSON.parse(event.config); - let configQuery = `config=${encodeURIComponent(JSON.stringify(config))}`; - - let passAlong = `fingerprint=${encodeURIComponent(event.fingerprint)}&${configQuery}`; - - twiml.play('https://buzzer-2439-prod.twil.io/buzzing_up_boosted.mp3'); - twiml.play({ digits: config.pressKey }); // configured in doorman what button to click and passed into this function - twiml.pause({ length: 1 }); - twiml.redirect(`/text-me?Method=doorman&${passAlong}`); - - callback(null, twiml); -}; \ No newline at end of file diff --git a/packages/doorman-client/functions/text-me.js b/packages/doorman-client/functions/text-me.js deleted file mode 100644 index 41e9671..0000000 --- a/packages/doorman-client/functions/text-me.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Send a NTFY message with an update of what happened. If the password was used or not... - */ - -const fetch = require('node-fetch'); - -exports.handler = async function(context, event, callback) { - let twiml = new Twilio.twiml.VoiceResponse(); - let config = JSON.parse(event.config); - - // should be a list of strings representing user ids in discord - let discordUsers = config.discordUsers || []; - - let msg; - let optionalJson = event.fingerprint; - - if (event.Method == 'doorman') { - msg = '🔓 Doorman buzzed someone up'; - } else if (event.Method == 'doorman-time-lock') { - msg = '🔒 Doorman rejected a buzzer call due to time restriction'; - } else if (event.Method == 'call') { - msg = '📞 Somebody buzzed the door and it dialed through to a fallback phone number'; - } - - msg += ` @ Door "${config.door}"`; - - let promises = discordUsers.map((u) => - fetch(context.DOORMAN_URL + `/api/door/notify?discordUser=${u}&msg=${msg}&json=${optionalJson}`) - .catch(err => console.log(err)) - ); - - await Promise.all(promises) - .catch (e => console.log(e)); - - return callback(null, twiml); -}; \ No newline at end of file