Added bytestream ALPN

This commit is contained in:
Ultradesu
2026-07-16 18:35:21 +03:00
parent b9c61e2249
commit 555222d6d7
9 changed files with 630 additions and 5 deletions
+14
View File
@@ -52,6 +52,9 @@ pub struct MusicDhtConfig {
/// network find each other knowing nothing but the network id. `None`
/// disables it; peers are then connected via tickets only.
pub rendezvous: Option<RendezvousConfig>,
/// Auxiliary ALPN protocols on which this peer accepts raw byte streams
/// (see [`crate::MusicDhtService::stream_acceptor`]).
pub stream_protocols: Vec<Vec<u8>>,
}
impl MusicDhtConfig {
@@ -76,6 +79,7 @@ pub struct MusicDhtConfigBuilder {
transport_timeout: Option<Duration>,
dial_timeout: Option<Duration>,
rendezvous: Option<RendezvousConfig>,
stream_protocols: Vec<Vec<u8>>,
}
impl MusicDhtConfigBuilder {
@@ -133,6 +137,15 @@ impl MusicDhtConfigBuilder {
self
}
/// Declares an auxiliary ALPN protocol on which this peer accepts raw
/// byte streams (see [`crate::MusicDhtService::stream_acceptor`]). May
/// be called multiple times, once per protocol. The ALPNs are validated
/// by the underlying network engine on service start.
pub fn stream_protocol(mut self, alpn: impl Into<Vec<u8>>) -> Self {
self.stream_protocols.push(alpn.into());
self
}
/// Validates and builds the configuration.
pub fn build(self) -> Result<MusicDhtConfig> {
let data_dir = self
@@ -157,6 +170,7 @@ impl MusicDhtConfigBuilder {
transport_timeout: self.transport_timeout.unwrap_or(DEFAULT_TRANSPORT_TIMEOUT),
dial_timeout: self.dial_timeout.unwrap_or(DEFAULT_DIAL_TIMEOUT),
rendezvous: self.rendezvous,
stream_protocols: self.stream_protocols,
};
for (name, value) in [
("republish_interval", config.republish_interval),
+4 -1
View File
@@ -105,4 +105,7 @@ pub use service::{
};
// Re-exported types from the transport layer that appear in this API.
pub use federation_net::{EndpointId, NetworkId, PeerTicket, RendezvousConfig};
pub use federation_net::{
ByteStream, EndpointAddr, EndpointId, NetworkId, PeerTicket, RecvStream, RendezvousConfig,
SendStream, StreamAcceptor,
};
+40 -1
View File
@@ -4,7 +4,10 @@ use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use std::time::{Duration, Instant};
use federation_net::{EndpointId, NetworkConfig, NetworkEngine, PeerTicket, SchemaId};
use federation_net::{
ByteStream, EndpointAddr, EndpointId, NetworkConfig, NetworkEngine, PeerTicket, SchemaId,
StreamAcceptor,
};
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
use tracing::info;
@@ -164,6 +167,9 @@ impl MusicDhtService {
if let Some(rendezvous) = config.rendezvous.clone() {
engine_builder = engine_builder.rendezvous(rendezvous);
}
for alpn in &config.stream_protocols {
engine_builder = engine_builder.stream_protocol(alpn.clone());
}
let engine_config = engine_builder
.build()
.map_err(|err| MusicDhtError::Network(err.to_string()))?;
@@ -241,6 +247,39 @@ impl MusicDhtService {
self.node.engine.is_connected(peer)
}
/// Takes the acceptor of incoming raw byte streams for the stream
/// protocol `alpn` declared in the configuration.
///
/// The acceptor for a protocol can be taken exactly once; see
/// [`federation_net::NetworkEngine::stream_acceptor`].
pub fn stream_acceptor(&self, alpn: &[u8]) -> Result<StreamAcceptor> {
self.node.ensure_running()?;
self.node.engine.stream_acceptor(alpn).map_err(Into::into)
}
/// Opens a raw byte stream to `peer` on the auxiliary ALPN `alpn`.
///
/// The peer is dialed using the address from its stored DHT contact
/// when one is known (which is the case for every peer that appears in
/// search results), falling back to whatever the transport itself knows
/// about the peer. See [`federation_net::NetworkEngine::open_stream`].
pub async fn open_stream(&self, peer: EndpointId, alpn: &[u8]) -> Result<ByteStream> {
self.node.ensure_running()?;
let contact_addr = self
.node
.known_contacts()
.into_iter()
.find(|contact| contact.peer_id == peer)
.and_then(|contact| contact.ticket.parse::<PeerTicket>().ok())
.map(|ticket| ticket.endpoint_addr);
let addr: EndpointAddr = contact_addr.unwrap_or_else(|| peer.into());
self.node
.engine
.open_stream(addr, alpn)
.await
.map_err(Into::into)
}
/// Synchronizes the published library with `specs`: the desired set of
/// items this peer wants to share.
///