diff --git a/example/immich.ts b/example/immich.ts index 5a92ec1..579deba 100644 --- a/example/immich.ts +++ b/example/immich.ts @@ -3,7 +3,7 @@ * https://raw.githubusercontent.com/immich-app/immich/main/docker/docker-compose.yml */ -import { Stack, Service, deploySingle } from "../mod.ts"; +import { Stack } from "../mod.ts"; interface ImmichStackOptions { stackName?: string; @@ -16,80 +16,72 @@ interface ImmichStackOptions { }; } -function immichStack(props: ImmichStackOptions) { - const redis = new Service("redis", { - image: "registry.hub.docker.com/library/redis:6.2-alpine", - restart: "unless-stopped", - }); +export class ImmichStack extends Stack { + constructor(props: ImmichStackOptions) { + super(props.stackName ?? "immich"); - // Create default credentials if not provided - props.postgres ??= { - password: "postgres", - username: "postgres", - database: "postgres", - }; + const redis = this.addService("redis", { + image: "registry.hub.docker.com/library/redis:6.2-alpine", + restart: "unless-stopped", + }); - const database = new Service("database", { - image: "registry.hub.docker.com/tensorchord/pgvecto-rs:pg14-v0.2.0", - restart: "unless-stopped", - environment: { - POSTGRES_USER: props.postgres.username, - POSTGRES_PASSWORD: props.postgres.password, - POSTGRES_DB: props.postgres.database, - }, - // todo volumes - }); + // Create default credentials if not provided + props.postgres ??= { + password: "postgres", + username: "postgres", + database: "postgres", + }; - const immichEnv = { - DB_HOSTNAME: database.name, - DB_USERNAME: props.postgres.username, - DB_PASSWORD: props.postgres.password, - DB_DATABASE_NAME: props.postgres.database, - REDIS_HOSTNAME: redis.name, - }; + const database = this.addService("database", { + image: "registry.hub.docker.com/tensorchord/pgvecto-rs:pg14-v0.2.0", + restart: "unless-stopped", + environment: { + POSTGRES_USER: props.postgres.username, + POSTGRES_PASSWORD: props.postgres.password, + POSTGRES_DB: props.postgres.database, + }, + // todo volumes + }); - const immichServer = new Service("immich-server", { - image: `ghcr.io/immich-app/immich-server:${ - props.immichVersion ?? "release" - }`, - restart: "unless-stopped", - command: ["start.sh", "immich"], - depends_on: [database.name, redis.name], - // todo volumes - environment: immichEnv, - ports: ["2283:3001"], - }); + const immichEnv = { + DB_HOSTNAME: database.name, + DB_USERNAME: props.postgres.username, + DB_PASSWORD: props.postgres.password, + DB_DATABASE_NAME: props.postgres.database, + REDIS_HOSTNAME: redis.name, + }; - const immichMicroservices = new Service("immich-microservices", { - image: `ghcr.io/immich-app/immich-server:${ - props.immichVersion ?? "release" - }`, - restart: "unless-stopped", - command: ["start.sh", "microservices"], - depends_on: [database.name, redis.name], - // todo volumes - environment: immichEnv, - }); + const immichServer = this.addService("immich-server", { + image: `ghcr.io/immich-app/immich-server:${ + props.immichVersion ?? "release" + }`, + restart: "unless-stopped", + command: ["start.sh", "immich"], + depends_on: [database.name, redis.name], + // todo volumes + environment: immichEnv, + ports: ["2283:3001"], + }); - const immichMachineLearning = new Service("immich-machine-learning", { - image: `ghcr.io/immich-app/immich-machine-learning:${ - props.immichVersion ?? "release" - }`, - // todo volumes - environment: immichEnv, - }); + const immichMicroservices = this.addService("immich-microservices", { + image: `ghcr.io/immich-app/immich-server:${ + props.immichVersion ?? "release" + }`, + restart: "unless-stopped", + command: ["start.sh", "microservices"], + depends_on: [database.name, redis.name], + // todo volumes + environment: immichEnv, + }); - return new Stack(props.stackName ?? "immich", { - services: [ - redis, - database, - immichServer, - immichMicroservices, - immichMachineLearning, - ], - }); + const immichMachineLearning = this.addService("immich-machine-learning", { + image: `ghcr.io/immich-app/immich-machine-learning:${ + props.immichVersion ?? "release" + }`, + // todo volumes + environment: immichEnv, + }); + } } -const stack = immichStack({ immichVersion: "v1.100.0" }); - -deploySingle(stack); +const stack = new ImmichStack({ immichVersion: "v1.100.0" }); diff --git a/mod.ts b/mod.ts index 2f043de..db84154 100644 --- a/mod.ts +++ b/mod.ts @@ -1,2 +1 @@ export * from "./src/components/mod.ts"; -export * from "./src/deployment.ts"; diff --git a/src/components/mod.ts b/src/components/mod.ts index a17ee57..a6b2e71 100644 --- a/src/components/mod.ts +++ b/src/components/mod.ts @@ -1,2 +1 @@ export * from "./stack.ts"; -export * from "./service.ts"; diff --git a/src/components/stack.ts b/src/components/stack.ts index f82fc5d..7d81433 100644 --- a/src/components/stack.ts +++ b/src/components/stack.ts @@ -1,19 +1,28 @@ -import { ComposeSpecification } from "../compose-schema.ts"; +import { ComposeSpecification, DefinitionsService } from "../compose-schema.ts"; +import { registerDeployment } from "../deployment.ts"; import { Service } from "./service.ts"; -interface StackOptions { - services: Service[]; -} - export class Stack { - constructor(public name: string, public options: StackOptions) {} + private services: Record = {}; + + constructor(public name: string) { + registerDeployment(this); + } + + public addService(name: string, service: DefinitionsService): Service { + if (this.services[name]) { + throw new Error(`Service ${name} already defined.`); + } + this.services[name] = new Service(name, service); + + return this.services[name]; + } public toComposeFile(): ComposeSpecification { - const services: ComposeSpecification["services"] = {}; - for (const service of this.options.services) { - services[service.name] = service.options; + const services: Record = {}; + for (const [name, service] of Object.entries(this.services)) { + services[name] = service.options; } - return { version: "3.8", services, diff --git a/src/deployment.ts b/src/deployment.ts index 273607d..615ad4b 100644 --- a/src/deployment.ts +++ b/src/deployment.ts @@ -1,22 +1,16 @@ import { Stack } from "./components/mod.ts"; import { ComposeSpecification } from "./compose-schema.ts"; -const deployments: Record = {}; -let printDeployments = false; +const deployments: Stack[] = []; -export function deploy(stack: Stack) { - deployments[stack.name] = stack.toComposeFile(); - printDeployments = true; -} - -export function deploySingle(stack: Stack) { - console.log(JSON.stringify(stack.toComposeFile(), null, 2)); +export function registerDeployment(stack: Stack) { + deployments.push(stack); } globalThis.addEventListener("unload", () => { - if (!printDeployments) { - return; + const stacks: Record = {}; + for (const stack of deployments) { + stacks[stack.name] = stack.toComposeFile(); } - // Print deployments - console.log(JSON.stringify(deployments, null, 2)); + console.log(JSON.stringify(stacks, null, 2)); });