Commit graph

110 commits

Author SHA1 Message Date
vrubelroman
d4eb61f994 prioritize interactive requests over background checks in shared Lichess-token queue
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 15s
/today, /yesterday, /week were queuing behind the entire periodic-check
backlog on the same rate-limited LICHESS_APP_TOKEN (observed ~2min wait on
prod for a single command). Add a two-tier priority queue to SharedTokenGate:
interactive on-demand requests jump ahead of background periodic checks,
which still drain normally when nothing interactive is waiting. Verified
locally end-to-end (isolated queue unit tests, live request with priority
correctly reaching Lichess, and a real successful accuracy fetch rendered
through StatsFormatter).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 10:25:34 +00:00
vrubelroman
0dbd0c400b enforce a real 6s cooldown between shared-token lichess.org requests, not just non-overlap
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 13s
A bare mutex around games/user and user/activity wasn't enough: Lichess kept
rejecting the shared LICHESS_APP_TOKEN with 429 "Please only run 1
request(s) at a time" even when calls were strictly sequential with only
~100-300ms between one finishing and the next starting (confirmed live on
prod: near every request was getting 429'd right after the previous mutex
fix went out). Track the last release time and force a minimum 6s gap
before the next call is allowed to start.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 23:33:11 +00:00
vrubelroman
31e6fdd23d serialize shared-token lichess.org requests to fix accuracy dropping again
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 15s
games/user and user/activity share one LICHESS_APP_TOKEN process-wide, and
Lichess allows only 1 concurrent request per token there (confirmed live:
429 "Please only run 1 request(s) at a time" under concurrent traffic).
The existing rate limiter only paced request starts 0.2s apart without
holding the lock through the request itself, so concurrent games/period
calls (periodic checks vs. on-demand /today etc.) could still collide and
get 429'd, silently dropping the accuracy shown in /today, /yesterday,
/week (that fetch is best-effort and swallows errors). Hold a dedicated
lock for the full request/response cycle on these two calls; puzzle
requests use per-user tokens and don't need it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 23:26:25 +00:00
vrubelroman
7ef5875f58 authenticate outgoing lichess.org requests to fix silent 404s on games/user
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 12s
Lichess started rejecting anonymous requests to games/user and
user/activity with a 404 (confirmed live: the same request with a valid
bearer token got a normal 429 instead), which our code silently read as
"user has no games" for every single tracked player, making periodic
checks report zero activity across the board. Add LICHESS_APP_TOKEN and
send it as a Bearer token on these two calls; it just needs to be any
valid token; it does not need to belong to the tracked player.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 23:01:35 +00:00
vrubelroman
08f97d413a stop infinite retry loop when user blocks the bot or deactivates account
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 11s
Forbidden from send_message was falling into the generic error handler,
which resets consecutive_errors to 0 right before the send attempt — so
backoff never grew past 60s and the pair retried forever, wasting request
queue capacity needed by other users' real periodic checks.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 20:00:56 +00:00
vrubelroman
619c00aa06 stop infinite retry loop on rejected Lichess tokens
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 12s
A gamer's periodic check would get permanently stuck if their stored token
was revoked/expired: our stats API collapsed both "Lichess rejected the
token" (401/403, permanent) and genuine transient errors into the same 502
response, so the bot treated an invalid token exactly like a network blip —
retrying the same window forever at a capped 300s backoff, never advancing
the checkpoint (observed in prod: Dor1zz stuck for 100+ consecutive errors
over 8+ hours, admin alerts firing every 25 failures).

Preserve the distinction that already existed one layer down (lichess_client.py
already tells 401/403 apart from other failures) instead of collapsing it in
stats_service.py: add PuzzleOfPeriodResponse.auth_failed, have main.py return
401 specifically for that case, and have the bot raise a distinct
InvalidTokenError instead of returning None. On InvalidTokenError, the bot now
clears the token for that pair, notifies the user to reconnect via /addtoken,
and continues tracking games normally instead of stalling forever.
2026-07-05 07:37:14 +00:00
vrubelroman
8080921141 fix periodic-check request queue throughput bottleneck
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 12s
The bot's request_queue.py 4s FIFO gate wasn't protecting against Lichess's
rate limiter — that's already handled downstream in LichessWebServices/
rate_limiter.py (0.2s, shared across all callers of our stats service). The
bot-side gate only paced calls to our own local service, and since it awaited
each request to full completion before dequeuing the next, real dispatch gaps
were max(4s, previous request's duration) — with 454 tracked gamer/user pairs,
any burst (e.g. after a restart) piled into the queue and took 10-20+ minutes
to drain.

Replace it with a paced-dispatch + bounded-concurrency design: a hard 2s floor
between dispatches (still never lets 2+ requests through in that window),
decoupled from completion time, with up to 10 requests actually in flight at
once via a semaphore. Doesn't touch the real Lichess-facing rate limit at all.

Also add deterministic per-(user,gamer) checkpoint jitter: previously every
pair sharing the same period_minutes re-locked onto the same wall-clock phase
on every restart (backlog collapse snaps period_end_approx to `now` for
everyone overdue at once), recreating the pileup each time. Jitter is stable
across restarts (crc32-based, not Python's salted hash()) and capped well
under the 2h stale-backlog threshold. Small startup stagger added too, purely
cosmetic smoothing on top of the jitter fix.
2026-07-04 20:30:49 +00:00
vrubelroman
ad6daf2918 suppress periodic notifications for stale collapsed backlogs
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 16s
The backlog-collapse fix (previous commit) correctly stops the checkpoint
from falling further behind, but it was still sending the full per-game
notification for whatever it caught up on — meaning a gamer whose checkpoint
had drifted weeks behind now dumps a multi-week, game-by-game report on the
user in one message. That's not a "periodic update" anymore, just spam.

When the collapsed window exceeds 2 hours, catch the checkpoint up silently
(still fixes the drift) but skip sending the notification for it — only
report activity that's actually recent going forward.
2026-07-04 19:14:36 +00:00
vrubelroman
b0173950b8 fix silent addgamer drop on restart and periodic-check backlog buildup
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 13s
Persist user_data (PicklePersistence) so an in-flight /addgamer username
prompt survives a bot restart instead of being silently swallowed by
handle_username when the in-memory awaiting flag is gone.

Collapse periodic-check backlog into a single request spanning the whole
missed gap instead of replaying it one period_minutes window at a time —
with enough tracked gamers sharing one RequestQueue, per-window replay
could never catch up and the checkpoint fell further behind indefinitely.
Notification period label now reflects the actual queried span (minutes/
hours/days) instead of the configured interval, so a weeks-old catch-up
no longer gets mislabeled as "for 15 minutes".
2026-07-04 18:33:45 +00:00
vrubelroman
62cdd750f8 align /lastyear_or_1000games table into a single monospace code block
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 29s
Column-align per-mode rows (games/rating change/rating/W-L-D/accuracy)
same as the other stats commands, instead of loose free-text lines.
Strip the invisible variation selector from bullet/classical emoji so
it doesn't throw off column padding.
2026-07-03 13:33:58 +00:00
vrubelroman
f154d3d7c3 align /getgamers and stats-message tables, unify stats body into one code block
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 31s
- /getgamers: column-aligned monospace table (username, ratings, period).
- Per-mode stats (rating/wins/losses/draws): column-aligned block, dropped
  the meaningless multi-game average accuracy row.
- format_stats_response/format_period_notification now wrap the whole
  message in a single markdown code block instead of alternating
  plain-text headers and separately-fenced tables.
- Rating row gets an emoji prefix to match the other three rows, so
  Telegram's monospace rendering keeps all values in the same column.
2026-07-03 13:20:50 +00:00
vrubelroman
2a7385290e fix silent onboarding drop-off in /addgamer flow
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 33s
Set awaiting_addgamer_username as soon as the menu is shown so typing a
username directly (without tapping the button) is handled instead of
being silently ignored. Also stop reporting a valid username as "not
found" when Lichess returns a non-404 error (rate limit/timeout), and
surface an error message if the addgamer menu itself fails to send.
2026-07-03 12:23:40 +00:00
vrubelroman
e9516f8664 show tracked player's piece color inline, drop redundant result text
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 33s
Add a small circle (/) glued right after the tracked player's name
in the per-game table to show which color they played, since the
white/black split was no longer visible once the opponent's name was
dropped. Replace the '1-0'/'0-1'/'1/2-1/2' result text with a plain
'-' separator — the leading outcome circle already conveys win/loss/draw.
2026-07-03 10:12:45 +00:00
vrubelroman
26cb066515 simplify per-game table: tracked player only, no rating diff column
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 31s
Reworked the per-game row layout to be relative to the tracked player
instead of white/black: the tracked player's name+accuracy+rating are
always shown first, the opponent's rating+accuracy (no name) always
second, regardless of which color each side played in a given game -
this keeps columns aligned across rows even as the tracked player
switches sides. Dropped the rating-change-per-game column added
earlier; it pushed the line past mobile width limits.
2026-07-03 10:08:35 +00:00
vrubelroman
d479e14bf9 add per-game accuracy and outcome table to stats/notifications
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 31s
Games-of-period responses can now include a per-game breakdown
(include_games) with Lichess post-analysis accuracy, plus which side
the tracked player was on and their rating change for that game.

- lichess_client.py requests accuracy=true from Lichess; stats_service
  computes per-mode average accuracy and builds GameRow entries
  (tracked_is_white, tracked_rating_diff) for blitz/rapid/classical
- /games/{username}/period gained an include_games query param
- formatters.py renders a column-aligned monospace table per game:
  outcome circle (win/loss/draw relative to the tracked player),
  rating change, accuracy, names/ratings, result — for today/yesterday
  and periodic notifications; week keeps an aggregate accuracy line
- usernames are Markdown-escaped before formatting since messages are
  now sent with parse_mode='Markdown'
2026-07-03 09:38:51 +00:00
vrubelroman
4a783225af fix periodic activity-check algorithm silently losing player activity
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 38s
Errors from Lichess (timeouts/5xx/invalid tokens) were being disguised
as "no activity" (HTTP 200, games_count/puzzles_in_period=0), causing
the bot to silently advance its checkpoint past real, undetected
activity. Puzzle-fetch failures weren't counted as errors at all, and
the periodic task died permanently after 5 consecutive errors with no
way to recover short of a manual restart. /setperiod also unconditionally
reset the checkpoint, dropping the window between the last check and
the command.

- API now returns success=false/502 on real errors instead of masking
  them as zero activity (models.py, stats_service.py, main.py)
- Puzzle-fetch errors are now treated the same as game-fetch errors:
  retry the same window instead of reporting "no puzzles"
- Notification delivery failures no longer silently advance the
  checkpoint
- Replaced the hard 5-error kill switch with capped backoff that keeps
  retrying indefinitely, plus an admin-bot notification if a player's
  monitoring has been failing for a prolonged period (~2h+)
- /setperiod only clears the checkpoint when disabling notifications,
  preserving continuity when a period is just changed

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-02 19:29:06 +00:00
vrubelroman
75e62b57a1 remove admin web panel (LichessWebView) from the project
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 43s
Unused component that also carried several security issues (default
admin credentials, hardcoded Flask secret key, debug mode, plaintext
passwords). Cleaned up compose files, CI/CD pipeline, and docs
accordingly; also dropped the stale IS_PROD config docs in favor of
the current .env-based setup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-02 18:32:06 +00:00
vrubelroman
1fe8deb0de ci: add Forgejo CI/CD pipeline with docker save/load deploy to prod
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 1m24s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 18:55:21 +00:00
vrubelroman
8828375207 refactor: move bot tokens to .env, remove hardcoded credentials
- Remove IS_PROD flag and hardcoded tokens from config.py
- Read TELEGRAM_BOT_TOKEN and ADMINPANEL_TELEGRAM_BOT_TOKEN from env
- Add env_file: .env to lichess-bot and admin-bot in docker-compose.yml
- Add .env to .gitignore (no longer tracked)
- Add .env.example with test tokens
2026-06-30 18:15:44 +00:00
vrubelroman
a5e3e6903d some 2026-06-09 11:50:47 +00:00
vrubelroman
0e3a0bfc48 Change API host port to 8002 2026-03-21 23:14:51 +03:00
vrubelroman
63e28c279c fix by codex 2026-03-21 22:58:47 +03:00
vrubel
3ffcf97c3f isProd = false 2026-02-05 23:53:36 +03:00
vrubel
20f96d0e0a fix critical bugs 2026-02-05 01:38:33 +03:00
vrubelroman
0de0deb14f delay in config and setup = 5sec 2026-02-04 23:51:32 +03:00
vrubel
2ac38440da удалили сообщения That's all и Processing request... 2026-01-22 16:25:33 +03:00
vrubelroman
b3b6a54e2d пофиксил баг отправки уведомлений 2025-12-06 00:28:53 +03:00
vrubelroman
6d51cf135d после неудачных попыток добавить игрока предлагается добавить игрока 2025-12-03 13:09:40 +03:00
vrubelroman
977787c858 заменил картинки 2025-12-03 13:02:14 +03:00
vrubelroman
6ed6ab866e добавлены картинки с подсказкой как добавить игрока 2025-12-03 02:33:38 +03:00
vrubelroman
ce586dcddb ↳ (активный игрок меняется в меню /getgamers) - удалили этот текст 2025-12-01 15:12:31 +03:00
vrubelroman
31ed5cf114 еще больше упростил стартовый текст 2025-12-01 14:29:07 +03:00
vrubelroman
f458044543 убран блок информации из /start в /help 2025-12-01 13:52:26 +03:00
vrubelroman
f58bf8b6a7 add /sendusers0 2025-11-28 18:28:51 +03:00
vrubelroman
f08bc3a1dc bold text in /addgamer 2025-11-28 18:11:13 +03:00
vrubelroman
d04a08936c /addgamer выдает страничку игрока 2025-11-23 16:53:12 +03:00
vrubelroman
50c5e93343 версионность не в конфиге 2025-11-23 13:11:58 +03:00
vrubelroman
4b6790be14 убрана чувствительность к регистру в никнейме 2025-11-23 12:51:14 +03:00
vrubelroman
e6967db17d аутентификация к веб админке 2025-11-23 02:36:15 +03:00
vrubelroman
595c9419f4 проверка на дубликаты и ряд багов 2025-11-23 01:46:12 +03:00
vrubelroman
ab03728d00 bug fix /addtoken 2025-11-21 23:49:26 +03:00
vrubelroman
776f4f2c1f trivial bug fix design 2025-11-21 23:43:53 +03:00
vrubelroman
30fca57382 redisign /start 2025-11-21 23:35:44 +03:00
vrubelroman
965b8775b7 add command /profile 2025-11-21 23:16:35 +03:00
vrubelroman
56c1048bcc adding docs 2025-11-20 14:19:08 +03:00
vrubelroman
711adb4126 ru en in web interface 2025-11-20 13:45:50 +03:00
vrubelroman
0c9a66a73c fix bug today yesterday 2025-11-20 13:16:15 +03:00
vrubelroman
123749415a switch ru/en 2025-11-20 12:43:00 +03:00
vrubelroman
c16a11cf63 очередь запросов и интервал 7 сек 2025-11-20 03:23:38 +03:00
vrubelroman
4dc5539da2 bug today 2025-11-20 03:14:06 +03:00