feat(brahman-handshake): Fase 1 — handshake brahman sobre stream libp2p

Segundo paso del plan "el encuentro entre Entes no se restringe a
local". El protocolo brahman (Hello / HelloAck / Ping / Pong /
MatchEvent / Farewell, frames postcard length-prefixed) ahora tambien
viaja sobre streams libp2p de la malla brahman-net — el mismo Init
acepta sesiones por Unix socket Y por libp2p indistintamente, y un
consumer remoto puede dial-ar al multiaddr y completar handshake.

Cambios:

- Session<S> y Client<S> genericos: ambos dejan de estar atados a
  UnixStream y pasan a ser genericos sobre S: AsyncRead + AsyncWrite
  + Unpin + Send + 'static. El path Unix queda como
  Client = Client<UnixStream> (default generico). Constructores
  nuevos: Server::session_from_stream(stream),
  Client::connect_with_stream(stream, card, wit).

- Refactor del post-handshake con split: tokio::select! sobre
  &mut self.stream requeria S: Sync indirectamente, y libp2p::Stream
  no es Sync. Reemplazado por tokio::io::split(stream) -> reader loop
  principal + writer task separada que drena el push channel. Writer
  compartido bajo Arc<Mutex<WriteHalf<S>>> para serializar Pong/Error
  inline con los MatchEvents pusheados. Cleanup garantizado en todas
  las ramas. La logica del post-handshake migra a funciones libres
  (run_post_handshake, handle_inbound_frame, cleanup,
  broadcast_match_diffs, do_handshake, register_session,
  validate_hello).

- Nuevo modulo brahman-handshake::network:
  - BRAHMAN_HANDSHAKE_PROTOCOL = "/brahman/handshake/1.0.0"
  - LibP2pHandshakeStream = Compat<libp2p::Stream>
  - run_libp2p_accept_loop(server, net): accept loop que delega cada
    stream entrante a session_from_stream(stream.compat()). Sesiones
    libp2p y Unix conviven en el mismo Server — comparten broker,
    push table, last_matches.
  - connect_libp2p(net, peer, card, wit): abre stream libp2p al peer
    y arranca handshake.
  - NetworkError tipado.

Deps: brahman-handshake gana brahman-net, futures, tokio-util.
brahman-net re-exporta Multiaddr, PeerId, Stream, StreamProtocol,
Protocol, OpenStreamError para que callers no necesiten dep directa
a libp2p.

Tests: 9 verdes en el path Unix (sin regresion). Nuevo
tests/network_libp2p.rs E2E que arma server con BrahmanNet, hace
listen TCP, monta accept loop; cliente con su propio BrahmanNet
dial-ea al peer_id, completa handshake remoto, ping, farewell.
Verifica que la sesion se registro durante la conversacion y se
removio tras farewell.
This commit is contained in:
Sergio
2026-05-09 12:51:43 +00:00
parent ad0d475a2e
commit 73dadbb166
9 changed files with 723 additions and 281 deletions
+55
View File
@@ -6,6 +6,61 @@ ratio/diff ver `git show <sha>`.
## 2026-05-09
### feat(brahman-handshake): Fase 1 — handshake brahman sobre stream libp2p
Segundo paso del plan "el encuentro entre Entes no se restringe a
local". El protocolo brahman (Hello / HelloAck / Ping / Pong /
MatchEvent / Farewell, frames postcard length-prefixed) ahora también
viaja sobre streams libp2p de la malla `brahman-net` — el mismo Init
acepta sesiones por Unix socket Y por libp2p indistintamente, y un
consumer remoto puede dial-ar al multiaddr y completar handshake.
Cambios:
- **`Session<S>` y `Client<S>` genéricos**: ambos dejan de estar atados
a `UnixStream` y pasan a ser genéricos sobre `S: AsyncRead +
AsyncWrite + Unpin + Send + 'static`. El path Unix queda como
`Client = Client<UnixStream>` (default genérico). Constructores
nuevos: `Server::session_from_stream(stream)`,
`Client::connect_with_stream(stream, card, wit)`.
- **Refactor del post-handshake con split**: `tokio::select!` sobre
`&mut self.stream` requería `S: Sync` indirectamente, y
`libp2p::Stream` no es Sync. Reemplazado por
`tokio::io::split(stream)` → reader loop principal + writer task
separada que drena el push channel. Writer compartido bajo
`Arc<Mutex<WriteHalf<S>>>` para serializar Pong/Error inline con
los MatchEvents pusheados. Cleanup garantizado en todas las ramas.
La lógica del post-handshake migra a funciones libres
(`run_post_handshake`, `handle_inbound_frame`, `cleanup`,
`broadcast_match_diffs`, `do_handshake`, `register_session`,
`validate_hello`).
- **Nuevo módulo `brahman-handshake::network`**:
- `BRAHMAN_HANDSHAKE_PROTOCOL = "/brahman/handshake/1.0.0"`.
- `LibP2pHandshakeStream = Compat<libp2p::Stream>` (alias del
stream una vez convertido al mundo `tokio::io`).
- `run_libp2p_accept_loop(server, net)`: bucle accept sobre el
protocolo que delega cada stream entrante a una `Session`
construida vía `server.session_from_stream(stream.compat())`.
Sesiones libp2p y Unix conviven en el mismo `Server`
comparten broker, push table, last_matches.
- `connect_libp2p(net, peer, card, wit)`: abre stream libp2p al
`peer` y arranca handshake.
- `NetworkError` tipado (`OpenStream`, `Handshake`, `AcceptStream`).
Deps: `brahman-handshake` gana `brahman-net`, `futures`, `tokio-util`.
`brahman-net` re-exporta `Multiaddr`, `PeerId`, `Stream`,
`StreamProtocol`, `Protocol`, `OpenStreamError` para que callers no
necesiten dep directa a libp2p.
Tests:
- 9 tests unit + integration verdes (sin regresión en el path Unix).
- Nuevo `tests/network_libp2p.rs`: test E2E que arma server con
Unix socket + BrahmanNet, hace listen TCP, monta el accept loop;
cliente con su propio BrahmanNet dial-ea al peer_id, completa
handshake remoto, pinguea, farewell. Verifica que la sesión se
registró durante la conversación y se removió tras farewell.
Próximo: Fase 2 (discovery remoto vía DHT — anunciar Cards bajo
flow type, broker query local + remoto).
### feat(brahman-net): capa P2P compartida — Fase 0 (extracción del swarm libp2p)
Primer paso del plan "el encuentro entre Entes no se restringe a local".
El swarm libp2p que vivía dentro de `minga-p2p::network` (282 LOC) sale