Parte II — Tronco e radici
04 · Le radici: sottoterra
I baobab di una stessa regione si toccano con le radici. Una mucua non ha bisogno di internet per trovarne un'altra: basta che esista un cammino — un cavo, un'antenna, una rete Tor, o qualcuno che cammina con una chiavetta USB.
File da leggere
infra/sankofa.py— la facciata;infra/sync/__init__.pysceglie il backend.infra/sync/base.pyeinfra/sync/gitannex.py— i comandi git/annex veri (_execuccide l'albero dei processi allo scadere del timeout).services/links.py— i remote di ogni galassia, i tentativi via Tor, la riscoperta dell'.onion, l'autorizzazione tramite chiave SSH.services/sincronizacao.py—sincronizar_galaxia, il cuore del sync.infra/merge_bbx.py— il driver di merge semantico dei.bbx.services/pedidos.py— lo store-and-forward (richieste e rotte).infra/farol_lan.py,infra/tor_service.py,infra/ssh_keys.py.services/propagacao.py— l'identità locale rispecchiata in ogni galassia.
Git per il testo, git-annex per il resto
saber.bbxe i testi piccoli vanno in git (cronologia completa, merge).- Foto, video, PDF, sottotitoli
.vtt, testi OCR vanno nell'annex: in git resta solo un link con la chiave (SHA256E-s…--hash.ext). Ogni mucua decide cosa vuole avere (wanted) e può chiedere il resto più tardi. Il predefinito (DEFAULT_WANTED) porta sempre gli allegati di evento, mocambola e territorio, e quelli di articolo e collezione fino a 20 MB — le immagini del testo e le copertine; una galassia con il vecchio predefinito si aggiorna da sola alla sincronizzazione (garantir_wanted). - La regola sta in
GITATTRIBUTES(infra/sync/base.py):*.ocr.txt annex.largefiles=anythingvince su*.txt annex.largefiles=nothing. - Le stesse regole vanno anche nel
.git/info/attributesLOCALE (vince su quello versionato e si rifà a ogni sync), con un limite: il testo va in git solo fino a 2 MB (LIMITE_TEXTO_GIT) — un.jsonda 300 MB va nell'annex. Senza git-annex nel PATH, il file pesante resta fuori dal commit invece di entrare crudo in git. Ciò che è già entrato male:bbx annex-reparar(o Curare › File pesanti in git), inservices/annex_reparo.py.
Un ciclo di sincronizzazione
sequenceDiagram
autonumber
participant T as timer / POST /sync
participant S as sincronizar_galaxia
participant L as links
participant G as Sankofa (git-annex)
participant M as merge_bbx (driver)
participant R as SaberRepository
T->>S: galassia X
S->>S: TravaGalaxia (flock) — già in corso? esce
S->>L: garantir_annex_uuids (remote ↔ uuid della mucua)
alt qualche link è .onion
S->>S: _garantir_tor_local (avvia il Tor proprio)
end
loop ogni link abilitato
S->>G: git annex sync --remote=link (con nuovi tentativi se Tor)
G->>M: conflitto in *.bbx → merge campo per campo
alt fallito ed è .onion
S->>L: redescobrir_onion (chiede il nuovo indirizzo)
S->>G: riprova
end
end
S->>G: resolver_conflitos (interrompe un merge pendente e lo segnala)
S->>R: reindex(incremental=True)
opt data=true
S->>R: refrescar_presenca()
end
S->>S: atualizar_estado (svuota le cache)
Il merge che non si rompe
Un conflitto testuale in un saber.bbx lascerebbe lo YAML non valido, il saber sparirebbe dall'indice e la galassia smetterebbe di sincronizzarsi. Il driver merge_bbx.py unisce campo per campo: dizionari per chiave, liste di allegati per filename, scalari per l'updated più recente, e il corpo markdown con git merge-file. È simmetrico: eseguito sulla mucua A o sulla B, produce gli stessi byte — è questo che fa convergere la rete.
garantir_driver_merge scrive la regola in .git/info/attributes (locale, non versionato) prima di ogni sync: si ripara da sé quando cambia il percorso di Python.
Richieste: il contenuto viaggia di mano in mano
stateDiagram-v2
[*] --> ativo: criar_pedido (cercare | inviare)
ativo --> ativo: giro senza successo (il TTL non cambia)
ativo --> ativo: ha ottenuto la copia e NON sono la destinazione → copy --to salto successivo
ativo --> [*]: sono la destinazione e l'ho ricevuta → richiesta RIMOSSA
ativo --> expirado: ttl ≤ 0 (salti) o troppo vecchia
ativo --> cancelado: cancelar_pedido
expirado --> [*]
cancelado --> [*]
- La richiesta è un saber (
nature: pedido) scritto nel ramo della mucua che l'ha fatta — viaggia in git come qualsiasi altro. ttlconta salti, non tempo. L'età massima (_velho_demais) vale solo per una richiesta che non si è mai mossa.- Il ciclo non cancella mai una copia da solo. L'auto-drop ha già causato perdita di dati; liberare spazio è un'azione esplicita (
POST …/dropar). - Le rotte (
nature: rota) sono liste ordinate di mucua — il percorso di chi porta la chiavetta._proximo_saltodecide a chi spingere.
Cammini di rete
| Cammino | Dove sta | Il dettaglio che conta |
|---|---|---|
| SSH via internet | uri_internet della mucua | formato utente@host[:porta]; il percorso remoto è sempre ~utente/.baobaxia/galaxias/<cartella> (util.montar_url_ssh_galaxia) |
| Tor | uri_tor + tor_service.py | Tor proprio sulla porta SOCKS 19050; ProxyCommand con nc; diagnostica in infra/sync/tor_diagnostico.py |
| Rete locale | farol_lan.py | annuncio UDP multicast; l'indirizzo viene dall'origine del datagramma, non da ciò che dice il pacchetto |
| A piedi | richieste + rotte | store-and-forward |
La fiducia tra mucua è la chiave SSH: ssh_keys.py mantiene l'authorized_keys dell'utente baobaxia, la cui shell è git-annex-shell — passano solo comandi git/annex.
Identità rispecchiata
La mucua locale, il suo territorio e i suoi account vengono replicati con gli stessi UUID in ogni galassia di questa istanza (propagacao.sincronizar_identidade). È così che la stessa persona esiste in più archivi.
Esercizi
- Esegui
testes/test_merge_bbx.pye leggitest_as_duas_mucuas_convergem_para_os_mesmos_bytes. Costruisci a mano un conflitto (due modifiche dello stesso titolo) e guarda chi vince. - In
test_pedidos_logica_pratica.py, trova il caso "una richiesta soddisfatta viene RIMOSSA". Perché rimuoverla, e non segnarla come soddisfatta? - Disegna, per la tua regione, una
rotareale: quali mucua, in che ordine, e chi porta la chiavetta. - In
test_farol_rede_local.py, trova il test che verifica che l'indirizzo viene dall'ORIGINE del datagramma, e non dal contenuto del pacchetto. Quale attacco evita?
Da discutere
- Cosa significa "essere sincronizzati" in una rete in cui non sono mai tutti online nello stesso momento?
- Chi merita di essere un salto in una rotta? Che fiducia richiede?
