-
Notifications
You must be signed in to change notification settings - Fork 178
/
Copy pathServer.ts
118 lines (106 loc) · 3.76 KB
/
Server.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
import express, { NextFunction, Request, Response } from 'express';
import morgan from 'morgan';
import bodyParser from 'body-parser';
import * as Controllers from 'controllers';
import { NotFound } from 'ts-httpexceptions';
import compression from 'compression';
import { __PROD__, credentials, httpPort, httpsPort, webhookOptions } from 'config/environments';
import http from 'http';
import https from 'https';
import cron from 'node-cron';
import { Hierarchy } from 'models';
import * as Tracers from 'tracers';
import { errorHandlerMiddleware, frontendMiddleware, redirectMiddleware } from 'middlewares';
import { execute, issueHttpsCertificate, pull } from 'utils/misc';
import { frontendBuildDir, frontendBuiltDir, frontendDir, rootDir } from 'config/paths';
const Webhook = require('express-github-webhook');
export default class Server {
readonly hierarchy = new Hierarchy();
readonly tracers = Object.values(Tracers).map(Tracer => new Tracer());
private readonly app = express();
private readonly webhook = webhookOptions && Webhook(webhookOptions);
constructor() {
this.app
.use(compression())
.use(morgan(__PROD__ ? 'tiny' : 'dev'))
.use(redirectMiddleware())
.use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: true }))
.use('/api', this.getApiRouter())
.use(frontendMiddleware(this));
if (this.webhook) {
this.app.use(this.webhook);
}
this.app.use(errorHandlerMiddleware());
if (this.webhook) {
this.webhook.on('push', async (repo: string, data: any) => {
const { ref, head_commit } = data;
if (ref !== 'refs/heads/master') return;
if (!head_commit) throw new Error('The `head_commit` is empty.');
switch (repo) {
case 'server':
await this.update(head_commit.id);
break;
case 'algorithm-visualizer':
await this.updateFrontend(head_commit.id);
break;
case 'algorithms':
await this.hierarchy.update(head_commit.id);
break;
default:
throw new Error(`Webhook from unknown repository '${repo}'.`);
}
});
this.webhook.on('release', async (repo: string, data: any) => {
const tracer = this.tracers.find(tracer => repo === `tracers.${tracer.lang}`);
if (!tracer) throw new Error(`Tracer not found for repository '${repo}'.`);
await tracer.update(data.release);
});
}
if (credentials) {
cron.schedule('0 0 1 * *', () => {
issueHttpsCertificate();
});
}
}
getApiRouter() {
const router = express.Router();
Object.values(Controllers).forEach(Controller => new Controller(this).route(router));
router.use((req: Request, res: Response, next: NextFunction) => {
next(new NotFound('API not found.'));
});
return router;
};
async update(commit?: string) {
await pull(rootDir, 'server', commit);
await execute('npm install', {
cwd: rootDir,
stdout: process.stdout,
stderr: process.stderr,
});
process.exit(0);
};
async updateFrontend(commit?: string) {
await pull(frontendDir, 'algorithm-visualizer', commit);
await execute([
'npm install',
'npm run build',
`rm -rf ${frontendBuiltDir}`,
`mv ${frontendBuildDir} ${frontendBuiltDir}`,
].join(' && '), {
cwd: frontendDir,
stdout: process.stdout,
stderr: process.stderr,
});
}
start() {
const httpServer = http.createServer(this.app);
httpServer.listen(httpPort);
console.info(`http: listening on port ${httpPort}`);
if (credentials) {
const httpsServer = https.createServer(credentials, this.app);
httpsServer.listen(httpsPort);
console.info(`https: listening on port ${httpsPort}`);
}
}
}