================================================================================ 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 = "..." --> 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:'', ...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 === '') 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:, author }) | +--> tombstone_validator.js :: buildValidatedTombstoneSet(msgs) acepta SOLO si author(tombstone) === author(target) [autoría] EDITAR: ssb.publish({ ...nuevo, replaces: }) + 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 (ref = hash) (luego se publica un mensaje con ese ref dentro de content) MOSTRAR / DESCARGAR: vista genera ó 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: · 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(). ================================================================================