Skip to content

Commit

Permalink
Merge pull request #40 from sima-land/38-bun-deno-support
Browse files Browse the repository at this point in the history
Шаг 2 #38
  • Loading branch information
krutoo committed Mar 17, 2023
2 parents 7b2581b + 25442f7 commit 34c5a31
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 91 deletions.
11 changes: 2 additions & 9 deletions src/http-server/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Request, Response, NextFunction, Handler, ErrorRequestHandler } from 'express';
import type { Request, Response, NextFunction } from 'express';

// @todo переименовать в HandlerContext
export interface ResponseContext {
req: Request;
res: Response;
Expand Down Expand Up @@ -31,11 +32,3 @@ export interface ConventionalJson {
critical_css?: string;
meta?: any;
}

export interface DefaultMiddleware {
start: Handler[];
logging: Handler[];
tracing: Handler[];
metrics: Handler[];
finish: Array<Handler | ErrorRequestHandler>;
}
19 changes: 18 additions & 1 deletion src/http-server/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
import type { Request, Response } from 'express';
import type { Handler, Request, Response } from 'express';
import type { ConventionalJson, PageAssets, PageTemplate, PageTemplateData } from './types';
import type { BaseConfig } from '../config/types';
import { isIP } from 'net';

/**
* Объединяет промежуточные слои в один.
* @param list Промежуточные слои.
* @return Промежуточный слой.
*/
export function composeMiddleware(list: Handler[]) {
return list.reduce((a, b) => (req, res, next) => {
a(req, res, err => {
if (err) {
return next(err);
}

b(req, res, next);
});
});
}

/**
* Определяет IP входящего запроса.
* @param req Входящий запрос.
Expand Down
4 changes: 2 additions & 2 deletions src/preset/browser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function PresetBrowser(): Preset {
[KnownToken.logger, provideLogger],
[KnownToken.sagaMiddleware, provideSagaMiddleware],
[KnownToken.Http.Client.factory, provideHttpClientFactory],
[KnownToken.Http.Client.LogMiddleware.handler, provideHttpClientLogHandler],
[KnownToken.Http.Client.Middleware.Log.handler, provideHttpClientLogHandler],
[KnownToken.SsrBridge.clientSide, provideBridgeClientSide],
[KnownToken.Http.Api.knownHosts, provideKnownHttpApiHosts],
]);
Expand Down Expand Up @@ -86,7 +86,7 @@ export function provideKnownHttpApiHosts(resolve: Resolve): StrictMap<KnownHttpA
}

export function provideHttpClientFactory(resolve: Resolve): HttpClientFactory {
const logHandler = resolve(KnownToken.Http.Client.LogMiddleware.handler);
const logHandler = resolve(KnownToken.Http.Client.Middleware.Log.handler);

return function createHttpClient(config = {}) {
const client = create(config);
Expand Down
47 changes: 27 additions & 20 deletions src/preset/node/response.ts → src/preset/node/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,22 @@ import { HttpStatus } from '../parts/utils';
* Возвращает preset с зависимостями по умолчанию для работы в рамках ответа на http-запрос.
* @return Preset.
*/
export function PresetResponse(): Preset {
export function PresetHandler(): Preset {
return createPreset([
// saga
[KnownToken.sagaMiddleware, provideSagaMiddleware],
[KnownToken.Response.builder, () => new PageResponse()],
[KnownToken.Response.render, provideRender],
[KnownToken.Response.template, provideTemplate],
[KnownToken.Response.main, provideMain],
[KnownToken.Response.params, provideParams],

// http client
[KnownToken.Http.Client.factory, provideHttpClientFactory],
[KnownToken.Http.Client.LogMiddleware.handler, provideHttpClientLogHandler],
[KnownToken.Http.Client.Middleware.Log.handler, provideHttpClientLogHandler],

// http handler
[KnownToken.Http.Handler.main, provideMain],
[KnownToken.Http.Handler.Request.specificParams, provideSpecificParams],
[KnownToken.Http.Handler.Response.builder, () => new PageResponse()],
[KnownToken.Http.Handler.Response.Page.assets, () => ({ js: '', css: '' })],
[KnownToken.Http.Handler.Response.Page.template, provideTemplate],
[KnownToken.Http.Handler.Response.Page.render, provideRender],
]);
}

Expand All @@ -40,8 +46,8 @@ export function provideHttpClientFactory(resolve: Resolve): HttpClientFactory {

const appConfig = resolve(KnownToken.Config.base);
const tracer = resolve(KnownToken.Tracing.tracer);
const context = resolve(KnownToken.Response.context);
const logHandler = resolve(KnownToken.Http.Client.LogMiddleware.handler);
const context = resolve(KnownToken.Http.Handler.context);
const logHandler = resolve(KnownToken.Http.Client.Middleware.Log.handler);

// @todo добавить при необходимости (но тогда в логе будет значительно больше ошибок)
// const controller = new AbortController();
Expand Down Expand Up @@ -73,7 +79,7 @@ export function provideHttpClientFactory(resolve: Resolve): HttpClientFactory {
}

export function provideRender(resolve: Resolve): (element: JSX.Element) => string {
const { res } = resolve(KnownToken.Response.context);
const { res } = resolve(KnownToken.Http.Handler.context);

return function render(element: JSX.Element): string {
res.emit(RESPONSE_EVENT.renderStart);
Expand All @@ -97,16 +103,17 @@ export function provideTemplate(resolve: Resolve): PageTemplate {
}

export function provideMain(resolve: Resolve): VoidFunction {
const context = resolve(KnownToken.Response.context);
const assets = resolve(KnownToken.Response.assets);
const prepare = resolve(KnownToken.Response.prepare);
const render = resolve(KnownToken.Response.render);
const template = resolve(KnownToken.Response.template);
const logger = resolve(KnownToken.logger);
const builder = resolve(KnownToken.Response.builder);
const context = resolve(KnownToken.Http.Handler.context);
const assets = resolve(KnownToken.Http.Handler.Response.Page.assets);
const prepare = resolve(KnownToken.Http.Handler.Response.Page.prepare);
const render = resolve(KnownToken.Http.Handler.Response.Page.render);
const template = resolve(KnownToken.Http.Handler.Response.Page.template);
const builder = resolve(KnownToken.Http.Handler.Response.builder);

return async function main() {
try {
// @todo это билдер ответа но в ответе может не быть markup, assets и тд, подумать и переделать
builder
.markup(await render(await prepare()))
.assets(assets)
Expand All @@ -133,8 +140,8 @@ export function provideMain(resolve: Resolve): VoidFunction {
};
}

export function provideParams(resolve: Resolve): Record<string, unknown> {
const context = resolve(KnownToken.Response.context);
export function provideSpecificParams(resolve: Resolve): Record<string, unknown> {
const context = resolve(KnownToken.Http.Handler.context);

try {
const headerValue = context.req.header('simaland-params');
Expand Down Expand Up @@ -164,8 +171,8 @@ export function HandlerProvider(appFactory: () => Application) {
const app = appFactory();

app.attach(parent);
app.bind(KnownToken.Response.context).toValue({ req, res, next });
app.get(KnownToken.Response.main)();
app.bind(KnownToken.Http.Handler.context).toValue({ req, res, next });
app.get(KnownToken.Http.Handler.main)();
};
};
}
67 changes: 45 additions & 22 deletions src/preset/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import path from 'path';
import type { Logger, LoggerEventHandler } from '../../log/types';
import type { Tracer } from '@opentelemetry/api';
import type { DefaultMiddleware } from '../../http-server/types';
import { Resolve, Preset, createPreset } from '../../di';
import {
BasicTracerProvider,
Expand All @@ -23,7 +22,7 @@ import {
import { createDefaultMetrics, createMetricsHttpApp } from '../../metrics/node';
import { JaegerExporter } from '@opentelemetry/exporter-jaeger';
import { create } from 'middleware-axios';
import Express from 'express';
import Express, { Handler } from 'express';
import { init, Handlers, getCurrentHub } from '@sentry/node';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { Resource } from '@opentelemetry/resources';
Expand All @@ -38,26 +37,46 @@ import { provideBaseConfig } from '../parts/providers';
import pino from 'pino';
import PinoPretty from 'pino-pretty';
import { config as applyDotenv } from 'dotenv';
import { composeMiddleware } from '../../http-server/utils';

/**
* Возвращает preset с зависимостями по умолчанию для frontend-микросервисов на Node.js.
* @return Preset.
*/
export function PresetNode(): Preset {
return createPreset([
// config
[KnownToken.Config.source, provideConfigSource],
[KnownToken.Config.base, provideBaseConfig],

// log
[KnownToken.logger, provideLogger],

// tracing
[KnownToken.Tracing.tracer, provideTracer],
[KnownToken.Tracing.spanExporter, provideSpanExporter],
[KnownToken.Tracing.tracerProvider, provideTracerProvider],
[KnownToken.Tracing.tracerProviderResource, provideTracerProviderResource],

// metrics
[KnownToken.Metrics.httpApp, createMetricsHttpApp],

// http client
[KnownToken.Http.Client.factory, () => create],

// http server
[KnownToken.Http.Server.factory, () => Express],
[KnownToken.Http.Server.Defaults.middleware, provideDefaultMiddleware],
[KnownToken.Metrics.httpApp, createMetricsHttpApp],
[KnownToken.SsrBridge.serverSide, provideBridgeServerSide],
[KnownToken.Http.Server.Middleware.request, () => Handlers.requestHandler()],
[KnownToken.Http.Server.Middleware.log, provideHttpServerLogMiddleware],
[KnownToken.Http.Server.Middleware.metrics, provideHttpServerMetricsMiddleware],
[KnownToken.Http.Server.Middleware.tracing, provideHttpServerTracingMiddleware],
[KnownToken.Http.Server.Middleware.error, () => Handlers.errorHandler()],

// http api
[KnownToken.Http.Api.knownHosts, provideKnownHttpApiHosts],

// ssr bridge
[KnownToken.SsrBridge.serverSide, provideBridgeServerSide],
]);
}

Expand Down Expand Up @@ -164,28 +183,32 @@ export function provideTracerProviderResource(resolve: Resolve): Resource {
);
}

export function provideDefaultMiddleware(resolve: Resolve): DefaultMiddleware {
export function provideHttpServerLogMiddleware(resolve: Resolve): Handler {
const config = resolve(KnownToken.Config.base);
const logger = resolve(KnownToken.logger);
const tracer = resolve(KnownToken.Tracing.tracer);

return logMiddleware(config, logger);
}

export function provideHttpServerMetricsMiddleware(resolve: Resolve): Handler {
const config = resolve(KnownToken.Config.base);
const metrics = createDefaultMetrics();

return {
start: [Handlers.requestHandler()],
logging: [logMiddleware(config, logger)],
tracing: [tracingMiddleware(tracer)],
metrics: [
responseMetricsMiddleware(config, {
counter: metrics.requestCount,
histogram: metrics.responseDuration,
}),
renderMetricsMiddleware(config, {
histogram: metrics.renderDuration,
}),
],
finish: [Handlers.errorHandler()],
};
return composeMiddleware([
responseMetricsMiddleware(config, {
counter: metrics.requestCount,
histogram: metrics.responseDuration,
}),
renderMetricsMiddleware(config, {
histogram: metrics.renderDuration,
}),
]);
}

export function provideHttpServerTracingMiddleware(resolve: Resolve): Handler {
const tracer = resolve(KnownToken.Tracing.tracer);

return tracingMiddleware(tracer);
}

export function provideBridgeServerSide(resolve: Resolve): BridgeServerSide {
Expand Down
76 changes: 39 additions & 37 deletions src/tokens.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { createToken } from './di';
import type { Application } from 'express';
import type {
DefaultMiddleware,
PageAssets,
PageTemplate,
ResponseContext,
} from './http-server/types';
import type { Application, ErrorRequestHandler, Handler } from 'express';
import type { PageAssets, PageTemplate, ResponseContext } from './http-server/types';
import type { SagaExtendedMiddleware } from './utils/redux-saga';
import type { Logger } from './log/types';
import type { HttpClientFactory } from './http-client/types';
Expand All @@ -22,8 +17,8 @@ import type { LogMiddlewareHandlerInit } from './http-client/middleware/log';
export const KnownToken = {
// config
Config: {
source: createToken<ConfigSource>('config.source'),
base: createToken<BaseConfig>('config.base'),
source: createToken<ConfigSource>('config/source'),
base: createToken<BaseConfig>('config/base'),
},

// cache
Expand All @@ -37,51 +32,58 @@ export const KnownToken = {

// tracing
Tracing: {
tracer: createToken<Tracer>('tracing.tracer'),
spanExporter: createToken<SpanExporter>('tracing.span-exporter'),
tracerProvider: createToken<BasicTracerProvider>('tracing.tracer-provider'),
tracerProviderResource: createToken<Resource>('tracing.tracer-provider-resource'),
tracer: createToken<Tracer>('tracing/tracer'),
spanExporter: createToken<SpanExporter>('tracing/span-exporter'),
tracerProvider: createToken<BasicTracerProvider>('tracing/tracer-provider'),
tracerProviderResource: createToken<Resource>('tracing/resource'),
},

// metrics
Metrics: {
httpApp: createToken<Application>('metrics.http-app'),
httpApp: createToken<Application>('metrics/http-app'),
},

// http
Http: {
Api: {
knownHosts: createToken<StrictMap<KnownHttpApiKey>>('http/api/known-hosts'),
},
Client: {
factory: createToken<HttpClientFactory>('http.client.factory'),
LogMiddleware: {
handler: createToken<LogMiddlewareHandlerInit>('http.client.log-middleware.handler'),
factory: createToken<HttpClientFactory>('client/factory'),
Middleware: {
Log: {
handler: createToken<LogMiddlewareHandlerInit>('log/handler'),
},
},
},
Server: {
factory: createToken<() => Application>('http.server.factory'),
Defaults: {
middleware: createToken<DefaultMiddleware>('http.server.defaults.middleware'),
factory: createToken<() => Application>('server/factory'),
Middleware: {
request: createToken<Handler>('middleware/request'),
log: createToken<Handler>('middleware/log'),
tracing: createToken<Handler>('middleware/tracing'),
metrics: createToken<Handler>('middleware/metrics'),
error: createToken<ErrorRequestHandler>('middleware/error'),
},
},
Api: {
knownHosts: createToken<StrictMap<KnownHttpApiKey>>('http.api.known-hosts'),
Handler: {
main: createToken<() => void>('handler/main'),
context: createToken<ResponseContext>('handler/context'),
Request: {
specificParams: createToken<Record<string, unknown>>('request/specific-params'),
},
Response: {
builder: createToken<PageResponse>('response/builder'),
Page: {
assets: createToken<PageAssets>('page/assets'),
template: createToken<PageTemplate>('page/template'),
prepare: createToken<() => JSX.Element | Promise<JSX.Element>>('page/prepare'),
render: createToken<(element: JSX.Element) => string | Promise<string>>('page/render'),
},
},
},
},

// scope: page response
Response: {
builder: createToken<PageResponse>('response/builder'),

// @todo переименовать в requestSimaParams или убрать
params: createToken<Record<string, unknown>>('response/params'),

template: createToken<PageTemplate>('response/template'),
context: createToken<ResponseContext>('response/context'),
assets: createToken<PageAssets>('response/assets'),
prepare: createToken<() => JSX.Element | Promise<JSX.Element>>('response/prepare'),
render: createToken<(element: JSX.Element) => string | Promise<string>>('response/render'),
main: createToken<() => void>('response/main'),
},

// SSR
SsrBridge: {
clientSide: createToken<BridgeClientSide<unknown>>('ssr-bridge/client-side'),
Expand Down

0 comments on commit 34c5a31

Please sign in to comment.