import axios, { AxiosResponse, AxiosError } from 'axios'; import dotenv from 'dotenv'; import express, { NextFunction, Request, Response } from 'express'; import firebaseAdmin from 'firebase-admin'; import fsp from 'fs/promises'; import path from 'path'; dotenv.config(); const STATIC_WEB_DIR = 'public'; (async () => { try { const gcmSettings = JSON.parse( await fsp.readFile(process.env.GOOGLE_GLOUD_MESSAGING_CREDENTIALS ?? 'google-cloud/gcm-api.json', { encoding: 'utf-8' }) ); const server = express(); const firebase = firebaseAdmin.initializeApp(); server.get('/topics/:regToken', async (req, res, next) => { try { const regToken = req.params.regToken; const { apiToken } = gcmSettings; const response = await axios.get>(`https://iid.googleapis.com/iid/info/${regToken}?details=true`, { headers: { Authorization: `key=${apiToken}` } }); res.send(response.data); } catch (err) { next(err); } }); server.put('/topics/:topic/:regToken', async (req, res, next) => { try { const topic = req.params.topic; const regToken = req.params.regToken; const response = await firebase.messaging().subscribeToTopic(regToken, topic); if (!response.failureCount) return res.send({ ok: true }); throw response.errors; } catch (err) { next(err); } }); server.delete('/topics/:topic/:regToken', async (req, res, next) => { try { const topic = req.params.topic; const regToken = req.params.regToken; const response = await firebase.messaging().unsubscribeFromTopic(regToken, topic); if (!response.failureCount) return res.send({ ok: true }); throw response.errors; } catch (err) { next(err); } }); server.get('/logo.png', async (req, res, next) => { try { const files = await fsp.readdir(STATIC_WEB_DIR, { encoding: 'utf-8' }); const logo = files.find(file => file.includes('logo') && file.endsWith('.png')); if (!logo) { throw { type: 'http', message: 'File not found', status: 404 }; } res.sendFile(path.resolve(STATIC_WEB_DIR, logo)); } catch (err) { next(err); } }); server.use('/', express.static(STATIC_WEB_DIR)); server.use('**', express.static(path.join(STATIC_WEB_DIR, 'index.html'))); server.use((err: any, req: Request, res: Response, next: NextFunction) => { let log = false; if (err instanceof AxiosError) { log = true; res.status(err.status ?? err.response?.status ?? 500).send(err.message); } else { const keys = Object.keys(err); if (keys.includes('type') && err.type === 'http') { res.status(err.status).send(err.message); } else { log = true; res.status(500).send(JSON.stringify(err)); } } if (log) console.error('[ERROR] Webservice ErrorHandler caught:', err); }); const port = Number(process.env.WEB_PORT ?? '80'); server.listen(port, () => console.log('[FCM BACKEND] Webserver running at', `http://localhost:${port}`)); } catch (err) { console.error(err); process.exit(1); } })();