diff --git a/LambdaEntry.js b/LambdaEntry.js index 4fe57b4..730b730 100644 --- a/LambdaEntry.js +++ b/LambdaEntry.js @@ -1,45 +1,47 @@ const { createServer, proxy } = require('aws-serverless-express'); const { init } = require('./dist/App'); +const { Environment } = require('./dist/helpers/Environment'); const { Pool } = require('./dist/apiBase/pool'); const AWS = require('aws-sdk'); const { Logger } = require('./dist/helpers/Logger'); -const { Repositories } = require('./dist/repositories/Repositories'); const { SocketHelper } = require('./dist/helpers/SocketHelper'); const { ApiGatewayManagementApi } = require('aws-sdk'); -const gwManagement = new ApiGatewayManagementApi({ apiVersion: '2020-04-16', endpoint: process.env.SOCKET_URL }); + +Environment.init(process.env.APP_ENV); Pool.initPool(); +const gwManagement = new ApiGatewayManagementApi({ apiVersion: '2020-04-16', endpoint: Environment.socketUrl }); async function logMessage(message) { - const wl = new Logger(); - wl.error(message); - await wl.flush(); + const wl = new Logger(); + wl.error(message); + await wl.flush(); } module.exports.handleWeb = function handleWeb(event, context) { - AWS.config.update({ region: 'us-east-2' }); - init().then(app => { - const server = createServer(app); - return proxy(server, event, context); - }); + AWS.config.update({ region: 'us-east-2' }); + init().then(app => { + const server = createServer(app); + return proxy(server, event, context); + }); } module.exports.handleSocket = async function handleSocket(event) { - const rc = event.requestContext; - const eventType = rc.eventType; - const connectionId = rc.connectionId; - //console.log(eventType); - if (eventType == "DISCONNECT") await SocketHelper.handleDisconnect(connectionId) //; Repositories.getCurrent().connection.deleteForSocket(connectionId); - else if (eventType == "MESSAGE") { - const payload = { churchId: "", conversationId: "", action: "socketId", data: rc.connectionId } - //try { - await gwManagement.postToConnection({ ConnectionId: rc.connectionId, Data: JSON.stringify(payload) }).promise(); - //} catch (e) { logMessage(e.toString()); } - - - } - return { statusCode: 200, body: 'success' } + const rc = event.requestContext; + const eventType = rc.eventType; + const connectionId = rc.connectionId; + //console.log(eventType); + if (eventType == "DISCONNECT") await SocketHelper.handleDisconnect(connectionId) //; Repositories.getCurrent().connection.deleteForSocket(connectionId); + else if (eventType == "MESSAGE") { + const payload = { churchId: "", conversationId: "", action: "socketId", data: rc.connectionId } + //try { + await gwManagement.postToConnection({ ConnectionId: rc.connectionId, Data: JSON.stringify(payload) }).promise(); + //} catch (e) { logMessage(e.toString()); } + + + } + return { statusCode: 200, body: 'success' } } \ No newline at end of file diff --git a/config/dev.json b/config/dev.json new file mode 100644 index 0000000..5c54d72 --- /dev/null +++ b/config/dev.json @@ -0,0 +1,11 @@ +{ + "appEnv": "dev", + "appName": "MessagingApi", + "contentRoot": "http://localhost:3402", + "fileStore": "disk", + "mailSystem": "SMTP", + "s3Bucket": "", + "deliveryProvider": "local", + "socketPort": 8087, + "socketUrl": "" +} \ No newline at end of file diff --git a/config/prod.json b/config/prod.json new file mode 100644 index 0000000..782b7cb --- /dev/null +++ b/config/prod.json @@ -0,0 +1,11 @@ +{ + "appEnv": "prod", + "appName": "MessagingApi", + "contentRoot": "https://content.churchapps.org", + "fileStore": "S3", + "mailSystem": "SES", + "s3Bucket": "churchapps-content", + "deliveryProvider": "aws", + "socketPort": 0, + "socketUrl": "wss://socket.churchapps.org/" +} \ No newline at end of file diff --git a/config/staging.json b/config/staging.json new file mode 100644 index 0000000..383d9cb --- /dev/null +++ b/config/staging.json @@ -0,0 +1,11 @@ +{ + "appEnv": "staging", + "appName": "MessagingApi", + "contentRoot": "https://content.staging.churchapps.org", + "fileStore": "S3", + "mailSystem": "SES", + "s3Bucket": "staging-churchapps-content", + "deliveryProvider": "aws", + "socketPort": 0, + "socketUrl": "wss://socket.staging.churchapps.org/" +} \ No newline at end of file diff --git a/src/App.ts b/src/App.ts index adac0bb..7cd6a08 100644 --- a/src/App.ts +++ b/src/App.ts @@ -8,23 +8,24 @@ import express from "express"; import { CustomAuthProvider } from "./apiBase/auth"; import cors from "cors" import { SocketHelper } from "./helpers/SocketHelper"; +import { Environment } from "./helpers"; export const init = async () => { - dotenv.config(); - const container = new Container(); - await container.loadAsync(bindings); - const app = new InversifyExpressServer(container, null, null, null, CustomAuthProvider); + dotenv.config(); + const container = new Container(); + await container.loadAsync(bindings); + const app = new InversifyExpressServer(container, null, null, null, CustomAuthProvider); - const configFunction = (expApp: express.Application) => { - expApp.use(bodyParser.urlencoded({ extended: true })); - expApp.use(bodyParser.json()); - expApp.use(cors()) - }; + const configFunction = (expApp: express.Application) => { + expApp.use(bodyParser.urlencoded({ extended: true })); + expApp.use(bodyParser.json()); + expApp.use(cors()) + }; - const server = app.setConfig(configFunction).build(); + const server = app.setConfig(configFunction).build(); - if (process.env.DELIVERY_PROVIDER === "local") SocketHelper.init(); + if (Environment.deliveryProvider === "local") SocketHelper.init(); - return server; + return server; } diff --git a/src/apiBase b/src/apiBase index 05af8cd..7a7316b 160000 --- a/src/apiBase +++ b/src/apiBase @@ -1 +1 @@ -Subproject commit 05af8cd91adeb2fac2168a20cf29b379305b9f97 +Subproject commit 7a7316bbefa1d0c70894813e14728e8f0b80a17b diff --git a/src/helpers/Environment.ts b/src/helpers/Environment.ts new file mode 100644 index 0000000..0c19775 --- /dev/null +++ b/src/helpers/Environment.ts @@ -0,0 +1,31 @@ +import fs from "fs"; +import path from "path"; + +import { EnvironmentBase } from "../apiBase"; + +export class Environment extends EnvironmentBase { + + static deliveryProvider: string; + static socketPort: number; + static socketUrl: string; + + static init(environment: string) { + let file = "dev.json"; + if (environment === "staging") file = "staging.json"; + if (environment === "prod") file = "prod.json"; + + + const relativePath = "../../config/" + file; + const physicalPath = path.resolve(__dirname, relativePath); + + const json = fs.readFileSync(physicalPath, "utf8"); + const data = JSON.parse(json); + this.populateBase(data); + + this.deliveryProvider = data.deliveryProvider; + this.socketPort = data.socketPort; + this.socketUrl = data.socketUrl; + + } + +} \ No newline at end of file diff --git a/src/helpers/Logger.ts b/src/helpers/Logger.ts index 1afee58..a3827f8 100644 --- a/src/helpers/Logger.ts +++ b/src/helpers/Logger.ts @@ -2,56 +2,56 @@ import "reflect-metadata"; import winston from "winston"; import WinstonCloudWatch from "winston-cloudwatch"; import AWS from 'aws-sdk'; - +import { Environment } from "./Environment"; export class Logger { - private _logger: winston.Logger = null; - private wc: WinstonCloudWatch; - private pendingMessages = false; - - public error(msg: string | object) { - if (this._logger === null) this.init(); - this.pendingMessages = true; - this._logger.error(msg); + private _logger: winston.Logger = null; + private wc: WinstonCloudWatch; + private pendingMessages = false; + + public error(msg: string | object) { + if (this._logger === null) this.init(); + this.pendingMessages = true; + this._logger.error(msg); + } + + public info(msg: string | object) { + if (this._logger === null) this.init(); + this.pendingMessages = true; + this._logger.info(msg); + } + + + private init() { + this.pendingMessages = false; + AWS.config.update({ region: 'us-east-2' }); + if (Environment.appEnv === "dev") { + this._logger = winston.createLogger({ transports: [new winston.transports.Console()], format: winston.format.json() }); + // this.wc = new WinstonCloudWatch({ logGroupName: 'StreamingLiveDev', logStreamName: 'ChatApi' }); + // this._logger = winston.createLogger({ transports: [this.wc], format: winston.format.json() }); } - - public info(msg: string | object) { - if (this._logger === null) this.init(); - this.pendingMessages = true; - this._logger.info(msg); + else if (Environment.appEnv === "staging") { + this.wc = new WinstonCloudWatch({ logGroupName: 'CoreApis', logStreamName: 'MessagingApi' }); + this._logger = winston.createLogger({ transports: [this.wc], format: winston.format.json() }); } - - - private init() { - this.pendingMessages = false; - AWS.config.update({ region: 'us-east-2' }); - if (process.env.API_ENV === "dev") { - this._logger = winston.createLogger({ transports: [new winston.transports.Console()], format: winston.format.json() }); - // this.wc = new WinstonCloudWatch({ logGroupName: 'StreamingLiveDev', logStreamName: 'ChatApi' }); - // this._logger = winston.createLogger({ transports: [this.wc], format: winston.format.json() }); - } - else if (process.env.API_ENV === "staging") { - this.wc = new WinstonCloudWatch({ logGroupName: 'CoreApis', logStreamName: 'MessagingApi' }); - this._logger = winston.createLogger({ transports: [this.wc], format: winston.format.json() }); - } - else if (process.env.API_ENV === "prod") { - this.wc = new WinstonCloudWatch({ logGroupName: 'CoreApis', logStreamName: 'MessagingApi' }); - this._logger = winston.createLogger({ transports: [this.wc], format: winston.format.json() }); - } - this._logger.info("Logger initialized"); + else if (Environment.appEnv === "prod") { + this.wc = new WinstonCloudWatch({ logGroupName: 'CoreApis', logStreamName: 'MessagingApi' }); + this._logger = winston.createLogger({ transports: [this.wc], format: winston.format.json() }); } - - public flush() { - const promise = new Promise((resolve) => { - if (this.pendingMessages) { - this.wc.kthxbye(() => { - this._logger = null; - resolve(); - }); - } else resolve(); + this._logger.info("Logger initialized"); + } + + public flush() { + const promise = new Promise((resolve) => { + if (this.pendingMessages) { + this.wc.kthxbye(() => { + this._logger = null; + resolve(); }); - return promise; - } + } else resolve(); + }); + return promise; + } } diff --git a/src/helpers/SocketHelper.ts b/src/helpers/SocketHelper.ts index 62a119a..202f737 100644 --- a/src/helpers/SocketHelper.ts +++ b/src/helpers/SocketHelper.ts @@ -4,53 +4,54 @@ import { PayloadInterface, SocketConnectionInterface } from "./Interfaces"; import { Repositories } from "../repositories" import { Connection } from "../models" import { DeliveryHelper } from "./DeliveryHelper"; +import { Environment } from "."; export class SocketHelper { - private static wss: WebSocket.Server = null; - private static connections: SocketConnectionInterface[] = []; - - static init = () => { - const port = parseInt(process.env.SOCKET_PORT, 0); - if (port > 0) { - SocketHelper.wss = new WebSocket.Server({ port }); - console.log("Listening on websocket port " + port); - - SocketHelper.wss.on('connection', (socket) => { - const sc: SocketConnectionInterface = { id: UniqueIdHelper.shortId(), socket } - SocketHelper.connections.push(sc); - const payload: PayloadInterface = { churchId: "", conversationId: "", action: "socketId", data: sc.id } - sc.socket.send(JSON.stringify(payload)); - sc.socket.on('close', async () => { - // console.log("DELETING " + sc.id); - await SocketHelper.handleDisconnect(sc.id); - }); - }); - } - } - - static handleDisconnect = async (socketId: string) => { - // console.log("handleDisconnect"); - // console.log(socketId); - const connections = await Repositories.getCurrent().connection.loadBySocketId(socketId); - await Repositories.getCurrent().connection.deleteForSocket(socketId); - connections.forEach((c: Connection) => { - DeliveryHelper.sendAttendance(c.churchId, c.conversationId); + private static wss: WebSocket.Server = null; + private static connections: SocketConnectionInterface[] = []; + + static init = () => { + const port = Environment.socketPort; + if (port > 0) { + SocketHelper.wss = new WebSocket.Server({ port }); + console.log("Listening on websocket port " + port); + + SocketHelper.wss.on('connection', (socket) => { + const sc: SocketConnectionInterface = { id: UniqueIdHelper.shortId(), socket } + SocketHelper.connections.push(sc); + const payload: PayloadInterface = { churchId: "", conversationId: "", action: "socketId", data: sc.id } + sc.socket.send(JSON.stringify(payload)); + sc.socket.on('close', async () => { + // console.log("DELETING " + sc.id); + await SocketHelper.handleDisconnect(sc.id); }); - + }); } - - static getConnection = (id: string) => { - let result: SocketConnectionInterface = null; - SocketHelper.connections.forEach(sc => { if (sc.id === id) result = sc; }); - return result; - } - - static deleteConnection = (id: string) => { - for (let i = SocketHelper.connections.length - 1; i >= 0; i--) { - const sc = SocketHelper.connections[i]; - if (sc.id === id) SocketHelper.connections.splice(i, 1); - } + } + + static handleDisconnect = async (socketId: string) => { + // console.log("handleDisconnect"); + // console.log(socketId); + const connections = await Repositories.getCurrent().connection.loadBySocketId(socketId); + await Repositories.getCurrent().connection.deleteForSocket(socketId); + connections.forEach((c: Connection) => { + DeliveryHelper.sendAttendance(c.churchId, c.conversationId); + }); + + } + + static getConnection = (id: string) => { + let result: SocketConnectionInterface = null; + SocketHelper.connections.forEach(sc => { if (sc.id === id) result = sc; }); + return result; + } + + static deleteConnection = (id: string) => { + for (let i = SocketHelper.connections.length - 1; i >= 0; i--) { + const sc = SocketHelper.connections[i]; + if (sc.id === id) SocketHelper.connections.splice(i, 1); } + } } \ No newline at end of file diff --git a/src/helpers/index.ts b/src/helpers/index.ts index 5d59832..484d8ef 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -1,4 +1,5 @@ export * from './Permissions' export * from '../apiBase/helpers/Interfaces' -export { UniqueIdHelper } from "../apiBase/helpers"; \ No newline at end of file +export { UniqueIdHelper } from "../apiBase/helpers"; +export { Environment } from "./Environment"; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index e12ad39..e944e5a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,9 @@ import { init } from './App'; import { Pool } from './apiBase/pool'; -const port = process.env.SERVER_PORT; +import { Environment } from './helpers/Environment'; +const port = process.env.SERVER_PORT; +Environment.init(process.env.APP_ENV); Pool.initPool(); diff --git a/tools/initdb.ts b/tools/initdb.ts index e7a193e..f5cf045 100644 --- a/tools/initdb.ts +++ b/tools/initdb.ts @@ -1,9 +1,11 @@ import dotenv from "dotenv"; +import { Environment } from "../src/helpers/Environment"; import { Pool } from "../src/apiBase/pool"; import { DBCreator } from "../src/apiBase/tools/DBCreator" const init = async () => { dotenv.config(); + Environment.init(process.env.APP_ENV); console.log("Connecting"); Pool.initPool();