runv-server

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

commit 799a9dbcaf091d012dfcfde7de2beb9ba203856a
parent 27ae2f5decf16d8af7006b6398048df3c3e90d75
Author: Pablo Murad <pablo@pablomurad.com>
Date:   Sat, 21 Mar 2026 15:09:35 -0300

chat, gemini and gopher

Diffstat:
Mscripts/admin/patch_irc.py | 39++++++++++++++++++++++++++++-----------
Mscripts/docs/irc_patch.md | 7+++++--
Mtools/motd/60-runv | 6+++---
3 files changed, 36 insertions(+), 16 deletions(-)

diff --git a/scripts/admin/patch_irc.py b/scripts/admin/patch_irc.py @@ -43,6 +43,7 @@ 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_SERVER_NAME: Final[str] = "runv" +DEFAULT_AUTOJOIN: Final[str] = "#runv" MIN_UID_USER: Final[int] = 1000 @@ -66,7 +67,6 @@ IRC_PATCH_SKIP_USERS: Final[frozenset[str]] = frozenset( "irc", "_apt", "nobody", - "pmurad-admin", "entre", "admin", "postmaster", @@ -207,14 +207,26 @@ def usernames_from_homes(homes_root: Path, log: logging.Logger) -> list[str]: def resolve_all_users(users_json: Path, homes_root: Path, log: logging.Logger) -> list[str]: from_json = load_usernames_from_json(users_json, log) - if from_json is not None and from_json: - log.info("utilizadores a partir de %s (%d)", users_json, len(from_json)) - return [u for u in from_json if u not in IRC_PATCH_SKIP_USERS] - if from_json is not None and from_json == []: - log.info("%s vazio — fallback /home", users_json) - users = usernames_from_homes(homes_root, log) - log.info("utilizadores a partir de %s (%d)", homes_root, len(users)) - return users + from_homes = usernames_from_homes(homes_root, log) + + if from_json is None: + log.info("utilizadores a partir de %s (%d); JSON indisponível", homes_root, len(from_homes)) + return from_homes + + if not from_json: + log.info("%s vazio — só homes em %s (%d)", users_json, homes_root, len(from_homes)) + return from_homes + + merged = sorted(set(from_json) | set(from_homes)) + log.info( + "utilizadores: união %s (%d) + %s (%d) → %d contas", + users_json, + len(from_json), + homes_root, + len(from_homes), + len(merged), + ) + return [u for u in merged if u not in IRC_PATCH_SKIP_USERS] def weechat_config_dir(home: Path) -> Path: @@ -563,9 +575,12 @@ def parse_args(argv: list[str] | None) -> argparse.Namespace: ) p.add_argument( "--autojoin", - default="", + default=DEFAULT_AUTOJOIN, metavar="CHANNELS", - help='canais separados por vírgula, ex.: "#runv,#geral" (vazio = nenhum)', + help=( + f'canais separados por vírgula (padrão: {DEFAULT_AUTOJOIN!r}); ' + 'use --autojoin "" para não autoentrar em canais' + ), ) ug = p.add_mutually_exclusive_group(required=True) ug.add_argument("--user", metavar="USER", help="apenas este utilizador Unix") @@ -634,6 +649,8 @@ def main(argv: list[str] | None = None) -> int: print("========== patch_irc — resumo ==========") print(f"Modo: {'DRY-RUN' if args.dry_run else 'aplicação'}") print(f"Host: {args.host}:{port} TLS: {args.tls} servidor na config: {args.server_name}") + aj = args.autojoin.strip() + print(f"Autojoin: {aj if aj else '(nenhum)'}") if not args.skip_backfill: print(f"Utilizadores processados: {len(users)} falhas: {failures}") print("Comando para utilizadores: chat") diff --git a/scripts/docs/irc_patch.md b/scripts/docs/irc_patch.md @@ -18,8 +18,10 @@ sudo python3 admin/patch_irc.py --user alice --verbose ``` - Instala **`/usr/local/bin/chat`** (salvo `--skip-launcher`). -- Por utilizador: `~/.config/weechat/`, servidor interno **`runv`** (por defeito), nick = **username Unix**, nicks alternativos `user_`, `user__`, `user|away`. +- Por utilizador: `~/.config/weechat/`, servidor interno **`runv`** (por defeito), nick = **username Unix**, nicks alternativos `user_`, `user__`, `user|away`, autojoin por defeito no canal **`#runv`**. +- Com **`--all-users`**, a lista de contas é a **união** de: usernames em `users.json` **e** utilizadores com diretório em `--homes-root` (por omissão `/home`), UID ≥ 1000 e fora da lista interna de contas de sistema — assim contas de administração (ex.: `pmurad-admin`) que não estão no JSON também são provisionadas. - Exige **`weechat-headless`** no sistema para aplicar o patch; sem esse binário o script falha com mensagem clara (`apt install weechat-headless`). +- Configurações já aplicadas sem o canal comum: voltar a correr com **`--force`** para atualizar `autojoin` (e restantes opções) para os defaults atuais. ## O que o utilizador faz @@ -37,7 +39,7 @@ Opcional: variável de ambiente **`WEECHAT_HOME`** para outro directório de dad | TLS | ligado (`--tls`; omitir `--no-tls`) | | Porta | `6697` com TLS, `6667` sem TLS (ou `--port`) | | Nome do servidor na config | `runv` | -| Autojoin | vazio; `--autojoin '#canal1,#canal2'` | +| Autojoin | `#runv`; `--autojoin ""` para nenhum; ou `--autojoin '#canal1,#canal2'` | Não há SASL/NickServ automático; no código há comentários para extensão futura com **dados seguros** (sem senhas em texto plano). @@ -60,6 +62,7 @@ sudo python3 admin/patch_irc.py --user "$(logname)" --verbose command -v chat && ls -l "$(command -v chat)" command -v weechat-headless sudo -u USER test -f /home/USER/.config/weechat/irc.conf && grep '^runv\.' /home/USER/.config/weechat/irc.conf +sudo -u USER grep '^runv\.autojoin' /home/USER/.config/weechat/irc.conf ``` Substitui `USER` por um utilizador real. diff --git a/tools/motd/60-runv b/tools/motd/60-runv @@ -30,7 +30,7 @@ RUNV_ART # Últimas 9 sessões em last(1) → grelha 3×3 (primeiro campo = utilizador) print_last_sessions_3x3() { if ! command -v last >/dev/null 2>&1; then - printf ' %s\n' "${D}(comando last indisponível)${R}" + printf ' %b\n' "${D}(comando last indisponível)${R}" return fi tf=$(mktemp -t runvmotd.XXXXXX 2>/dev/null) || tf=/tmp/runvmotd.$$ @@ -43,7 +43,7 @@ print_last_sessions_3x3() { ' > "$tf" || true if ! [ -s "$tf" ]; then - printf ' %s\n' "${D}(sem registos recentes em wtmp)${R}" + printf ' %b\n' "${D}(sem registos recentes em wtmp)${R}" rm -f "$tf" trap - EXIT HUP INT return @@ -75,7 +75,7 @@ printf ' %blynx%b %b—%b navegador web no terminal.\n' "${G}" "${R}" " printf ' %btmux%b %b—%b multiplexador de terminal (várias sessões).\n' "${G}" "${R}" "${D}" "${R}" printf ' %bbyobu%b %b—%b barra de estado e atalhos sobre tmux/screen.\n' "${G}" "${R}" "${D}" "${R}" printf ' %bmutt%b %b—%b cliente de e-mail no terminal.\n' "${G}" "${R}" "${D}" "${R}" -printf ' %bchat%b %b—%b IRC da rede da casa (configuração pelo admin).\n' "${G}" "${R}" "${D}" "${R}" +printf ' %bchat%b %b—%b IRC da rede da casa.\n' "${G}" "${R}" "${D}" "${R}" printf ' %badventure%b %b—%b jogo de aventura em texto (bsdgames).\n' "${G}" "${R}" "${D}" "${R}" print_last_sessions_3x3