diff --git a/Dockerfile b/Dockerfile index 812d62c..7e99468 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,12 @@ -FROM oven/bun:1.0.15-alpine +FROM oven/bun:1.0.15-alpine as builder WORKDIR /app COPY package.json . COPY bun.lockb . RUN bun i COPY . . -ENTRYPOINT ["bun", "run", "src/index.ts"] +RUN bun build ./src/index.ts --target bun --outdir ./build + +FROM oven/bun:1.0.15-alpine +WORKDIR /app +COPY --from=builder /app/build/index.js /app/index.js +ENTRYPOINT ["bun", "run", "index.js"] diff --git a/bun.lockb b/bun.lockb index 4a896d8..cebe52d 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/docker-compose.yaml b/docker-compose.yaml index ac4cc32..eb27655 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,11 +1,11 @@ version: "3.7" services: - # consumer: - # build: . - # command: watch -d 2023-12-15 -i 5 -f JB - # volumes: - # - ./config:/app/config + consumer: + build: . + command: watch -d 28-12-2023 -i 5 -f JToW + volumes: + - ./config:/app/config redis: image: docker.dragonflydb.io/dragonflydb/dragonfly ports: diff --git a/package.json b/package.json index 49f7b13..25119bf 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "commander": "^11.1.0", - "core-js": "^3.34.0", "fetch-cookie": "^2.1.0", "ioredis": "^5.3.2", "js-yaml": "^4.1.0", @@ -36,8 +35,7 @@ "pino": "^8.16.2", "pino-pretty": "^10.2.3", "query-string": "^8.1.0", - "reflect-metadata": "^0.1.14", - "ts-node": "^10.9.2", - "tsyringe": "^4.8.0" + "reflect-metadata": "^0.2.1", + "ts-node": "^10.9.2" } } diff --git a/src/cli/cli.ts b/src/cli/cli.ts index 85bf164..d6a5356 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -1,20 +1,15 @@ -import { autoInjectable, inject } from "tsyringe"; import { program } from "commander"; import { SearcherBuilder } from "../domain/searcher/builder.ts"; -import { svc } from "../system/constants.ts"; import type { Logger } from "pino"; import { trace } from "@opentelemetry/api"; import { RootConfig } from "../config/root.config.ts"; import Redis from "ioredis"; -@autoInjectable() class Cli { constructor( private readonly builder: SearcherBuilder, - @inject(svc.Logger) private readonly logger: Logger, private readonly cfg: RootConfig, - @inject(svc.livecache) private readonly redis: Redis, ) {} @@ -50,6 +45,7 @@ class Cli { }) => { await tracer.startActiveSpan("watch", async (span) => { const [day, month, year] = date.split("-"); + const originalDate = date; date = `${year}-${month}-${day}`; const d = new Date(date); const i = parseInt(interval); @@ -81,10 +77,8 @@ class Cli { const sch = await a.Search(); const timing: Record = {}; for (const s of sch) timing[s.departure_time] = s.available_seats; - const cmd = await this.redis.publish( - `ktmb:schedule:${from}:${date}`, - JSON.stringify(timing), - ); + const key = `ktmb:schedule:${from}:${originalDate}`; + const _ = await this.redis.publish(key, JSON.stringify(timing)); } this.logger.info({ index: index++ }, "Watch complete"); span.end(); diff --git a/src/domain/search_core.ts b/src/domain/search_core.ts index cbb5a3c..f39e75b 100644 --- a/src/domain/search_core.ts +++ b/src/domain/search_core.ts @@ -4,7 +4,6 @@ import * as cheerio from "cheerio"; import { From, TrainSchedule } from "./interface.ts"; import { stringify } from "querystring"; import moment from "moment"; -import { autoInjectable } from "tsyringe"; const fetch = fetchCookie(nodeFetch); @@ -61,7 +60,6 @@ interface TrainScheduleResp { data: string; } -@autoInjectable() class SearchCore { async mainKTMBPage(): Promise { const referer = "https://online.ktmb.com.my/"; diff --git a/src/domain/searcher/builder.ts b/src/domain/searcher/builder.ts index 4906c04..c01b182 100644 --- a/src/domain/searcher/builder.ts +++ b/src/domain/searcher/builder.ts @@ -7,9 +7,7 @@ import { import { StatelessScheduleSearcher } from "./stateless_schedule_searcher.ts"; import { LoadedScheduleSearcher } from "./loaded_schedule_searcher.ts"; import { FixedScheduleSearcher } from "./fixed_schedule_searcher.ts"; -import { autoInjectable } from "tsyringe"; -@autoInjectable() class SearcherBuilder { constructor(private readonly searchCore: SearchCore) {} diff --git a/src/index.ts b/src/index.ts index c2a1ce9..b9408c9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,14 +1,12 @@ -import "core-js"; import "reflect-metadata"; -import { container } from "tsyringe"; import { Cli } from "./cli/cli.ts"; -import { svc } from "./system/constants.ts"; - import { RootConfig } from "./config/root.config"; import { ConfigLoader } from "./system/loader.ts"; import { OtelService } from "./system/tracing.ts"; -import Redis, { RedisOptions } from "ioredis"; +import { loadRedis } from "./load-redis.ts"; +import { SearcherBuilder } from "./domain/searcher/builder.ts"; +import { SearchCore } from "./domain/search_core.ts"; // start up that cannot use DI const landscape = process.env.LANDSCAPE; @@ -23,33 +21,10 @@ const otel = new OtelService(cfg); const logger = await otel.start(); // Start DI -cfg.cache.forEach((v, k) => { - const endpoint = v.endpoints.get("0")!; - - const [host, port] = endpoint.split(":") as [string, string]; - - const o: RedisOptions = { - name: k, - host, - db: 0, - port: parseInt(port), - autoResubscribe: v.autoResubscribe, - commandTimeout: v.commandTimeout, - connectTimeout: v.connectTimeout, - enableAutoPipelining: v.enableAutoPipelining, - keyPrefix: v.keyPrefix, - readOnly: v.readOnly, - password: v.password, - }; - - if (v.tls) o.tls = {}; - - const redis = new Redis(o); - container.register(svc[k + "cache"], { useValue: redis }); -}); -container.register(RootConfig, { useValue: cfg }); -container.register(svc.Logger, { useValue: logger }); +const caches = loadRedis(cfg); +const searchCore = new SearchCore(); +const searchBuilder = new SearcherBuilder(searchCore); -const cli = container.resolve(Cli); +const cli = new Cli(searchBuilder, logger, cfg, caches.get("live")!); await cli.start(); diff --git a/src/load-redis.ts b/src/load-redis.ts new file mode 100644 index 0000000..8736c67 --- /dev/null +++ b/src/load-redis.ts @@ -0,0 +1,32 @@ +import Redis, { RedisOptions } from "ioredis"; +import { RootConfig } from "./config/root.config.ts"; + +const loadRedis = (config: RootConfig): Map => { + return new Map( + [...config.cache.entries()].map(([k, v]) => { + const endpoint = v.endpoints.get("0")!; + const [host, port] = endpoint.split(":") as [string, string]; + + const o: RedisOptions = { + name: k, + host, + db: 0, + port: parseInt(port), + autoResubscribe: v.autoResubscribe, + commandTimeout: v.commandTimeout, + connectTimeout: v.connectTimeout, + enableAutoPipelining: v.enableAutoPipelining, + keyPrefix: v.keyPrefix, + readOnly: v.readOnly, + password: v.password, + }; + + if (v.tls) o.tls = {}; + + const redis = new Redis(o); + return [k, redis]; + }), + ); +}; + +export { loadRedis };