/
http.listener.ts
68 lines (62 loc) · 2.52 KB
/
http.listener.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
import { IncomingMessage, OutgoingMessage } from 'http';
import { of, Subject } from 'rxjs';
import { catchError, defaultIfEmpty, mergeMap, tap, takeWhile } from 'rxjs/operators';
import { combineMiddlewares } from '../effects/effects.combiner';
import {
HttpEffectResponse,
HttpMiddlewareEffect,
HttpErrorEffect,
HttpOutputEffect,
} from '../effects/http-effects.interface';
import { HttpRequest, HttpResponse, HttpStatus } from '../http.interface';
import { handleResponse } from '../response/response.handler';
import { RouteEffect, RouteEffectGroup } from '../router/router.interface';
import { resolveRouting } from '../router/router.resolver';
import { factorizeRouting } from '../router/router.factory';
import { defaultError$ } from '../error/error.effect';
import { createStaticInjectionContainer } from '../server/server.injector';
import { createEffectMetadata } from '../effects/effectsMetadata.factory';
export interface HttpListenerConfig {
middlewares?: HttpMiddlewareEffect[];
effects: (RouteEffect | RouteEffectGroup)[];
error$?: HttpErrorEffect;
output$?: HttpOutputEffect;
}
export const httpListener = ({
middlewares = [],
effects,
error$ = defaultError$,
output$ = out$ => out$,
}: HttpListenerConfig) => {
const requestSubject$ = new Subject<{ req: HttpRequest; res: HttpResponse; }>();
const combinedMiddlewares = combineMiddlewares(...middlewares);
const routing = factorizeRouting(effects);
const injector = createStaticInjectionContainer();
const defaultMetadata = createEffectMetadata({ inject: injector.get });
const defaultResponse = { status: HttpStatus.NOT_FOUND } as HttpEffectResponse;
requestSubject$.pipe(
tap(({ req, res }) => res.send = handleResponse(res)(req)),
mergeMap(({ req, res }) => combinedMiddlewares(of(req), res, defaultMetadata).pipe(
takeWhile(() => !res.finished),
mergeMap(resolveRouting(routing, defaultMetadata)(res)),
defaultIfEmpty(defaultResponse),
mergeMap(out => output$(of(out), res, defaultMetadata)),
tap(res.send),
catchError(error =>
error$(of(req), res, createEffectMetadata({ ...defaultMetadata, error })).pipe(
mergeMap(out => output$(of(out), res, createEffectMetadata({ ...defaultMetadata, error }))),
tap(res.send),
),
),
)),
).subscribe();
const httpServer = (req: IncomingMessage, res: OutgoingMessage) => requestSubject$.next({
req: req as HttpRequest,
res: res as HttpResponse,
});
httpServer.config = {
routing,
injector,
};
return httpServer;
};