diff options
Diffstat (limited to 'u/server')
-rw-r--r-- | u/server/activity/fourohfour.ts | 27 | ||||
-rw-r--r-- | u/server/activity/health.ts | 77 | ||||
-rw-r--r-- | u/server/activity/mod.ts | 20 | ||||
-rw-r--r-- | u/server/filter/json.ts | 43 | ||||
-rw-r--r-- | u/server/filter/method.ts | 10 | ||||
-rw-r--r-- | u/server/filter/mod.ts | 28 |
6 files changed, 123 insertions, 82 deletions
diff --git a/u/server/activity/fourohfour.ts b/u/server/activity/fourohfour.ts index 48740df..6449abd 100644 --- a/u/server/activity/fourohfour.ts +++ b/u/server/activity/fourohfour.ts @@ -1,4 +1,5 @@ import { + type IActivity, type ITraceable, JsonResponse, type PenguenoRequest, @@ -16,12 +17,20 @@ const messages = [ "ヽ(;▽;)ノ Eep! This route has ghosted you~", ]; const randomFourOhFour = () => messages[Math.random() * messages.length]; -export const FourOhFourActivity = ( - req: ITraceable<PenguenoRequest, ServerTrace>, -) => - req - .move( - new JsonResponse(req, randomFourOhFour(), { - status: 404, - }), - ); + +export interface IFourOhFourActivity { + fourOhFour: IActivity; +} + +export class FourOhFourActivityImpl implements IFourOhFourActivity { + public fourOhFour( + req: ITraceable<PenguenoRequest, ServerTrace>, + ) { + return req + .move( + new JsonResponse(req, randomFourOhFour(), { status: 404 }), + ) + .map((resp) => Promise.resolve(resp.get())) + .get(); + } +} diff --git a/u/server/activity/health.ts b/u/server/activity/health.ts index b9efa3a..0f54a99 100644 --- a/u/server/activity/health.ts +++ b/u/server/activity/health.ts @@ -1,4 +1,5 @@ import { + type IActivity, type IEither, type ITraceable, JsonResponse, @@ -14,39 +15,53 @@ export enum HealthCheckInput { CHECK, } export enum HealthCheckOutput { - YAASQUEEN, + YAASSSLAYQUEEN, +} + +export interface IHealthCheckActivity { + checkHealth: IActivity; } const healthCheckMetric = Metric.fromName("Health"); -export const HealthCheckActivity = ( - check: Mapper< +export interface HealthChecker extends + Mapper< ITraceable<HealthCheckInput, ServerTrace>, Promise<IEither<Error, HealthCheckOutput>> - >, -) => -(req: ITraceable<PenguenoRequest, ServerTrace>) => - req - .bimap(TraceUtil.withFunctionTrace(HealthCheckActivity)) - .bimap(TraceUtil.withMetricTrace(healthCheckMetric)) - .flatMap((r) => r.move(HealthCheckInput.CHECK).map(check)) - .map(TraceUtil.promiseify((h) => { - const health = h.get(); - health.mapBoth((e) => { - h.trace.trace(healthCheckMetric.failure); - h.trace.addTrace(LogLevel.ERROR).trace(`${e}`); - return new JsonResponse( - req, - "oh no, i need to eat more vegetables (。•́︿•̀。)...", - { status: 500 }, - ); - }, (_healthy) => { - h.trace.trace(healthCheckMetric.success); - const msg = `think im healthy!! (✿˘◡˘) ready to do work~`; - h.trace.trace(msg); - return new JsonResponse( - req, - msg, - { status: 200 }, - ); - }); - })); + > {} +export class HealthCheckActivityImpl implements IHealthCheckActivity { + constructor( + private readonly check: HealthChecker, + ) {} + + public checkHealth(req: ITraceable<PenguenoRequest, ServerTrace>) { + return req + .bimap(TraceUtil.withFunctionTrace(this.checkHealth)) + .bimap(TraceUtil.withMetricTrace(healthCheckMetric)) + .flatMap((r) => r.move(HealthCheckInput.CHECK).map(this.check)) + .peek(TraceUtil.promiseify((h) => + h.get().fold((err) => { + if (err) { + h.trace.trace(healthCheckMetric.failure); + h.trace.addTrace(LogLevel.ERROR).trace(`${err}`); + return; + } + h.trace.trace(healthCheckMetric.success); + }) + )) + .map(TraceUtil.promiseify((h) => + h.get() + .mapBoth( + () => "oh no, i need to eat more vegetables (。•́︿•̀。)...", + () => "think im healthy!! (✿˘◡˘) ready to do work~", + ) + .fold((errMsg, okMsg) => + new JsonResponse( + req, + errMsg ?? okMsg, + { status: errMsg ? 500 : 200 }, + ) + ) + )) + .get(); + } +} diff --git a/u/server/activity/mod.ts b/u/server/activity/mod.ts index 9bd512f..82d8ec4 100644 --- a/u/server/activity/mod.ts +++ b/u/server/activity/mod.ts @@ -1,15 +1,13 @@ -import type { PenguenoResponse, RequestFilter } from "@emprespresso/pengueno"; +import type { + ITraceable, + PenguenoRequest, + PenguenoResponse, + ServerTrace, +} from "@emprespresso/pengueno"; -export enum StatusOK { - FOLLOW = 300, - OK = 200, -} -export interface ActivityOk { - readonly status: StatusOK; -} - -export interface IActivity<Trace> - extends RequestFilter<ActivityOk, Trace, PenguenoResponse> { +export interface IActivity { + (req: ITraceable<PenguenoRequest, ServerTrace>): Promise<PenguenoResponse>; } export * from "./health.ts"; +export * from "./fourohfour.ts"; diff --git a/u/server/filter/json.ts b/u/server/filter/json.ts index c839707..4a2961e 100644 --- a/u/server/filter/json.ts +++ b/u/server/filter/json.ts @@ -3,46 +3,49 @@ import { type IEither, type ITraceable, LogLevel, + Metric, + PenguenoError, type PenguenoRequest, type RequestFilter, type ServerTrace, TraceUtil, } from "@emprespresso/pengueno"; -import { Metric } from "../../trace/mod.ts"; -type JsonTransformer<R, ParsedJson = unknown> = ( - json: ITraceable<ParsedJson, ServerTrace>, -) => IEither<Error, R>; +export interface JsonTransformer<R, ParsedJson = unknown> { + (json: ITraceable<ParsedJson, ServerTrace>): IEither<PenguenoError, R>; +} const ParseJsonMetric = Metric.fromName("JsonParse"); export const jsonModel = <MessageT>( jsonTransformer: JsonTransformer<MessageT>, -): RequestFilter<MessageT, Error> => +): RequestFilter<MessageT> => (r: ITraceable<PenguenoRequest, ServerTrace>) => - r - .bimap(TraceUtil.withMetricTrace(ParseJsonMetric)) + r.bimap(TraceUtil.withMetricTrace(ParseJsonMetric)) .map((j) => Either.fromFailableAsync<Error, MessageT>(j.get().json()) .then((either) => either.mapLeft((errReason) => { j.trace.addTrace(LogLevel.WARN).trace(`${errReason}`); - return new Error("seems to be invalid JSON (>//<) can you fix?"); + return new PenguenoError( + "seems to be invalid JSON (>//<) can you fix?", + 400, + ); }) ) ) - .flatMapAsync( - TraceUtil.promiseify((traceableEitherJson) => - traceableEitherJson.map((t) => - t.get().mapRight(traceableEitherJson.move).flatMap( - jsonTransformer, - ) + .peek( + TraceUtil.promiseify((traceableEither) => + traceableEither.get().mapBoth( + () => traceableEither.trace.trace(ParseJsonMetric.failure), + () => traceableEither.trace.trace(ParseJsonMetric.success), ) ), ) - .peek(TraceUtil.promiseify((traceableEither) => - traceableEither.get().mapBoth( - () => traceableEither.trace.trace(ParseJsonMetric.failure), - () => traceableEither.trace.trace(ParseJsonMetric.success), - ) - )) + .map( + TraceUtil.promiseify((traceableEitherJson) => + traceableEitherJson.get() + .mapRight(traceableEitherJson.move) + .flatMap(jsonTransformer) + ), + ) .get(); diff --git a/u/server/filter/method.ts b/u/server/filter/method.ts index 350f04c..6b0419d 100644 --- a/u/server/filter/method.ts +++ b/u/server/filter/method.ts @@ -1,8 +1,8 @@ import { Either, type ITraceable, - JsonResponse, LogLevel, + PenguenoError, type PenguenoRequest, type RequestFilter, type ServerTrace, @@ -22,7 +22,7 @@ type HttpMethod = export const requireMethod = ( methods: Array<HttpMethod>, -): RequestFilter<HttpMethod, JsonResponse> => +): RequestFilter<HttpMethod> => (req: ITraceable<PenguenoRequest, ServerTrace>) => req.bimap(TraceUtil.withFunctionTrace(requireMethod)) .move(Promise.resolve(req.get())) @@ -32,10 +32,10 @@ export const requireMethod = ( if (!methods.includes(method)) { const msg = "that's not how you pet me (⋟﹏⋞)~"; t.trace.addTrace(LogLevel.WARN).trace(msg); - return Either.left<JsonResponse, HttpMethod>( - new JsonResponse(req, msg, { status: 405 }), + return Either.left<PenguenoError, HttpMethod>( + new PenguenoError(msg, 405), ); } - return Either.right<JsonResponse, HttpMethod>(method); + return Either.right<PenguenoError, HttpMethod>(method); })) .get(); diff --git a/u/server/filter/mod.ts b/u/server/filter/mod.ts index 22ddad5..bbf37df 100644 --- a/u/server/filter/mod.ts +++ b/u/server/filter/mod.ts @@ -1,13 +1,29 @@ -import type { - IEither, - ITraceable, - PenguenoRequest, - ServerTrace, +import { + type IEither, + type ITraceable, + LogLevel, + type PenguenoRequest, + type ServerTrace, } from "@emprespresso/pengueno"; +export enum ErrorSource { + USER = LogLevel.WARN, + SYSTEM = LogLevel.ERROR, +} + +export class PenguenoError extends Error { + public readonly source: ErrorSource; + constructor(message: string, public readonly status: number) { + super(message); + this.source = Math.floor(status / 100) === 4 + ? ErrorSource.USER + : ErrorSource.SYSTEM; + } +} + export interface RequestFilter< T, - Err, + Err extends PenguenoError = PenguenoError, RIn = ITraceable<PenguenoRequest, ServerTrace>, > { (req: RIn): Promise<IEither<Err, T>>; |