From 60090f3ea1c7cad2a7e6d658615404575844e2d1 Mon Sep 17 00:00:00 2001 From: Zsolt Tasnadi Date: Mon, 23 Feb 2026 22:45:38 +0100 Subject: [PATCH] replace cronjob to own solution --- Dockerfile | 14 +---- cronjob | 2 - docker-compose.yml | 4 +- env-example | 1 + statusbot.pas | 125 ++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 125 insertions(+), 21 deletions(-) delete mode 100644 cronjob diff --git a/Dockerfile b/Dockerfile index e1762a4..487c5ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,23 +1,13 @@ -# Dockerfile - FPC Discord bot SSL támogatással FROM debian:12-slim RUN apt-get update && apt-get install -y \ - fpc fp-units-fcl fp-units-net tzdata curl jq \ + fpc fp-units-fcl fp-units-net tzdata \ libssl3 libssl-dev \ && apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /app COPY statusbot.pas . -# Fordítás RUN fpc statusbot.pas -# Cron telepítése -RUN apt-get update && apt-get install -y cron && apt-get clean && rm -rf /var/lib/apt/lists/* - -# Cron fájl másolása -COPY cronjob /etc/cron.d/discord-cron -RUN chmod 0644 /etc/cron.d/discord-cron && crontab /etc/cron.d/discord-cron - -# Konténer mindig fusson, cron háttérben -CMD ["cron", "-f"] \ No newline at end of file +CMD ["./statusbot"] \ No newline at end of file diff --git a/cronjob b/cronjob deleted file mode 100644 index 19c2865..0000000 --- a/cronjob +++ /dev/null @@ -1,2 +0,0 @@ -# cronjob - minden kedd 9:00 magyar idő szerint -0 9 * * 2 root TZ=Europe/Budapest /app/statusbot diff --git a/docker-compose.yml b/docker-compose.yml index 31e1ce6..ed380fd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,9 +2,11 @@ services: statusbot: build: . container_name: statusbot + restart: unless-stopped environment: + RUN_AT: "${RUN_AT}" DISCORD_BOT_TOKEN: "${DISCORD_BOT_TOKEN}" DISCORD_CHANNEL_ID: "${DISCORD_CHANNEL_ID}" THREAD_NAME: "${THREAD_NAME}" THREAD_MESSAGE: "${THREAD_MESSAGE}" - ARCHIVE_DURATION: "${ARCHIVE_DURATION}" + ARCHIVE_DURATION: "${ARCHIVE_DURATION}" \ No newline at end of file diff --git a/env-example b/env-example index c36781e..4753801 100644 --- a/env-example +++ b/env-example @@ -1,3 +1,4 @@ +RUN_AT=3:9:0 DISCORD_BOT_TOKEN=DISCORD_BOT_TOKEN DISCORD_CHANNEL_ID=DISCORD_CHANNEL_ID ARCHIVE_DURATION=10080 diff --git a/statusbot.pas b/statusbot.pas index 43660a9..2f260bd 100644 --- a/statusbot.pas +++ b/statusbot.pas @@ -1,6 +1,6 @@ program DiscordCreateThread; {$MODE OBJFPC} -{$H+} // Enable AnsiString +{$H+} uses SysUtils, Classes, fphttpclient, opensslsockets, DateUtils; @@ -49,12 +49,12 @@ begin end; end; +procedure RunCore; var Token, ChannelID, ThreadMessage: string; ThreadBody, MessageBody, Response: string; ThreadIDStart, ThreadIDEnd: Integer; ThreadID: string; - begin Token := GetEnvironmentVariable('DISCORD_BOT_TOKEN'); ChannelID := GetEnvironmentVariable('DISCORD_CHANNEL_ID'); @@ -62,12 +62,11 @@ begin ThreadBody := Format( '{"name":"%s","auto_archive_duration":%d}', - [StringReplace(GetThreadName,'"','\"',[rfReplaceAll]), GetArchiveDuration] + [StringReplace(GetThreadName, '"', '\"', [rfReplaceAll]), GetArchiveDuration] ); Response := HttpPost(DISCORD_API + '/channels/' + ChannelID + '/threads', ThreadBody, Token); - // egyszerű parsing az id kinyeréséhez ThreadIDStart := Pos('"id":"', Response); if ThreadIDStart > 0 then begin @@ -77,8 +76,122 @@ begin if ThreadID <> '' then begin - MessageBody := Format('{"content":"%s"}',[StringReplace(ThreadMessage,'"','\"',[rfReplaceAll])]); + MessageBody := Format('{"content":"%s"}', [StringReplace(ThreadMessage, '"', '\"', [rfReplaceAll])]); HttpPost(DISCORD_API + '/channels/' + ThreadID + '/messages', MessageBody, Token); end; end; -end. \ No newline at end of file +end; + +// RUN_AT format: "::" +// day_of_week: 1=Sunday, 2=Monday, 3=Tuesday, 4=Wednesday, 5=Thursday, 6=Friday, 7=Saturday +function ParseRunAt(out TargetDow, TargetHour, TargetMinute: Integer): Boolean; +var + RunAt: string; + Parts: TStringList; +begin + ParseRunAt := False; + RunAt := GetEnvironmentVariable('RUN_AT'); + if RunAt = '' then Exit; + + Parts := TStringList.Create; + try + Parts.Delimiter := ':'; + Parts.StrictDelimiter := True; + Parts.DelimitedText := RunAt; + + if Parts.Count < 3 then Exit; + + TargetDow := StrToIntDef(Parts[0], -1); + TargetHour := StrToIntDef(Parts[1], -1); + TargetMinute := StrToIntDef(Parts[2], -1); + + if (TargetDow < 1) or (TargetDow > 7) then Exit; + if (TargetHour < 0) or (TargetHour > 23) then Exit; + if (TargetMinute < 0) or (TargetMinute > 59) then Exit; + + ParseRunAt := True; + finally + Parts.Free; + end; +end; + +function ShouldFire(TargetDow, TargetHour, TargetMinute: Integer): Boolean; +var + H, M, S, MS: Word; +begin + DecodeTime(SysUtils.Now, H, M, S, MS); + ShouldFire := (DayOfWeek(SysUtils.Now) = TargetDow) and + (Integer(H) = TargetHour) and + (Integer(M) = TargetMinute); +end; + +const + DAY_NAMES: array[1..7] of string = ( + 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' + ); + +var + Fired: Boolean; + LastCheckedMinute: Integer; + CurrentMinute: Integer; + H, M, S, MS: Word; + TargetDow, TargetHour, TargetMinute: Integer; + +begin + if not ParseRunAt(TargetDow, TargetHour, TargetMinute) then + begin + WriteLn('Error: RUN_AT environment variable is not set or invalid.'); + WriteLn('Format: RUN_AT=::'); + WriteLn('Example (Tuesday 9:00): RUN_AT=3:9:0'); + Halt(1); + end; + + WriteLn('==========================================='); + WriteLn(' Discord Thread Scheduler'); + WriteLn('==========================================='); + WriteLn(Format(' Started at : %s', [FormatDateTime('yyyy-mm-dd hh:nn:ss', SysUtils.Now)])); + WriteLn(Format(' Channel ID : %s', [GetEnvironmentVariable('DISCORD_CHANNEL_ID')])); + WriteLn(Format(' Thread name: %s', [GetEnvironmentVariable('THREAD_NAME')])); + WriteLn(Format(' Fires every: %s at %02d:%02d', [DAY_NAMES[TargetDow], TargetHour, TargetMinute])); + WriteLn('==========================================='); + + Fired := False; + LastCheckedMinute := -1; + + while True do + begin + DecodeTime(SysUtils.Now, H, M, S, MS); + CurrentMinute := Integer(H) * 60 + Integer(M); + + if CurrentMinute <> LastCheckedMinute then + begin + LastCheckedMinute := CurrentMinute; + + WriteLn(Format('[%s] Current time: %s | Waiting for: %s %02d:%02d', + [FormatDateTime('yyyy-mm-dd hh:nn', SysUtils.Now), + FormatDateTime('ddd hh:nn', SysUtils.Now), + DAY_NAMES[TargetDow], TargetHour, TargetMinute])); + + if ShouldFire(TargetDow, TargetHour, TargetMinute) then + begin + if not Fired then + begin + WriteLn(Format('[%s] Trigger matched, running core...', + [FormatDateTime('yyyy-mm-dd hh:nn', SysUtils.Now)])); + try + RunCore; + WriteLn('Core executed successfully.'); + except + on E: Exception do + WriteLn('Error: ', E.Message); + end; + Fired := True; + end; + end + else + Fired := False; + end; + + Sleep(10000); + end; +end.