refactor: telegram config via pos config telegram; fix listener pipe + entertainment bugs
- Drop sender 'config'/'config set' subcommand — redundant with 'pos config telegram' (same POS_CONFIG registry: masked token input/display, chat-id validation, chmod 600); sender/listener error hints now point there. - Listener: load_map now uses a \x1f delimiter, so mapped /commands containing '|' are no longer truncated at the first pipe. - entertainment send: forward extra plugin args (previously dropped); pass '--' before the message so leading '-' plugin output isn't parsed as an option. - write_config_key/cfg_write: replace unescaped sed writes with grep-v+append so values with &, |, \ round-trip safely. - sync_systemd: daemon-reload after removing timer units. - config-ui: 'digits' validation accepts negative group/supergroup chat ids.
This commit is contained in:
@@ -16,6 +16,8 @@ summary (newest last).
|
|||||||
|
|
||||||
## Done
|
## Done
|
||||||
|
|
||||||
|
- **2026-08-09** — Telegram sender `config` / `config set` removed — redundant with `pos config telegram` (same `# POS_CONFIG:` registry, masked token display + input, chat-id validation, chmod 600); sender/listener error hints now point there. Deep-review bugfixes in the same commit: mapped `/command` values containing `|` are no longer truncated (`load_map` switched from a `|` to a `\x1f` delimiter — previously `/up=echo hi | head` silently ran `echo hi `); `pos entertainment send <plugin> [args…]` actually forwards the extra args (every arg was `shift`ed in the flag loop, so `$@` was empty) and passes `--` before the message so leading-`-` plugin output isn't parsed as an option; `write_config_key` (entertainment-lib) and `cfg_write` (config-ui) replaced unescaped `sed -i "s|^K=.*|K=\"$v\"|"` with grep-v+append so values with `&`/`|`/`\` no longer mangle (also the path all telegram config now flows through); `sync_systemd` daemon-reloads after removing timer units; `digits` config validation accepts negative group/supergroup chat ids (`-100…`).
|
||||||
|
|
||||||
- **2026-08-09** — Fixed telegram listener editor crash on remove/edit/test: `ui_pick` printed its menu listing to **stdout**, so `idx="$(ui_pick)"` captured the menu *and* the number, and `MAP_CMDS[$idx]` (arithmetic array subscript) blew up with "syntax error in expression". Menu decoration now goes to stderr; only the picked index is emitted on stdout. Pre-existing bug (before the `::desc` work), exposed by the description column.
|
- **2026-08-09** — Fixed telegram listener editor crash on remove/edit/test: `ui_pick` printed its menu listing to **stdout**, so `idx="$(ui_pick)"` captured the menu *and* the number, and `MAP_CMDS[$idx]` (arithmetic array subscript) blew up with "syntax error in expression". Menu decoration now goes to stderr; only the picked index is emitted on stdout. Pre-existing bug (before the `::desc` work), exposed by the description column.
|
||||||
|
|
||||||
- **2026-08-09** — Telegram listener pushes its mapped `/commands` to the bot's `/` menu via `setMyCommands` (auto after every map edit, on `--enable`, and at daemon start; manual `--sync-commands` flag). Map lines may carry a menu description: `/cmd::short description=bash command` (falls back to the bash command, ~40 chars). Names are validated against Telegram's lowercase `[a-z0-9_]` rule — invalid ones are skipped from the menu with a warning but still resolve when typed; empty map clears the menu. Fixed latent bugs found by the sync work: `map_has` (awk `END{exit 1}` overrode the match), and `warn()` went to stdout so it leaked into the generated JSON (now stderr).
|
- **2026-08-09** — Telegram listener pushes its mapped `/commands` to the bot's `/` menu via `setMyCommands` (auto after every map edit, on `--enable`, and at daemon start; manual `--sync-commands` flag). Map lines may carry a menu description: `/cmd::short description=bash command` (falls back to the bash command, ~40 chars). Names are validated against Telegram's lowercase `[a-z0-9_]` rule — invalid ones are skipped from the menu with a warning but still resolve when typed; empty map clears the menu. Fixed latent bugs found by the sync work: `map_has` (awk `END{exit 1}` overrode the match), and `warn()` went to stdout so it leaked into the generated JSON (now stderr).
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ Linux_post_install/
|
|||||||
│ ├── pos # Main dispatcher — smart arg matching to pos-* scripts
|
│ ├── pos # Main dispatcher — smart arg matching to pos-* scripts
|
||||||
<!-- GEN:START tree -->
|
<!-- GEN:START tree -->
|
||||||
│ ├── pos-communication-telegram-listener # Telegram bot listener: map /command → bash, run them on chat messages
|
│ ├── pos-communication-telegram-listener # Telegram bot listener: map /command → bash, run them on chat messages
|
||||||
│ ├── pos-communication-telegram-sender # Send Telegram messages/files/links/stickers via Bot API (send, test, config set)
|
│ ├── pos-communication-telegram-sender # Send Telegram messages/files/links/stickers via Bot API (send, test)
|
||||||
│ ├── pos-config # Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry)
|
│ ├── pos-config # Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry)
|
||||||
│ ├── pos-docker-compose # Docker Compose service manager (ls/up/down/restart/logs/update/config)
|
│ ├── pos-docker-compose # Docker Compose service manager (ls/up/down/restart/logs/update/config)
|
||||||
│ ├── pos-docker-health # One-glance container health dashboard (exits 1 if unhealthy)
|
│ ├── pos-docker-health # One-glance container health dashboard (exits 1 if unhealthy)
|
||||||
@@ -251,7 +251,7 @@ All non-interactive `pos` commands log output to `~/.local/share/linux_post_inst
|
|||||||
|----------|---------|--------|-------------|
|
|----------|---------|--------|-------------|
|
||||||
<!-- GEN:START dispatch -->
|
<!-- GEN:START dispatch -->
|
||||||
| communication | telegram-listener | `pos-communication-telegram-listener` | Telegram bot listener: map /command → bash, run them on chat messages |
|
| communication | telegram-listener | `pos-communication-telegram-listener` | Telegram bot listener: map /command → bash, run them on chat messages |
|
||||||
| communication | telegram-sender | `pos-communication-telegram-sender` | Send Telegram messages/files/links/stickers via Bot API (send, test, config set) |
|
| communication | telegram-sender | `pos-communication-telegram-sender` | Send Telegram messages/files/links/stickers via Bot API (send, test) |
|
||||||
| | config | `pos-config` | Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry) |
|
| | config | `pos-config` | Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry) |
|
||||||
| docker | compose | `pos-docker-compose` | Docker Compose service manager (ls/up/down/restart/logs/update/config) |
|
| docker | compose | `pos-docker-compose` | Docker Compose service manager (ls/up/down/restart/logs/update/config) |
|
||||||
| docker | health | `pos-docker-health` | One-glance container health dashboard (exits 1 if unhealthy) |
|
| docker | health | `pos-docker-health` | One-glance container health dashboard (exits 1 if unhealthy) |
|
||||||
@@ -553,8 +553,8 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
|||||||
| `features/autostart.sh` | 14 | Boot-time feature (moved from `bin/`, flag-gated service) |
|
| `features/autostart.sh` | 14 | Boot-time feature (moved from `bin/`, flag-gated service) |
|
||||||
<!-- GEN:START filetable -->
|
<!-- GEN:START filetable -->
|
||||||
| `bin/pos` | 270 | CLI dispatcher with smart arg matching + logging + category help |
|
| `bin/pos` | 270 | CLI dispatcher with smart arg matching + logging + category help |
|
||||||
| `bin/pos-communication-telegram-listener` | 508 | Telegram bot listener: map /command → bash, run them on chat messages |
|
| `bin/pos-communication-telegram-listener` | 509 | Telegram bot listener: map /command → bash, run them on chat messages |
|
||||||
| `bin/pos-communication-telegram-sender` | 270 | Send Telegram messages/files/links/stickers via Bot API (send, test, config set) |
|
| `bin/pos-communication-telegram-sender` | 220 | Send Telegram messages/files/links/stickers via Bot API (send, test) |
|
||||||
| `bin/pos-config` | 80 | Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry) |
|
| `bin/pos-config` | 80 | Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry) |
|
||||||
| `bin/pos-docker-compose` | 366 | Docker Compose service manager (ls/up/down/restart/logs/update/config) |
|
| `bin/pos-docker-compose` | 366 | Docker Compose service manager (ls/up/down/restart/logs/update/config) |
|
||||||
| `bin/pos-docker-health` | 110 | One-glance container health dashboard (exits 1 if unhealthy) |
|
| `bin/pos-docker-health` | 110 | One-glance container health dashboard (exits 1 if unhealthy) |
|
||||||
|
|||||||
+1
-1
@@ -150,7 +150,7 @@ PACKAGES=(
|
|||||||
Two kinds of config, don't mix them up:
|
Two kinds of config, don't mix them up:
|
||||||
|
|
||||||
- **Machine defaults shipped by the installer:** place the file in `config/` and add copy logic to `postinstall.sh`. If it contains secrets, add to `.gitignore` and document in `DOC/`.
|
- **Machine defaults shipped by the installer:** place the file in `config/` and add copy logic to `postinstall.sh`. If it contains secrets, add to `.gitignore` and document in `DOC/`.
|
||||||
- **Runtime tool config set by the user:** `~/.config/linux_post_install/<tool>.env` with `chmod 600`. Load it with env-var precedence (flags > environment > file). Patterns: `pos-docker-compose` (`compose.env`), `pos-communication-telegram-sender` (`telegram.env`, token masked in `config` output), and the shared ones below. Never store tokens in the repo.
|
- **Runtime tool config set by the user:** `~/.config/linux_post_install/<tool>.env` with `chmod 600`. Load it with env-var precedence (flags > environment > file). Patterns: `pos-docker-compose` (`compose.env`), `pos-communication-telegram-sender` (`telegram.env`, edited via `pos config telegram` — token masked), and the shared ones below. Never store tokens in the repo.
|
||||||
- `system.env` — shared "system" settings loaded by `pos-system-*` tools via `load_system_env()` in `lib/common.sh` (currently `BACKUP_SERVICE_ROOTS`, `HEALTH_BACKUP_MAX_AGE_DAYS`). Env already exported wins over the file.
|
- `system.env` — shared "system" settings loaded by `pos-system-*` tools via `load_system_env()` in `lib/common.sh` (currently `BACKUP_SERVICE_ROOTS`, `HEALTH_BACKUP_MAX_AGE_DAYS`). Env already exported wins over the file.
|
||||||
- `notify.env` — alerting platform selection (`NOTIFY_PLATFORM=telegram,matrix`), read by `lib/notify.sh`.
|
- `notify.env` — alerting platform selection (`NOTIFY_PLATFORM=telegram,matrix`), read by `lib/notify.sh`.
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -33,15 +33,14 @@ templates (without overwriting an existing file):
|
|||||||
|
|
||||||
| File | Used by | Keys |
|
| File | Used by | Keys |
|
||||||
|------|---------|------|
|
|------|---------|------|
|
||||||
| `telegram.env` | `pos communication telegram`, everything that alerts | `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID` |
|
| `telegram.env` | `pos communication telegram sender` / `listener`, everything that alerts | `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID` |
|
||||||
| `notify.env` | `lib/notify.sh` (all alerting) | `NOTIFY_PLATFORM` (e.g. `telegram,matrix`) |
|
| `notify.env` | `lib/notify.sh` (all alerting) | `NOTIFY_PLATFORM` (e.g. `telegram,matrix`) |
|
||||||
| `system.env` | `pos system health`, `pos system backup` | `BACKUP_SERVICE_ROOTS`, `HEALTH_BACKUP_MAX_AGE_DAYS` |
|
| `system.env` | `pos system health`, `pos system backup` | `BACKUP_SERVICE_ROOTS`, `HEALTH_BACKUP_MAX_AGE_DAYS` |
|
||||||
| `compose.env` | `pos docker compose` | `TS_AUTHKEY`, `TZ`, `DNS_SERVER`, `SERVICES_BASE` |
|
| `compose.env` | `pos docker compose` | `TS_AUTHKEY`, `TZ`, `DNS_SERVER`, `SERVICES_BASE` |
|
||||||
| `entertainment.env` | `pos entertainment *` | plugin keys (`WEATHER_LAT`…), `ENABLED` |
|
| `entertainment.env` | `pos entertainment *` | plugin keys (`WEATHER_LAT`…), `ENABLED` |
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pos communication telegram sender config set TELEGRAM_BOT_TOKEN=123:ABC
|
pos config telegram # set TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID
|
||||||
pos communication telegram sender config set TELEGRAM_CHAT_ID=98765
|
|
||||||
pos entertainment config set WEATHER_LAT=36.51 WEATHER_LON=40.75
|
pos entertainment config set WEATHER_LAT=36.51 WEATHER_LON=40.75
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+2
-5
@@ -208,13 +208,10 @@ Subcommands that need input prompt interactively when args are omitted.
|
|||||||
| `pos communication telegram sender send "text" --parse-mode <mode>` | Send with Telegram formatting; `<mode>` is `plain` (default), `markdown`, or `html` (passed as `parse_mode` to the API — also applies to captions). Markdown/HTML use raw Telegram syntax — unescaped characters may be rejected by the API (400) |
|
| `pos communication telegram sender send "text" --parse-mode <mode>` | Send with Telegram formatting; `<mode>` is `plain` (default), `markdown`, or `html` (passed as `parse_mode` to the API — also applies to captions). Markdown/HTML use raw Telegram syntax — unescaped characters may be rejected by the API (400) |
|
||||||
| `pos communication telegram sender send … --token <t> --chat-id <id>` | One-shot override of token/chat ID |
|
| `pos communication telegram sender send … --token <t> --chat-id <id>` | One-shot override of token/chat ID |
|
||||||
| `pos communication telegram sender test` | Sends a canned test message using the current config |
|
| `pos communication telegram sender test` | Sends a canned test message using the current config |
|
||||||
| `pos communication telegram sender config` | Shows current config (bot token masked) |
|
|
||||||
| `pos communication telegram sender config set TELEGRAM_BOT_TOKEN=...` | Saves a bot token (600 perms) |
|
|
||||||
| `pos communication telegram sender config set TELEGRAM_CHAT_ID=...` | Saves the target chat ID |
|
|
||||||
|
|
||||||
`send` option validation: `--caption` is only valid with media types (file/photo/video/audio/voice/animation), `--no-preview` only with `--type message`/`link`, and `--type` only accepts `message|file|link|sticker|photo|video|audio|voice|animation`. An explicit `--type` always overrides auto-detection.
|
`send` option validation: `--caption` is only valid with media types (file/photo/video/audio/voice/animation), `--no-preview` only with `--type message`/`link`, and `--type` only accepts `message|file|link|sticker|photo|video|audio|voice|animation`. An explicit `--type` always overrides auto-detection.
|
||||||
|
|
||||||
The bot token is a secret — it is stored only in `~/.config/linux_post_install/telegram.env` and never in the repo. Requires network access to `api.telegram.org`.
|
The bot token is a secret — it is stored only in `~/.config/linux_post_install/telegram.env` and never in the repo. Edit `TELEGRAM_BOT_TOKEN` / `TELEGRAM_CHAT_ID` interactively with `pos config telegram` (masked input + display). Requires network access to `api.telegram.org`.
|
||||||
|
|
||||||
`pos communication telegram listener` in detail:
|
`pos communication telegram listener` in detail:
|
||||||
|
|
||||||
@@ -241,7 +238,7 @@ Map entries may carry an optional **description** shown in the bot's `/` menu: `
|
|||||||
| `pos entertainment send` | List available plugins + usage |
|
| `pos entertainment send` | List available plugins + usage |
|
||||||
| `pos entertainment send <plugin> [--print] [--markdown] [args…]` | Run the plugin, send its output to Telegram (silent) |
|
| `pos entertainment send <plugin> [--print] [--markdown] [args…]` | Run the plugin, send its output to Telegram (silent) |
|
||||||
| `pos entertainment send <plugin> --print` | Print the output locally; do not send |
|
| `pos entertainment send <plugin> --print` | Print the output locally; do not send |
|
||||||
| `pos entertainment send <plugin> --markdown` | Send with `--parse-mode markdown` (via `pos communication telegram`) |
|
| `pos entertainment send <plugin> --markdown` | Send with `--parse-mode markdown` (via `pos communication telegram sender`) |
|
||||||
| `pos entertainment config` | Show the config file (`~/.config/linux_post_install/entertainment.env`) |
|
| `pos entertainment config` | Show the config file (`~/.config/linux_post_install/entertainment.env`) |
|
||||||
| `pos entertainment config set KEY=VALUE…` | Set keys (any UPPER_SNAKE key; warns if no installed plugin uses it) and re-sync the schedule |
|
| `pos entertainment config set KEY=VALUE…` | Set keys (any UPPER_SNAKE key; warns if no installed plugin uses it) and re-sync the schedule |
|
||||||
| `pos entertainment enable <plugin> [interval]` | Add plugin to `ENABLED` + schedule it as a systemd user timer |
|
| `pos entertainment enable <plugin> [interval]` | Add plugin to `ENABLED` + schedule it as a systemd user timer |
|
||||||
|
|||||||
@@ -19,14 +19,15 @@ health digests, backup alerts, firewall changes — and can be used directly.
|
|||||||
### One-time setup
|
### One-time setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pos communication telegram sender config set TELEGRAM_BOT_TOKEN=123456:ABC...
|
pos config telegram
|
||||||
pos communication telegram sender config set TELEGRAM_CHAT_ID=987654321
|
# edit TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID (masked input), then test:
|
||||||
pos communication telegram sender config
|
pos communication telegram sender test
|
||||||
# config lives in ~/.config/linux_post_install/telegram.env (chmod 600)
|
# config lives in ~/.config/linux_post_install/telegram.env (chmod 600)
|
||||||
```
|
```
|
||||||
|
|
||||||
The bot token comes from @BotFather, the chat ID from @userinfobot (or by
|
The bot token comes from @BotFather, the chat ID from @userinfobot (or by
|
||||||
starting a chat and reading it). `sender config` shows the configured chat id.
|
starting a chat and reading it). `pos config telegram` shows the current values
|
||||||
|
(token masked).
|
||||||
|
|
||||||
### Send
|
### Send
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ pos communication telegram sender send /path/to/report.pdf # auto-detects
|
|||||||
- **On-call file drop:** `pos communication telegram sender send ~/log/nginx-error.log`
|
- **On-call file drop:** `pos communication telegram sender send ~/log/nginx-error.log`
|
||||||
|
|
||||||
**Troubleshooting:**
|
**Troubleshooting:**
|
||||||
- "Not configured (no token or chat id)" → run `sender config set` for both values.
|
- "Not configured (no token or chat id)" → run `pos config telegram` and set both values.
|
||||||
- Send succeeds but nothing arrives → the chat must have started the bot
|
- Send succeeds but nothing arrives → the chat must have started the bot
|
||||||
(press `Start` / send `/start` once).
|
(press `Start` / send `/start` once).
|
||||||
- **Markdown silently empty** → Telegram uses its own MarkdownV2; unmatched
|
- **Markdown silently empty** → Telegram uses its own MarkdownV2; unmatched
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ Commands:
|
|||||||
Push the mapped /commands to the bot's "/" menu (setMyCommands)
|
Push the mapped /commands to the bot's "/" menu (setMyCommands)
|
||||||
--run Run the polling loop in the foreground (used by the service)
|
--run Run the polling loop in the foreground (used by the service)
|
||||||
|
|
||||||
Config: $CONFIG_FILE (TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID)
|
Config: $CONFIG_FILE (TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID — edit with 'pos config telegram')
|
||||||
Map: $MAP_FILE — '/cmd=bash command' per line (optional
|
Map: $MAP_FILE — '/cmd=bash command' per line (optional
|
||||||
'/cmd::short description=bash command' shown in the bot menu)
|
'/cmd::short description=bash command' shown in the bot menu)
|
||||||
|
|
||||||
@@ -76,8 +76,9 @@ load_config() {
|
|||||||
|
|
||||||
# ── command map (MAP_FILE) ──────────────────────────────────────
|
# ── command map (MAP_FILE) ──────────────────────────────────────
|
||||||
# Lines: /cmd=bash command, or /cmd::description=bash command. Keys keep the
|
# Lines: /cmd=bash command, or /cmd::description=bash command. Keys keep the
|
||||||
# leading slash; read via awk so values may contain '='. The map is re-read
|
# leading slash; read via awk so values may contain '='. Entries are emitted
|
||||||
# per message — edits apply without restarting the listener.
|
# with a \x1f (unit separator) delimiter so bash commands may contain pipes.
|
||||||
|
# The map is re-read per message — edits apply without restarting the listener.
|
||||||
|
|
||||||
map_entries() {
|
map_entries() {
|
||||||
[ -f "$MAP_FILE" ] || return 0
|
[ -f "$MAP_FILE" ] || return 0
|
||||||
@@ -90,7 +91,7 @@ map_entries() {
|
|||||||
cmd="$left"
|
cmd="$left"
|
||||||
desc=""
|
desc=""
|
||||||
fi
|
fi
|
||||||
printf '%s|%s|%s\n' "$cmd" "$desc" "${line#*=}"
|
printf '%s\x1f%s\x1f%s\n' "$cmd" "$desc" "${line#*=}"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +133,8 @@ MAP_CMDS=(); MAP_VALS=(); MAP_DESCS=(); MAP_N=0
|
|||||||
load_map() {
|
load_map() {
|
||||||
MAP_CMDS=(); MAP_VALS=(); MAP_DESCS=(); MAP_N=0
|
MAP_CMDS=(); MAP_VALS=(); MAP_DESCS=(); MAP_N=0
|
||||||
[ -f "$MAP_FILE" ] || return 0
|
[ -f "$MAP_FILE" ] || return 0
|
||||||
local i=0 line cmd desc value
|
local i=0 cmd desc value
|
||||||
while IFS='|' read -r cmd desc value; do
|
while IFS=$'\x1f' read -r cmd desc value; do
|
||||||
[ -n "$cmd" ] || continue
|
[ -n "$cmd" ] || continue
|
||||||
i=$((i + 1))
|
i=$((i + 1))
|
||||||
MAP_CMDS[$i]="$cmd"; MAP_DESCS[$i]="$desc"; MAP_VALS[$i]="$value"
|
MAP_CMDS[$i]="$cmd"; MAP_DESCS[$i]="$desc"; MAP_VALS[$i]="$value"
|
||||||
@@ -182,7 +183,7 @@ build_commands_json() {
|
|||||||
|
|
||||||
sync_bot_commands() {
|
sync_bot_commands() {
|
||||||
load_config
|
load_config
|
||||||
[ -n "${TELEGRAM_BOT_TOKEN:-}" ] || { warn "no bot token — run 'pos communication telegram config set TELEGRAM_BOT_TOKEN=...' first"; return 1; }
|
[ -n "${TELEGRAM_BOT_TOKEN:-}" ] || { warn "no bot token — run 'pos config telegram' first"; return 1; }
|
||||||
command -v jq &>/dev/null || { warn "jq not found — cannot sync bot commands"; return 1; }
|
command -v jq &>/dev/null || { warn "jq not found — cannot sync bot commands"; return 1; }
|
||||||
local json n
|
local json n
|
||||||
json="$(build_commands_json)"
|
json="$(build_commands_json)"
|
||||||
@@ -462,8 +463,8 @@ handle_message() {
|
|||||||
run_daemon() {
|
run_daemon() {
|
||||||
command -v jq &>/dev/null || err "jq not found (install jq — in preinstall PACKAGES)"
|
command -v jq &>/dev/null || err "jq not found (install jq — in preinstall PACKAGES)"
|
||||||
load_config
|
load_config
|
||||||
[ -n "${TELEGRAM_BOT_TOKEN:-}" ] || err "No bot token — run 'pos communication telegram config set TELEGRAM_BOT_TOKEN=...'"
|
[ -n "${TELEGRAM_BOT_TOKEN:-}" ] || err "No bot token — run 'pos config telegram'"
|
||||||
[ -n "${TELEGRAM_CHAT_ID:-}" ] || err "No chat id — run 'pos communication telegram config set TELEGRAM_CHAT_ID=...'"
|
[ -n "${TELEGRAM_CHAT_ID:-}" ] || err "No chat id — run 'pos config telegram'"
|
||||||
sync_bot_commands || true
|
sync_bot_commands || true
|
||||||
|
|
||||||
local offset=0
|
local offset=0
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
# POS: communication telegram-sender — Send Telegram messages/files/links/stickers via Bot API (send, test, config set)
|
# POS: communication telegram-sender — Send Telegram messages/files/links/stickers via Bot API (send, test)
|
||||||
# POS_FLAGS: --type --caption --parse-mode --no-preview --token --chat-id --markdown
|
# POS_FLAGS: --type --caption --parse-mode --no-preview --token --chat-id --markdown
|
||||||
# POS_SUBCMDS: send test config
|
# POS_SUBCMDS: send test
|
||||||
# POS_CONFIG: telegram | telegram.env | TELEGRAM_BOT_TOKEN=secret:Bot token from @BotFather | TELEGRAM_CHAT_ID=digits:Numeric chat id from @userinfobot
|
# POS_CONFIG: telegram | telegram.env | TELEGRAM_BOT_TOKEN=secret:Bot token from @BotFather | TELEGRAM_CHAT_ID=digits:Numeric chat id from @userinfobot
|
||||||
|
|
||||||
CONFIG_DIR="$HOME/.config/linux_post_install"
|
CONFIG_DIR="$HOME/.config/linux_post_install"
|
||||||
@@ -18,8 +18,6 @@ Send Telegram messages via the Bot API.
|
|||||||
Commands:
|
Commands:
|
||||||
send <value> [options] Send a message, link, or media (auto-detects the type)
|
send <value> [options] Send a message, link, or media (auto-detects the type)
|
||||||
test Send a test message using the current config
|
test Send a test message using the current config
|
||||||
config Show current config (token masked)
|
|
||||||
config set KEY=VALUE Set TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID
|
|
||||||
|
|
||||||
Types (auto-detected when --type is omitted):
|
Types (auto-detected when --type is omitted):
|
||||||
message Plain text (default)
|
message Plain text (default)
|
||||||
@@ -41,8 +39,8 @@ Options:
|
|||||||
--token <t> Override token for one send
|
--token <t> Override token for one send
|
||||||
--chat-id <id> Override chat id for one send
|
--chat-id <id> Override chat id for one send
|
||||||
|
|
||||||
Config file: $CONFIG_FILE
|
Config: $CONFIG_FILE (TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID)
|
||||||
Keys: TELEGRAM_BOT_TOKEN | TELEGRAM_CHAT_ID
|
edit it with 'pos config telegram'
|
||||||
|
|
||||||
Precedence: CLI flags > environment > config file.
|
Precedence: CLI flags > environment > config file.
|
||||||
|
|
||||||
@@ -75,20 +73,10 @@ load_config() {
|
|||||||
done < <(grep -E '^[A-Z_]+=' "$CONFIG_FILE" || true)
|
done < <(grep -E '^[A-Z_]+=' "$CONFIG_FILE" || true)
|
||||||
}
|
}
|
||||||
|
|
||||||
mask_token() {
|
|
||||||
local t="$1"
|
|
||||||
[ -z "$t" ] && { echo "(not set)"; return; }
|
|
||||||
if [ "${#t}" -le 12 ]; then
|
|
||||||
echo "${t:0:4}... (${#t} chars)"
|
|
||||||
else
|
|
||||||
echo "${t:0:6}...${t: -4} (${#t} chars)"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
send_request() {
|
send_request() {
|
||||||
local endpoint="$1"; shift
|
local endpoint="$1"; shift
|
||||||
[ -z "${TELEGRAM_BOT_TOKEN:-}" ] && err "No bot token — run 'pos communication telegram config set TELEGRAM_BOT_TOKEN=...'"
|
[ -z "${TELEGRAM_BOT_TOKEN:-}" ] && err "No bot token — run 'pos config telegram'"
|
||||||
[ -z "${TELEGRAM_CHAT_ID:-}" ] && err "No chat id — run 'pos communication telegram config set TELEGRAM_CHAT_ID=...'"
|
[ -z "${TELEGRAM_CHAT_ID:-}" ] && err "No chat id — run 'pos config telegram'"
|
||||||
curl -fsS -m 60 -X POST "$API/bot${TELEGRAM_BOT_TOKEN}/${endpoint}" "$@" >/dev/null
|
curl -fsS -m 60 -X POST "$API/bot${TELEGRAM_BOT_TOKEN}/${endpoint}" "$@" >/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,37 +199,6 @@ cmd_send() {
|
|||||||
echo "[+] $type${auto:+ (auto-detected)} sent to chat ${TELEGRAM_CHAT_ID}"
|
echo "[+] $type${auto:+ (auto-detected)} sent to chat ${TELEGRAM_CHAT_ID}"
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_config() {
|
|
||||||
load_config
|
|
||||||
echo "Config: $CONFIG_FILE"
|
|
||||||
echo " TELEGRAM_BOT_TOKEN = $(mask_token "${TELEGRAM_BOT_TOKEN:-}")"
|
|
||||||
echo " TELEGRAM_CHAT_ID = ${TELEGRAM_CHAT_ID:-}"
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd_config_set() {
|
|
||||||
local kv="$1"
|
|
||||||
local key="${kv%%=*}"
|
|
||||||
local val="${kv#*=}"
|
|
||||||
case "$key" in
|
|
||||||
TELEGRAM_BOT_TOKEN|TELEGRAM_CHAT_ID) ;;
|
|
||||||
*) err "Unknown key '$key' (allowed: TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID)" ;;
|
|
||||||
esac
|
|
||||||
[ -z "$val" ] && err "No value given (expected $key=...)"
|
|
||||||
|
|
||||||
mkdir -p "$CONFIG_DIR"
|
|
||||||
if [ -f "$CONFIG_FILE" ]; then
|
|
||||||
if grep -q "^${key}=" "$CONFIG_FILE"; then
|
|
||||||
sed -i "s|^${key}=.*|${key}=${val}|" "$CONFIG_FILE"
|
|
||||||
else
|
|
||||||
echo "${key}=${val}" >>"$CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "${key}=${val}" >"$CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
chmod 600 "$CONFIG_FILE"
|
|
||||||
echo "[+] $key saved to $CONFIG_FILE"
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd="${1:-}"
|
cmd="${1:-}"
|
||||||
|
|
||||||
case "$cmd" in
|
case "$cmd" in
|
||||||
@@ -255,13 +212,6 @@ case "$cmd" in
|
|||||||
send_message "Test message from pos $(date '+%Y-%m-%d %H:%M:%S')"
|
send_message "Test message from pos $(date '+%Y-%m-%d %H:%M:%S')"
|
||||||
echo "[+] test message sent to chat ${TELEGRAM_CHAT_ID}"
|
echo "[+] test message sent to chat ${TELEGRAM_CHAT_ID}"
|
||||||
;;
|
;;
|
||||||
config)
|
|
||||||
shift
|
|
||||||
case "${1:-}" in
|
|
||||||
set) shift; [ $# -eq 1 ] || usage; cmd_config_set "$1" ;;
|
|
||||||
*) cmd_config ;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
echo "ERROR: Unknown telegram command '$cmd'"
|
echo "ERROR: Unknown telegram command '$cmd'"
|
||||||
echo "Run 'pos communication telegram-sender --help' for usage."
|
echo "Run 'pos communication telegram-sender --help' for usage."
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ that stdout is what gets sent.
|
|||||||
Modes:
|
Modes:
|
||||||
(default) Send the plugin output to Telegram (silent)
|
(default) Send the plugin output to Telegram (silent)
|
||||||
--print Print the output locally instead of sending
|
--print Print the output locally instead of sending
|
||||||
--markdown Send with Markdown parse_mode (via pos communication telegram)
|
--markdown Send with Markdown parse_mode (via pos communication telegram sender)
|
||||||
|
|
||||||
Available plugins:
|
Available plugins:
|
||||||
$plugins
|
$plugins
|
||||||
@@ -69,7 +69,7 @@ dir="$(plugin_dir)"
|
|||||||
script="$(resolve_plugin "$dir" "$plugin")"
|
script="$(resolve_plugin "$dir" "$plugin")"
|
||||||
|
|
||||||
rc=0
|
rc=0
|
||||||
output="$( "$script" "$@" )" || rc=$?
|
output="$( "$script" "${plugin_args[@]}" )" || rc=$?
|
||||||
if [ "$rc" -ne 0 ]; then
|
if [ "$rc" -ne 0 ]; then
|
||||||
err "Plugin '$plugin' failed (exit $rc)"
|
err "Plugin '$plugin' failed (exit $rc)"
|
||||||
fi
|
fi
|
||||||
@@ -87,7 +87,7 @@ telegram="$(dirname "$0")/pos-communication-telegram-sender"
|
|||||||
[ -n "$telegram" ] && [ -x "$telegram" ] || err "pos-communication-telegram-sender not found next to this script"
|
[ -n "$telegram" ] && [ -x "$telegram" ] || err "pos-communication-telegram-sender not found next to this script"
|
||||||
|
|
||||||
if [ "$MARKDOWN" -eq 1 ]; then
|
if [ "$MARKDOWN" -eq 1 ]; then
|
||||||
exec "$telegram" send "$output" --parse-mode markdown
|
exec "$telegram" send --parse-mode markdown -- "$output"
|
||||||
else
|
else
|
||||||
exec "$telegram" send "$output"
|
exec "$telegram" send -- "$output"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ _pos_flags[usb-server]="--ls --ls-shared --share --unshare --auto-share --callba
|
|||||||
# GEN:END posflags
|
# GEN:END posflags
|
||||||
# GEN:START possubcmds
|
# GEN:START possubcmds
|
||||||
declare -A _pos_subcmds
|
declare -A _pos_subcmds
|
||||||
_pos_subcmds[communication-telegram-sender]="send test config"
|
_pos_subcmds[communication-telegram-sender]="send test"
|
||||||
_pos_subcmds[docker-compose]="ls installed up down restart logs update config"
|
_pos_subcmds[docker-compose]="ls installed up down restart logs update config"
|
||||||
_pos_subcmds[docker-vbox]="create enter stop start rm ls"
|
_pos_subcmds[docker-vbox]="create enter stop start rm ls"
|
||||||
# GEN:END possubcmds
|
# GEN:END possubcmds
|
||||||
|
|||||||
+7
-7
@@ -176,7 +176,8 @@ cfg_value() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Write KEY="value" (append or replace) with mkdir -p + chmod 600; a value of
|
# Write KEY="value" (append or replace) with mkdir -p + chmod 600; a value of
|
||||||
# "-" removes the key's line. Same semantics as write_config_key().
|
# "-" removes the key's line. Same semantics as write_config_key(). Replaces
|
||||||
|
# via grep-v + append (not sed), so values may contain &, |, \ etc. safely.
|
||||||
cfg_write() {
|
cfg_write() {
|
||||||
local file="$1" key="$2" val="$3" tmp
|
local file="$1" key="$2" val="$3" tmp
|
||||||
mkdir -p "$(dirname "$file")"
|
mkdir -p "$(dirname "$file")"
|
||||||
@@ -188,11 +189,10 @@ cfg_write() {
|
|||||||
chmod 600 "$file"
|
chmod 600 "$file"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if [ -f "$file" ] && grep -q "^${key}=" "$file" 2>/dev/null; then
|
tmp="$(mktemp)"
|
||||||
sed -i "s|^${key}=.*|${key}=\"${val}\"|" "$file"
|
grep -v "^${key}=" "$file" 2>/dev/null >"$tmp" || true
|
||||||
else
|
printf '%s="%s"\n' "$key" "$val" >>"$tmp"
|
||||||
echo "${key}=\"${val}\"" >>"$file"
|
mv "$tmp" "$file"
|
||||||
fi
|
|
||||||
chmod 600 "$file"
|
chmod 600 "$file"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ cfg_display() {
|
|||||||
cfg_validate() {
|
cfg_validate() {
|
||||||
local flags="$1" val="$2"
|
local flags="$1" val="$2"
|
||||||
case ",$flags," in
|
case ",$flags," in
|
||||||
*,digits,*) [[ "$val" =~ ^[0-9]+$ ]] || { echo "must be digits only"; return 1; } ;;
|
*,digits,*) [[ "$val" =~ ^-?[0-9]+$ ]] || { echo "must be digits only (a leading '-' is allowed for group/supergroup ids)"; return 1; } ;;
|
||||||
esac
|
esac
|
||||||
case ",$flags," in
|
case ",$flags," in
|
||||||
*,num,*) [[ "$val" =~ ^-?[0-9]+$ ]] || { echo "must be an integer"; return 1; } ;;
|
*,num,*) [[ "$val" =~ ^-?[0-9]+$ ]] || { echo "must be an integer"; return 1; } ;;
|
||||||
|
|||||||
@@ -24,13 +24,12 @@ config_value() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
write_config_key() {
|
write_config_key() {
|
||||||
local key="$1" val="$2"
|
local key="$1" val="$2" tmp
|
||||||
mkdir -p "$CONFIG_DIR"
|
mkdir -p "$CONFIG_DIR"
|
||||||
if [ -f "$CONFIG_FILE" ] && grep -q "^${key}=" "$CONFIG_FILE" 2>/dev/null; then
|
tmp="$(mktemp)"
|
||||||
sed -i "s|^${key}=.*|${key}=\"${val}\"|" "$CONFIG_FILE"
|
grep -v "^${key}=" "$CONFIG_FILE" 2>/dev/null >"$tmp" || true
|
||||||
else
|
printf '%s="%s"\n' "$key" "$val" >>"$tmp"
|
||||||
echo "${key}=\"${val}\"" >>"$CONFIG_FILE"
|
mv "$tmp" "$CONFIG_FILE"
|
||||||
fi
|
|
||||||
chmod 600 "$CONFIG_FILE"
|
chmod 600 "$CONFIG_FILE"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +335,7 @@ sync_systemd() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
local f p
|
local f p removed=0
|
||||||
for f in "$USER_SYSTEMD_DIR"/${TIMER_PREFIX}-*.timer; do
|
for f in "$USER_SYSTEMD_DIR"/${TIMER_PREFIX}-*.timer; do
|
||||||
[ -f "$f" ] || continue
|
[ -f "$f" ] || continue
|
||||||
p="${f##*/}"; p="${p#${TIMER_PREFIX}-}"; p="${p%.timer}"
|
p="${f##*/}"; p="${p#${TIMER_PREFIX}-}"; p="${p%.timer}"
|
||||||
@@ -344,7 +343,9 @@ sync_systemd() {
|
|||||||
systemctl --user disable --now "$(unit_name "$p").timer" >/dev/null 2>&1 || true
|
systemctl --user disable --now "$(unit_name "$p").timer" >/dev/null 2>&1 || true
|
||||||
rm -f "$USER_SYSTEMD_DIR/$(unit_name "$p").timer" "$USER_SYSTEMD_DIR/$(unit_name "$p").service"
|
rm -f "$USER_SYSTEMD_DIR/$(unit_name "$p").timer" "$USER_SYSTEMD_DIR/$(unit_name "$p").service"
|
||||||
log "removed timer for '$p'"
|
log "removed timer for '$p'"
|
||||||
|
removed=1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
[ "$removed" -eq 1 ] && systemctl --user daemon-reload >/dev/null 2>&1 || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user