Skip to content

Commit a7b73e3

Browse files
Merge pull request #14143 from nestjs/feat/expose-listening-stream
feat(core): expose listening stream from http adapter host
2 parents 491ed77 + 1a076fc commit a7b73e3

File tree

3 files changed

+54
-2
lines changed

3 files changed

+54
-2
lines changed

packages/core/helpers/http-adapter-host.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Observable, Subject } from 'rxjs';
12
import { AbstractHttpAdapter } from '../adapters/http-adapter';
23

34
/**
@@ -16,6 +17,8 @@ export class HttpAdapterHost<
1617
T extends AbstractHttpAdapter = AbstractHttpAdapter,
1718
> {
1819
private _httpAdapter?: T;
20+
private _listen$ = new Subject<void>();
21+
private isListening = false;
1922

2023
/**
2124
* Accessor for the underlying `HttpAdapter`
@@ -35,4 +38,31 @@ export class HttpAdapterHost<
3538
get httpAdapter(): T {
3639
return this._httpAdapter;
3740
}
41+
42+
/**
43+
* Observable that allows to subscribe to the `listen` event.
44+
* This event is emitted when the HTTP application is listening for incoming requests.
45+
*/
46+
get listen$(): Observable<void> {
47+
return this._listen$.asObservable();
48+
}
49+
50+
/**
51+
* Sets the listening state of the application.
52+
*/
53+
set listening(listening: boolean) {
54+
this.isListening = listening;
55+
56+
if (listening) {
57+
this._listen$.next();
58+
this._listen$.complete();
59+
}
60+
}
61+
62+
/**
63+
* Returns a boolean indicating whether the application is listening for incoming requests.
64+
*/
65+
get listening(): boolean {
66+
return this.isListening;
67+
}
3868
}

packages/core/nest-application.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,12 @@ export class NestApplication
294294
public async listen(port: number | string, hostname: string): Promise<any>;
295295
public async listen(port: number | string, ...args: any[]): Promise<any> {
296296
this.assertNotInPreviewMode('listen');
297-
!this.isInitialized && (await this.init());
298297

298+
if (!this.isInitialized) {
299+
await this.init();
300+
}
301+
302+
const httpAdapterHost = this.container.getHttpAdapterHostRef();
299303
return new Promise((resolve, reject) => {
300304
const errorHandler = (e: any) => {
301305
this.logger.error(e?.toString?.());
@@ -323,6 +327,8 @@ export class NestApplication
323327
if (address) {
324328
this.httpServer.removeListener('error', errorHandler);
325329
this.isListening = true;
330+
331+
httpAdapterHost.listening = true;
326332
resolve(this.httpServer);
327333
}
328334
if (isCallbackInOriginalArgs) {

packages/core/test/helpers/application-ref-host.spec.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,27 @@ import { expect } from 'chai';
22
import { HttpAdapterHost } from '../../helpers/http-adapter-host';
33

44
describe('HttpAdapterHost', () => {
5-
const applicationRefHost = new HttpAdapterHost();
5+
let applicationRefHost: HttpAdapterHost;
6+
beforeEach(() => {
7+
applicationRefHost = new HttpAdapterHost();
8+
});
9+
610
it('should wrap application reference', () => {
711
const ref = {};
812
applicationRefHost.httpAdapter = ref as any;
913

1014
expect(applicationRefHost.httpAdapter).to.be.eql(ref);
1115
});
16+
17+
it('should emit listen event when listening is set to true', done => {
18+
applicationRefHost.listen$.subscribe(() => {
19+
expect(applicationRefHost.listening).to.be.true;
20+
done();
21+
});
22+
applicationRefHost.listening = true;
23+
});
24+
25+
it('listening should return false if the application isnt listening yet', () => {
26+
expect(applicationRefHost.listening).to.be.false;
27+
});
1228
});

0 commit comments

Comments
 (0)