Skip to content

broadcaster: /pool_status, a pin switch, and the last block in snapshots - #95

Merged
rsantacroce merged 2 commits into
mainfrom
feat/broadcaster-commands
Oct 2, 2026
Merged

rsantacroce merged 2 commits into
mainfrom
feat/broadcaster-commands

Conversation

@rsantacroce

@rsantacroce rsantacroce commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Why

Running the broadcaster in a team forum group (pool.beta.avonpool.xyz posting to a topic, #94) turned up three gaps:

  1. Pinning is all or nothing. The bot there is a plain member and may post but not pin. BROADCASTER_LIVE=1 then logs not enough rights to manage pinned messages on every new live message, and there was no way to keep the message without the pin attempt.
  2. No way to ask. Stats arrive on a schedule, but nobody in the chat can ask for them now.
  3. No last block. The snapshots show the all-time block count but not when the last block was found, which is the first thing people ask.

What

BROADCASTER_LIVE_PIN=0 posts and edits the live message without pinning it. The default is 1, so existing setups are unchanged.

BROADCASTER_COMMANDS=1 answers /pool_status with the current stats, as a reply in the topic where it was typed. It is off by default.

  • Separate loop: lib/commands.js runs its own getUpdates long poll beside the poster. The long poll bypasses the send queue, so a held poll never delays a post, and a failure in it never stops the posts.
  • Configured chat only: it answers only in TELEGRAM_CHAT_ID (numeric id or @username). /pool_status@another_bot is ignored.
  • Cooldown: at most one reply per chat per BROADCASTER_COMMAND_COOLDOWN_SEC (default 30).
  • Command menu: the command is registered with setMyCommands. A bot in privacy mode reliably sees only the addressed /pool_status@bot form, which is what a tap in the menu sends.
  • No backlog, no repeats: the first start skips commands sent earlier. The read offset is kept in broadcaster.json, so a restart answers nothing twice.
  • Failures: if the dashboard can't be read, the reply says so instead of the command going unanswered. A Telegram failure at startup is retried rather than switching commands off.
  • Dry run: commands stay off under BROADCASTER_DRY_RUN, which has no bot to read with.

Last block line. The live message, the periodic update and the /pool_status reply now show Last block: #970,851 · 1h 39m ago. This is the newest pending or confirmed block, never an orphaned or rejected one.

Current hashrate and share counts (second commit). The stat block shared by the digest, the live message, the periodic update and /pool_status now leads with the 5-minute rate, and gives the rejected count beside the accepted one:

Hashrate now: 3.33 PH/s (5m)
Hashrate: 2.33 PH/s (1h) · 2.00 PH/s (24h)
Shares (24h): 34,763 accepted · 76 rejected (0.22%)

index.js now builds one state object and one persist() shared by both loops, so neither can save over the other with a stale copy.

Docs: the README has a new /pool_status section covering privacy mode and the one-getUpdates-reader-per-bot rule, and the config table is updated. .env.example, docker-compose.yml and the systemd unit comments are updated too.

Tests

npm test in broadcaster/: 33 pass, 12 of them new.

  • Commands (8, new file): backlog skip and offset persistence; reply in the right topic, quoting the command; General topic gets no thread id; other chats, other bots and non-commands are ignored; @username matching; cooldown; reply when the dashboard fails.
  • Broadcaster (2): no pin with LIVE_PIN=0; the last block line skips orphaned blocks.
  • Telegram client (2): reply routing; getUpdates is not queued behind posts.

A /pool_status reply, rendered from pool.beta.avonpool.xyz's live API:

🟢 avonpool_beta — status

Hashrate now: 3.33 PH/s (5m)
Hashrate: 2.33 PH/s (1h) · 2.00 PH/s (24h)
Active workers (24h): 1
Shares (24h): 34,763 accepted · 76 rejected (0.22%)
Best share (24h): 66.89M
Last share: 27s ago
Last block: #970,851 · 1h 41m ago
Blocks (all time): 60

🤖 Generated with Claude Code

rsantacroce and others added 2 commits October 2, 2026 09:39
Three additions to the broadcaster.

BROADCASTER_LIVE_PIN=0 posts the live message without pinning it. A bot
that may post in a group but not pin (a plain member of a forum group, for
example) otherwise logs "not enough rights to manage pinned messages" on
every new live message. Default 1, so nothing changes unless it is set.

BROADCASTER_COMMANDS=1 answers /pool_status in TELEGRAM_CHAT_ID with the
current stats, as a reply in the topic it was typed in. lib/commands.js
runs its own getUpdates long poll beside the poster, so a held poll never
delays a post and a failure there never stops one. getUpdates bypasses
the send queue for the same reason. Details:
- Only the configured chat is answered (numeric id or @username), so
  adding the bot elsewhere does not make it reply there.
- "/pool_status@other_bot" is ignored.
- At most one reply per chat per BROADCASTER_COMMAND_COOLDOWN_SEC
  (default 30).
- The command is registered in the bot's "/" menu, because a bot in
  privacy mode only reliably sees the addressed "/pool_status@bot" form a
  menu tap sends.
- The first start skips the backlog. The offset is kept in
  broadcaster.json, so a restart answers nothing twice.
- A dashboard failure gets a short "can't be read right now" reply.
- Startup failures are retried rather than switching the command off.
- Off under BROADCASTER_DRY_RUN, which has no bot to read with.

The live message, the periodic update and the /pool_status reply now show
"Last block: #<height> · <age> ago": the newest pending or confirmed
block, never an orphaned or rejected one.

index.js now builds one state object and one persist() for both loops, so
neither can save over the other with a stale copy.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The stat block shared by the digest, the live message, the periodic
update and /pool_status now leads with the current rate, the dashboard's
5-minute hashrate_5m:

  Hashrate now: 3.33 PH/s (5m)
  Hashrate: 2.33 PH/s (1h) · 2.00 PH/s (24h)

The shares line gives the rejected count beside the accepted one, keeping
the rate:

  Shares (24h): 34,763 accepted · 76 rejected (0.22%)

Both fields were already in /api/status.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@rsantacroce
rsantacroce merged commit 5dfe151 into main Oct 2, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant