mod.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. use std::sync::{Arc, Weak};
  2. use async_trait::async_trait;
  3. use log::debug;
  4. use smol::Executor;
  5. use crate::Result;
  6. use super::{p2p::P2pPtr, protocol::ProtocolVersion, ChannelPtr};
  7. /// Seed sync session creates a connection to the seed nodes specified in settings.
  8. /// A new seed sync session is created every time we call p2p::start(). The seed
  9. /// sync session loops through all the configured seeds and tries to connect to
  10. /// them using a Connector. Seed sync either connects successfully,
  11. /// fails with an error or times out.
  12. ///
  13. /// If a seed node connects successfully, it runs a version exchange protocol,
  14. /// stores the channel in the p2p list of channels, and disconnects, removing
  15. /// the channel from the channel list.
  16. ///
  17. /// The channel is registered using Session trait method, register_channel().
  18. /// This invokes the Protocol Registry method attach(). Usually this returns a
  19. /// list of protocols that we loop through and start. In this case, attach()
  20. /// uses the bitflag selector to identify seed sessions and exclude them.
  21. ///
  22. /// The version exchange occurs inside register_channel(). We create a handshake
  23. /// task that runs the version exchange with the function
  24. /// perform_handshake_protocols(). This runs the version exchange protocol,
  25. /// stores the channel in the p2p list of channels, and subscribes to a stop
  26. /// signal.
  27. pub mod seedsync_session;
  28. pub mod manual_session;
  29. /// Inbound connections session. Manages the creation of inbound sessions. Used
  30. /// to create an inbound session and start and stop the session.
  31. ///
  32. /// Class consists of 3 pointers: a weak pointer to the p2p parent class, an
  33. /// acceptor pointer, and a stoppable task pointer. Using a weak pointer to P2P
  34. /// allows us to avoid circular dependencies.
  35. pub mod inbound_session;
  36. /// Outbound connections session. Manages the creation of outbound sessions.
  37. /// Used to create an outbound session and stop and start the session.
  38. ///
  39. /// Class consists of a weak pointer to the p2p interface and a vector
  40. /// of outbound connection slots. Using a weak pointer to p2p allows us to avoid
  41. /// circular dependencies. The vector of slots is wrapped in a mutex lock. This
  42. /// is switched on everytime we instantiate a connection slot and insures that
  43. /// no other part of the program uses the slots at the same time.
  44. pub mod outbound_session;
  45. // bitwise selectors for the protocol_registry
  46. pub type SessionBitflag = u32;
  47. pub const SESSION_INBOUND: SessionBitflag = 0b0001;
  48. pub const SESSION_OUTBOUND: SessionBitflag = 0b0010;
  49. pub const SESSION_MANUAL: SessionBitflag = 0b0100;
  50. pub const SESSION_SEED: SessionBitflag = 0b1000;
  51. pub const SESSION_ALL: SessionBitflag = 0b1111;
  52. pub use inbound_session::InboundSession;
  53. pub use manual_session::ManualSession;
  54. pub use outbound_session::OutboundSession;
  55. pub use seedsync_session::SeedSyncSession;
  56. pub type SessionWeakPtr = Arc<Weak<dyn Session + Send + Sync + 'static>>;
  57. /// Removes channel from the list of connected channels when a stop signal is
  58. /// received.
  59. async fn remove_sub_on_stop(p2p: P2pPtr, channel: ChannelPtr) {
  60. debug!(target: "net", "remove_sub_on_stop() [START]");
  61. // Subscribe to stop events
  62. let stop_sub = channel.clone().subscribe_stop().await;
  63. if stop_sub.is_ok() {
  64. // Wait for a stop event
  65. stop_sub.unwrap().receive().await;
  66. }
  67. debug!(target: "net",
  68. "remove_sub_on_stop(): received stop event. Removing channel {}",
  69. channel.address()
  70. );
  71. // Remove channel from p2p
  72. p2p.remove(channel).await;
  73. debug!(target: "net", "remove_sub_on_stop() [END]");
  74. }
  75. #[async_trait]
  76. /// Session trait.
  77. /// Defines methods that are used across sessions. Implements registering the
  78. /// channel and initializing the channel by performing a network handshake.
  79. pub trait Session: Sync {
  80. /// Registers a new channel with the session. Performs a network handshake
  81. /// and starts the channel.
  82. // if we need to pass Self as an Arc we can do so like this:
  83. // pub trait MyTrait: Send + Sync {
  84. // async fn foo(&self, self_: Arc<dyn MyTrait>) {}
  85. // }
  86. async fn register_channel(
  87. &self,
  88. channel: ChannelPtr,
  89. executor: Arc<Executor<'_>>,
  90. ) -> Result<()> {
  91. debug!(target: "net", "Session::register_channel() [START]");
  92. // Protocols should all be initialized but not started
  93. // We do this so that the protocols can begin receiving and buffering messages
  94. // while the handshake protocol is ongoing.
  95. // They are currently in sleep mode.
  96. let p2p = self.p2p();
  97. let protocols =
  98. p2p.protocol_registry().attach(self.type_id(), channel.clone(), p2p.clone()).await;
  99. // Perform the handshake protocol
  100. let protocol_version = ProtocolVersion::new(channel.clone(), self.p2p().settings()).await;
  101. let handshake_task =
  102. self.perform_handshake_protocols(protocol_version, channel.clone(), executor.clone());
  103. // Switch on the channel
  104. channel.start(executor.clone());
  105. // Wait for handshake to finish.
  106. handshake_task.await?;
  107. // Now the channel is ready
  108. debug!(target: "net", "Session handshake complete. Activating remaining protocols");
  109. // Now start all the protocols
  110. // They are responsible for managing their own lifetimes and
  111. // correctly self destructing when the channel ends.
  112. for protocol in protocols {
  113. // Activate protocol
  114. protocol.start(executor.clone()).await?;
  115. }
  116. debug!(target: "net", "Session::register_channel() [END]");
  117. Ok(())
  118. }
  119. /// Performs network handshake to initialize channel. Adds the channel to
  120. /// the list of connected channels, and prepares to remove the channel
  121. /// when a stop signal is received.
  122. async fn perform_handshake_protocols(
  123. &self,
  124. protocol_version: Arc<ProtocolVersion>,
  125. channel: ChannelPtr,
  126. executor: Arc<Executor<'_>>,
  127. ) -> Result<()> {
  128. // Perform handshake
  129. protocol_version.run(executor.clone()).await?;
  130. // Channel is now initialized
  131. // Add channel to p2p
  132. self.p2p().store(channel.clone()).await;
  133. // Subscribe to stop, so can remove from p2p
  134. executor.spawn(remove_sub_on_stop(self.p2p(), channel)).detach();
  135. // Channel is ready for use
  136. Ok(())
  137. }
  138. async fn get_info(&self) -> serde_json::Value;
  139. /// Returns a pointer to the p2p network interface.
  140. fn p2p(&self) -> P2pPtr;
  141. fn type_id(&self) -> u32;
  142. }