Add sling messaging to buttons

This commit is contained in:
Christopher Cookman 2026-01-08 22:09:00 -07:00
parent 2921a7c23c
commit 4ebb66cec5
3 changed files with 94 additions and 16 deletions

2
.gitignore vendored
View file

@ -139,3 +139,5 @@ dist
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
.vite/
slingtoken.txt

View file

@ -16,7 +16,7 @@
"text": "6PM Announcement",
"btnClass": "btn-secondary",
"faIcon": "",
"name": "LivePage",
"name": "6PMAnnouncement",
"doubleHeight": false,
"context": {
"context": "custom-emergency.9001.1",
@ -28,7 +28,7 @@
"text": "15 Min Warning",
"btnClass": "btn-info",
"faIcon": "",
"name": "LivePage",
"name": "CloseWarning",
"doubleHeight": false,
"context": {
"context": "custom-emergency.9001.1",
@ -40,7 +40,7 @@
"text": "Pool Closed",
"btnClass": "btn-warning",
"faIcon": "",
"name": "LivePage",
"name": "PoolClosed",
"doubleHeight": false,
"context": {
"context": "custom-emergency.9001.1",
@ -52,7 +52,7 @@
"text": "Health Code Violation",
"btnClass": "btn-warning",
"faIcon": "",
"name": "LivePage",
"name": "HealthCodeViolation",
"doubleHeight": false,
"context": {
"context": "custom-emergency.9001.1",
@ -64,7 +64,7 @@
"text": "Snack Shop 15 Min Warning",
"btnClass": "btn-info",
"faIcon": "",
"name": "LivePage",
"name": "SnackShopWarning",
"doubleHeight": false,
"context": {
"context": "custom-emergency.9001.1",
@ -77,7 +77,7 @@
"text": "Snack Shop Closed",
"btnClass": "btn-warning",
"faIcon": "",
"name": "LivePage",
"name": "SnackShopClosed",
"doubleHeight": false,
"context": {
"context": "custom-emergency.9001.1",
@ -98,7 +98,9 @@
"context": "custom-emergency.9002.1",
"timeout": 30000,
"cid": "Emergency Announcement"
}
},
"sling_chat_id": "17132563",
"sling_chat_message": "A user has initiated an Emergency Announcement."
},
{
"text": "Lightning Alert",
@ -116,7 +118,7 @@
{
"text": "EAP Stand By",
"btnClass": "btn-primary",
"name": "LightningAlert",
"name": "EAPStandBy",
"faIcon": "fa-duotone fa-solid fa-pause",
"doubleHeight": false,
"context": {
@ -124,12 +126,14 @@
"timeout": 30000,
"cid": "\"Weather Alert\" <9000>",
"dial": "9000"
}
},
"sling_chat_id": "17132563",
"sling_chat_message": "CUDA ALERT: EAP Activation - Stand By"
},
{
"text": "EAP Evacuate",
"btnClass": "btn-danger",
"name": "LightningAlert",
"name": "EAPEvac",
"faIcon": "fa-duotone fa-solid fa-person-to-door",
"doubleHeight": false,
"context": {
@ -137,12 +141,14 @@
"timeout": 30000,
"cid": "\"Weather Alert\" <9000>",
"dial": "9000"
}
},
"sling_chat_id": "17132563",
"sling_chat_message": "CUDA ALERT: EAP Activation - Evacuate"
},
{
"text": "Fire Evac",
"btnClass": "btn-danger",
"name": "LightningAlert",
"name": "FireEvac",
"faIcon": "fa-duotone fa-solid fa-fire",
"doubleHeight": false,
"context": {
@ -150,7 +156,9 @@
"timeout": 30000,
"cid": "\"Weather Alert\" <9000>",
"dial": "9000"
}
},
"sling_chat_id": "17132563",
"sling_chat_message": "Fire Evacuation"
}
]

View file

@ -5,7 +5,16 @@ require('dotenv').config();
const phonesCfg = require('./phones.json');
const buttonsCfg = require('./buttons.json');
const fs = require('fs');
const path = require('path');
if (!fs.existsSync(path.join(__dirname, 'slingtoken.txt'))) {
// Create empty file
fs.writeFileSync(path.join(__dirname, 'slingtoken.txt'), '', 'utf8');
console.warn('slingtoken.txt file created. Please add your Sling token to this file to use sling messaging!');
}
var slingToken = fs.readFileSync(path.join(__dirname, 'slingtoken.txt'), 'utf8').trim();
const contexts = {};
// Generate contexts from buttonsCfg
@ -16,24 +25,47 @@ Object.keys(buttonsCfg).forEach(category => {
context: button.context.context,
timeout: button.context.timeout,
cid: button.context.cid,
...(button.context.dial && { dial: button.context.dial })
...(button.context.dial && { dial: button.context.dial }),
...(button.sling_chat_id && { sling_chat_id: button.sling_chat_id }),
...(button.sling_chat_message && { sling_chat_message: button.sling_chat_message })
};
}
});
});
console.log('Generated contexts:', contexts);
//console.log('Generated contexts:', contexts);
function trigCall(pageType, phone) {
// If contexts[pageType] does not exist, return an error
if (!contexts[pageType]) {
throw new Error(`Invalid page type: ${pageType}`);
}
const { context, timeout, cid, dial } = contexts[pageType];
const { context, timeout, cid, dial, sling_chat_id, sling_chat_message } = contexts[pageType];
const targetNumber = dial || phone;
if (!targetNumber) {
throw new Error(`Phone number is required for page type: ${pageType}`);
}
// Slink chat notification
if (sling_chat_id && sling_chat_message) {
fetch(`https://api.getsling.com/v1/conversations/${sling_chat_id}/messages`, {
method: 'POST',
headers: {
'Authorization': `${slingToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
'content': sling_chat_message
})
}).then(res => res.json()).then(data => {
if (data && data.success) {
console.log('Sling chat message sent successfully.');
} else {
console.error('Error sending Sling chat message:', data);
}
});
}
originateCall(targetNumber, context, 0, timeout, cid).then((output) => {
console.log(`Call originated: ${output}`);
}).catch((error) => {
@ -68,6 +100,42 @@ function originateCall(number, context, delay, timeout, cid, variables = {}) {
}
// Sling chat stuff; Check current token with GET https://api.getsling.com/v1/account/session, refresh with POST https://api.getsling.com/v1/account/session (GET NEW TOKEN FROM RETURN AUTHORIZATION HEADER)
async function slingAuthLoop() {
console.log("Start slingAuthLoop")
if (!slingToken) {
console.warn('No Sling token provided in environment variables.');
return;
}
setTimeout(slingAuthLoop, 15 * 60 * 1000); // Refresh every 15 minutes
const sessionCheck = await fetch('https://api.getsling.com/v1/account/session', {
method: 'GET',
headers: {
'Authorization': `${slingToken}`
}
});
console.log(sessionCheck)
if (sessionCheck && sessionCheck.ok) {
console.log('Sling session is valid. Refreshing token...');
const sessionRefresh = await fetch('https://api.getsling.com/v1/account/session', {
method: 'POST',
headers: {
'Authorization': `${slingToken}`
}
});
const newToken = sessionRefresh.headers.get('Authorization');
if (newToken) {
slingToken = newToken;
fs.writeFileSync(path.join(__dirname, 'slingtoken.txt'), newToken, 'utf8');
console.log('Sling token refreshed.');
}
} else {
console.error('Sling session is invalid. Please get a new token manually!');
}
}
slingAuthLoop();
const app = express();
const HOST = process.env.HOST || 'localhost';
const PORT = process.env.PORT || 3000;