runv-server

server tooling for runv.club
Log | Files | Refs | README

commit 8f21b46d62364b6f11a92b0d06efa97dd079ac74
parent b43375bf7b3a8a175d1e466ba34943240ae6039c
Author: Pablo Murad <pablo@pablomurad.com>
Date:   Fri, 27 Mar 2026 01:25:00 -0300

patch irc

Diffstat:
Mdocs/05-tools-and-system-experience.md | 4++--
Mpatches/patch_irc.py | 2+-
Mscripts/admin/create_runv_user.py | 4++--
Mtools/bin/chat | 4++--
Mtools/bin/runv-help | 2+-
Mtools/tools.py | 36++++++++++++++++++++++++++++++++++++
6 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/docs/05-tools-and-system-experience.md b/docs/05-tools-and-system-experience.md @@ -28,8 +28,8 @@ Flags úteis: `--force`, `--skip-apt` (ver `--help`). ## IRC / comando `chat` - **Utilizador:** no servidor, use apenas o comando `chat` (wrapper em `/usr/local/bin/chat` após `tools/tools.py` ou `patches/patch_irc.py`). O cliente gráfico no terminal é `weechat` / `weechat-curses` (pacote `chat` no manifesto APT). -- **Por omissão** (após `patches/patch_irc.py`): o WeeChat fica com um único servidor com autoconnect no arranque — nome interno **`runv`**, endereço **`irc.portalidea.com.br`**, porta **6697**, **TLS ligado**, autojoin só **`#runv`**. Outras redes que o utilizador adicionar manualmente **não** autoconectam por defeito (o patch desliga `autoconnect` nos outros servidores já existentes, sem apagar redes). -- **Provisionamento:** o patch corre com `weechat-headless -a -r '…' --stdout` (o `-a` evita auto-connect durante o batch). O launcher **`chat` não usa `-a`**. Novas contas Unix criadas com `scripts/admin/create_runv_user.py` invocam o patch automaticamente para esse utilizador. +- **Por omissão** (após `patches/patch_irc.py`): o WeeChat fica com um único servidor com autoconnect no arranque — nome interno **`runv`**, endereço **`irc.tilde.chat`**, porta **6697**, **TLS ligado**, autojoin só **`#runv`**. Outras redes que o utilizador adicionar manualmente **não** autoconectam por defeito (o patch desliga `autoconnect` nos outros servidores já existentes, sem apagar redes). +- **Provisionamento:** o patch corre com `weechat-headless -a -r '…' --stdout` (o `-a` evita auto-connect durante o batch). O launcher **`chat` não usa `-a`**. Novas contas Unix criadas com `scripts/admin/create_runv_user.py` invocam o patch automaticamente para esse utilizador. O `tools/tools.py` também aplica o backfill IRC ao final da execução. - **Backfill / admin:** `sudo python3 patches/patch_irc.py --all-users` (ou `--user NOME`). Requer `weechat-headless` no sistema. Próximo: [06-site-and-apache.md](06-site-and-apache.md). diff --git a/patches/patch_irc.py b/patches/patch_irc.py @@ -45,7 +45,7 @@ VERSION: Final[str] = "0.04" DEFAULT_USERS_JSON: Final[Path] = Path("/var/lib/runv/users.json") DEFAULT_HOMES_ROOT: Final[Path] = Path("/home") -DEFAULT_HOST: Final[str] = "irc.portalidea.com.br" +DEFAULT_HOST: Final[str] = "irc.tilde.chat" DEFAULT_PORT_TLS: Final[int] = 6697 DEFAULT_SERVER_NAME: Final[str] = "runv" DEFAULT_AUTOJOIN: Final[str] = "#runv" diff --git a/scripts/admin/create_runv_user.py b/scripts/admin/create_runv_user.py @@ -1257,7 +1257,7 @@ def try_patch_irc_for_new_user( log: logging.Logger, ) -> None: """ - Executa ``patches/patch_irc.py --user`` (WeeChat headless: servidor «runv», TLS, #runv). + Executa ``patches/patch_irc.py --user`` (WeeChat headless: servidor «runv», irc.tilde.chat, TLS, #runv). Não aborta o provisionamento se o patch falhar; contas em ``IRC_PATCH_SKIP_USERS`` são ignoradas. """ if dry_run: @@ -1908,7 +1908,7 @@ def main(argv: list[str] | None = None) -> int: print(" public_gopher: pronto (gophermap)") print(" public_gemini: pronto (index.gmi)") print(" bind Gemini: /var/gemini/users/<user> <- ~/public_gemini (se o diretório existir)") - print(" IRC: comando «chat» → irc.portalidea.com.br (TLS) #runv (patch_irc.py)") + print(" IRC: comando «chat» → irc.tilde.chat (TLS) #runv (patch_irc.py)") if args.with_readme: print(" README.md: criado em ~/README.md (pt-BR)") else: diff --git a/tools/bin/chat b/tools/bin/chat @@ -1,6 +1,6 @@ #!/bin/sh # runv.club — cliente IRC interactivo; config em ~/.config/weechat. -# Por omissão (após patches/patch_irc.py): servidor interno «runv» → irc.portalidea.com.br:6697 (TLS), canal #runv. +# Por omissão (após patches/patch_irc.py): servidor interno «runv» → irc.tilde.chat:6697 (TLS), canal #runv. # Utilizadores: use só o comando «chat»; não é preciso memorizar outros nomes de binário. IRC_UI="" @@ -33,7 +33,7 @@ if [ ! -f "$CONFIG_DIR/irc.conf" ]; then echo "runv: peça ao admin para correr patches/patch_irc.py (rede IRC da casa)." >&2 elif ! grep -q '^runv\.' "$CONFIG_DIR/irc.conf" 2>/dev/null; then echo "runv: aviso — servidor «runv» não está definido em $CONFIG_DIR/irc.conf." >&2 - echo "runv: o admin pode aplicar patches/patch_irc.py (TLS, #runv em irc.portalidea.com.br)." >&2 + echo "runv: o admin pode aplicar patches/patch_irc.py (TLS, #runv em irc.tilde.chat)." >&2 fi exec "$IRC_UI" -d "$CONFIG_DIR" "$@" diff --git a/tools/bin/runv-help b/tools/bin/runv-help @@ -29,7 +29,7 @@ printf ' %bgit%b Controlo de versão.\n' "${G}" "${R}" printf ' %bless%b Paginar ficheiros longos (ex.: less README.md).\n' "${G}" "${R}" printf ' %btmux%b / %bbyobu%b Multiplexadores de terminal (várias sessões).\n' "${G}" "${R}" "${G}" "${R}" printf ' %bmutt%b E-mail no terminal.\n' "${G}" "${R}" -printf ' %bchat%b IRC da rede da casa (após o admin aplicar o patch no servidor).\n' "${G}" "${R}" +printf ' %bchat%b IRC da rede da casa.\n' "${G}" "${R}" printf ' %btree%b Árvore de diretórios.\n' "${G}" "${R}" printf ' %brunv-games%b Jogos do servidor (inclui adventure e gotchi).\n' "${G}" "${R}" printf '\n' diff --git a/tools/tools.py b/tools/tools.py @@ -34,6 +34,7 @@ DEST_BIN_DIR: Path = Path("/usr/local/bin") DEST_MOTD: Path = Path("/etc/update-motd.d/60-runv") DEST_SKEL: Path = Path("/etc/skel") DEST_SSHD_DROPIN: Path = Path("/etc/ssh/sshd_config.d/90-runv-jailed.conf") +PATCH_IRC_PATH: Path = TOOL_ROOT.parent / "patches" / "patch_irc.py" @dataclass @@ -452,6 +453,38 @@ def install_skel( os.chmod(gemini_dir, 0o755) +def apply_irc_patch( + *, + dry_run: bool, + log: logging.Logger, + summary: RunSummary, +) -> None: + if not PATCH_IRC_PATH.is_file(): + msg = f"patch IRC não encontrado: {PATCH_IRC_PATH}" + summary.errors.append(msg) + log.error("%s", msg) + return + + cmd = [sys.executable, str(PATCH_IRC_PATH), "--all-users"] + if dry_run: + log.info("[dry-run] %s", " ".join(cmd)) + summary.copied.append(f"patch IRC (simulado): {' '.join(cmd)}") + return + + r = run_subprocess(cmd, dry_run=False, log=log) + assert r is not None + if r.returncode != 0: + err = (r.stderr or r.stdout or "").strip() + msg = f"patch_irc.py falhou (código {r.returncode})" + (f": {err}" if err else "") + summary.errors.append(msg) + log.error("%s", msg) + return + + summary.copied.append("patch IRC aplicado a todos os utilizadores") + if r.stdout.strip(): + log.info("patch IRC: %s", r.stdout.strip().splitlines()[-1]) + + def print_summary(summary: RunSummary, log: logging.Logger) -> None: print() print("========== runv-tools — resumo ==========") @@ -539,6 +572,9 @@ def main(argv: list[str] | None = None) -> int: log.info("Sincronizando skel em %s", DEST_SKEL) install_skel(force=args.force, dry_run=args.dry_run, log=log, summary=summary) + log.info("Aplicando patch IRC (chat / WeeChat)") + apply_irc_patch(dry_run=args.dry_run, log=log, summary=summary) + print_summary(summary, log) return 0