control: add iroh gossip transport announcements and ec-node control CLI
This commit is contained in:
parent
fba1f3a7d5
commit
fe97623ba8
5 changed files with 494 additions and 23 deletions
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use anyhow::{Context, Result};
|
||||
use bytes::Bytes;
|
||||
use ec_core::StreamCatalogEntry;
|
||||
use ec_core::{StreamCatalogEntry, StreamControlAnnouncement};
|
||||
use futures_lite::StreamExt;
|
||||
use iroh::address_lookup::{
|
||||
DhtAddressLookup, DiscoveryEvent, DnsAddressLookup, MdnsAddressLookup, PkarrPublisher, UserData,
|
||||
|
|
@ -23,6 +23,7 @@ use std::time::{Duration, Instant};
|
|||
|
||||
pub const ALPN_MOQ: &[u8] = b"every.channel/moq/0";
|
||||
pub const DEFAULT_CATALOG_TOPIC: &str = "every.channel/catalog/v1";
|
||||
pub const DEFAULT_CONTROL_TOPIC: &str = "every.channel/control/v1";
|
||||
pub const MDNS_USER_DATA: &str = "every.channel";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -176,6 +177,11 @@ pub fn catalog_topic() -> TopicId {
|
|||
TopicId::from_bytes(*hash.as_bytes())
|
||||
}
|
||||
|
||||
pub fn control_topic() -> TopicId {
|
||||
let hash = blake3::hash(DEFAULT_CONTROL_TOPIC.as_bytes());
|
||||
TopicId::from_bytes(*hash.as_bytes())
|
||||
}
|
||||
|
||||
pub fn parse_endpoint_addr(value: &str) -> Result<EndpointAddr> {
|
||||
let value = value.trim();
|
||||
if value.starts_with('{') {
|
||||
|
|
@ -326,3 +332,75 @@ impl CatalogGossip {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ControlGossip {
|
||||
sender: GossipSender,
|
||||
receiver: GossipReceiver,
|
||||
_router: Router,
|
||||
_gossip: Gossip,
|
||||
_memory_lookup: MemoryLookup,
|
||||
}
|
||||
|
||||
impl ControlGossip {
|
||||
pub async fn join(endpoint: Endpoint, peers: &[String]) -> Result<Self> {
|
||||
let memory_lookup = MemoryLookup::new();
|
||||
endpoint.address_lookup().add(memory_lookup.clone());
|
||||
|
||||
let gossip = Gossip::builder().spawn(endpoint.clone());
|
||||
let router = Router::builder(endpoint.clone())
|
||||
.accept(GOSSIP_ALPN, gossip.clone())
|
||||
.spawn();
|
||||
|
||||
let peer_addrs = peers
|
||||
.iter()
|
||||
.map(|peer| parse_endpoint_addr(peer))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.context("failed to parse control peer addr")?;
|
||||
for peer in &peer_addrs {
|
||||
memory_lookup.add_endpoint_info(peer.clone());
|
||||
}
|
||||
let peer_ids = peer_addrs
|
||||
.iter()
|
||||
.map(|addr| addr.id)
|
||||
.collect::<Vec<PublicKey>>();
|
||||
|
||||
let (sender, receiver) = gossip
|
||||
.subscribe_and_join(control_topic(), peer_ids)
|
||||
.await?
|
||||
.split();
|
||||
|
||||
Ok(Self {
|
||||
sender,
|
||||
receiver,
|
||||
_router: router,
|
||||
_gossip: gossip,
|
||||
_memory_lookup: memory_lookup,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn announce(&mut self, announcement: StreamControlAnnouncement) -> Result<()> {
|
||||
let bytes = serde_json::to_vec(&announcement)?;
|
||||
self.sender.broadcast(Bytes::from(bytes)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn next_announcement(&mut self) -> Result<Option<StreamControlAnnouncement>> {
|
||||
while let Some(event) = self.receiver.try_next().await? {
|
||||
if let Event::Received(msg) = event {
|
||||
if let Ok(announcement) =
|
||||
serde_json::from_slice::<StreamControlAnnouncement>(&msg.content)
|
||||
{
|
||||
return Ok(Some(announcement));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn add_peers(&self, peers: Vec<EndpointAddr>) {
|
||||
for peer in peers {
|
||||
self._memory_lookup.add_endpoint_info(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue