tatami 0.1.1

A library for creating satellites and interacting with Tatami protocols.
Documentation
use std::io;

use libp2p::{
	swarm::{DialError, NetworkInfo},
	Multiaddr, PeerId, TransportError,
};
use tokio::sync::oneshot;

use crate::{satellite::Message, Shoji, ShojiError, TatamiError};

#[derive(Debug)]
/// The commands that Shoji will give to the Satellite
pub enum ShojiCommand {
	/// `get_closest_peers` to the given Peer ID
	GetClosestPeers(PeerId),
	/// Send back the local peer id
	LocalPeerId(oneshot::Sender<PeerId>),
	/// Dial a known peer by its Peer ID
	DialPeer(PeerId, oneshot::Sender<Result<(), DialError>>),
	/// Dial an unknown peer by it's Multiaddress
	DialAddress(Multiaddr, oneshot::Sender<Result<(), DialError>>),
	/// Send back a vector of listening multiaddresses
	Listeners(oneshot::Sender<Vec<Multiaddr>>),
	/// Listen on the multiaddress
	ListenOn(
		Multiaddr,
		oneshot::Sender<Result<(), TransportError<io::Error>>>,
	),
	/// Ban this Peer ID
	BanPeerId(PeerId),
	/// Unban this Peer ID
	UnbanPeerId(PeerId),
	/// Send back a vector of connected PeerIds
	ConnectedPeers(oneshot::Sender<Vec<PeerId>>),
	/// Disconnect from this Peer ID
	DisconnectPeerId(PeerId, oneshot::Sender<Result<(), TatamiError>>),
	/// Is the Satellite connected to this Peer ID?
	IsConnected(PeerId, oneshot::Sender<bool>),
	/// Send back information about the Network
	NetworkInfo(oneshot::Sender<NetworkInfo>),
	/// Add an address to the DHT
	AddAddress(PeerId, Multiaddr),
	/// Publish a message
	PublishMessage(Message, oneshot::Sender<Result<(), TatamiError>>),
	/// Publish a payload
	Publish(Vec<u8>, oneshot::Sender<Result<(), TatamiError>>),
}

// The paper-wall is fragile.
impl Shoji {
	/// Returns the Satellite's Peer ID.
	pub async fn local_peer_id(&self) -> Result<PeerId, ShojiError> {
		let (sender, receiver) = oneshot::channel();
		self.commander
			.send(ShojiCommand::LocalPeerId(sender))
			.await?;
		Ok(receiver.await?)
	}

	/// Tries to find and connect to the closest peers to the given Peer ID.
	/// This function will not return anything, it simply does the thing.
	pub async fn get_closest_peers(&self, peer_id: PeerId) -> Result<(), ShojiError> {
		Ok(self
			.commander
			.send(ShojiCommand::GetClosestPeers(peer_id))
			.await?)
	}

	/// Dial a known peer fromm the ID
	pub async fn dial_peer(&self, peer_id: PeerId) -> Result<(), ShojiError> {
		let (sender, receiver) = oneshot::channel();
		self.commander
			.send(ShojiCommand::DialPeer(peer_id, sender))
			.await?;
		Ok(receiver.await??)
	}

	/// Dial an unknown peer from the Multiaddress
	pub async fn dial_address(&self, address: Multiaddr) -> Result<(), ShojiError> {
		let (sender, receiver) = oneshot::channel();
		self.commander
			.send(ShojiCommand::DialAddress(address, sender))
			.await?;
		Ok(receiver.await??)
	}

	/// Disconnect a given Peer ID
	pub async fn disconnect_peer_id(&self, peer_id: PeerId) -> Result<(), ShojiError> {
		let (sender, receiver) = oneshot::channel();
		self.commander
			.send(ShojiCommand::DisconnectPeerId(peer_id, sender))
			.await?;
		receiver.await?.or(Err(ShojiError::Generic))
	}

	/// Publish a message
	pub async fn publish_message(&self, message: Message) -> Result<(), TatamiError> {
		let (sender, receiver) = oneshot::channel();
		self.commander
			.send(ShojiCommand::PublishMessage(message, sender))
			.await?;
		receiver.await?
	}

	/// Publish some data
	pub async fn publish(&self, payload: Vec<u8>) -> Result<(), TatamiError> {
		let (sender, receiver) = oneshot::channel();
		self.commander
			.send(ShojiCommand::Publish(payload, sender))
			.await?;
		receiver.await?
	}

	/// Return a vector of all Multiaddresses the Satellite is listening at
	pub async fn listeners(&self) -> Result<Vec<Multiaddr>, ShojiError> {
		let (sender, receiver) = oneshot::channel();
		self.commander.send(ShojiCommand::Listeners(sender)).await?;
		Ok(receiver.await?)
	}

	/// Return a vector of all connected peers
	pub async fn connected_peers(&self) -> Result<Vec<PeerId>, ShojiError> {
		let (sender, receiver) = oneshot::channel();
		self.commander
			.send(ShojiCommand::ConnectedPeers(sender))
			.await?;
		Ok(receiver.await?)
	}

	/// Listen on a given Multiaddress
	pub async fn listen_on(&self, address: Multiaddr) -> Result<(), ShojiError> {
		let (sender, receiver) = oneshot::channel();
		self.commander
			.send(ShojiCommand::ListenOn(address, sender))
			.await?;
		Ok(receiver.await??)
	}

	/// Ban a Peer ID
	pub async fn ban_peer(&self, peer_id: PeerId) -> Result<(), ShojiError> {
		self.commander
			.send(ShojiCommand::BanPeerId(peer_id))
			.await?;
		Ok(())
	}

	/// Check whter or not a peer is connected
	pub async fn is_connected(&self, peer_id: PeerId) -> Result<bool, ShojiError> {
		let (sender, receiver) = oneshot::channel();
		self.commander
			.send(ShojiCommand::IsConnected(peer_id, sender))
			.await?;
		Ok(receiver.await?)
	}

	/// Unban a Peer ID
	pub async fn unban_peer(&self, peer_id: PeerId) -> Result<(), ShojiError> {
		self.commander
			.send(ShojiCommand::UnbanPeerId(peer_id))
			.await?;
		Ok(())
	}

	/// Get information about the network
	pub async fn network_info(&self) -> Result<NetworkInfo, ShojiError> {
		let (sender, receiver) = oneshot::channel();
		self.commander
			.send(ShojiCommand::NetworkInfo(sender))
			.await?;
		Ok(receiver.await?)
	}

	/// Get information about the network
	pub async fn add_address(
		&self,
		peer_id: PeerId,
		multiaddr: Multiaddr,
	) -> Result<(), ShojiError> {
		self.commander
			.send(ShojiCommand::AddAddress(peer_id, multiaddr))
			.await?;
		Ok(())
	}
}