end-to-end CI to match containerization on rest of adipu_server
All checks were successful
Deploy to Server / deploy (push) Successful in 18s
All checks were successful
Deploy to Server / deploy (push) Successful in 18s
This commit is contained in:
67
index.js
67
index.js
@@ -1,4 +1,4 @@
|
||||
const admin = require('firebase-admin');
|
||||
const push = require('./push');
|
||||
const { verify, hash } = require('argon2');
|
||||
const express = require('express');
|
||||
const { json } = require('express');
|
||||
@@ -54,7 +54,8 @@ const wsMessageRateLimiter = new RateLimiterMemory({
|
||||
|
||||
const path = require('path');
|
||||
const app = express();
|
||||
const port = 3000;
|
||||
const port = parseInt(process.env.PORT || '3002', 10);
|
||||
app.set('trust proxy', true);
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
app.use(json());
|
||||
|
||||
@@ -79,9 +80,9 @@ const io = socketIo(server, {
|
||||
let agenda;
|
||||
|
||||
(async () => {
|
||||
// 1. Connect to MongoDB
|
||||
// 1. Connect to MongoDB (URI comes from env in containerized deploys)
|
||||
await connectDB();
|
||||
agenda = await initializeAgenda('mongodb://localhost:27017/myScheduledApp', pool, io);
|
||||
agenda = await initializeAgenda(process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/myScheduledApp', pool, io);
|
||||
})();
|
||||
|
||||
(async () => {
|
||||
@@ -96,25 +97,11 @@ let agenda;
|
||||
await pool.query("DELETE FROM user_pending_emails WHERE expires_at < NOW()");
|
||||
console.log("Cleared expired pending email changes");
|
||||
|
||||
// Add battery_soc column if this is the first deploy with battery support
|
||||
await pool.query("ALTER TABLE devices ADD COLUMN IF NOT EXISTS battery_soc SMALLINT");
|
||||
// Schema lives in db/schema.sql and is applied by db/migrate.js before this
|
||||
// process starts (compose CMD chains them).
|
||||
|
||||
// Add fcm_token column for push notification delivery
|
||||
await pool.query("ALTER TABLE users ADD COLUMN IF NOT EXISTS fcm_token TEXT");
|
||||
|
||||
// Add timezone support
|
||||
await pool.query("ALTER TABLE users ADD COLUMN IF NOT EXISTS timezone TEXT DEFAULT 'America/Chicago'");
|
||||
await pool.query("ALTER TABLE devices ADD COLUMN IF NOT EXISTS timezone TEXT");
|
||||
await pool.query("ALTER TABLE groups ADD COLUMN IF NOT EXISTS timezone TEXT");
|
||||
|
||||
// Initialise Firebase Admin SDK for push notifications
|
||||
if (process.env.FIREBASE_SERVICE_ACCOUNT_JSON) {
|
||||
admin.initializeApp({
|
||||
credential: admin.credential.cert(JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT_JSON)),
|
||||
});
|
||||
} else {
|
||||
console.warn("FIREBASE_SERVICE_ACCOUNT_JSON not set — push notifications disabled");
|
||||
}
|
||||
// Initialise APNs provider (lazy — push.js logs a warning if env is missing)
|
||||
push.init();
|
||||
})();
|
||||
const JWT_SECRET = process.env.JWT_SECRET;
|
||||
const TOKEN_EXPIRY = '5d';
|
||||
@@ -2014,8 +2001,9 @@ app.post('/update_schedule', authenticateToken, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(port, '127.0.0.1', () => {
|
||||
console.log(`Example app listening on 127.0.0.1:${port}`);
|
||||
const bindHost = process.env.BIND_HOST || '0.0.0.0';
|
||||
server.listen(port, bindHost, () => {
|
||||
console.log(`Example app listening on ${bindHost}:${port}`);
|
||||
});
|
||||
|
||||
app.post('/periph_schedule_list', authenticateToken, async (req, res) => {
|
||||
@@ -2430,12 +2418,12 @@ app.post('/update_group_schedule', authenticateToken, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Store/update the FCM token for the authenticated user
|
||||
app.post('/register_fcm_token', authenticateToken, async (req, res) => {
|
||||
// Store/update the APNs device token for the authenticated user
|
||||
app.post('/register_apns_token', authenticateToken, async (req, res) => {
|
||||
const { token } = req.body;
|
||||
if (!token || typeof token !== 'string') return res.sendStatus(400);
|
||||
try {
|
||||
await pool.query("UPDATE users SET fcm_token=$1 WHERE id=$2", [token, req.user]);
|
||||
await pool.query("UPDATE users SET apns_token=$1 WHERE id=$2", [token, req.user]);
|
||||
res.sendStatus(204);
|
||||
} catch {
|
||||
res.sendStatus(500);
|
||||
@@ -2477,26 +2465,27 @@ app.post('/battery_alert', authenticateToken, async (req, res) => {
|
||||
io.to(rows[0].socket).emit("battery_alert", { deviceId: req.peripheral, type, soc });
|
||||
}
|
||||
|
||||
// FCM — background push for persistent alerts (not transient voltage dips)
|
||||
const fcmPushTypes = ['overvoltage', 'critical_low', 'low_20', 'low_10'];
|
||||
if (fcmPushTypes.includes(type) && admin.apps.length > 0) {
|
||||
const { rows: fcmRows } = await pool.query(
|
||||
"SELECT u.fcm_token FROM users u JOIN devices d ON d.user_id=u.id WHERE d.id=$1 AND u.fcm_token IS NOT NULL",
|
||||
// APNs — background push for persistent alerts (not transient voltage dips)
|
||||
const pushTypes = ['overvoltage', 'critical_low', 'low_20', 'low_10'];
|
||||
if (pushTypes.includes(type)) {
|
||||
const { rows: tokenRows } = await pool.query(
|
||||
"SELECT u.apns_token FROM users u JOIN devices d ON d.user_id=u.id WHERE d.id=$1 AND u.apns_token IS NOT NULL",
|
||||
[req.peripheral]
|
||||
);
|
||||
if (fcmRows.length === 1) {
|
||||
const fcmContent = {
|
||||
if (tokenRows.length === 1) {
|
||||
const pushContent = {
|
||||
overvoltage: { title: 'Battery Fault', body: 'Overvoltage detected. Please check your charger.' },
|
||||
critical_low: { title: 'Battery Critical', body: `Battery at ${soc}% — device is shutting down.` },
|
||||
low_20: { title: 'Battery Low', body: `Battery at ${soc}%. Consider charging soon.` },
|
||||
low_10: { title: 'Battery Very Low', body: `Battery at ${soc}% — charge now.` },
|
||||
};
|
||||
const { title, body } = fcmContent[type];
|
||||
await admin.messaging().send({
|
||||
token: fcmRows[0].fcm_token,
|
||||
notification: { title, body },
|
||||
const { title, body } = pushContent[type];
|
||||
await push.sendNotification(tokenRows[0].apns_token, {
|
||||
title,
|
||||
body,
|
||||
data: { type, soc: String(soc), deviceId: String(req.peripheral) },
|
||||
}).catch(err => console.error('FCM send failed:', err.message));
|
||||
pool, // lets push.js scrub the token if APNs returns 410 Unregistered
|
||||
}).catch(err => console.error('APNs send failed:', err.message));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user