Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions network/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright 2018 Kodebox, Inc.
// This file is part of CodeChain.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use std::collections::HashMap;
use std::sync::{Arc, Weak};

use mio::Token;
use parking_lot::RwLock;

use super::Extension;

#[derive(Clone, Eq, PartialEq)]
pub struct NodeId(Token);

pub enum Error {
DuplicatedApplicationName,
ExtensionDropped,
}

pub struct ClientApi {
client: Weak<Client>,
extension: Weak<Extension>,
}

impl ClientApi {
fn send_async(&self, id: &NodeId, message: &Vec<u8>) {
if let Some(extension) = self.extension.upgrade() {
let _need_encryption = extension.need_encryption();
info!("send {:?} to {:?}", message, id.0);
} else {
info!("The extension already dropped");
}
}

fn send_sync(&self, id: &NodeId, message: &Vec<u8>) -> Result<(), Error> {
if let Some(extension) = self.extension.upgrade() {
let _need_encryption = extension.need_encryption();
info!("send {:?} to {:?}", message, id.0);
Ok(())
} else {
info!("The extension already dropped");
Err(Error::ExtensionDropped)
}
}

fn connect_sync(&self, id: &NodeId) -> Result<(), Error> {
if let Some(extension) = self.extension.upgrade() {
let _need_encryption = extension.need_encryption();
info!("connect_async to {:?}", id.0);
Ok(())
} else {
info!("The extension already dropped");
Err(Error::ExtensionDropped)
}
}
}

struct Client {
extensions: RwLock<HashMap<String, Weak<Extension>>>,
}

impl Client {
pub fn register_extension(client: Arc<Client>, extension: Arc<Extension>) -> Result<(), Error> {
let name = extension.name();
let mut extensions = client.extensions.write();
if extensions.contains_key(&name) {
return Err(Error::DuplicatedApplicationName)
}
let api = Arc::new(ClientApi {
client: Arc::downgrade(&client),
extension: Arc::downgrade(&extension),
});
if let Some(_) = extensions.insert(name, Arc::downgrade(&extension)) {
unreachable!();
}
extension.on_initialize(api);
Ok(())
}

fn new() -> Self {
Self {
extensions: RwLock::new(HashMap::new()),
}
}

fn on_message(&self, name: &String, id: &NodeId, data: &Vec<u8>) {
let extensions = self.extensions.read();
if let Some(extension) = extensions.get(name) {
if let Some(extension) = extension.upgrade() {
extension.on_message(&id, data);
} else {
info!("The extension already dropped");
}
} else {
info!("The handler for {} doesn't exist.", name);
}
}

fn on_node_added(&self, id: &NodeId) {
let extensions = self.extensions.read();
for (_, extension) in extensions.iter() {
if let Some(extension) = extension.upgrade() {
extension.on_node_added(&id);
} else {
info!("ClientApi already dropped");
}
}
}

fn on_node_removed(&self, id: &NodeId) {
let extensions = self.extensions.read();
for (_, extension) in extensions.iter() {
if let Some(extension) = extension.upgrade() {
extension.on_node_removed(&id);
} else {
info!("The extension already dropped");
}
}
}
}
39 changes: 39 additions & 0 deletions network/src/extension.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2018 Kodebox, Inc.
// This file is part of CodeChain.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use std::sync::Arc;

use super::ClientApi;
use super::Error;
use super::NodeId;

pub trait Extension {
fn name(&self) -> String;
fn need_encryption(&self) -> bool;

fn on_initialize(&self, api: Arc<ClientApi>);

fn on_node_added(&self, id: &NodeId);
fn on_node_removed(&self, id: &NodeId);

fn on_connected(&self, id: &NodeId);
fn on_connection_allowed(&self, id: &NodeId);
fn on_connection_denied(&self, id: &NodeId, error: Error);

fn on_message(&self, id: &NodeId, message: &Vec<u8>);

fn on_close(&self);
}
8 changes: 6 additions & 2 deletions network/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,15 @@ extern crate codechain_crypto as ccrypto;
extern crate codechain_io as cio;
extern crate codechain_types as ctypes;

mod client;
mod connection;
mod extension;
mod handshake;
pub mod session;
pub mod address;
pub mod kademlia;

pub use address::Address;
pub use handshake::HandshakeService;
pub use self::address::Address;
pub use self::client::{ClientApi, Error, NodeId};
pub use self::extension::Extension;
pub use self::handshake::HandshakeService;