index.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import axios, { AxiosResponse, AxiosError } from 'axios';
  2. import dotenv from 'dotenv';
  3. import express, { NextFunction, Request, Response } from 'express';
  4. import firebaseAdmin from 'firebase-admin';
  5. import fsp from 'fs/promises';
  6. import path from 'path';
  7. dotenv.config();
  8. const STATIC_WEB_DIR = 'public';
  9. (async () => {
  10. try {
  11. const gcmSettings = JSON.parse(
  12. await fsp.readFile(process.env.GOOGLE_GLOUD_MESSAGING_CREDENTIALS ?? 'google-cloud/gcm-api.json', { encoding: 'utf-8' })
  13. );
  14. const server = express();
  15. const firebase = firebaseAdmin.initializeApp();
  16. server.get('/topics/:regToken', async (req, res, next) => {
  17. try {
  18. const regToken = req.params.regToken;
  19. const { apiToken } = gcmSettings;
  20. const response = await axios.get<any, AxiosResponse<any>>(`https://iid.googleapis.com/iid/info/${regToken}?details=true`, {
  21. headers: {
  22. Authorization: `key=${apiToken}`
  23. }
  24. });
  25. res.send(response.data);
  26. } catch (err) {
  27. next(err);
  28. }
  29. });
  30. server.put('/topics/:topic/:regToken', async (req, res, next) => {
  31. try {
  32. const topic = req.params.topic;
  33. const regToken = req.params.regToken;
  34. const response = await firebase.messaging().subscribeToTopic(regToken, topic);
  35. if (!response.failureCount) return res.send({ ok: true });
  36. throw response.errors;
  37. } catch (err) {
  38. next(err);
  39. }
  40. });
  41. server.delete('/topics/:topic/:regToken', async (req, res, next) => {
  42. try {
  43. const topic = req.params.topic;
  44. const regToken = req.params.regToken;
  45. const response = await firebase.messaging().unsubscribeFromTopic(regToken, topic);
  46. if (!response.failureCount) return res.send({ ok: true });
  47. throw response.errors;
  48. } catch (err) {
  49. next(err);
  50. }
  51. });
  52. server.get('/logo.png', async (req, res, next) => {
  53. try {
  54. const files = await fsp.readdir(STATIC_WEB_DIR, { encoding: 'utf-8' });
  55. const logo = files.find(file => file.includes('logo') && file.endsWith('.png'));
  56. if (!logo) {
  57. throw { type: 'http', message: 'File not found', status: 404 };
  58. }
  59. res.sendFile(path.resolve(STATIC_WEB_DIR, logo));
  60. } catch (err) {
  61. next(err);
  62. }
  63. });
  64. server.use('/', express.static(STATIC_WEB_DIR));
  65. server.use('**', express.static(path.join(STATIC_WEB_DIR, 'index.html')));
  66. server.use((err: any, req: Request, res: Response, next: NextFunction) => {
  67. let log = false;
  68. if (err instanceof AxiosError) {
  69. log = true;
  70. res.status(err.status ?? err.response?.status ?? 500).send(err.message);
  71. } else {
  72. const keys = Object.keys(err);
  73. if (keys.includes('type') && err.type === 'http') {
  74. res.status(err.status).send(err.message);
  75. } else {
  76. log = true;
  77. res.status(500).send(JSON.stringify(err));
  78. }
  79. }
  80. if (log) console.error('[ERROR] Webservice ErrorHandler caught:', err);
  81. });
  82. const port = Number(process.env.WEB_PORT ?? '80');
  83. server.listen(port, () => console.log('[FCM BACKEND] Webserver running at', `http://localhost:${port}`));
  84. } catch (err) {
  85. console.error(err);
  86. process.exit(1);
  87. }
  88. })();