From 2c95e13aab18c409fbe36cb2753fc73c9d304de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 10 Feb 2026 01:57:48 +0100 Subject: [PATCH] Client work --- packages/effect-docker/src/BaseClient.ts | 15 ---- packages/effect-docker/src/Client153.ts | 17 ----- packages/effect-docker/src/Docker153Client.ts | 33 +++++++++ .../effect-docker/src/DockerBaseClient.ts | 70 +++++++++++++++++++ packages/effect-docker/src/test.ts | 30 ++++++++ 5 files changed, 133 insertions(+), 32 deletions(-) delete mode 100644 packages/effect-docker/src/BaseClient.ts delete mode 100644 packages/effect-docker/src/Client153.ts create mode 100644 packages/effect-docker/src/Docker153Client.ts create mode 100644 packages/effect-docker/src/DockerBaseClient.ts create mode 100644 packages/effect-docker/src/test.ts diff --git a/packages/effect-docker/src/BaseClient.ts b/packages/effect-docker/src/BaseClient.ts deleted file mode 100644 index 3e2e971..0000000 --- a/packages/effect-docker/src/BaseClient.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { HttpClient } from "@effect/platform" - - -export const BaseClientTypeId: unique symbol = Symbol.for("@effect-docker/BaseClient/BaseClient") -export type BaseClientTypeId = typeof BaseClientTypeId - -export interface BaseClient { - readonly [BaseClientTypeId]: BaseClientTypeId - readonly httpClient: HttpClient.HttpClient -} - -export abstract class BaseClientImpl implements BaseClient { - readonly [BaseClientTypeId]: BaseClientTypeId = BaseClientTypeId - constructor(readonly httpClient: HttpClient.HttpClient) {} -} diff --git a/packages/effect-docker/src/Client153.ts b/packages/effect-docker/src/Client153.ts deleted file mode 100644 index e75f7b2..0000000 --- a/packages/effect-docker/src/Client153.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { type BaseClient, BaseClientImpl } from "./BaseClient.js" - - -export * from "./gen/v1.53/index.js" - -export const Client153TypeId: unique symbol = Symbol.for("@effect-docker/Client153/Client153") -export type Client153TypeId = typeof Client153TypeId - -export interface Client153 extends BaseClient { - readonly [Client153TypeId]: Client153TypeId - - -} - -export class Client153Impl extends BaseClientImpl implements Client153 { - readonly [Client153TypeId]: Client153TypeId = Client153TypeId -} diff --git a/packages/effect-docker/src/Docker153Client.ts b/packages/effect-docker/src/Docker153Client.ts new file mode 100644 index 0000000..e62d972 --- /dev/null +++ b/packages/effect-docker/src/Docker153Client.ts @@ -0,0 +1,33 @@ +import { HttpClient, HttpClientRequest } from "@effect/platform" +import { Effect } from "effect" +import { type DockerBaseClient, DockerBaseClientImpl, type DockerClientContainerError } from "./DockerBaseClient.js" +import type { ContainerSummary } from "./gen/v1.53/index.js" + + +export * from "./gen/v1.53/index.js" + +export const Docker153ClientTypeId: unique symbol = Symbol.for("@effect-docker/Docker153Client/Docker153Client") +export type Docker153ClientTypeId = typeof Docker153ClientTypeId + +export interface Docker153Client extends DockerBaseClient { + readonly [Docker153ClientTypeId]: Docker153ClientTypeId + + listContainers(): Effect.Effect +} + +export class Docker153ClientImpl +extends DockerBaseClientImpl +implements Docker153Client { + readonly [Docker153ClientTypeId]: Docker153ClientTypeId = Docker153ClientTypeId + + listContainers() { + return this.httpContainerClient.get("/json").pipe( + + ) + } +} + +export const make: Effect.Effect = HttpClient.HttpClient.pipe( + Effect.map(HttpClient.mapRequest(HttpClientRequest.prependUrl("/v1.53"))), + Effect.map(client => new Docker153ClientImpl(client)), +) diff --git a/packages/effect-docker/src/DockerBaseClient.ts b/packages/effect-docker/src/DockerBaseClient.ts new file mode 100644 index 0000000..1d87dd3 --- /dev/null +++ b/packages/effect-docker/src/DockerBaseClient.ts @@ -0,0 +1,70 @@ +import { HttpClient, type HttpClientError, HttpClientRequest } from "@effect/platform" +import { Effect, Match, Schema } from "effect" + + +export const DockerBaseClientTypeId: unique symbol = Symbol.for("@effect-docker/DockerBaseClient/DockerBaseClient") +export type DockerBaseClientTypeId = typeof DockerBaseClientTypeId + +export interface DockerBaseClient { + readonly [DockerBaseClientTypeId]: DockerBaseClientTypeId + + readonly httpClient: HttpClient.HttpClient.With + readonly httpContainerClient: HttpClient.HttpClient.With +} + +export class DockerBaseClientImpl implements DockerBaseClient { + readonly [DockerBaseClientTypeId]: DockerBaseClientTypeId = DockerBaseClientTypeId + + readonly httpClient: HttpClient.HttpClient.With + readonly httpContainerClient: HttpClient.HttpClient.With + + constructor(httpClient: HttpClient.HttpClient) { + this.httpClient = httpClient.pipe( + HttpClient.filterStatus(status => status !== 400 && status !== 500), + HttpClient.catchTag("ResponseError", e => Match.value(e.response.status).pipe( + Match.when(400, () => Effect.andThen( + e.response.json as Effect.Effect, + ({ message }) => new BadParameter({ message }, true), + )), + Match.when(500, () => Effect.andThen( + e.response.json as Effect.Effect, + ({ message }) => new ServerError({ message }, true), + )), + Match.orElse(Effect.fail), + ) as Effect.Effect), + ) + + this.httpContainerClient = this.httpClient.pipe( + HttpClient.mapRequest(HttpClientRequest.appendUrl("/containers")), + HttpClient.filterStatus(status => status !== 404), + HttpClient.catchTag("ResponseError", e => Match.value(e.response.status).pipe( + Match.when(404, () => Effect.andThen( + e.response.json as Effect.Effect, + ({ message }) => new NoSuchContainer({ message }, true), + )), + Match.orElse(Effect.fail), + ) as Effect.Effect), + ) + } +} + +export interface HttpErrorResponse { + readonly message: string +} + + +export class BadParameter extends Schema.TaggedError("@effect-docker/DockerBaseClient/BadParameter")("BadParameter", { + message: Schema.String, +}) {} + +export class ServerError extends Schema.TaggedError("@effect-docker/DockerBaseClient/ServerError")("ServerError", { + message: Schema.String, +}) {} + +export type DockerClientError = HttpClientError.HttpClientError | BadParameter | ServerError + +export class NoSuchContainer extends Schema.TaggedError("@effect-docker/DockerBaseClient/NoSuchContainer")("NoSuchContainer", { + message: Schema.String, +}) {} + +export type DockerClientContainerError = DockerClientError | NoSuchContainer diff --git a/packages/effect-docker/src/test.ts b/packages/effect-docker/src/test.ts new file mode 100644 index 0000000..8dd9d3e --- /dev/null +++ b/packages/effect-docker/src/test.ts @@ -0,0 +1,30 @@ +import { HttpClient } from "@effect/platform" +import { NodeHttpClient, NodeRuntime } from "@effect/platform-node" +import { Effect, Schema } from "effect" + + +export class NotFound extends Schema.TaggedError("NotFound")("NotFound", { + message: Schema.String, +}) {} + +const program = Effect.gen(function*() { + const client = yield* HttpClient.HttpClient.pipe( + Effect.map(HttpClient.filterStatus(status => status !== 404)), + Effect.map(HttpClient.catchTag("ResponseError", e => + e.response.status === 404 + ? Effect.andThen(e.response.text, message => Effect.fail(new NotFound({ message: "" }))) + : Effect.fail(e) + )), + ) + const res = yield* client.get("https://docs.docker.com/adolf") + console.log(res.status) +// console.log(yield* res.text) + +}).pipe(Effect.withSpan("program", { + attributes: { source: "Playground" } +})) + +program.pipe( + Effect.provide(NodeHttpClient.layer), + NodeRuntime.runMain +)