From fd0081d4d0b8f7d57eb343b8a110707bacb82fda Mon Sep 17 00:00:00 2001 From: chiko Date: Mon, 20 Oct 2025 23:12:38 +0200 Subject: [PATCH 01/13] Fixed dockerfile, added a docker-compose.yml, added db init function to run on every startup --- Crontab | 2 ++ Dockerfile | 13 +++++++++---- docker-compose.yml | 5 +++++ package.json | 3 ++- src/app.ts | 2 +- src/sendNotification.ts | 10 ++++++---- src/sql.ts | 4 +++- 7 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 Crontab create mode 100644 docker-compose.yml diff --git a/Crontab b/Crontab new file mode 100644 index 0000000..b6ea5bc --- /dev/null +++ b/Crontab @@ -0,0 +1,2 @@ +0 8 * * * bun run ./src/app.ts --today > /dev/null 2>&1 +0 * * * * bun run ./src/app.ts > /dev/null 2>&1 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index c4a8a55..775a558 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM debian:12 AS base WORKDIR /opt/app RUN apt-get update && \ - apt-get install -y curl unzip ca-certificates python3 python3-pip && \ + apt-get install -y curl unzip cron ca-certificates python3 python3-pip && \ rm -rf /var/lib/apt/lists/* # install BunJs RUN curl -fsSL https://bun.com/install | bash @@ -38,7 +38,12 @@ FROM base AS release COPY --from=install /temp/prod/node_modules node_modules COPY --from=prerelease /opt/app/src/app.ts . COPY --from=prerelease /opt/app/package.json . +COPY --from=prerelease /opt/app/entrypoint.sh . +COPY Crontab /etc/cron.d/ +RUN chmod 0644 /etc/cron.d/Crontab +# USER bun +RUN touch /var/log/cron.log +# RUN chmod +x entrypoint.sh +# ENTRYPOINT ["./entrypoint.sh"] VOLUME ["/opt/app/data/db"] -# run the app -USER bun -ENTRYPOINT ["./entrypoint.sh"] \ No newline at end of file +CMD cron && tail -f /var/log/cron.log \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..67e3b70 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,5 @@ +services: + app: + build: . + volumes: + - ./data/db:./data/db \ No newline at end of file diff --git a/package.json b/package.json index 32b5b91..434a70f 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "dev:init": "bun run ./src/app.ts --init", "db:init": "bun run ./run/db_init.ts", "db:deleteall": "bun run ./run/db_deleteall.ts", - "build": "bun build ./src/app.ts --compile --outfile ./build/77th_event_calendar_notification", + "build": "bun build --compile --minify --sourcemap ./src/app.ts --outfile ./build/77th_event_calendar_notification", + "build:linux": "bun build --compile --minify --sourcemap --target=bun-linux-arm64 ./src/app.ts --outfile ./build/77th_event_calendar_notification", "docker:build": "docker build -t chiko/77th_eventcalendarntfy:0.1.0 ." }, "peerDependencies": { diff --git a/src/app.ts b/src/app.ts index 70c6df5..db8a048 100644 --- a/src/app.ts +++ b/src/app.ts @@ -112,7 +112,7 @@ async function main( ) { } return false; })( ev ); - sendNotification( + await sendNotification( `${today_prefix ? "TODAY " : ""}${notification_prefix ? notification_prefix + ": " : ""} ${ev.title} (${ TEventType[ ev.event_type ] })`, `${body}` // `${ev.link || "https://77th-jsoc.com/#/events"}` diff --git a/src/sendNotification.ts b/src/sendNotification.ts index cb0a754..3792745 100644 --- a/src/sendNotification.ts +++ b/src/sendNotification.ts @@ -1,14 +1,16 @@ import * as Bun from "bun"; -export function sendNotification(title: string, body: string, click?: string | null) { +export async function sendNotification(title: string, body: string, click?: string | null) { const command = [ "python", - "./app/notification.py", + "./src/notification.py", `--title=${title}`, `--body=${body}`, ]; - if (click) { + if ( click ) { command.push(`--click=${click}`); } - Bun.spawn(command); + const proc = Bun.spawn(command); + const text = await proc.stdout.text(); + console.log("sendNotification: " + text); } diff --git a/src/sql.ts b/src/sql.ts index 04be71c..6d55878 100644 --- a/src/sql.ts +++ b/src/sql.ts @@ -10,4 +10,6 @@ export const db = new Database(db_filepath); export function init () { Event.createTable(db); -} \ No newline at end of file +} + +init(); \ No newline at end of file From 877d9e37b3f07c0947f9ba728a6e487c5ed38e11 Mon Sep 17 00:00:00 2001 From: chiko Date: Mon, 20 Oct 2025 23:16:35 +0200 Subject: [PATCH 02/13] Udpated Dockerfile, changed Crontab for testing purposes --- Crontab | 2 +- Dockerfile | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Crontab b/Crontab index b6ea5bc..c1dd39e 100644 --- a/Crontab +++ b/Crontab @@ -1,2 +1,2 @@ -0 8 * * * bun run ./src/app.ts --today > /dev/null 2>&1 +1 * * * * bun run ./src/app.ts --today > /dev/null 2>&1 0 * * * * bun run ./src/app.ts > /dev/null 2>&1 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 775a558..4de43a6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,22 +28,24 @@ RUN cd /temp/prod && bun install --frozen-lockfile --production # then copy all (non-ignored) project files into the image FROM base AS prerelease COPY --from=install /temp/dev/node_modules node_modules -COPY . . +COPY . ./ # [optional] tests & build ENV NODE_ENV=production # copy production dependencies and source code into final image FROM base AS release +WORKDIR /opt/app COPY --from=install /temp/prod/node_modules node_modules COPY --from=prerelease /opt/app/src/app.ts . COPY --from=prerelease /opt/app/package.json . -COPY --from=prerelease /opt/app/entrypoint.sh . +#COPY --from=prerelease .entrypoint.sh . COPY Crontab /etc/cron.d/ RUN chmod 0644 /etc/cron.d/Crontab +COPY . ./ # USER bun RUN touch /var/log/cron.log # RUN chmod +x entrypoint.sh # ENTRYPOINT ["./entrypoint.sh"] VOLUME ["/opt/app/data/db"] -CMD cron && tail -f /var/log/cron.log \ No newline at end of file +CMD bun run ./src/app.ts --today && cron && tail -f /var/log/cron.log \ No newline at end of file From 3167bd7976b8363a56cac367cb739104c127ba73 Mon Sep 17 00:00:00 2001 From: chiko Date: Mon, 20 Oct 2025 23:24:56 +0200 Subject: [PATCH 03/13] added dotenv as python dependency --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 356ca44..eb8f961 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -apprise \ No newline at end of file +apprise +dotenv \ No newline at end of file From 66212229f5a27636412652e01751bb1ab1193a87 Mon Sep 17 00:00:00 2001 From: chiko Date: Mon, 20 Oct 2025 23:48:31 +0200 Subject: [PATCH 04/13] fixed python dependency and Dockerfile Volume Bind --- Dockerfile | 2 +- docker-compose.yml | 2 +- requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4de43a6..12c0164 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,5 +47,5 @@ COPY . ./ RUN touch /var/log/cron.log # RUN chmod +x entrypoint.sh # ENTRYPOINT ["./entrypoint.sh"] -VOLUME ["/opt/app/data/db"] +VOLUME /opt/app/data/db CMD bun run ./src/app.ts --today && cron && tail -f /var/log/cron.log \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 67e3b70..2570df8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,4 +2,4 @@ services: app: build: . volumes: - - ./data/db:./data/db \ No newline at end of file + - ./data/db:/opt/app/data/db \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index eb8f961..b4d8f3e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ apprise -dotenv \ No newline at end of file +python-dotenv \ No newline at end of file From 714738dcbaa88be4316912d543e04b968d275658 Mon Sep 17 00:00:00 2001 From: chiko Date: Tue, 21 Oct 2025 01:16:59 +0200 Subject: [PATCH 05/13] Fixing python... --- Dockerfile | 7 ++--- src/notification.py | 64 ++++++++++++++++++++++------------------- src/sendNotification.ts | 2 +- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Dockerfile b/Dockerfile index 12c0164..06f59b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,12 @@ FROM debian:12 AS base WORKDIR /opt/app +ENV PYTHONPATH=/app RUN apt-get update && \ apt-get install -y curl unzip cron ca-certificates python3 python3-pip && \ rm -rf /var/lib/apt/lists/* # install BunJs RUN curl -fsSL https://bun.com/install | bash ENV PATH="/root/.bun/bin:$PATH" -# symlink python3 to python -RUN ln -s /usr/bin/python3 /usr/bin/python # install dependencies into temp directory # this will cache them and speed up future builds @@ -17,8 +16,8 @@ COPY package.json bun.lock /temp/dev/ RUN cd /temp/dev && bun install --frozen-lockfile # and install python dependencies COPY ./requirements.txt . -RUN pip3 install --break-system-packages -r ./requirements.txt - +RUN python3 -m pip install -r requirements.txt +# RUN python3 -m pip install -U python-dotenv # install with --production (exclude devDependencies) RUN mkdir -p /temp/prod COPY package.json bun.lock /temp/prod/ diff --git a/src/notification.py b/src/notification.py index cda75a9..13a3dfb 100644 --- a/src/notification.py +++ b/src/notification.py @@ -1,37 +1,41 @@ from dotenv import load_dotenv import os -load_dotenv() # Load environment variables from .env file -ntfy_username = os.getenv('ntfy_username') -ntfy_password = os.getenv('ntfy_password') -ntfy_host = os.getenv('ntfy_host') -ntfy_topic = os.getenv('ntfy_topic') -dc_webhook = os.getenv('dc_webhook') -dc_botname = os.getenv('dc_botname') -dc_avatar_url = os.getenv('dc_avatar_url') +def main(): + load_dotenv() # Load environment variables from .env file + ntfy_username = os.getenv('ntfy_username') + ntfy_password = os.getenv('ntfy_password') + ntfy_host = os.getenv('ntfy_host') + ntfy_topic = os.getenv('ntfy_topic') + dc_webhook = os.getenv('dc_webhook') + dc_botname = os.getenv('dc_botname') + dc_avatar_url = os.getenv('dc_avatar_url') -from argparse import ArgumentParser -import apprise + from argparse import ArgumentParser + import apprise -parser = ArgumentParser() -parser.add_argument("--title") -parser.add_argument("--body") -parser.add_argument("--click") -args = parser.parse_args() -print(args) + parser = ArgumentParser() + parser.add_argument("--title") + parser.add_argument("--body") + parser.add_argument("--click") + args = parser.parse_args() + print(args) -apobj = apprise.Apprise() -# config = apprise.AppriseConfig() -# config.add('https://myserver:8080/path/to/config') -if ntfy_host and ntfy_topic: - ntfy_link = f"ntfys://{ntfy_username}:{ntfy_password}@{ntfy_host}/{ntfy_topic}" - if args.click: - ntfy_link = ntfy_link + "?click=" + args.click - apobj.add(ntfy_link) -if dc_webhook: - apobj.add(f"discord://{dc_webhook}?avatar_url={dc_avatar_url}&botname={dc_botname}"); + apobj = apprise.Apprise() + # config = apprise.AppriseConfig() + # config.add('https://myserver:8080/path/to/config') + if ntfy_host and ntfy_topic: + ntfy_link = f"ntfys://{ntfy_username}:{ntfy_password}@{ntfy_host}/{ntfy_topic}" + if args.click: + ntfy_link = ntfy_link + "?click=" + args.click + apobj.add(ntfy_link) + if dc_webhook: + apobj.add(f"discord://{dc_webhook}?avatar_url={dc_avatar_url}&botname={dc_botname}"); -apobj.notify( - body=args.body, - title=args.title -) \ No newline at end of file + apobj.notify( + body=args.body, + title=args.title + ) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/src/sendNotification.ts b/src/sendNotification.ts index 3792745..639ff21 100644 --- a/src/sendNotification.ts +++ b/src/sendNotification.ts @@ -2,7 +2,7 @@ import * as Bun from "bun"; export async function sendNotification(title: string, body: string, click?: string | null) { const command = [ - "python", + "python3", "./src/notification.py", `--title=${title}`, `--body=${body}`, From 156a2db485f6e679a821ad34965c026e15e13472 Mon Sep 17 00:00:00 2001 From: chiko Date: Tue, 21 Oct 2025 01:21:39 +0200 Subject: [PATCH 06/13] fixing docker file --- Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 06f59b1..1c38a6d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,6 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* # install BunJs RUN curl -fsSL https://bun.com/install | bash -ENV PATH="/root/.bun/bin:$PATH" # install dependencies into temp directory # this will cache them and speed up future builds @@ -16,7 +15,7 @@ COPY package.json bun.lock /temp/dev/ RUN cd /temp/dev && bun install --frozen-lockfile # and install python dependencies COPY ./requirements.txt . -RUN python3 -m pip install -r requirements.txt +RUN python3 -m pip install --break-system-packages -r requirements.txt # RUN python3 -m pip install -U python-dotenv # install with --production (exclude devDependencies) RUN mkdir -p /temp/prod From 1bf297752d8ea42e11e45e8cb892d6d3606e16a0 Mon Sep 17 00:00:00 2001 From: chiko Date: Tue, 21 Oct 2025 01:23:41 +0200 Subject: [PATCH 07/13] more dockerfile fixing --- Dockerfile | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1c38a6d..f5c1d1e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,5 @@ FROM debian:12 AS base WORKDIR /opt/app -ENV PYTHONPATH=/app RUN apt-get update && \ apt-get install -y curl unzip cron ca-certificates python3 python3-pip && \ rm -rf /var/lib/apt/lists/* @@ -13,15 +12,17 @@ FROM base AS install RUN mkdir -p /temp/dev COPY package.json bun.lock /temp/dev/ RUN cd /temp/dev && bun install --frozen-lockfile -# and install python dependencies -COPY ./requirements.txt . -RUN python3 -m pip install --break-system-packages -r requirements.txt -# RUN python3 -m pip install -U python-dotenv + # install with --production (exclude devDependencies) RUN mkdir -p /temp/prod COPY package.json bun.lock /temp/prod/ RUN cd /temp/prod && bun install --frozen-lockfile --production +# and install python dependencies +COPY ./requirements.txt . +RUN python3 -m pip install --break-system-packages -r requirements.txt +# RUN python3 -m pip install -U python-dotenv + # copy node_modules from temp directory # then copy all (non-ignored) project files into the image FROM base AS prerelease From 92a2c6956a74ed96d3bb971518d60594645b053f Mon Sep 17 00:00:00 2001 From: chiko Date: Tue, 21 Oct 2025 01:26:18 +0200 Subject: [PATCH 08/13] forgot the ENV for bun --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index f5c1d1e..44e3e8f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* # install BunJs RUN curl -fsSL https://bun.com/install | bash - +ENV PATH="/root/.bun/bin:$PATH" # install dependencies into temp directory # this will cache them and speed up future builds FROM base AS install From 457a49e75474509ae78e0ed8943d323d01c1465d Mon Sep 17 00:00:00 2001 From: chiko Date: Tue, 21 Oct 2025 02:22:51 +0200 Subject: [PATCH 09/13] fuck python, switching to apprise-api as a docker container --- Dockerfile | 5 +++-- docker-compose.yml | 19 ++++++++++++++++++- src/app.ts | 28 +++++++++++++++++++++++----- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 44e3e8f..19ef720 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM debian:12 AS base WORKDIR /opt/app RUN apt-get update && \ + # apt-get install -y curl unzip cron ca-certificates python3 python3-pip && \ apt-get install -y curl unzip cron ca-certificates python3 python3-pip && \ rm -rf /var/lib/apt/lists/* # install BunJs @@ -19,8 +20,8 @@ COPY package.json bun.lock /temp/prod/ RUN cd /temp/prod && bun install --frozen-lockfile --production # and install python dependencies -COPY ./requirements.txt . -RUN python3 -m pip install --break-system-packages -r requirements.txt +# COPY ./requirements.txt . +# RUN python3 -m pip install --break-system-packages -r requirements.txt # RUN python3 -m pip install -U python-dotenv # copy node_modules from temp directory diff --git a/docker-compose.yml b/docker-compose.yml index 2570df8..2b45635 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,4 +2,21 @@ services: app: build: . volumes: - - ./data/db:/opt/app/data/db \ No newline at end of file + - ./data/db:/opt/app/data/db + apprise: + image: caronc/apprise:latest + environment: + - APPRISE_WORKER_COUNT=1 + - APPRISE_STATEFUL_MODE=simple + - PUID=$(id -u) + - PGID=$(id -g) + volumes: + - ./data/apprise/config:/config + - ./data/apprise/plugin:/plugin + - ./data/apprise/attach:/attach + ports: + - 8000:8000 +networks: + default: + external: true + name: npm \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index db8a048..384df25 100644 --- a/src/app.ts +++ b/src/app.ts @@ -112,11 +112,29 @@ async function main( ) { } return false; })( ev ); - await sendNotification( - `${today_prefix ? "TODAY " : ""}${notification_prefix ? notification_prefix + ": " : ""} ${ev.title} (${ TEventType[ ev.event_type ] })`, - `${body}` - // `${ev.link || "https://77th-jsoc.com/#/events"}` - ); + const title = `${today_prefix ? "TODAY " : ""}${notification_prefix ? notification_prefix + ": " : ""} ${ev.title} (${ TEventType[ ev.event_type ] })`; + + await fetch("http://localhost:8000/notify", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + urls: [ + `ntfys://${process.env.ntfy_username}:${process.env.ntfy_password}@${process.env.ntfy_host}/${process.env.ntfy_topic}${ ev.link ? `?click=${ev.link}`: "?click=https://77th-jsoc.com/#/events" }`, + `discord://${process.env.dc_webhook}?avatar_url=${process.env.dc_avatar_url}&botname=${process.env.dc_botname}` + ].join(","), + title: title, + body: body, + format: "text" + }) + }); + + // await sendNotification( + // title, + // body + // // `${ev.link || "https://77th-jsoc.com/#/events"}` + // ); ev.set_notification("done", db); } }; From de11a6934c310f998751763fec263f377d347e66 Mon Sep 17 00:00:00 2001 From: chiko Date: Tue, 21 Oct 2025 02:29:54 +0200 Subject: [PATCH 10/13] fixing docker-compose.yml --- docker-compose.yml | 9 ++++++--- src/app.ts | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2b45635..132d01a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,15 +1,18 @@ services: - app: + app: build: . volumes: - ./data/db:/opt/app/data/db + depends_on: + - apprise apprise: image: caronc/apprise:latest + hostname: apprise environment: - APPRISE_WORKER_COUNT=1 - APPRISE_STATEFUL_MODE=simple - - PUID=$(id -u) - - PGID=$(id -g) + # - PUID=$(id -u) + # - PGID=$(id -g) volumes: - ./data/apprise/config:/config - ./data/apprise/plugin:/plugin diff --git a/src/app.ts b/src/app.ts index 384df25..86f295e 100644 --- a/src/app.ts +++ b/src/app.ts @@ -114,7 +114,7 @@ async function main( ) { })( ev ); const title = `${today_prefix ? "TODAY " : ""}${notification_prefix ? notification_prefix + ": " : ""} ${ev.title} (${ TEventType[ ev.event_type ] })`; - await fetch("http://localhost:8000/notify", { + await fetch("http://apprise:8000/notify", { method: "POST", headers: { "Content-Type": "application/json" From 5f735dce6a06ef27871081047eaa07c9dcfa4144 Mon Sep 17 00:00:00 2001 From: chiko Date: Tue, 21 Oct 2025 02:35:59 +0200 Subject: [PATCH 11/13] container healthchecks.. --- docker-compose.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 132d01a..b4111ef 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,9 @@ services: volumes: - ./data/db:/opt/app/data/db depends_on: + apprise: + condition: service_healthy + links: - apprise apprise: image: caronc/apprise:latest @@ -19,7 +22,12 @@ services: - ./data/apprise/attach:/attach ports: - 8000:8000 -networks: - default: - external: true - name: npm \ No newline at end of file + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/status"] + interval: 30s + timeout: 10s + retries: 5 +# networks: +# default: +# external: true +# name: npm \ No newline at end of file From 8c5d6de5a44e274832e3344d15a15c6549219927 Mon Sep 17 00:00:00 2001 From: chiko Date: Tue, 21 Oct 2025 02:47:36 +0200 Subject: [PATCH 12/13] fixed not loading the env file for docker --- docker-compose.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index b4111ef..a0fca37 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,9 @@ services: build: . volumes: - ./data/db:/opt/app/data/db + env_file: + - path: ./.env + required: true depends_on: apprise: condition: service_healthy From 1729332373fb259b075ba31050e22eb5e90d961d Mon Sep 17 00:00:00 2001 From: chiko Date: Tue, 21 Oct 2025 23:34:50 +0200 Subject: [PATCH 13/13] removed Python and the Python Script, added the apprise-api docker container to the Docker-compose to send notificaiton --- .gitignore | 1 + Crontab | 2 - Dockerfile | 42 ++++++++++++--------- docker-compose.yml | 9 +++-- docker/Crontab | 2 + docker/cron-bun-log | 8 ++++ entrypoint.sh | 6 --- requirements.txt | 2 - src/app.ts | 79 +++++++++++++++------------------------ src/sendNotification.ts | 40 ++++++++++++-------- src/sendNotificationPy.ts | 16 ++++++++ src/util.ts | 12 ++++++ 12 files changed, 125 insertions(+), 94 deletions(-) delete mode 100644 Crontab create mode 100644 docker/Crontab create mode 100644 docker/cron-bun-log delete mode 100644 entrypoint.sh delete mode 100644 requirements.txt create mode 100644 src/sendNotificationPy.ts diff --git a/.gitignore b/.gitignore index 398a986..5d4c927 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json *.db *.sqlite +data \ No newline at end of file diff --git a/Crontab b/Crontab deleted file mode 100644 index c1dd39e..0000000 --- a/Crontab +++ /dev/null @@ -1,2 +0,0 @@ -1 * * * * bun run ./src/app.ts --today > /dev/null 2>&1 -0 * * * * bun run ./src/app.ts > /dev/null 2>&1 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 19ef720..d23c855 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,24 @@ FROM debian:12 AS base +ARG BUILD_DATE +ARG VERSION +LABEL build_version="77th_eventcalendarntfy ${VERSION}, Build-date:- ${BUILD_DATE}" +LABEL maintainer="chiko " WORKDIR /opt/app -RUN apt-get update && \ - # apt-get install -y curl unzip cron ca-certificates python3 python3-pip && \ - apt-get install -y curl unzip cron ca-certificates python3 python3-pip && \ - rm -rf /var/lib/apt/lists/* +RUN set -eux && \ + echo "Updating APT" && \ + apt-get update -y -qq && \ + apt-get upgrade -y -qq && \ + echo "Installing tools" && \ + apt-get install -y -qq \ + curl unzip cron ca-certificates logrotate && \ + echo "Cleaning up" && \ + apt-get --yes autoremove --purge && \ + apt-get clean --yes && \ + rm --recursive --force --verbose /var/lib/apt/lists/* && \ + rm --recursive --force --verbose /tmp/* && \ + rm --recursive --force --verbose /var/tmp/* && \ + rm --recursive --force --verbose /var/cache/apt/archives/* && \ + truncate --size 0 /var/log/*log # install BunJs RUN curl -fsSL https://bun.com/install | bash ENV PATH="/root/.bun/bin:$PATH" @@ -19,33 +34,26 @@ RUN mkdir -p /temp/prod COPY package.json bun.lock /temp/prod/ RUN cd /temp/prod && bun install --frozen-lockfile --production -# and install python dependencies -# COPY ./requirements.txt . -# RUN python3 -m pip install --break-system-packages -r requirements.txt -# RUN python3 -m pip install -U python-dotenv +COPY ./docker/Crontab /etc/cron.d/ +RUN chmod 0644 /etc/cron.d/Crontab +COPY ./docker/cron-bun-log /etc/logrotate.d/ +RUN mkdir /var/log/cron && touch /var/log/cron.log # copy node_modules from temp directory # then copy all (non-ignored) project files into the image FROM base AS prerelease COPY --from=install /temp/dev/node_modules node_modules COPY . ./ - # [optional] tests & build ENV NODE_ENV=production # copy production dependencies and source code into final image FROM base AS release -WORKDIR /opt/app COPY --from=install /temp/prod/node_modules node_modules -COPY --from=prerelease /opt/app/src/app.ts . COPY --from=prerelease /opt/app/package.json . #COPY --from=prerelease .entrypoint.sh . -COPY Crontab /etc/cron.d/ -RUN chmod 0644 /etc/cron.d/Crontab COPY . ./ -# USER bun -RUN touch /var/log/cron.log -# RUN chmod +x entrypoint.sh -# ENTRYPOINT ["./entrypoint.sh"] +RUN mkdir /var/log/cron && touch /var/log/cron.log VOLUME /opt/app/data/db +# VOLUME /var/log/cron CMD bun run ./src/app.ts --today && cron && tail -f /var/log/cron.log \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index a0fca37..ebcd829 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,7 @@ services: build: . volumes: - ./data/db:/opt/app/data/db + - ./data/app/log:/var/log env_file: - path: ./.env required: true @@ -23,12 +24,12 @@ services: - ./data/apprise/config:/config - ./data/apprise/plugin:/plugin - ./data/apprise/attach:/attach - ports: - - 8000:8000 + # ports: + #- 8880:8000 healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/status"] - interval: 30s - timeout: 10s + interval: 10s + timeout: 5s retries: 5 # networks: # default: diff --git a/docker/Crontab b/docker/Crontab new file mode 100644 index 0000000..0eee489 --- /dev/null +++ b/docker/Crontab @@ -0,0 +1,2 @@ +8 * * * * bun run ./src/app.ts --today > /var/log/cron.log 2>&1 +*/15 * * * * bun run ./src/app.ts > /var/log/cron.log 2>&1 \ No newline at end of file diff --git a/docker/cron-bun-log b/docker/cron-bun-log new file mode 100644 index 0000000..a5f9fb4 --- /dev/null +++ b/docker/cron-bun-log @@ -0,0 +1,8 @@ +/var/log/cron.log { + daily + rotate 7 + compress + missingok + notifempty + copytruncate +} \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100644 index f3fc625..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -crontab -l > mycron -echo "0 8 * * * bun run ./src/app.ts --today > /dev/null 2>&1" >> mycron -echo "0 * * * * bun run ./src/app.ts > /dev/null 2>&1" >> mycron -crontab mycron -rm mycron \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index b4d8f3e..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -apprise -python-dotenv \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index 86f295e..723d77b 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,31 +1,25 @@ import { TEventType } from "./component/event/event.types"; import { db } from "./sql"; import { Event, type TEventEntityNew, type TGetEventsOptions } from "./component/event/events"; +import { createPlaceholders, getTsNow, pad_l2 } from "./util"; import { sendNotification } from "./sendNotification"; -import { createPlaceholders, pad_l2 } from "./util"; const argv = require('minimist')(process.argv.slice(2)); -console.dir(argv) +console.log("App started"); +console.dir({argv}) -// const TS_TODAY = new Date(); - -function getTsNow() { - const now = new Date(); - const rtn = { - year: now.getFullYear(), - month: now.getMonth() + 1, - day: now.getDate(), - minute: now.getMinutes(), - seconds: now.getSeconds() - } - return rtn; -} - -async function main( ) { +async function main ( ) { + console.log("Excecuting main()"); const TODAY = getTsNow(); + console.dir(TODAY); const events_currentMonth = await Event.fetch_events( TODAY.year, TODAY.month , -120 ); + console.log("events_currentMonth.length:" + events_currentMonth.length ); const events_nextMonth = await Event.fetch_events( TODAY.year, TODAY.month + 1 , -120 ); + console.log("events_nextMonth.length:" + events_nextMonth.length ); const events = [...events_currentMonth, ...events_nextMonth]; + console.log("events.length:" + events.length ); + + // const TS_TODAY = new Date(); // Write to JSON File Section START // const data = JSON.stringify(events, null, 2); // const TS = `${TS_TODAY.getFullYear()}-${TS_TODAY.getMonth() + 1}-${TS_TODAY.getDate()}_${TS_TODAY.getHours()}-${TS_TODAY.getMinutes()}-${TS_TODAY.getSeconds()}`; @@ -33,16 +27,19 @@ async function main( ) { // Write to JSON File Section END const allEventUids = events.map( event => { return event.uid; }); + console.dir(allEventUids ); const placeholders = createPlaceholders( allEventUids ); const getAllRelevantEventsQuery = db.query( `SELECT * FROM events WHERE uid IN (${placeholders}); ` ).as(Event ); const AllRelevantEvents = getAllRelevantEventsQuery.all(...allEventUids); - + console.log("AllRelevantEvents.length:" + AllRelevantEvents.length ); const eventsToInsert: TEventEntityNew[] = []; for ( const ev of events ) { + console.log("loop ev: " + [ ev.uid, ev.title, ev.date_at ].join( ", " ) ); const found = AllRelevantEvents.find(event => event.uid === ev.uid); if ( found ) { + console.log("loop ev found: " + [ found.uid, found.title, found.date_at ].join( ", " ) ); if ( found.title != ev.title || found.description != ev.description || @@ -55,29 +52,34 @@ async function main( ) { found.timezone != ev.timezone || found.link != ev.link ) { + console.log("loop ev different (changed): " + [ ev.uid, ev.title, ev.date_at ].join( ", " ) ); const newEventToInsert: TEventEntityNew = {... ev, notification: "changed"}; eventsToInsert.push( newEventToInsert ); } } else { + console.log("loop ev added (new): " + [ ev.uid, ev.title, ev.date_at ].join( ", " ) ); const newEventToInsert: TEventEntityNew = {... ev, notification: "new"}; eventsToInsert.push( newEventToInsert ); } } - + console.dir(eventsToInsert) Event.insert( eventsToInsert, db); - const options: TGetEventsOptions = { - } - if (argv.today) { - options.date = { + const where: TGetEventsOptions = {} + where.notification = ["new", "changed"] + if ( argv.today ) { + where.date = { year: TODAY.year, month: TODAY.month, day: TODAY.day } - } else { - options.notification = ["new", "changed"] } - const list_of_events = Event.get_events( options, db ); + const list_of_events = Event.get_events( where, db ); + console.dir({ + list_of_events, + where + }); for ( const ev of list_of_events ) { + console.log("loop list_of_events - ev: " + [ev.uid, ev.title, ev.date_at, "notification:" + ev.notification].join( ", " ) ); const body = [ `Title: ${ev.title}`, `Location: ${ev.location}`, @@ -87,6 +89,7 @@ async function main( ) { `By: ${ev.posted_by}`, `Link: ${ev.link}`, ].join("\n"); + console.log("loop list_of_events - ev 'body': " + body ); const notification_prefix = ( (event: Event) => { switch( event.notification) { case "new": @@ -113,28 +116,8 @@ async function main( ) { return false; })( ev ); const title = `${today_prefix ? "TODAY " : ""}${notification_prefix ? notification_prefix + ": " : ""} ${ev.title} (${ TEventType[ ev.event_type ] })`; - - await fetch("http://apprise:8000/notify", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - urls: [ - `ntfys://${process.env.ntfy_username}:${process.env.ntfy_password}@${process.env.ntfy_host}/${process.env.ntfy_topic}${ ev.link ? `?click=${ev.link}`: "?click=https://77th-jsoc.com/#/events" }`, - `discord://${process.env.dc_webhook}?avatar_url=${process.env.dc_avatar_url}&botname=${process.env.dc_botname}` - ].join(","), - title: title, - body: body, - format: "text" - }) - }); - - // await sendNotification( - // title, - // body - // // `${ev.link || "https://77th-jsoc.com/#/events"}` - // ); + console.log("loop list_of_events - ev 'title': " + title ); + await sendNotification( title, body, ev.link ? ev.link : null); ev.set_notification("done", db); } }; diff --git a/src/sendNotification.ts b/src/sendNotification.ts index 639ff21..66e61d4 100644 --- a/src/sendNotification.ts +++ b/src/sendNotification.ts @@ -1,16 +1,26 @@ -import * as Bun from "bun"; - -export async function sendNotification(title: string, body: string, click?: string | null) { - const command = [ - "python3", - "./src/notification.py", - `--title=${title}`, - `--body=${body}`, - ]; - if ( click ) { - command.push(`--click=${click}`); +export async function sendNotification(title: string, body: string, link?: string | null) { + console.dir({ + sendNotification: { + title, + body, + link } - const proc = Bun.spawn(command); - const text = await proc.stdout.text(); - console.log("sendNotification: " + text); -} + }); + const response = await fetch("http://apprise:8000/notify", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + urls: [ + `ntfys://${process.env.ntfy_username}:${process.env.ntfy_password}@${process.env.ntfy_host}/${process.env.ntfy_topic}${ link ? `?click=${link}`: "?click=https://77th-jsoc.com/#/events" }`, + `discord://${process.env.dc_webhook}?avatar_url=${process.env.dc_avatar_url}&botname=${process.env.dc_botname}` + ].join(","), + title: title, + body: body, + format: "text" + }) + }); + const responseBody = await response.json(); + return responseBody; +} \ No newline at end of file diff --git a/src/sendNotificationPy.ts b/src/sendNotificationPy.ts new file mode 100644 index 0000000..2fbf339 --- /dev/null +++ b/src/sendNotificationPy.ts @@ -0,0 +1,16 @@ +import * as Bun from "bun"; + +export async function sendNotificationPy(title: string, body: string, click?: string | null) { + const command = [ + "python3", + "./src/notification.py", + `--title=${title}`, + `--body=${body}`, + ]; + if ( click ) { + command.push(`--click=${click}`); + } + const proc = Bun.spawn(command); + const text = await proc.stdout.text(); + console.log("sendNotification: " + text); +} diff --git a/src/util.ts b/src/util.ts index 7d3314a..6f2f7ed 100644 --- a/src/util.ts +++ b/src/util.ts @@ -26,4 +26,16 @@ export function pad_l2 ( _thing: string | number ): string { _thing = JSON.stringify(_thing); }; return _thing.padStart(2, "0"); +} + +export function getTsNow() { + const now = new Date(); + const rtn = { + year: now.getFullYear(), + month: now.getMonth() + 1, + day: now.getDate(), + minute: now.getMinutes(), + seconds: now.getSeconds() + } + return rtn; } \ No newline at end of file