use super::support::{self, Endpoint, Network, ServiceHandle, ServiceImpl};
use maidsafe_utilities::event_sender;
use std::{fmt, io, thread};
use std::cell::{RefCell, RefMut};
use std::collections::HashSet;
use std::net::SocketAddr;
use std::rc::Rc;
pub const LISTENER_PORT: u16 = 5485;
pub struct Service(Rc<RefCell<ServiceImpl>>, Network);
impl Service {
pub fn new(event_sender: CrustEventSender) -> Result<Self, CrustError> {
Self::with_handle(&support::get_current(), event_sender)
}
pub fn with_handle(handle: &ServiceHandle,
event_sender: CrustEventSender)
-> Result<Self, CrustError> {
let network = handle.0
.borrow()
.network
.clone();
let service = Service(handle.0.clone(), network);
service.lock_and_poll(|imp| imp.start(event_sender));
Ok(service)
}
pub fn restart(&self, event_sender: CrustEventSender) {
self.lock_and_poll(|imp| imp.restart(event_sender))
}
pub fn start_bootstrap(&mut self,
blacklist: HashSet<SocketAddr>,
user: CrustUser)
-> Result<(), CrustError> {
self.lock_and_poll(|imp| imp.start_bootstrap(blacklist, user));
Ok(())
}
pub fn stop_bootstrap(&mut self) -> Result<(), CrustError> {
Ok(())
}
pub fn start_service_discovery(&mut self) {
trace!(target: "crust", "[MOCK] start_service_discovery not implemented in mock");
}
pub fn set_service_discovery_listen(&self, _listen: bool) {
trace!(target: "crust", "[MOCK] set_service_discovery_listen not implemented in mock");
}
pub fn has_peers_on_lan(&self) -> bool {
false
}
pub fn start_listening_tcp(&mut self) -> Result<(), CrustError> {
self.lock().start_listening_tcp(LISTENER_PORT);
Ok(())
}
pub fn prepare_connection_info(&self, result_token: u32) {
self.lock_and_poll(|imp| imp.prepare_connection_info(result_token))
}
pub fn connect(&self,
our_info: PrivConnectionInfo,
their_info: PubConnectionInfo)
-> Result<(), CrustError> {
self.lock_and_poll(|imp| imp.connect(our_info, their_info));
Ok(())
}
pub fn disconnect(&self, peer_id: PeerId) -> bool {
self.lock_and_poll(|imp| imp.disconnect(&peer_id))
}
pub fn send(&self, id: PeerId, data: Vec<u8>, _priority: u8) -> io::Result<()> {
if self.lock_and_poll(|imp| imp.send_message(&id, data)) {
Ok(())
} else {
let msg = format!("No connection to peer {:?}", id);
Err(io::Error::new(io::ErrorKind::Other, msg))
}
}
pub fn is_connected(&self, peer_id: &PeerId) -> bool {
self.lock_and_poll(|imp| imp.is_peer_connected(peer_id))
}
pub fn whitelist_peer(&self, peer_id: PeerId) {
self.lock().whitelist_peer(peer_id);
}
pub fn is_peer_whitelisted(&self, peer_id: &PeerId) -> bool {
self.lock().is_peer_whitelisted(peer_id)
}
pub fn is_peer_hard_coded(&self, _peer_id: &PeerId) -> bool {
true
}
pub fn id(&self) -> PeerId {
self.lock().peer_id
}
fn lock(&self) -> RefMut<ServiceImpl> {
self.0.borrow_mut()
}
fn lock_and_poll<F, R>(&self, f: F) -> R
where F: FnOnce(&mut ServiceImpl) -> R
{
let result = f(&mut *self.lock());
self.1.poll();
result
}
}
impl Drop for Service {
fn drop(&mut self) {
if !thread::panicking() {
self.lock_and_poll(|imp| imp.disconnect_all());
}
}
}
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct PeerId(pub usize);
impl fmt::Debug for PeerId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "PeerId({})", self.0)
}
}
#[derive(Debug)]
pub enum Event {
BootstrapAccept(PeerId, CrustUser),
BootstrapConnect(PeerId, SocketAddr),
BootstrapFailed,
ListenerStarted(u16),
ListenerFailed,
ConnectionInfoPrepared(ConnectionInfoResult),
ConnectSuccess(PeerId),
ConnectFailure(PeerId),
LostPeer(PeerId),
NewMessage(PeerId, Vec<u8>),
WriteMsgSizeProhibitive(PeerId, Vec<u8>),
}
pub type CrustEventSender = event_sender::MaidSafeObserver<Event>;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PrivConnectionInfo(pub PeerId, pub Endpoint);
impl PrivConnectionInfo {
pub fn to_pub_connection_info(&self) -> PubConnectionInfo {
PubConnectionInfo(self.0, self.1)
}
}
#[derive(Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable)]
pub struct PubConnectionInfo(pub PeerId, pub Endpoint);
impl PubConnectionInfo {
pub fn id(&self) -> PeerId {
self.0
}
}
#[derive(Debug)]
pub struct ConnectionInfoResult {
pub result_token: u32,
pub result: Result<PrivConnectionInfo, CrustError>,
}
#[derive(Debug)]
pub struct CrustError;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum CrustUser {
Node,
Client,
}