summaryrefslogtreecommitdiff
path: root/u/server
diff options
context:
space:
mode:
Diffstat (limited to 'u/server')
-rw-r--r--u/server/activity/fourohfour.ts27
-rw-r--r--u/server/activity/health.ts77
-rw-r--r--u/server/activity/mod.ts20
-rw-r--r--u/server/filter/json.ts43
-rw-r--r--u/server/filter/method.ts10
-rw-r--r--u/server/filter/mod.ts28
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>>;