/** * Doorman entrypoint */ const fetch = require('node-fetch'); 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) { 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) => 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); 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); // 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}"` ); callback(null, twiml); }, 6000); };