This commit is contained in:
19
src/Layers/express/ExpressApp.ts
Normal file
19
src/Layers/express/ExpressApp.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Config, Context, Effect, Layer } from "effect"
|
||||
import type { Express } from "express"
|
||||
|
||||
|
||||
export class ExpressApp extends Context.Tag("ExpressApp")<ExpressApp, Express>() {}
|
||||
|
||||
|
||||
const importExpress = Effect.tryPromise({
|
||||
try: () => import("express"),
|
||||
catch: cause => new Error("Could not import 'express'. Make sure it is installed.", { cause }),
|
||||
})
|
||||
|
||||
export const ExpressAppLive = (config: {
|
||||
readonly trustProxy?: Config.Config<boolean>
|
||||
}) => Layer.effect(ExpressApp, Effect.gen(function*() {
|
||||
const app = (yield* importExpress).default()
|
||||
app.set("trust proxy", yield* config.trustProxy || Config.succeed(false))
|
||||
return app
|
||||
}))
|
||||
67
src/Layers/express/ExpressNodeHTTPServer.ts
Normal file
67
src/Layers/express/ExpressNodeHTTPServer.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Config, Context, Effect, Layer, Match } from "effect"
|
||||
import type { Server } from "node:http"
|
||||
import type { AddressInfo } from "node:net"
|
||||
import { ExpressApp } from "./ExpressApp"
|
||||
|
||||
|
||||
export class ExpressNodeHTTPServer extends Context.Tag("ExpressNodeHTTPServer")<ExpressNodeHTTPServer, Server>() {}
|
||||
|
||||
|
||||
const importNodeHTTP = Effect.tryPromise({
|
||||
try: () => import("node:http"),
|
||||
catch: cause => new Error("Could not import 'node:http'. Make sure you are using a runtime that implements Node APIs.", { cause }),
|
||||
})
|
||||
|
||||
const serverListeningMessage = Match.type<AddressInfo | string | null>().pipe(
|
||||
Match.when(Match.null, () => "HTTP server listening"),
|
||||
Match.when(Match.string, v => `HTTP server listening on ${ v }`),
|
||||
Match.orElse(v => `HTTP server listening on ${ v.address }:${ v.port }`),
|
||||
)
|
||||
|
||||
export const ExpressNodeHTTPServerLive = (config: {
|
||||
readonly backlog?: Config.Config<number | undefined>
|
||||
readonly exclusive?: Config.Config<boolean | undefined>
|
||||
readonly host?: Config.Config<string | undefined>
|
||||
readonly ipv6Only?: Config.Config<boolean | undefined>
|
||||
readonly path?: Config.Config<string | undefined>
|
||||
readonly port?: Config.Config<number | undefined>
|
||||
readonly readableAll?: Config.Config<boolean | undefined>
|
||||
readonly signal?: AbortSignal
|
||||
readonly writableAll?: Config.Config<boolean | undefined>
|
||||
}) => Layer.effect(ExpressNodeHTTPServer, Effect.acquireRelease(
|
||||
Effect.gen(function*() {
|
||||
const app = yield* ExpressApp
|
||||
const http = yield* importNodeHTTP
|
||||
|
||||
const options = {
|
||||
backlog: yield* config.backlog || Config.succeed(undefined),
|
||||
exclusive: yield* config.exclusive || Config.succeed(undefined),
|
||||
host: yield* config.host || Config.succeed(undefined),
|
||||
ipv6Only: yield* config.ipv6Only || Config.succeed(undefined),
|
||||
path: yield* config.path || Config.succeed(undefined),
|
||||
port: yield* config.port || Config.succeed(undefined),
|
||||
readableAll: yield* config.readableAll || Config.succeed(undefined),
|
||||
signal: config.signal,
|
||||
writableAll: yield* config.writableAll || Config.succeed(undefined),
|
||||
} as const
|
||||
|
||||
return yield* Effect.async<Server>(resume => {
|
||||
const server = http.createServer(app).listen(options,
|
||||
() => resume(
|
||||
Effect.succeed(server).pipe(
|
||||
Effect.tap(Effect.logInfo(
|
||||
serverListeningMessage(server.address())
|
||||
))
|
||||
)
|
||||
)
|
||||
)
|
||||
})
|
||||
}),
|
||||
|
||||
server => Effect.gen(function*() {
|
||||
yield* Effect.logInfo("HTTP server is stopping. Waiting for existing connections to end...")
|
||||
yield* Effect.async(resume => {
|
||||
server.close(() => resume(Effect.logInfo("HTTP server closed")))
|
||||
})
|
||||
}),
|
||||
))
|
||||
2
src/Layers/express/index.ts
Normal file
2
src/Layers/express/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./ExpressApp"
|
||||
export * from "./ExpressNodeHTTPServer"
|
||||
Reference in New Issue
Block a user