Skip to main content

connexa/
types.rs

1#![allow(unused_imports)]
2use crate::error::ConnexaResult;
3use crate::handle::swarm::ConnectionTarget;
4use crate::prelude::swarm::{DialError, ListenError, ListenOpts, SwarmEvent};
5use bytes::Bytes;
6use either::Either;
7use futures::channel::{mpsc, oneshot};
8use futures::future::BoxFuture;
9use futures::stream::BoxStream;
10use indexmap::IndexSet;
11use libp2p::core::ConnectedPoint;
12#[cfg(feature = "gossipsub")]
13use libp2p::gossipsub::{MessageAcceptance, MessageId};
14#[cfg(feature = "kad")]
15use libp2p::kad::{Mode, PeerInfo, PeerRecord, ProviderRecord, Quorum, Record, RecordKey};
16#[cfg(feature = "rendezvous")]
17use libp2p::rendezvous::Cookie;
18#[cfg(feature = "request-response")]
19use libp2p::request_response::InboundRequestId;
20use libp2p::swarm::derive_prelude::ListenerId;
21use libp2p::swarm::dial_opts::DialOpts;
22use libp2p::swarm::{ConnectionError, ConnectionId};
23use libp2p::{Multiaddr, PeerId, StreamProtocol};
24use libp2p_connection_limits::ConnectionLimits;
25use other_error::ArcError;
26use std::collections::HashSet;
27use std::convert::Infallible;
28use std::sync::Arc;
29
30type Result<T> = std::io::Result<T>;
31
32#[derive(Debug)]
33pub enum Command<T = ()> {
34    Swarm(SwarmCommand),
35    #[cfg(feature = "gossipsub")]
36    Gossipsub(GossipsubCommand),
37    #[cfg(feature = "floodsub")]
38    Floodsub(FloodsubCommand),
39    #[cfg(feature = "kad")]
40    Dht(DHTCommand),
41    #[cfg(feature = "request-response")]
42    RequestResponse(RequestResponseCommand),
43    #[cfg(feature = "stream")]
44    Stream(StreamCommand),
45    #[cfg(feature = "rendezvous")]
46    Rendezvous(RendezvousCommand),
47    #[cfg(feature = "autonat")]
48    Autonat(AutonatCommand),
49    #[cfg(feature = "relay")]
50    AutoRelay(AutoRelayCommand),
51    Whitelist(WhitelistCommand),
52    Blacklist(BlacklistCommand),
53    ConnectionLimits(ConnectionLimitsCommand),
54    Peerstore(PeerstoreCommand),
55    Custom(T),
56}
57
58impl<T> From<SwarmCommand> for Command<T> {
59    fn from(cmd: SwarmCommand) -> Self {
60        Command::Swarm(cmd)
61    }
62}
63
64#[cfg(feature = "autonat")]
65impl<T> From<AutonatCommand> for Command<T> {
66    fn from(cmd: AutonatCommand) -> Self {
67        Command::Autonat(cmd)
68    }
69}
70
71#[cfg(feature = "gossipsub")]
72impl<T> From<GossipsubCommand> for Command<T> {
73    fn from(cmd: GossipsubCommand) -> Self {
74        Command::Gossipsub(cmd)
75    }
76}
77
78#[cfg(feature = "floodsub")]
79impl<T> From<FloodsubCommand> for Command<T> {
80    fn from(cmd: FloodsubCommand) -> Self {
81        Command::Floodsub(cmd)
82    }
83}
84
85#[cfg(feature = "kad")]
86impl<T> From<DHTCommand> for Command<T> {
87    fn from(cmd: DHTCommand) -> Self {
88        Command::Dht(cmd)
89    }
90}
91
92#[cfg(feature = "request-response")]
93impl<T> From<RequestResponseCommand> for Command<T> {
94    fn from(cmd: RequestResponseCommand) -> Self {
95        Command::RequestResponse(cmd)
96    }
97}
98
99#[cfg(feature = "stream")]
100impl<T> From<StreamCommand> for Command<T> {
101    fn from(cmd: StreamCommand) -> Self {
102        Command::Stream(cmd)
103    }
104}
105
106#[cfg(feature = "rendezvous")]
107impl<T> From<RendezvousCommand> for Command<T> {
108    fn from(cmd: RendezvousCommand) -> Self {
109        Command::Rendezvous(cmd)
110    }
111}
112
113#[cfg(feature = "relay")]
114impl<T> From<AutoRelayCommand> for Command<T> {
115    fn from(cmd: AutoRelayCommand) -> Self {
116        Command::AutoRelay(cmd)
117    }
118}
119
120impl<T> From<WhitelistCommand> for Command<T> {
121    fn from(cmd: WhitelistCommand) -> Self {
122        Command::Whitelist(cmd)
123    }
124}
125
126impl<T> From<BlacklistCommand> for Command<T> {
127    fn from(cmd: BlacklistCommand) -> Self {
128        Command::Blacklist(cmd)
129    }
130}
131
132impl<T> From<ConnectionLimitsCommand> for Command<T> {
133    fn from(cmd: ConnectionLimitsCommand) -> Self {
134        Command::ConnectionLimits(cmd)
135    }
136}
137
138impl<T> From<PeerstoreCommand> for Command<T> {
139    fn from(value: PeerstoreCommand) -> Self {
140        Command::Peerstore(value)
141    }
142}
143
144#[derive(Debug)]
145pub enum SwarmCommand {
146    Dial {
147        opt: DialOpts,
148        resp: oneshot::Sender<ConnexaResult<ConnectionId>>,
149    },
150    IsConnected {
151        peer_id: PeerId,
152        resp: oneshot::Sender<bool>,
153    },
154    Disconnect {
155        target_type: ConnectionTarget,
156        resp: oneshot::Sender<ConnexaResult<()>>,
157    },
158    ConnectedPeers {
159        resp: oneshot::Sender<Vec<PeerId>>,
160    },
161    ListenOn {
162        address: Multiaddr,
163        resp: oneshot::Sender<ConnexaResult<ListenerId>>,
164    },
165    GetListeningAddress {
166        id: ListenerId,
167        resp: oneshot::Sender<ConnexaResult<Vec<Multiaddr>>>,
168    },
169    RemoveListener {
170        listener_id: ListenerId,
171        resp: oneshot::Sender<ConnexaResult<()>>,
172    },
173    AddExternalAddress {
174        address: Multiaddr,
175        resp: oneshot::Sender<ConnexaResult<()>>,
176    },
177    RemoveExternalAddress {
178        address: Multiaddr,
179        resp: oneshot::Sender<ConnexaResult<()>>,
180    },
181    ListExternalAddresses {
182        resp: oneshot::Sender<Vec<Multiaddr>>,
183    },
184    ListListeningAddresses {
185        resp: oneshot::Sender<Vec<Multiaddr>>,
186    },
187    AddPeerAddress {
188        peer_id: PeerId,
189        address: Multiaddr,
190        resp: oneshot::Sender<ConnexaResult<()>>,
191    },
192    Listener {
193        resp: oneshot::Sender<mpsc::Receiver<ConnexaSwarmEvent>>,
194    },
195}
196
197#[derive(Debug, Clone)]
198pub enum ConnexaSwarmEvent {
199    ConnectionEstablished {
200        peer_id: PeerId,
201        connection_id: ConnectionId,
202        endpoint: ConnectedPoint,
203        established: u32,
204    },
205    ConnectionClosed {
206        peer_id: PeerId,
207        connection_id: ConnectionId,
208        endpoint: ConnectedPoint,
209        num_established: u32,
210        cause: Option<ArcError<ConnectionError>>,
211    },
212    IncomingConnection {
213        connection_id: ConnectionId,
214        local_addr: Multiaddr,
215        send_back_addr: Multiaddr,
216    },
217    IncomingConnectionError {
218        connection_id: ConnectionId,
219        local_addr: Multiaddr,
220        send_back_addr: Multiaddr,
221        error: ArcError<ListenError>,
222        peer_id: Option<PeerId>,
223    },
224    OutgoingConnectionError {
225        connection_id: ConnectionId,
226        peer_id: Option<PeerId>,
227        error: ArcError<DialError>,
228    },
229    NewListenAddr {
230        id: ListenerId,
231        address: Multiaddr,
232    },
233    ListenAddrExpired {
234        id: ListenerId,
235        address: Multiaddr,
236    },
237    ListenAddrClosed {
238        id: ListenerId,
239        addresses: Vec<Multiaddr>,
240    },
241    NewExternalAddr {
242        address: Multiaddr,
243    },
244    ExternalAddrExpired {
245        address: Multiaddr,
246    },
247    ExternalAddrOfPeer {
248        peer_id: PeerId,
249        address: Multiaddr,
250    },
251}
252
253#[cfg(feature = "floodsub")]
254#[derive(Debug)]
255pub enum FloodsubCommand {
256    Subscribe {
257        topic: libp2p::floodsub::Topic,
258        resp: oneshot::Sender<ConnexaResult<()>>,
259    },
260    Unsubscribe {
261        topic: libp2p::floodsub::Topic,
262        resp: oneshot::Sender<ConnexaResult<()>>,
263    },
264    AddNodeToPartialView {
265        peer_id: PeerId,
266        resp: oneshot::Sender<ConnexaResult<()>>,
267    },
268    RemoveNodeFromPartialView {
269        peer_id: PeerId,
270        resp: oneshot::Sender<ConnexaResult<()>>,
271    },
272    FloodsubListener {
273        topic: libp2p::floodsub::Topic,
274        resp: oneshot::Sender<ConnexaResult<mpsc::Receiver<FloodsubEvent>>>,
275    },
276    Publish(PubsubFloodsubPublish, oneshot::Sender<ConnexaResult<()>>),
277}
278
279#[cfg(feature = "gossipsub")]
280#[derive(Debug)]
281pub enum GossipsubCommand {
282    Subscribe {
283        topic: libp2p::gossipsub::TopicHash,
284        resp: oneshot::Sender<ConnexaResult<()>>,
285    },
286    Unsubscribe {
287        topic: libp2p::gossipsub::TopicHash,
288        resp: oneshot::Sender<ConnexaResult<()>>,
289    },
290    Subscribed {
291        resp: oneshot::Sender<ConnexaResult<Vec<libp2p::gossipsub::TopicHash>>>,
292    },
293    Peers {
294        topic: libp2p::gossipsub::TopicHash,
295        resp: oneshot::Sender<ConnexaResult<Vec<PeerId>>>,
296    },
297    GossipsubListener {
298        topic: libp2p::gossipsub::TopicHash,
299        resp: oneshot::Sender<ConnexaResult<mpsc::Receiver<GossipsubEvent>>>,
300    },
301    Publish {
302        topic: libp2p::gossipsub::TopicHash,
303        data: Bytes,
304        resp: oneshot::Sender<ConnexaResult<()>>,
305    },
306    ReportMessage {
307        peer_id: PeerId,
308        message_id: MessageId,
309        accept: MessageAcceptance,
310        resp: oneshot::Sender<ConnexaResult<bool>>,
311    },
312}
313
314#[derive(Debug)]
315pub enum ConnectionLimitsCommand {
316    Get {
317        resp: oneshot::Sender<Result<ConnectionLimits>>,
318    },
319    Set {
320        limits: ConnectionLimits,
321        resp: oneshot::Sender<Result<()>>,
322    },
323}
324
325#[cfg(feature = "floodsub")]
326#[derive(Debug)]
327pub enum PubsubFloodsubPublish {
328    Publish {
329        topic: libp2p::floodsub::Topic,
330        data: Bytes,
331    },
332    PublishAny {
333        topic: libp2p::floodsub::Topic,
334        data: Bytes,
335    },
336    PublishMany {
337        topics: Vec<libp2p::floodsub::Topic>,
338        data: Bytes,
339    },
340    PublishManyAny {
341        topics: Vec<libp2p::floodsub::Topic>,
342        data: Bytes,
343    },
344}
345
346#[cfg(feature = "autonat")]
347#[derive(Debug)]
348pub enum AutonatCommand {
349    PublicAddress {
350        resp: oneshot::Sender<ConnexaResult<Option<Multiaddr>>>,
351    },
352    NatStatus {
353        resp: oneshot::Sender<ConnexaResult<libp2p::autonat::NatStatus>>,
354    },
355    AddServer {
356        peer: PeerId,
357        address: Option<Multiaddr>,
358        resp: oneshot::Sender<ConnexaResult<()>>,
359    },
360    RemoveServer {
361        peer: PeerId,
362        resp: oneshot::Sender<ConnexaResult<()>>,
363    },
364    Probe {
365        address: Multiaddr,
366        resp: oneshot::Sender<ConnexaResult<()>>,
367    },
368}
369
370#[cfg(feature = "kad")]
371#[derive(Debug)]
372pub enum DHTCommand {
373    FindPeer {
374        peer_id: PeerId,
375        resp: oneshot::Sender<ConnexaResult<Vec<PeerInfo>>>,
376    },
377    Bootstrap {
378        lazy: bool,
379        resp: oneshot::Sender<ConnexaResult<()>>,
380    },
381    Provide {
382        key: RecordKey,
383        resp: oneshot::Sender<ConnexaResult<()>>,
384    },
385    StopProviding {
386        key: RecordKey,
387        resp: oneshot::Sender<ConnexaResult<()>>,
388    },
389    GetProviders {
390        key: RecordKey,
391        resp: oneshot::Sender<ConnexaResult<mpsc::Receiver<ConnexaResult<HashSet<PeerId>>>>>,
392    },
393    SetDHTMode {
394        mode: Option<Mode>,
395        resp: oneshot::Sender<ConnexaResult<()>>,
396    },
397    DHTMode {
398        resp: oneshot::Sender<ConnexaResult<Mode>>,
399    },
400
401    AddAddress {
402        peer_id: PeerId,
403        addr: Multiaddr,
404        resp: oneshot::Sender<ConnexaResult<()>>,
405    },
406
407    RemoveAddress {
408        peer_id: PeerId,
409        addr: Multiaddr,
410        resp: oneshot::Sender<ConnexaResult<()>>,
411    },
412
413    RemovePeer {
414        peer_id: PeerId,
415        resp: oneshot::Sender<ConnexaResult<()>>,
416    },
417    Get {
418        key: RecordKey,
419        resp: oneshot::Sender<ConnexaResult<mpsc::Receiver<ConnexaResult<PeerRecord>>>>,
420    },
421    Put {
422        key: RecordKey,
423        data: Bytes,
424        quorum: Quorum,
425        resp: oneshot::Sender<ConnexaResult<()>>,
426    },
427    Remove {
428        key: RecordKey,
429        resp: oneshot::Sender<ConnexaResult<()>>,
430    },
431    PutTo {
432        key: RecordKey,
433        target: Vec<PeerId>,
434        data: Bytes,
435        quorum: Quorum,
436        resp: oneshot::Sender<ConnexaResult<()>>,
437    },
438    Listener {
439        key: Option<RecordKey>,
440        resp: oneshot::Sender<ConnexaResult<mpsc::Receiver<DHTEvent>>>,
441    },
442}
443
444#[cfg(feature = "relay")]
445#[derive(Debug)]
446pub enum AutoRelayCommand {
447    AddStaticRelay {
448        peer_id: PeerId,
449        relay_addr: Multiaddr,
450        resp: oneshot::Sender<Result<bool>>,
451    },
452    RemoveStaticRelay {
453        peer_id: PeerId,
454        resp: oneshot::Sender<Result<bool>>,
455    },
456    DisableRelays {
457        resp: oneshot::Sender<Result<()>>,
458    },
459    ListStaticRelays {
460        resp: oneshot::Sender<Result<Vec<(PeerId, Vec<Multiaddr>)>>>,
461    },
462    GetStaticRelay {
463        peer_id: PeerId,
464        resp: oneshot::Sender<Result<Vec<Multiaddr>>>,
465    },
466    EnableAutoRelay {
467        resp: oneshot::Sender<Result<()>>,
468    },
469    DisableAutoRelay {
470        resp: oneshot::Sender<Result<()>>,
471    },
472}
473
474#[cfg(feature = "request-response")]
475type ResponseStream = BoxStream<'static, (PeerId, ConnexaResult<Bytes>)>;
476#[cfg(feature = "request-response")]
477type ResponseFuture = BoxFuture<'static, ConnexaResult<Bytes>>;
478
479type PeerAddressList = Vec<(PeerId, Vec<Multiaddr>)>;
480
481#[cfg(feature = "rendezvous")]
482type RendezvousDiscoverResponse = ConnexaResult<(Cookie, Vec<(PeerId, Vec<Multiaddr>)>)>;
483
484#[cfg(feature = "request-response")]
485#[derive(Debug)]
486pub enum RequestResponseCommand {
487    SendRequests {
488        protocol: Option<StreamProtocol>,
489        peers: IndexSet<PeerId>,
490        request: Bytes,
491        resp: oneshot::Sender<ConnexaResult<ResponseStream>>,
492    },
493    SendRequest {
494        protocol: Option<StreamProtocol>,
495        peer_id: PeerId,
496        request: Bytes,
497        resp: oneshot::Sender<ConnexaResult<ResponseFuture>>,
498    },
499    SendResponse {
500        protocol: Option<StreamProtocol>,
501        peer_id: PeerId,
502        request_id: InboundRequestId,
503        response: Bytes,
504        resp: oneshot::Sender<ConnexaResult<()>>,
505    },
506    ListenForRequests {
507        protocol: Option<StreamProtocol>,
508        resp: oneshot::Sender<ConnexaResult<mpsc::Receiver<(PeerId, InboundRequestId, Bytes)>>>,
509    },
510}
511
512#[cfg(feature = "stream")]
513#[derive(Debug)]
514pub enum StreamCommand {
515    NewStream {
516        protocol: StreamProtocol,
517        resp: oneshot::Sender<ConnexaResult<libp2p_stream::IncomingStreams>>,
518    },
519    ControlHandle {
520        resp: oneshot::Sender<ConnexaResult<libp2p_stream::Control>>,
521    },
522}
523
524#[cfg(feature = "rendezvous")]
525#[derive(Debug)]
526pub enum RendezvousCommand {
527    Register {
528        namespace: libp2p::rendezvous::Namespace,
529        peer_id: PeerId,
530        ttl: Option<u64>,
531        resp: oneshot::Sender<ConnexaResult<()>>,
532    },
533    Unregister {
534        namespace: libp2p::rendezvous::Namespace,
535        peer_id: PeerId,
536        resp: oneshot::Sender<ConnexaResult<()>>,
537    },
538    Discover {
539        namespace: Option<libp2p::rendezvous::Namespace>,
540        peer_id: PeerId,
541        cookie: Option<Cookie>,
542        ttl: Option<u64>,
543        resp: oneshot::Sender<RendezvousDiscoverResponse>,
544    },
545}
546
547#[cfg(feature = "kad")]
548#[derive(Clone, Debug)]
549pub enum DHTEvent {
550    PutRecord {
551        source: PeerId,
552        record: RecordHandle<Record>,
553    },
554    ProvideRecord {
555        record: RecordHandle<ProviderRecord>,
556    },
557}
558
559#[cfg(feature = "kad")]
560impl DHTEvent {
561    pub(crate) fn set_record_confirmation(&self, ch: oneshot::Sender<Record>) -> Self {
562        let mut event = self.clone();
563        match &mut event {
564            DHTEvent::PutRecord { record, .. } => {
565                record.confirm.replace(ch);
566                event
567            }
568            _ => unreachable!("DHTEvent::PutRecord called on non-PutRecord"),
569        }
570    }
571    pub(crate) fn set_provider_confirmation(&self, ch: oneshot::Sender<ProviderRecord>) -> Self {
572        let mut event = self.clone();
573        match &mut event {
574            DHTEvent::ProvideRecord { record, .. } => {
575                record.confirm.replace(ch);
576                event
577            }
578            _ => unreachable!("DHTEvent::ProvideRecord called on non-ProvideRecord"),
579        }
580    }
581}
582
583#[cfg(feature = "kad")]
584#[derive(Debug)]
585pub struct RecordHandle<R> {
586    /// The underlining record, if available
587    /// Note: a record is only provided if configured by kademlia behaviour
588    pub(crate) record: Option<R>,
589    pub(crate) confirm: Option<oneshot::Sender<R>>,
590}
591
592#[cfg(feature = "kad")]
593impl<R> RecordHandle<R> {
594    /// The record awaiting confirmation, if any.
595    pub fn record(&self) -> Option<&R> {
596        self.record.as_ref()
597    }
598
599    /// Accept the record as received, storing it locally.
600    pub fn accept(mut self) {
601        if let (Some(ch), Some(record)) = (self.confirm.take(), self.record.take()) {
602            let _ = ch.send(record);
603        }
604    }
605
606    /// Accept the record, storing the provided (possibly modified) value.
607    pub fn accept_with(mut self, record: R) {
608        if let Some(ch) = self.confirm.take() {
609            let _ = ch.send(record);
610        }
611    }
612
613    /// Reject the record so it is not stored. Dropping the handle has the same effect.
614    pub fn reject(self) {}
615}
616
617#[cfg(feature = "kad")]
618impl<R: Clone> Clone for RecordHandle<R> {
619    fn clone(&self) -> Self {
620        Self {
621            record: self.record.clone(),
622            confirm: None,
623        }
624    }
625}
626
627#[cfg(feature = "gossipsub")]
628#[derive(Debug, Clone, PartialEq, Eq)]
629pub enum GossipsubEvent {
630    Subscribed { peer_id: PeerId },
631    Unsubscribed { peer_id: PeerId },
632    Message { message: GossipsubMessage },
633}
634
635#[cfg(feature = "floodsub")]
636#[derive(Debug, Clone, PartialEq, Eq)]
637pub enum FloodsubEvent {
638    Subscribed { peer_id: PeerId },
639    Unsubscribed { peer_id: PeerId },
640    Message { message: FloodsubMessage },
641}
642
643#[cfg(feature = "gossipsub")]
644#[derive(Debug, Clone, PartialEq, Eq)]
645#[non_exhaustive]
646pub struct GossipsubMessage {
647    pub message_id: MessageId,
648    pub propagated_source: PeerId,
649    pub source: Option<PeerId>,
650    pub data: Bytes,
651    pub sequence_number: Option<u64>,
652}
653
654#[cfg(feature = "floodsub")]
655#[derive(Debug, Clone, PartialEq, Eq)]
656#[non_exhaustive]
657pub struct FloodsubMessage {
658    pub source: PeerId,
659    pub data: Bytes,
660    pub sequence_number: Vec<u8>,
661}
662
663#[derive(Debug)]
664pub enum WhitelistCommand {
665    Add {
666        peer_id: PeerId,
667        resp: oneshot::Sender<ConnexaResult<()>>,
668    },
669    Remove {
670        peer_id: PeerId,
671        resp: oneshot::Sender<ConnexaResult<()>>,
672    },
673    List {
674        resp: oneshot::Sender<ConnexaResult<Vec<PeerId>>>,
675    },
676}
677
678#[derive(Debug)]
679pub enum BlacklistCommand {
680    Add {
681        peer_id: PeerId,
682        resp: oneshot::Sender<ConnexaResult<()>>,
683    },
684    Remove {
685        peer_id: PeerId,
686        resp: oneshot::Sender<ConnexaResult<()>>,
687    },
688    List {
689        resp: oneshot::Sender<ConnexaResult<Vec<PeerId>>>,
690    },
691}
692
693#[derive(Debug)]
694pub enum PeerstoreCommand {
695    Add {
696        peer_id: PeerId,
697        addr: Multiaddr,
698        resp: oneshot::Sender<ConnexaResult<()>>,
699    },
700    RemoveAddress {
701        peer_id: PeerId,
702        addr: Multiaddr,
703        resp: oneshot::Sender<ConnexaResult<()>>,
704    },
705    Remove {
706        peer_id: PeerId,
707        resp: oneshot::Sender<ConnexaResult<Vec<Multiaddr>>>,
708    },
709    List {
710        peer_id: PeerId,
711        resp: oneshot::Sender<ConnexaResult<Vec<Multiaddr>>>,
712    },
713    ListAll {
714        resp: oneshot::Sender<ConnexaResult<PeerAddressList>>,
715    },
716}