Compare commits
2 Commits
bb6152f679
...
641f37c629
| Author | SHA1 | Date |
|---|---|---|
|
|
641f37c629 | |
|
|
e8869005da |
|
|
@ -0,0 +1,162 @@
|
|||
# Key Findings: Emacs + napi Integration Research
|
||||
|
||||
> Brainstorm session 2026-02-27 — distilled from TASKS.org last TODO
|
||||
|
||||
---
|
||||
|
||||
## 1. Three Candidate Packages Evaluated
|
||||
|
||||
| Package | Verdict | Why |
|
||||
|:--------|:--------|:----|
|
||||
| **emacs-jabber** (XMPP client) | Skip | Overkill for notifications. Full chat client overhead. Already have jabber.el configured for `jla@librebits.snikket.chat` but bot sends to `jla@librebits.info` (different JID). Would need account bridging. |
|
||||
| **json-rpc-server.el + Porthole** | Skip | Over-engineered. Requires HTTP port exposure from zzz → local machine, firewall rules, session auth. Powerful but unnecessary when simpler options exist. |
|
||||
| **Built-in file-notify (TRAMP)** | **Winner** | Real-time, zero dependencies, pure Emacs. Runs `inotifywait` on remote host via SSH. No new packages needed. |
|
||||
|
||||
---
|
||||
|
||||
## 2. TRAMP + file-notify: The Key Discovery
|
||||
|
||||
The GNU Emacs manual states: *"It is also possible to watch filesystems on remote machines"*
|
||||
|
||||
### How it works (confirmed via Emacs 30.1 source analysis)
|
||||
|
||||
1. `file-notify-add-watch` on a TRAMP path (e.g., `/ssh:fenix@zzz:/home/jara/python/`)
|
||||
2. TRAMP's `tramp-sh-handle-file-notify-add-watch` kicks in
|
||||
3. It runs `inotifywait -mq -e create,modify,delete <path>` **on the remote host** via SSH
|
||||
4. Events stream back in real-time through the SSH tunnel
|
||||
5. `tramp-sh-inotifywait-process-filter` parses them into standard Emacs file-notify events
|
||||
6. Your callback fires with `(event-type file-path)` — just like local inotify
|
||||
|
||||
### Backend priority on remote (SSH)
|
||||
|
||||
1. **inotifywait** (preferred) — already installed on zzz
|
||||
2. **gio monitor** (fallback) — GLib-based, more portable
|
||||
3. Error if neither found
|
||||
|
||||
### NOT polling
|
||||
|
||||
This is a persistent SSH process streaming events. Latency = network RTT only (~ms for zzz).
|
||||
|
||||
---
|
||||
|
||||
## 3. Existing Emacs Infrastructure (Already Installed)
|
||||
|
||||
| Component | Status | Where |
|
||||
|:----------|:-------|:------|
|
||||
| **jabber.el** | Configured | `~/.emacs.d/init.el` line ~815 (`jla@librebits.snikket.chat`) |
|
||||
| **jsonrpc.el** (v1.0.27) | Installed (LSP/eglot) | Built-in |
|
||||
| **file-notify** | Built-in | Emacs 30.1 core |
|
||||
| **notifications** (D-Bus) | Built-in | `(require 'notifications)` |
|
||||
| **Two Emacs daemons** | Running | `server` + `water` (UI lives in `water`) |
|
||||
| **TRAMP** | Built-in | SSH ControlMaster reuses connections |
|
||||
|
||||
---
|
||||
|
||||
## 4. Current Notification Flow (What Already Works)
|
||||
|
||||
```
|
||||
Student uploads via SFTP → zzz:/home/USER/python/
|
||||
│
|
||||
▼
|
||||
inotifywait (watcher script)
|
||||
│
|
||||
▼
|
||||
python-upload-watcher.sh (v7)
|
||||
- Batches by folder (10s silence window)
|
||||
- Maps username → full name
|
||||
- Detects re-entregas (delete+recreate <120s)
|
||||
- Filters noise (Thumbs.db, __pycache__, etc.)
|
||||
│
|
||||
▼
|
||||
xmpp-notify.py (slixmpp)
|
||||
zzz@librebits.info → jla@librebits.info
|
||||
│
|
||||
▼
|
||||
Fénix's XMPP client (phone/desktop)
|
||||
```
|
||||
|
||||
The Emacs integration adds a **parallel path** — doesn't replace XMPP.
|
||||
|
||||
---
|
||||
|
||||
## 5. Alternative Approach: emacsclient via SSH (Fallback Plan)
|
||||
|
||||
If TRAMP file-notify proves unstable with 40+ watches, the fallback is:
|
||||
|
||||
### Reverse SSH tunnel (anka4 → zzz)
|
||||
|
||||
```bash
|
||||
# On anka4 (professor's machine):
|
||||
autossh -M 0 -N -R 2222:localhost:22 fenix@qu3v3d0.tech
|
||||
```
|
||||
|
||||
### Watcher modification on zzz
|
||||
|
||||
```bash
|
||||
# Added to watcher scripts after existing notify_xmpp call:
|
||||
notify_emacs() {
|
||||
ssh -p 2222 -o ConnectTimeout=3 -o BatchMode=yes fenix@localhost \
|
||||
emacsclient --socket-name=water --eval \
|
||||
"(napi-notify \"$group\" \"$user\" \"$files\" \"$(date +%H:%M)\")" \
|
||||
2>/dev/null &
|
||||
}
|
||||
```
|
||||
|
||||
### Security hardening (optional)
|
||||
|
||||
Restrict the reverse-tunnel SSH key to emacsclient-only via `authorized_keys`:
|
||||
```
|
||||
command="/home/fenix/.local/bin/napi-emacs-gateway.sh",no-port-forwarding ssh-ed25519 AAAA...
|
||||
```
|
||||
|
||||
This approach requires:
|
||||
- `autossh` on anka4
|
||||
- New SSH key pair (zzz → anka4)
|
||||
- systemd unit for the tunnel
|
||||
- Modifications to both watcher scripts on zzz
|
||||
|
||||
**More moving parts than TRAMP**, which is why TRAMP is the primary plan.
|
||||
|
||||
---
|
||||
|
||||
## 6. The `emacs --daemon=napi` Idea
|
||||
|
||||
Fénix asked: *"Am I crazy saying that ~/napi could be running remotely, as long as a `emacs --daemon=napi` which I could hook into an `emacsclient`?"*
|
||||
|
||||
**Answer: Not crazy at all.** A dedicated Emacs daemon for napi:
|
||||
|
||||
- Isolates the 40 TRAMP watches from the main `water` daemon
|
||||
- Can crash/restart independently without affecting the UI
|
||||
- Light footprint (no packages loaded beyond TRAMP + napi.el)
|
||||
- Managed via systemd (`emacs-napi.service`)
|
||||
- Forwards notifications to `water` for display
|
||||
- Queryable: `emacsclient --socket-name=napi --eval '(napi-status)'`
|
||||
|
||||
---
|
||||
|
||||
## 7. Practical Limits
|
||||
|
||||
| Concern | Reality |
|
||||
|:--------|:--------|
|
||||
| **40 inotifywait processes on zzz** | Kernel limit is ~65536 watches. 40 is trivial. |
|
||||
| **40 SSH channels** | TRAMP uses ControlMaster — 1 actual connection, multiplexed. |
|
||||
| **Memory on zzz** | Each inotifywait: ~1MB RSS. 40 = ~40MB. Fine. |
|
||||
| **file-notify on dirs (not recursive)** | Each student has 1 upload dir. No recursion needed. |
|
||||
| **SSH drops** | TRAMP sends `stopped` event. Elisp handler auto-restores watch. |
|
||||
|
||||
---
|
||||
|
||||
## 8. Packages NOT Needed
|
||||
|
||||
| Package | Why Skip |
|
||||
|:--------|:---------|
|
||||
| **Porthole** | HTTP RPC is overkill when TRAMP does it natively |
|
||||
| **emacs-jabber** | XMPP notifications already work outside Emacs |
|
||||
| **filenotify-recursive** | Student dirs are flat (no subdirs to recurse) |
|
||||
| **autossh** | Not needed if TRAMP approach works |
|
||||
|
||||
---
|
||||
|
||||
## 9. Next Step
|
||||
|
||||
Implement `PLAN.md` — create `napi.el`, `napi-init.el`, systemd unit, and test.
|
||||
56
TASKS.org
56
TASKS.org
|
|
@ -1,45 +1,21 @@
|
|||
#+title: TASKS — napi
|
||||
#+date: [2026-02-25]
|
||||
* CLona no el contenido en sí sino tan sólo la esructura de ~/napi-data/ a ~/napi-data2/ , teniendo en cuenta que :
|
||||
** en dicha carpeta se alojaran los datos de otro grupo de estudiantes : el de el módulo Programación. Es decir el grupo ASIR1.
|
||||
** los cambios introducidos en el servidor Web deben ser compatibles con las aplicaciones existentes
|
||||
** tendrán acceso a sus notas via notas.qu3v3d0.tech tras introducir, por obra del hack 'regexp-based-nginx-after-catch-all-content-redirect' ya desplegado en 'zzz', su usuario y contraseña
|
||||
** TODO generar lista de alumnos - AKAs en el mismo fichero ~/napi-data2/programacion-seguimiento-de-practicas.md
|
||||
* TODO , corregir/depurar mensaje : Claude, fíjate en @Screenshots/*.png s decir, que el chatbot no liste nada de "__pycache__/"
|
||||
|
||||
* DONE Clonar estructura ~/napi-data/ a ~/napi-data2/ para ASIR1
|
||||
CLOSED: [2026-02-25]
|
||||
** DONE Crear ~/napi-data2/ con 21 carpetas (apellido) + _plantilla/notas.md adaptada a Programación
|
||||
** DONE Decisión arquitectónica: subdominio separado (asir1.qu3v3d0.tech) en vez de regex hack
|
||||
- Más KISS: cada server block es independiente, sin lógica condicional
|
||||
- SSL wildcard *.qu3v3d0.tech ya cubre todos los subdominios
|
||||
** DONE Crear /var/www/napi2/ en zzz con viewer.html + marked.min.js + twemoji.min.js
|
||||
** DONE Server block Nginx para asir1.qu3v3d0.tech (auth_pam → /var/www/napi2/data/$remote_user/)
|
||||
** DONE Crear 21 usuarios SFTP en zzz (apellido, leet-speak passwords, chroot /home/USER/python/)
|
||||
** DONE Unit systemd sshfs: ~/napi-data2/ ↔ zzz:/var/www/napi2/data/
|
||||
** DONE Generar lista alumnos-AKAs en ~/napi-data2/programacion-seguimiento-de-las-practicas.md
|
||||
|
||||
* DONE Watcher XMPP para entregas ASIR1 — python-upload-watcher.sh
|
||||
CLOSED: [2026-02-25]
|
||||
** DONE v1: notificación básica por fichero (inotifywait + xmpp-notify.py)
|
||||
** DONE v1.1: detectar creación de carpetas (CREATE,ISDIR)
|
||||
** DONE v2: batching por carpeta — UN mensaje XMPP con listado completo (10s de silencio)
|
||||
** DONE v3: detectar re-entregas (delete+recreate <120s)
|
||||
** DONE v4: fix — estado en disco en vez de variables bash (subshell pipeline)
|
||||
** DONE v5: fix — eliminar 'local' fuera de funciones (syntax error en subshell)
|
||||
** DONE v6: filtrar __pycache__/, *.pyc, .git/, .venv/, node_modules/, .idea/, .vscode/
|
||||
** DONE v7: nombre completo en notificaciones ([María Jara] en vez de [jara])
|
||||
* TODO que el chatbot, en vez de :
|
||||
|
||||
* DONE Corregir notificaciones: no listar __pycache__/
|
||||
CLOSED: [2026-02-25]
|
||||
- Resuelto en watcher v6: is_junk() + is_junk_path() filtran directorios y ficheros basura
|
||||
- Filtros: __pycache__, *.pyc, *.pyo, .git, .venv, node_modules, .idea, .vscode
|
||||
- También filtra basura Windows/macOS: Thumbs.db, desktop.ini, .DS_Store, *.tmp
|
||||
** zzz@librebits.info 17:04
|
||||
🐍 [jara] Entrega ASIR1: Practicas/adivina-el-numero.py (1812 bytes)
|
||||
|
||||
* DONE Nombre completo en notificaciones XMPP (nombre + apellido)
|
||||
CLOSED: [2026-02-25]
|
||||
- Resuelto en watcher v7: función fullname() mapea username → nombre completo
|
||||
- Ejemplo: [jara] → [María Jara], [barrios] → [Andrés Barrios]
|
||||
- El log sigue usando username (para correlacionar con el sistema)
|
||||
|
||||
* DONE Documentación actualizada
|
||||
CLOSED: [2026-02-25]
|
||||
- README.md: reescrito para cubrir ambos grupos (DDAW2 + ASIR1)
|
||||
- CLAUDE.md: actualizado con arquitectura multi-grupo
|
||||
- scripts/README.md: watcher v7, ejemplos con nombres completos
|
||||
- nginx/README.md: ambos server blocks documentados
|
||||
- Commits: aa3126c + 42c1a7d → pushed to origin/main
|
||||
** diga : zzz@librebits.info 17:04
|
||||
🐍 [maría jara] Entrega ASIR1: Practicas/adivina-el-numero.py (1812 bytes)
|
||||
es decir, mencionar el/la autor/a de la entrega por ambos, nombre y apellido
|
||||
|
||||
|
||||
|
||||
* esto
|
||||
|
|
|
|||
Loading…
Reference in New Issue