-
Notifications
You must be signed in to change notification settings - Fork 950
/
server.ts
129 lines (111 loc) · 3.63 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
119
120
121
122
123
124
125
126
127
128
129
import { Server as HttpServer } from "http";
import express, { Application, Router } from "express";
import { join } from "path";
import { Logger } from "pino";
import { createNodeMiddleware as createWebhooksMiddleware } from "@octokit/webhooks";
import { getLog } from "../helpers/get-log";
import { getLoggingMiddleware } from "./logging-middleware";
import { createWebhookProxy } from "../helpers/webhook-proxy";
import { VERSION } from "../version";
import { ApplicationFunction, ServerOptions } from "../types";
import { Probot } from "../";
import { engine } from "express-handlebars";
type State = {
httpServer?: HttpServer;
port?: number;
host?: string;
webhookPath: string;
webhookProxy?: string;
eventSource?: EventSource;
};
export class Server {
static version = VERSION;
public expressApp: Application;
public log: Logger;
public version = VERSION;
public probotApp: Probot;
private state: State;
constructor(options: ServerOptions = {} as ServerOptions) {
this.expressApp = express();
this.log = options.log || getLog().child({ name: "server" });
this.probotApp = new options.Probot();
this.state = {
port: options.port,
host: options.host,
webhookPath: options.webhookPath || "/",
webhookProxy: options.webhookProxy,
};
this.expressApp.use(getLoggingMiddleware(this.log));
this.expressApp.use(
"/probot/static/",
express.static(join(__dirname, "..", "..", "static"))
);
this.expressApp.use(
this.state.webhookPath,
createWebhooksMiddleware(this.probotApp.webhooks, {
path: "/",
})
);
this.expressApp.engine(
"handlebars",
engine({
defaultLayout: false,
})
);
this.expressApp.set("view engine", "handlebars");
this.expressApp.set("views", join(__dirname, "..", "..", "views"));
this.expressApp.get("/ping", (req, res) => res.end("PONG"));
}
public async load(appFn: ApplicationFunction) {
await appFn(this.probotApp, {
getRouter: (path) => this.router(path),
});
}
public async start() {
this.log.info(
`Running Probot v${this.version} (Node.js: ${process.version})`
);
const port = this.state.port || 3000;
const { host, webhookPath, webhookProxy } = this.state;
const printableHost = host ?? "localhost";
this.state.httpServer = (await new Promise((resolve, reject) => {
const server = this.expressApp.listen(
port,
...((host ? [host] : []) as any),
() => {
if (webhookProxy) {
this.state.eventSource = createWebhookProxy({
logger: this.log,
path: webhookPath,
port: port,
url: webhookProxy,
}) as EventSource;
}
this.log.info(`Listening on http://${printableHost}:${port}`);
resolve(server);
}
);
server.on("error", (error: NodeJS.ErrnoException) => {
if (error.code === "EADDRINUSE") {
error = Object.assign(error, {
message: `Port ${port} is already in use. You can define the PORT environment variable to use a different port.`,
});
}
this.log.error(error);
reject(error);
});
})) as HttpServer;
return this.state.httpServer;
}
public async stop() {
if (this.state.eventSource) this.state.eventSource.close();
if (!this.state.httpServer) return;
const server = this.state.httpServer;
return new Promise((resolve) => server.close(resolve));
}
public router(path: string = "/") {
const newRouter = Router();
this.expressApp.use(path, newRouter);
return newRouter;
}
}