-
Notifications
You must be signed in to change notification settings - Fork 2
/
app.ts
141 lines (121 loc) · 4.55 KB
/
app.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* eslint-disable @typescript-eslint/no-var-requires*/
/* eslint-disable @typescript-eslint/no-unused-vars*/
/* eslint-disable unused-imports/no-unused-vars*/
import express from 'express';
import cors from 'cors';
import cookieParser from 'cookie-parser';
import fs from 'fs';
import { createServer as createHttpsServer } from 'https';
import { createServer as createHttpServer } from 'http';
import { Server } from 'colyseus';
import { monitor } from '@colyseus/monitor';
import { GameRoom } from './GameRoom';
import { ErrorHandler } from './src/helpers/ErrorHandler';
import betterLogging from 'better-logging';
import { Connection, createConnection } from 'typeorm';
import globalRouter from './src/router/global.router';
import Environment from './src/module/environment';
import { WebSocketTransport } from '@colyseus/ws-transport';
import dotenv_expand from 'dotenv-expand';
dotenv_expand(require('dotenv').config());
/**
* Establishes the database connection using TypeORM and runs actions to prepare the database for later use.
* @Note: Since TypeORM seems to incorrectly handle promise exceptions, handling them is omitted.
* This is done explicitly to receive some kind of stack trace via the 'UnhandledPromiseRejectionWarning'
* in case an error occurs.
*/
async function connectToDataBase(): Promise<Connection> {
const con: Connection = await createConnection();
console.log('Running open migrations (if present)');
await con.runMigrations();
if (Environment.NODE_ENV === 'development') {
console.info('[DEV] Synchronizing database model to Entities');
await con.synchronize();
}
return;
}
/** Builds an http server that hosts the actual application depending on the current environment */
function buildHTTPServer(expressApp): { server; protocol } {
if (Environment.NODE_ENV === 'production') {
const s = createHttpsServer(
{
key: fs.readFileSync(Environment.TLS_KEY),
cert: fs.readFileSync(Environment.TLS_CRT),
},
expressApp
);
return { server: s, protocol: 'https' };
} else if (Environment.NODE_ENV === 'development') {
return { server: createHttpServer(expressApp), protocol: 'http' };
}
}
/** Main entrypoint for the server startup */
async function run(): Promise<void> {
if (!Environment.isLoaded) {
console.error('Environment was not loaded. Aborting server startup.');
return;
}
betterLogging(console, {
saveToFile: `${Environment.LOGGING_PATH}/${new Date().toISOString().split('T')[0]
}.log`,
});
const requestHandler: express.Application = express();
/** Configure express */
requestHandler.use(express.json());
requestHandler.use(cookieParser());
requestHandler.use(express.urlencoded({ extended: true }));
requestHandler.use(cors());
requestHandler.use('/api', globalRouter);
requestHandler.use('/colyseus', monitor());
requestHandler.use('/', (req, res, next) => {
res.sendFile(__dirname + '/index.html');
});
/** Configure error handling for express*/
requestHandler.use(ErrorHandler.logErrors);
requestHandler.use(ErrorHandler.handleKnownError);
requestHandler.use(ErrorHandler.handleUnexpectedError);
console.info(`Connecting to DB at ${Environment.DB_HOST}:${Environment.DB_PORT}`);
await connectToDataBase();
console.log('Building HTTP server.');
const { server, protocol } = buildHTTPServer(requestHandler);
console.info(`Instantiating Colyseus Server.`);
const colyseus = new Server({
transport: new WebSocketTransport({
pingInterval: 10000,
pingMaxRetries: 3,
}),
});
colyseus.define('game', GameRoom);
colyseus.onShutdown(function () {
console.info(`Game server is going down.`);
});
server.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
console.error(
`Failed to start the internal server. PORT: ${Environment.SERVER_PORT} is already in use.`
);
console.error(
'Please ensure the specified port is not used by a different service or a second instance of the Brettspiel_Backend.'
);
console.error('Original issue:', { err });
} else {
console.error(
'The HTTP server encountered an unspecified error',
{ err },
err.code
);
}
server.close();
});
server.once('listening', () => {
colyseus.attach({ server: server });
console.info(
`Listening for [${protocol}] on port: [${Environment.SERVER_PORT}]`
);
});
server.listen(Environment.SERVER_PORT);
}
if (require.main === module) {
Environment.loadEnv();
run().then((r) => console.info('Setup Completed.'));
}