OASIS_LINUX/docs/devs/architecture/05-mapa-funciones.txt
SITO ddd2787b73 Oasis 0.9.5 con Karvan para escritorio
Rama de desarrollo experimental sobre el Oasis de epsylon, sin afiliacion con el
proyecto original. Base: 0.9.5.

Trae el modulo Karvan —salas efimeras en memoria con autodestruccion por TTL, chat
que funciona sin JavaScript y llamadas de audio y video sobre WebRTC— con el enlace
en el menu lateral por el mismo patron que el resto de modulos: renderKarvanLink
calcado de renderPollsLink, entrada en modules_view y en la lista de /modules.

Los estilos del modulo van en su propia hoja, styles/karvan.css, siguiendo el patron
de highlight.css: asi se ve igual con cualquier tema, sin depender del tema movil.

Sin servidores ICE de terceros: no hay STUN de fabrica, porque un STUN aprende la IP
publica y el momento de cada llamada. Solo candidatos host salvo que se configure un
TURN propio en oasis-config.json, con credenciales efimeras por el mecanismo REST de
coturn.

El codigo propio vive separado —views/fork/, backend/fork_routes.js,
models/karvan_model.js y translations/fork/— de modo que sobre los ficheros de
upstream solo hay enganches de una linea y cada version nueva se integra sin
arrastrar nada.

Respecto al arbol de Android: fuera el wrapper y main.js, que es su arranque; el
tema vuelve a Dark-SNH y se restauran los modulos que en movil se recortan por peso.

Verificado arrancando sin OASIS_MOBILE: nueve rutas OK, menu lateral de upstream con
27 grupos y el enlace de Karvan, cero rastro de la interfaz movil (ni hexagonos, ni
topbar, ni barra inferior), y una sala creada y servida.
2026-08-19 00:35:08 +02:00

262 lines
13 KiB
Text

================================================================================
OASIS · MAPA DE FUNCIONES Y FLUJO
Cómo se relacionan las funciones lógicas entre archivos,
la persistencia (SSB) y la media (blobs)
versión 0.8.1
================================================================================
LEYENDA
[proc] proceso ( ) función / método
--> llamada / flujo === límite de proceso ~~~ red / disco
*.js archivo #NNN número de línea aprox.
================================================================================
0. VISIÓN GLOBAL: DOS PROCESOS
================================================================================
NAVEGADOR OTROS PEERS SSB
(HTML puro, (misma SHS cap)
sin JS) |
| HTTP :3000 | net:IP:8008~shs
v v ~~~~~~~~~~~~~
============================[proc gui]== ==============[proc sbot]======
| src/backend/backend.js (Koa router) | | src/server/SSB_server.js |
| | | SecretStack({caps}).use(..)|
| cooler = src/client/gui.js | | ssb-db (log append-only) |
| | | <-> | ssb-ebt / ssb-friends |
| | cooler.open() |unix | ssb-blobs / ssb-conn |
| v |sock | ssb-box / ssb-private |
| ssb (cliente muxrpc) ---------------|~noauth-> muxrpc API (publish,get, |
| | | createLogStream,...) |
========================================= ===============================
modelos + vistas replicación P2P por gossip
================================================================================
1. CADENA DE UNA PETICIÓN (el patrón de TODO módulo)
================================================================================
navegador
| GET /modulo (o POST /modulo/accion)
v
middleware.js (#43..#209) ── app.listen({host,port})
| setLanguage(cookie) · gate indexación · refresco shared-state(60s)
v
backend.js router.get('/modulo') #1270..#7124 (~472 rutas)
| checkMod(ctx,'moduloMod') #170 ── off? --> redirect /modules
|
+--> xModel.metodo(filtro) [ LECTURA / ESCRITURA SSB ] -----+
| (src/models/xxx_model.js) |
| v
| <------------------ datos JS ------------------------ cooler.open()
| (gui.js)
+--> xView(datos, filtro) [ RENDER HTML ] |
| (src/views/xxx_view.js) v
| template(i18n.titulo, section(...)) ssb muxrpc
v
ctx.body = "<html>...</html>" --> Koa --> navegador
POST: koaBody() -> stripDangerousTags() -> xModel.crear() -> ctx.redirect()
(patrón Post/Redirect/Get; el GET siguiente re-renderiza)
================================================================================
2. PERSISTENCIA: cómo el MODELO habla con SSB (pull-stream + publish)
================================================================================
src/models/xxx_model.js = module.exports = ({cooler, ...deps}) => ({...})
openSsb() ............ if(!ssb) ssb = await cooler.open(); // lazy, cacheado
|
v
ESCRIBIR (persistir):
ssb.publish({ type:'<tipo>', ...campos }, cb)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--> ssb-db: añade mensaje FIRMADO (ed25519) al log append-only
| del feed propio @miclave.ed25519
+--> ssb-ebt replica el mensaje a los peers (hops<=2) ~~~~>
LEER (consultar):
pull(
ssb.createLogStream({limit}) <-- lee el log local (todos los feeds
pull.filter(m => m.value.content.type === '<tipo>') replicados)
pull.collect((err,res)=>...)
)
(variantes: ssb.messagesByType, ssb.query.read, ssb.backlinks.read,
ssb.createUserStream{id})
BORRAR (lógico; el log NO se borra):
ssb.publish({ type:'tombstone', target:<msgId>, author })
|
+--> tombstone_validator.js :: buildValidatedTombstoneSet(msgs)
acepta SOLO si author(tombstone) === author(target) [autoría]
EDITAR:
ssb.publish({ ...nuevo, replaces:<idAnterior> }) + tombstone del viejo
|
+--> al leer, se sigue la cadena replaces -> hasta la "punta"
----------------------------------------------------------------------------
TIPOS DE MENSAJE (content.type) = el discriminador en el log compartido
----------------------------------------------------------------------------
nativos SSB : post · vote(like) · contact(follow/block) · about(perfil)
Oasis : votes · tombstone · task · event · calendar · transfer ·
tribe · market · report · job · project · gameScore · ...
================================================================================
3. MEDIA: cómo viajan los ficheros (BLOBS, fuera del log)
================================================================================
El log solo guarda el HASH. El binario viaja aparte por la red SSB.
SUBIR:
navegador --(multipart)--> backend.js --> blobHandler.js
ssb.blobs.add(pull-stream) --> &<sha256>.sha256 (ref = hash)
(luego se publica un mensaje con ese ref dentro de content)
MOSTRAR / DESCARGAR:
vista genera <img src="/blob/&xxx.sha256"> ó markdown.js resuelve menciones
|
v
backend.js ruta /blob/:id --> blobHandler.js
ssb.blobs.has(id)? --- no ---> ssb.blobs.want(id) ~~~~~~~~~~~~~~~~~>
| (gossip "want/has" a los peers)
+-- si ---> ssb.blobs.get(id) -> pull-stream -> ctx.body (bytes)
límite: 50 MB (ssb_config.js #17-19)
================================================================================
4. RENDER: cómo la VISTA construye HTML (hyperaxe, sin .html)
================================================================================
src/views/xxx_view.js
require("../server/node_modules/hyperaxe") -> div(), form(), section()...
require('./main_views') -> { template, i18n, userLink, markdown, chips }
exports.xView(datos) =
template( i18n.xTitle, // <- LAYOUT global
section( h2(i18n.xTitle), ...lista... ) )
|
v
main_views.js :: template(titulo, ...elems) #1017..#1321
html
+- head: <title> · CSS · /assets/themes/<tema>.css (oasis-config.themes)
+- body
+- header (logo, inbox badge <- shared-state, publish, search)
+- sidebar-left = navGroup(...) { renderXxxLink() por módulo }
| navLink({href,emoji,text}) #327
| renderGamesLink() #898 -> si gamesMod==='on' (config-manager)
+- main-content = tus secciones
i18n: objeto compartido mutado por setLanguage(lang) (11 idiomas)
backend middleware lo fija por cookie en cada request
markdown.js: ssb-markdown -> resuelve @feed,%msg,&blob,#hashtag a rutas /...
================================================================================
5. GRAFO DE DEPENDENCIAS ENTRE ARCHIVOS
================================================================================
src/backend/backend.js (orquestador central)
|--require--> ../client/gui.js .................. cooler (conexión SSB)
|--require--> ../client/middleware.js ........... http server Koa
|--require--> ../configs/config-manager.js ...... getConfig/saveConfig
|--require--> ../configs/shared-state.js ........ estado en memoria
|--require--> ./sanitizeHtml.js / ./blobHandler.js
|--require--> ../server/SSB_server.js ........... config + (sbot in-process)
|--require--> ../models/*_model.js (factories: ({cooler,deps}))
| |--inyecta--> otros modelos (agenda<-tasks,events,market..)
| |--inyecta--> *Crypto (crypto.js por dominio)
|--require--> ../views/*_view.js (funciones de render)
src/models/xxx_model.js
|--require--> pull-stream · moment
|--require--> ./tombstone_validator.js (función pura, sin deps)
|--require--> ../configs/config-manager.js
|--recibe----> cooler (NO importa gui directamente)
src/views/xxx_view.js
|--require--> hyperaxe
|--require--> ./main_views.js { template, i18n, userLink, helpers }
|--require--> moment · (a veces) ../server/SSB_server (feedId propio)
src/views/main_views.js (el "framework" de vistas)
|--require--> hyperaxe · lodash · highlight.js · qrcode · moment
|--require--> ./markdown.js · ../backend/renderUrl.js · ./sanitizeHtml?
|--require--> ../backend/nameCache.js (Map nombres <- main_models warmup)
|--require--> ../client/gui.js · ../configs/{config-manager,shared-state}
|--require--> ../client/assets/translations/i18n.js (11 idiomas)
src/server/SSB_server.js (sbot)
|--require--> secret-stack · ssb-caps · ssb-db · plugins ssb-*
|--require--> ./ssb_config.js (<- server-config.json) · ./ssb_metadata.js
|--require--> ./lanRouter.js (descubrimiento LAN)
================================================================================
6. EL MÓDULO GAMES, DE PRINCIPIO A FIN (ejemplo concreto)
================================================================================
MENU main_views.js #898 renderGamesLink() --(gamesMod==on)--> /games
|
LOBBY backend.js #1358 GET /games |
checkMod #170 -> gamesModel.getHallOfFame() #40 ----------+
| pull(createLogStream) |
| filter type==='gameScore' |
| best[game:author]=max(score) |
gamesView(filter,hall) #95 -> HTML |
|
PLAY GET /games/:name #1364 -> gameShellView(name) #60 |
<iframe src="/game-assets/<name>/index.html"> |
| |
STATIC middleware.js #109 mount('/game-assets', src/games/) ~~disk~+
|
JUEGO src/games/<name>/index.html (HTML+CSS+JS inline, canvas)
al terminar: form POST -> /games/submit-score target=_top
|
SCORE POST /games/submit-score #1369
gamesModel.submitScore(game,score) #28
ssb.publish({type:'gameScore',game,score}) ~~> SSB log
redirect /games?filter=scoring -> Hall of Fame
LISTAS A SINCRONIZAR (sin registro central):
games_view.js getGames() #5 + VALID_GAME_IDS #58 (16 juegos)
games_model.js VALID_GAMES #5 (14 -> falta rps,audio)
backend.js listas módulos #1346 #7038 #7054 #7040 ('games')
oasis-config.json modules.gamesMod
modules_view.js array modules #23
oasis_*.js gamesTitle, games<Nombre>Title/Desc (x11 idiomas)
================================================================================
7. CONFIG Y ESTADO (puntos de coordinación transversal)
================================================================================
oasis-config.json <--getConfig()/saveConfig()--> config-manager.js
| modules.{xMod:on/off} themes.current ux.current language
| wish pmVisibility lanBroadcasting ssbLogStream.limit wallet
+--leen--> backend.js (checkMod) · main_views (render links/tema) · modelos
server-config.json <-- ssb_config.js --> SSB_server.js
| caps.shs (red privada) friends.hops=2 connections (puerto 8008, unix)
shared-state.js (memoria, NO persistente)
| inboxCount carbon peersOnline ecoValue lastRefresh
+--escribe--> middleware refresco 60s +--lee--> main_views (badges)
nameCache.js (Map en memoria)
+--alimenta--> main_models._startNameWarmup (escucha 'about' en live)
+--consume---> main_models.about · main_views (mostrar nombres)
================================================================================
RESUMEN EN UNA FRASE
================================================================================
backend.js enruta -> el MODELO persiste/lee mensajes tipados en el log SSB
(replicado P2P por hops) y los blobs por want/has -> la VISTA (hyperaxe)
los pinta dentro de template() con i18n y tema -> y todo módulo se activa con
un flag xMod en oasis-config.json comprobado por checkMod().
================================================================================