This repository has been archived by the owner on Nov 2, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
http-server.ts
180 lines (153 loc) · 4.26 KB
/
http-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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import * as http from 'http';
/**
* Defines how an HttpServer may be configured.
*/
export type HttpServerConfig = {
host?: string,
port?: number
};
/**
* Defines the common interface and shared functionality that all Servers should have.
*/
export class HttpServer {
/**
* Internal Node.js http server.
*/
private httpServer: http.Server = null;
/**
* List of ServerManagers in charge of the server.
*/
protected serverManagers: {[key: string]: ServerManager} = {};
/**
* Where the HttpServer configurations are stored.
*/
protected config: HttpServerConfig = {
host: 'localhost',
port: 3000
};
/**
* Constructs and configures a new HttpServer.
*/
constructor(options?: HttpServerConfig) {
this.configure(options);
}
/**
* Attaches a ServerManager(s) to this server.
*/
public attach(name: string, manager: ServerManager): this;
public attach(managers: {[key: string]: ServerManager}): this;
public attach(p1: string | {[key: string]: ServerManager}, p2?: ServerManager): this {
// Force the overloads into a single case
let managers;
if (typeof p1 === 'string') {
managers = {};
managers[p1] = p2;
} else {
managers = p1;
}
// Add the managers and assign their internal `peers` property
for (let key in managers) {
let manager = managers[key];
manager.peers = this.serverManagers;
this.serverManagers[key] = manager;
}
return this;
}
/**
* Alias for attach(...)
*/
public with(name: string, manager: ServerManager): this;
public with(managers: {[key: string]: ServerManager}): this;
public with(p1: string | {[key: string]: ServerManager}, p2?: ServerManager): this {
// @ts-ignore: since `with` is an alias, this is fine
return this.attach(p1, p2);
}
/**
* Returns the ServerManager with the given name.
*/
public getManager(key: string): ServerManager {
return this.serverManagers[key];
}
/**
* Returns whether or not the server is running.
*/
public isRunning(): boolean {
return this.httpServer !== null && this.httpServer.address() !== null;
}
/**
* Applies configurations to the HttpServer.
*/
public configure(options: HttpServerConfig): this {
if (this.isRunning()) throw new Error('Cannot make configuration changes while the server is running!');
Object.assign(this.config, options);
return this;
}
/**
* Starts the HttpServer and returns a Promise for when it's ready.
*/
public start(): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
this.httpServer = http.createServer();
for (let name in this.serverManagers)
this.serverManagers[name].setup(this.httpServer);
this.httpServer.listen(this.config.port, () => {
resolve(true);
});
});
}
/**
* Stops the HttpServer and returns a Promise for when it's done.
*/
public stop(): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
this.httpServer.close(() => {
this.httpServer = null;
for (let name in this.serverManagers)
this.serverManagers[name].takedown();
resolve(true);
});
});
}
}
/**
* A special class that can be attached to HttpServers to manage them; the "management" part must be implemented.
*/
export abstract class ServerManager {
/**
* Contains a reference to the other ServerManagers on the HttpServer that this manager is attached to. (only
* available after it has been attached)
*/
private peers: {[key: string]: ServerManager};
/**
* Where configs specific to the ServerManager are stored.
*/
protected config = {};
/**
* Constructs a new ServerManager and applies any additional configurations.
*/
constructor(options?: unknown) {
this.configure(options);
}
/**
* Modifies the internal config object.
*/
public configure(options): this {
Object.assign(this.config, options);
return this;
}
/**
* Since there can be multiple managers on an HttpServer, one manager may wish to communicate with another. This
* function will return one of the other managers by name.
*/
public getPeer(name: string): ServerManager {
return this.peers[name];
}
/**
* Configures the Node http server instance upon starting.
*/
public abstract setup(httpServer: http.Server);
/**
* Performs any necessary cleanup after the HttpServer stops listening.
*/
public abstract takedown();
}