From 4cad1fbe2b7040e2cc0cbb335beba7fb5201c67d Mon Sep 17 00:00:00 2001 From: Martin Dimitrov Date: Sat, 26 Oct 2024 13:31:15 -0700 Subject: [PATCH] discord notifications --- .gitea/workflows/deploy-twilio.yaml | 1 + bun.lockb | Bin 396464 -> 404960 bytes packages/doorman-api/.env.example | 5 ++- .../doorman-api/functions/api/door/info.js | 1 + .../doorman-api/functions/api/door/notify.js | 15 +++++++ .../functions/common/discord.private.js | 39 ++++++++++++++++++ packages/doorman-api/package.json | 3 +- packages/doorman-client/.env.example | 1 - .../functions/buzzer-activated.js | 16 +++---- .../functions/call-residents.js | 13 ++++-- .../doorman-client/functions/door-open.js | 9 ++-- packages/doorman-client/functions/text-me.js | 24 ++++++----- packages/doorman-client/package.json | 2 +- 13 files changed, 97 insertions(+), 32 deletions(-) create mode 100644 packages/doorman-api/functions/api/door/notify.js create mode 100644 packages/doorman-api/functions/common/discord.private.js diff --git a/.gitea/workflows/deploy-twilio.yaml b/.gitea/workflows/deploy-twilio.yaml index afc975c..5a25c6a 100644 --- a/.gitea/workflows/deploy-twilio.yaml +++ b/.gitea/workflows/deploy-twilio.yaml @@ -25,6 +25,7 @@ jobs: AUTH_TOKEN: ${{ secrets.TWILIO_AUTH_TOKEN }} AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }} - name: Deploy Doorman Buzzer Client run: bun run deploy-buzzer-client diff --git a/bun.lockb b/bun.lockb index 55ec6193c1b8b9c4d636becdde1c286845b693a9..c9b4164636921076588053c590b014bd55764618 100755 GIT binary patch delta 19561 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 N!RSzRvr^EP{|0y-Vj} console.error(e)); + + return callback(null, response); +}; diff --git a/packages/doorman-api/functions/common/discord.private.js b/packages/doorman-api/functions/common/discord.private.js new file mode 100644 index 0000000..448b9ee --- /dev/null +++ b/packages/doorman-api/functions/common/discord.private.js @@ -0,0 +1,39 @@ +// reusing from refbounty: +// https://gitea.chromart.cc/martin/refbounty/src/commit/1f40d7870a530fe7e7acbc3b901024092c9fb90a/packages/server/src/connectors/DiscordConnector.ts +// https://gitea.chromart.cc/martin/refbounty/src/commit/1f40d7870a530fe7e7acbc3b901024092c9fb90a/packages/server/src/utils/DiscordUtils.ts + +const { Client, GatewayIntentBits } = require("discord.js"); + +let conn; + +exports.getDiscordClient = async (context) => { + if (!conn) { + const client = new Client({ + intents: [GatewayIntentBits.DirectMessages], + rest: { + timeout: 60_000, // 1 minute + } + }); + + await client.login(context.DISCORD_BOT_TOKEN); + conn = client; + } + + return conn; +}; + + +exports.sendMessageToUser = async ( + context, + userId, + msg, +) => { + try { + const client = await exports.getDiscordClient(context); + const user = await client.users.fetch(userId); + return user.send(msg); + } catch (e) { + console.log(e); + console.log(`Failed to send msg to ${userId}`); + } +} diff --git a/packages/doorman-api/package.json b/packages/doorman-api/package.json index 15b4d70..d65b5c1 100644 --- a/packages/doorman-api/package.json +++ b/packages/doorman-api/package.json @@ -4,12 +4,13 @@ "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "twilio-run", + "start": "twilio-run --live --port 8080", "deploy": "twilio-run deploy --load-system-env --env .env.example --service-name doorman --environment=prod --override-existing-project" }, "dependencies": { "@aws-sdk/client-dynamodb": "^3.609.0", "@twilio/runtime-handler": "1.3.0", + "discord.js": "^14.16.3", "twilio": "^3.56" }, "devDependencies": { diff --git a/packages/doorman-client/.env.example b/packages/doorman-client/.env.example index 5af0929..03505de 100644 --- a/packages/doorman-client/.env.example +++ b/packages/doorman-client/.env.example @@ -1,5 +1,4 @@ DOORMAN_URL=https://doorman.chromart.cc -NTFY_DOMAIN=ntfy.chromart.cc # twilio auth ACCOUNT_SID= diff --git a/packages/doorman-client/functions/buzzer-activated.js b/packages/doorman-client/functions/buzzer-activated.js index c8b6788..b079764 100644 --- a/packages/doorman-client/functions/buzzer-activated.js +++ b/packages/doorman-client/functions/buzzer-activated.js @@ -8,7 +8,6 @@ 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}`) @@ -24,7 +23,7 @@ exports.handler = async function(context, event, callback) { return; } - const promise = new Promise(() => null, () => null); + let configQuery = `config=${encodeURIComponent(JSON.stringify(config))}`; // poll Doorman, to see if we should unlock const interval = setInterval(() => { @@ -33,19 +32,16 @@ exports.handler = async function(context, event, callback) { // handle the case where doorman is explictly rejecting the buzzer if (res.status === 410) { clearInterval(interval); - twiml.redirect('/text-me?method=doorman-time-lock'); + twiml.redirect(`/text-me?method=doorman-time-lock&${configQuery}`); callback(null, twiml); - promise.resolve(); } // we got the successful unlock else if (res.status === 200) { clearInterval(interval); - const body = await res.json(); - twiml.redirect(`/door-open?fingerprint=${encodeURIComponent(JSON.stringify(body))}&pressKey=${config.pressKey}`); + twiml.redirect(`/door-open?fingerprint=${encodeURIComponent(JSON.stringify(body))}&${configQuery}`); callback(null, twiml); - promise.resolve(); } }) .catch(err => console.log(err)); @@ -53,11 +49,9 @@ exports.handler = async function(context, event, callback) { // redirect to call after 6s setTimeout(() => { - twiml.redirect(`/call-residents?numbers=${encodeURIComponent(config.fallbackNumbers)}`); + twiml.redirect(`/call-residents?${configQuery}`); callback(null, twiml); - promise.resolve(); }, 6000); - await promise; - return callback(null, twiml); + // return callback(null, twiml); }; \ No newline at end of file diff --git a/packages/doorman-client/functions/call-residents.js b/packages/doorman-client/functions/call-residents.js index 891c15f..f1f4752 100644 --- a/packages/doorman-client/functions/call-residents.js +++ b/packages/doorman-client/functions/call-residents.js @@ -4,13 +4,18 @@ exports.handler = function(context, event, callback) { let twiml = new Twilio.twiml.VoiceResponse(); - // numbers are passed in - let numbers = event.numbers.split(','); + 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', timeLimit: 20, timeout: 20}); + let dial = twiml.dial({ + action: `/text-me?Method=call&${configQuery}`, + timeLimit: 20, + timeout: 20 + }); - numbers.forEach(number => { + config.fallbackNumbers.forEach(number => { dial.number(number); }); diff --git a/packages/doorman-client/functions/door-open.js b/packages/doorman-client/functions/door-open.js index 3399d38..7075f74 100644 --- a/packages/doorman-client/functions/door-open.js +++ b/packages/doorman-client/functions/door-open.js @@ -4,10 +4,13 @@ exports.handler = function(context, event, callback) { let twiml = new Twilio.twiml.VoiceResponse(); - let passAlong = `fingerprint=${encodeURIComponent(event.fingerprint)}`; + let config = JSON.parse(event.config); + let configQuery = `config=${encodeURIComponent(JSON.stringify(config))}`; - twiml.play('https://smart-door-buzzer-3172.twil.io/buzzing_up_boosted.mp3'); - twiml.play({ digits: event.pressKey }); // configured in doorman what button to click and passed into this function + 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}`); diff --git a/packages/doorman-client/functions/text-me.js b/packages/doorman-client/functions/text-me.js index 06de072..f06886b 100644 --- a/packages/doorman-client/functions/text-me.js +++ b/packages/doorman-client/functions/text-me.js @@ -4,27 +4,31 @@ const fetch = require('node-fetch'); -exports.handler = function(context, event, callback) { +exports.handler = async function(context, event, callback) { let twiml = new Twilio.twiml.VoiceResponse(); + // should be a list of strings representing user ids in discord + let discordUsers = JSON.parse(event.config).discordUsers || []; + let bodyText; if (event.Method == 'doorman') { bodyText = 'Doorman buzzed someone up!'; const fingerprint = JSON.parse(event.fingerprint); - bodyText += `\n\n${JSON.stringify(fingerprint, null, 4)}`; + bodyText += `\n\n\`\`\`${JSON.stringify(fingerprint, null, 4)}\`\`\``; } else if (event.Method == 'doorman-time-lock') { bodyText = 'Doorman rejected a buzzer call due to time restriction'; } else if (event.Method == 'call') { bodyText = 'Somebody buzzed the door and it dialed through to a phone.'; } - // send webhook to ntfy - fetch(`https://${context.NTFY_DOMAIN}/buzzer`, { - method: "POST", - body: bodyText, - }) - .then(res => callback(null, twiml)) - // even if we error then we should just end the call normally - .catch(err => callback(null, twiml)); + let promises = discordUsers.map((u) => + fetch(context.DOORMAN_URL + `/api/door/notify?discordUser=${u}&msg=${bodyText}`) + .catch(err => console.log(err)) + ); + + await Promise.all(promises) + .catch (e => console.log(e)); + + return callback(null, twiml); }; \ No newline at end of file diff --git a/packages/doorman-client/package.json b/packages/doorman-client/package.json index 75dd944..86a9770 100644 --- a/packages/doorman-client/package.json +++ b/packages/doorman-client/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "twilio-run --live", + "start": "twilio-run --live --port 4500", "deploy": "twilio-run deploy --load-system-env --env .env.example --service-name buzzer --environment=prod --override-existing-project" }, "dependencies": {