@@ -26,27 +26,29 @@ class Server extends EventEmitter<Server.Events> {
2626 */
2727 public readonly errors = new ServerErrorRegistry ( ) ;
2828 private readonly server : http . Server ;
29+ private readonly port ?: number ;
2930 private readonly copyOrigin : boolean ;
3031 private readonly handleConditionalRequests : boolean ;
3132
3233 /**
3334 * Create a new HTTP server.
3435 * @param options Server options.
3536 */
36- public constructor ( options : Server . Options ) {
37+ public constructor ( options ? : Server . Options ) {
3738 super ( ) ;
3839 this . server = http . createServer ( {
3940 joinDuplicateHeaders : true ,
4041 } , this . listener . bind ( this ) ) ;
4142
42- this . globalHeaders = new Headers ( options . globalHeaders ) ;
43+ this . globalHeaders = new Headers ( options ? .globalHeaders ) ;
4344 if ( ! this . globalHeaders . has ( "server" ) )
4445 this . globalHeaders . set ( "Server" , `cldn/${ packageJson . version } ` ) ;
4546
46- this . copyOrigin = options . copyOrigin ?? false ;
47- this . handleConditionalRequests = options . handleConditionalRequests ?? true ;
47+ this . port = options ?. port ;
48+ this . copyOrigin = options ?. copyOrigin ?? false ;
49+ this . handleConditionalRequests = options ?. handleConditionalRequests ?? true ;
4850
49- this . server . listen ( options . port , process . env . HOST , ( ) => this . emit ( "listening" ) ) ;
51+ if ( this . port !== undefined ) this . listen ( this . port ) . then ( ) ;
5052
5153 this . once ( "listening" , ( ) => {
5254 if ( this . listenerCount ( "error" ) === 0 )
@@ -59,20 +61,45 @@ class Server extends EventEmitter<Server.Events> {
5961 return this . server . keepAliveTimeout ;
6062 }
6163
62- public async close ( ) : Promise < void > {
64+ /**
65+ * Close the server. Will stop accepting new connections and wait for existing connections to close.
66+ * @param [timeout=5000] Maximum time to wait for existing connections to close before forcibly closing them.
67+ */
68+ public async close ( timeout = 5000 ) : Promise < void > {
69+ if ( ! this . server . listening )
70+ throw new Error ( "Server is not listening." ) ;
6371 this . emit ( "closing" ) ;
72+ let timeoutId : NodeJS . Timeout ;
6473 await Promise . race ( [
6574 new Promise < void > ( resolve => {
75+ timeoutId = setTimeout ( ( ) => {
76+ this . server . closeAllConnections ( ) ;
77+ resolve ( ) ;
78+ } , timeout )
79+ } ) ,
80+ new Promise < void > ( resolve => {
81+ clearTimeout ( timeoutId ) ;
6682 this . server . close ( ( ) => resolve ( ) ) ;
6783 } ) ,
68- new Promise < void > ( resolve => setTimeout ( ( ) => {
69- this . server . closeAllConnections ( ) ;
70- resolve ( ) ;
71- } , 5000 ) ) ,
7284 ] ) ;
7385 this . emit ( "closed" ) ;
7486 }
7587
88+ /**
89+ * Start listening for connections.
90+ * @param port The HTTP listener port. From 1 to 65535. Ports 1–1023 require privileges.
91+ */
92+ public listen ( port : number ) : Promise < void > {
93+ if ( this . server . listening )
94+ throw new Error ( "Server is already listening." ) ;
95+ return new Promise ( resolve => {
96+ this . server . listen ( port , process . env . HOST , ( ) => {
97+ this . emit ( "listening" , port , process . env . HOST ) ;
98+ resolve ( ) ;
99+ } ) ;
100+ } ) ;
101+ }
102+
76103 private async listener ( req : http . IncomingMessage , res : http . ServerResponse ) {
77104 let apiRequest : Request ;
78105 try {
@@ -175,9 +202,9 @@ namespace Server {
175202 export interface Options {
176203 /**
177204 * The HTTP listener port. From 1 to 65535. Ports 1–1023 require
178- * privileges.
205+ * privileges. If not set, { @link Server#listen|Server.listen()} must be called manually.
179206 */
180- readonly port : number ;
207+ readonly port ? : number ;
181208
182209 /**
183210 * Headers to send with every response.
@@ -207,7 +234,7 @@ namespace Server {
207234 /**
208235 * Server is listening and ready to accept connections.
209236 */
210- listening : [ void ] ;
237+ listening : [ port : number , host ?: string ] ;
211238
212239 /**
213240 * The server is closing and not accepting new connections.
0 commit comments