Просмотр исходного кода

integrate darkpulse backend code

ghassmo 4 лет назад
Родитель
Сommit
174256b80c

+ 127 - 0
Cargo.lock

@@ -33,6 +33,41 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
 
+[[package]]
+name = "aead"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877"
+dependencies = [
+ "generic-array 0.14.4",
+]
+
+[[package]]
+name = "aes"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
+dependencies = [
+ "cfg-if 1.0.0",
+ "cipher",
+ "cpufeatures",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
+name = "aes-gcm"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6"
+dependencies = [
+ "aead",
+ "aes",
+ "cipher",
+ "ctr",
+ "ghash",
+ "subtle",
+]
+
 [[package]]
 name = "ahash"
 version = "0.3.8"
@@ -893,6 +928,15 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "cipher"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
+dependencies = [
+ "generic-array 0.14.4",
+]
+
 [[package]]
 name = "clang-sys"
 version = "1.3.0"
@@ -1339,6 +1383,15 @@ dependencies = [
  "syn 1.0.82",
 ]
 
+[[package]]
+name = "ctr"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
+dependencies = [
+ "cipher",
+]
+
 [[package]]
 name = "curve25519-dalek"
 version = "2.1.3"
@@ -1369,6 +1422,7 @@ dependencies = [
 name = "darkfi"
 version = "0.2.0"
 dependencies = [
+ "aes-gcm",
  "anyhow",
  "arrayvec 0.7.2",
  "async-channel",
@@ -1383,6 +1437,7 @@ dependencies = [
  "blake2s_simd",
  "bs58 0.4.0",
  "bytes 1.1.0",
+ "chrono",
  "clap",
  "crypto_api_chachapoly",
  "dirs 4.0.0",
@@ -1407,6 +1462,7 @@ dependencies = [
  "rand 0.8.4",
  "ripemd160",
  "rocksdb",
+ "rusqlite",
  "secp256k1",
  "serde",
  "serde_json",
@@ -1414,6 +1470,7 @@ dependencies = [
  "signal-hook",
  "signal-hook-async-std",
  "simple_logger",
+ "simplelog",
  "smol",
  "solana-client",
  "solana-sdk",
@@ -1847,6 +1904,18 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
 
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
+[[package]]
+name = "fallible-streaming-iterator"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
+
 [[package]]
 name = "fastrand"
 version = "1.5.0"
@@ -2180,6 +2249,16 @@ dependencies = [
  "wasi 0.10.0+wasi-snapshot-preview1",
 ]
 
+[[package]]
+name = "ghash"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99"
+dependencies = [
+ "opaque-debug 0.3.0",
+ "polyval",
+]
+
 [[package]]
 name = "gif"
 version = "0.11.3"
@@ -3413,6 +3492,18 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "polyval"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1"
+dependencies = [
+ "cfg-if 1.0.0",
+ "cpufeatures",
+ "opaque-debug 0.3.0",
+ "universal-hash",
+]
+
 [[package]]
 name = "ppv-lite86"
 version = "0.2.15"
@@ -3962,6 +4053,21 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "rusqlite"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ba4d3462c8b2e4d7f4fcfcf2b296dc6b65404fbbc7b63daa37fd485c149daf7"
+dependencies = [
+ "bitflags",
+ "fallible-iterator",
+ "fallible-streaming-iterator",
+ "hashlink",
+ "libsqlite3-sys",
+ "memchr",
+ "smallvec",
+]
+
 [[package]]
 name = "rust-argon2"
 version = "0.8.3"
@@ -4374,6 +4480,17 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "simplelog"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecabc0118918611790b8615670ab79296272cbe09496b6884b02b1e929c20886"
+dependencies = [
+ "chrono",
+ "log",
+ "termcolor",
+]
+
 [[package]]
 name = "slab"
 version = "0.4.5"
@@ -5606,6 +5723,16 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
 
+[[package]]
+name = "universal-hash"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
+dependencies = [
+ "generic-array 0.14.4",
+ "subtle",
+]
+
 [[package]]
 name = "untrusted"
 version = "0.7.1"

+ 17 - 1
Cargo.toml

@@ -58,7 +58,7 @@ easy-parallel = "3.1.0"
 native-tls = "0.2.8"
 async-native-tls = "0.4.0"
 async-executor = "1.4.1"
-futures = "0.3.18"
+futures = "0.3.17"
 smol = "1.2.5"
 
 # Utilities
@@ -102,7 +102,23 @@ solana-sdk = {version = "1.8.6", optional = true}
 spl-associated-token-account = {version = "1.0.3", features = ["no-entrypoint"], optional = true}
 spl-token = {version = "3.2.0", features = ["no-entrypoint"], optional = true}
 
+aes-gcm = {version = "0.9.4", optional = true}
+simplelog = {version = "0.11.1", optional = true}
+chrono = {version = "0.4.19", optional = true}
+rusqlite = {version = "0.26.3", optional = true}
+
 [features]
 btc = ["bdk", "bitcoin", "secp256k1"]
 eth = ["keccak-hasher", "hash-db"]
 sol = ["solana-sdk", "solana-client", "spl-token", "spl-associated-token-account"]
+darkpulse = ["aes-gcm", "simplelog", "chrono","rusqlite"]
+
+
+
+[[bin]]         
+name = "darkpulse"    
+required-features = ["darkpulse"]
+
+[[bin]]         
+name = "eth"    
+required-features = ["eth"]

+ 29 - 0
sql/darkpulse_schema.sql

@@ -0,0 +1,29 @@
+
+BEGIN TRANSACTION;
+
+CREATE TABLE IF NOT EXISTS node (
+	id INTEGER PRIMARY KEY AUTOINCREMENT,
+	username TEXT NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS channel(
+	channel_id INTEGER PRIMARY KEY AUTOINCREMENT,
+	channel_name TEXT NOT NULL,
+	channel_secret INT(32) NOT NULL,
+	address CHAR(58) NOT NULL,
+	UNIQUE("channel_name")
+);
+
+CREATE TABLE IF NOT EXISTS slab(
+	slab_id INTEGER PRIMARY KEY AUTOINCREMENT,
+	nonce INT(12)  NOT NULL,
+	cipher_text BLOB NOT NULL ,
+	cipher_text_hash INT(32) NOT NULL,
+	channel_id INTEGER NOT NULL,
+	FOREIGN KEY(channel_id) REFERENCES channel(channel_id)
+	UNIQUE("cipher_text_hash")
+);
+
+COMMIT;
+
+

+ 162 - 0
src/bin/darkpulse.rs

@@ -0,0 +1,162 @@
+use async_std::sync::{Arc, Mutex};
+
+use drk::darkpulse::{
+    dbsql, net::messages, utility, CiphertextHash, cli_option::CliOption, control_message::ControlCommand, MemPool,
+    slabs_manager::SlabsManager,
+};
+
+use drk::Result;
+
+use async_executor::Executor;
+use easy_parallel::Parallel;
+use log::*;
+use drk::net::P2p;
+use smol::Unblock;
+
+async fn on_receive_slab(
+    p2p: Arc<P2p>,
+    slab_rx: async_channel::Receiver<CiphertextHash>,
+) -> Result<()> {
+    loop {
+        let slab = slab_rx.recv().await?;
+        p2p.broadcast(messages::InvMessage {
+            slabs_hash: vec![slab],
+        })
+        .await?;
+        }
+}
+
+async fn start(executor: Arc<Executor<'_>>, options: CliOption, db: dbsql::Dbsql) -> Result<()> {
+    let p2p = P2p::new(options.network_settings);
+
+    p2p.clone().start(executor.clone()).await?;
+
+    let p2p_run_task = executor.spawn(p2p.clone().run(executor.clone()));
+
+    let _mem_pool: MemPool = Arc::new(Mutex::new(vec![]));
+
+    // choose a channel
+    if let Some(new_channel) = options.new_channel {
+        info!(
+            "channel added with the name {}",
+            new_channel.get_channel_name()
+        );
+        db.add_channel(&new_channel).unwrap();
+    }
+    let main_channel = utility::choose_channel(&db, options.channel_name)?;
+    let channels = db.get_channels()?;
+    let username = utility::setup_username(options.username, &db)?;
+
+    let (slab_sx, slab_rx) = async_channel::unbounded::<CiphertextHash>();
+
+    let slabman = SlabsManager::new(db, slab_sx, main_channel.clone()).await;
+
+    let subscribtion = p2p.subscribe_channel().await;
+
+    let executor2 = executor.clone();
+    let setup_channels_task = executor2.clone().spawn(async move {
+        loop {
+            let network_channel = subscribtion.receive().await.unwrap();
+            utility::setup_network_channel(executor2.clone(), network_channel, slabman.clone())
+                .await;
+            }
+    });
+
+    let receive_slab = executor.spawn(on_receive_slab(p2p.clone(), slab_rx.clone()));
+
+    p2p.broadcast(messages::SyncMessage {}).await?;
+
+    let stdin = Unblock::new(std::io::stdin());
+    let mut stdin = futures::io::BufReader::new(stdin);
+
+    loop {
+        println!("[1] Send Message");
+        println!("[2] Send Sync");
+        println!("[3] list available channels");
+        println!("[4] show the channel address");
+        println!("[5] Quit");
+
+        let buf = utility::read_line(&mut stdin).await?;
+
+        match &buf[..] {
+            "1" => {
+                let slab = utility::pack_slab(
+                    &main_channel.get_channel_secret(),
+                    username.clone(),
+                    String::from("Hello"),
+                    ControlCommand::Message,
+                )
+                    .await?;
+
+                p2p.broadcast(slab).await?;
+            }
+            "2" => {
+                p2p.broadcast(messages::SyncMessage {}).await?;
+            }
+            "3" => {
+                println!("------------------");
+                println!("Available channels:");
+                for channel in channels.iter() {
+                    println!("- {}", channel.get_channel_name());
+                }
+                println!("NOTE: switch with one of the available channels by using --channel flag");
+                println!("------------------");
+            }
+            "4" => {
+                println!("------------------");
+                println!("Address: {}", main_channel.get_channel_address());
+                println!("------------------");
+            }
+            "5" => break,
+            _ => {}
+        }
+    }
+
+    setup_channels_task.cancel().await;
+    p2p_run_task.cancel().await;
+    receive_slab.cancel().await;
+    Ok(())
+}
+
+pub fn main() -> Result<()> {
+    use simplelog::*;
+
+    let cli_option = CliOption::get()?;
+
+    let debug_level = if cli_option.verbose {
+        LevelFilter::Debug
+    } else {
+        LevelFilter::Off
+    };
+
+    CombinedLogger::init(vec![
+        TermLogger::new(debug_level, Config::default(), TerminalMode::Mixed, ColorChoice::Always),
+        WriteLogger::new(
+            LevelFilter::Debug,
+            Config::default(),
+            std::fs::File::create("/tmp/darkpulsenode.log").unwrap(),
+        ),
+    ])
+        .unwrap();
+
+    let mut db = dbsql::Dbsql::new()?;
+    db.start()?;
+
+    let ex = Arc::new(Executor::new());
+    let (signal, shutdown) = async_channel::unbounded::<()>();
+    let ex2 = ex.clone();
+
+    let (_, result) = Parallel::new()
+        // Run four executor threads.
+        .each(0..3, |_| smol::future::block_on(ex.run(shutdown.recv())))
+        // Run the main future on the current thread.
+        .finish(|| {
+            smol::future::block_on(async move {
+                start(ex2, cli_option, db).await?;
+                drop(signal);
+                Ok::<(), drk::Error>(())
+            })
+        });
+
+    result
+}

+ 51 - 0
src/darkpulse/aes.rs

@@ -0,0 +1,51 @@
+use aes_gcm::aead::{generic_array::GenericArray, Aead, NewAead};
+use aes_gcm::Aes256Gcm;
+
+pub type AesKey = [u8; 32];
+pub type Plaintext = Vec<u8>;
+pub type Ciphertext = Vec<u8>;
+
+pub fn aes_encrypt(
+    shared_secret: &AesKey,
+    nonce: &[u8; 12],
+    plaintext: &[u8],
+) -> Option<Ciphertext> {
+    // Rust is gay, I need to convert to 'GenericArray' whatever the fuck that is...
+    let key = GenericArray::from_slice(&shared_secret[..]);
+    let cipher = Aes256Gcm::new(key);
+
+    let nonce = GenericArray::from_slice(nonce);
+    let ciphertext = cipher.encrypt(nonce, plaintext);
+    ciphertext.ok()
+}
+
+pub fn aes_decrypt(
+    shared_secret: &AesKey,
+    nonce: &[u8; 12],
+    ciphertext: &Ciphertext,
+) -> Option<Plaintext> {
+    // Rust is gay, I need to convert to 'GenericArray' whatever the fuck that is...
+    let key = GenericArray::from_slice(&shared_secret[..]);
+    let cipher = Aes256Gcm::new(key);
+
+    let nonce = GenericArray::from_slice(nonce);
+
+    let plaintext = cipher.decrypt(nonce, ciphertext.as_ref());
+    plaintext.ok()
+}
+
+#[test]
+fn test_aes() {
+    let sh_secret = "e02e56a41320d8ebefa946753e9f69587c16d43876cf5bbac86c0ea0e9253d14".as_bytes();
+
+    let mut channel_secret = [0u8; 32];
+    channel_secret.copy_from_slice(&sh_secret[0..32]);
+
+    let nonce = [3; 12];
+
+    let ciphertext = aes_encrypt(&channel_secret, &nonce, b"plaintext message").unwrap();
+
+    let plaintext = aes_decrypt(&channel_secret, &nonce, &ciphertext).unwrap();
+    // OK it works!
+    assert_eq!(&plaintext, b"plaintext message");
+}

+ 106 - 0
src/darkpulse/channel.rs

@@ -0,0 +1,106 @@
+use bs58;
+use rand::Rng;
+use sha2::{Digest, Sha256};
+
+use crate::Result;
+
+#[derive(Clone, Debug)]
+pub struct Channel {
+    channel_secret: [u8; 32],
+    channel_name: String,
+    address: String,
+    id: Option<u32>,
+}
+
+impl Channel {
+    pub fn new(
+        channel_name: String,
+        channel_secret: [u8; 32],
+        address: String,
+        id: u32,
+    ) -> Channel {
+        Channel {
+            channel_secret,
+            channel_name,
+            address,
+            id: Some(id),
+        }
+    }
+
+    pub fn gen_new(channel_name: String) -> Channel {
+        let channel_secret = rand::thread_rng().gen::<[u8; 32]>();
+        let address = Self::gen_address(channel_secret);
+        Channel {
+            channel_secret,
+            channel_name,
+            address,
+            id: None,
+        }
+    }
+
+    pub fn gen_new_with_addr(channel_name: String, channel_address: String) -> Result<Channel> {
+        let mut decoded = bs58::decode(channel_address.clone()).into_vec()?;
+        let mut channel_secret: [u8; 32] = [0; 32];
+        channel_secret.copy_from_slice(&mut decoded[4..36]);
+        Ok(Channel {
+            channel_secret,
+            channel_name,
+            address: channel_address,
+            id: None,
+        })
+    }
+
+    pub fn gen_address(channel_secret: [u8; 32]) -> String {
+        let mut hasher = Sha256::new();
+
+        let version: u32 = 1;
+        let mut payload = version.to_be_bytes().to_vec();
+        let mut channel_secret = channel_secret.to_vec();
+        payload.append(&mut channel_secret);
+        hasher.update(payload.clone());
+        let result = hasher.finalize();
+
+        let mut checksum: [u8; 4] = [0; 4];
+        checksum.copy_from_slice(&result[..4]);
+
+        payload.append(&mut checksum.to_vec());
+
+        let encoded = bs58::encode(payload).into_string();
+
+        encoded
+    }
+
+    pub fn get_channel_secret(&self) -> [u8; 32] {
+        self.channel_secret
+    }
+
+    pub fn get_channel_name(&self) -> &String {
+        &self.channel_name
+    }
+
+    pub fn get_channel_id(&self) -> &Option<u32> {
+        &self.id
+    }
+
+    pub fn get_channel_address(&self) -> &String {
+        &self.address
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::{Channel, Result};
+
+    #[test]
+    fn create_channel_form_address() -> Result<()> {
+        let channel = Channel::gen_new(String::from("test"));
+        let channel_address = channel.get_channel_address();
+        let channel2 = Channel::gen_new_with_addr(String::from("test"), channel_address.clone())?;
+        assert_eq!(channel.get_channel_secret(), channel2.get_channel_secret());
+        assert_eq!(
+            channel.get_channel_address(),
+            channel2.get_channel_address()
+        );
+        Ok(())
+    }
+}

+ 196 - 0
src/darkpulse/cli_option.rs

@@ -0,0 +1,196 @@
+use std::net::SocketAddr;
+
+use clap::{App, Arg, SubCommand};
+
+use super::channel::Channel;
+use crate::net::Settings;
+use crate::Result;
+
+pub struct CliOption {
+    pub network_settings: Settings,
+    pub username: Option<String>,
+    pub channel_name: Option<String>,
+    pub new_channel: Option<Channel>,
+    pub verbose: bool,
+    pub log_path: Box<std::path::PathBuf>,
+}
+
+impl CliOption {
+    pub fn get() -> Result<CliOption> {
+        let mat = App::new("DarkPulse")
+            .version("0.0.1")
+            .author("Dark Renaissance Technologies")
+            .about("An anonymous p2p chat application")
+            .arg(
+                Arg::with_name("accept")
+                    .short("a")
+                    .value_name("ADDRESSES")
+                    .help("accept address")
+                    .long("accept")
+                    .required(true),
+            )
+            .arg(
+                Arg::with_name("slots")
+                    .value_name("SLOTS")
+                    .long("slots")
+                    .help("Connection slots"),
+            )
+            .arg(
+                Arg::with_name("verbose")
+                    .takes_value(false)
+                    .long("verbose")
+                    .help("increase verbosity"),
+            )
+            .arg(
+                Arg::with_name("connects")
+                    .value_name("MANUAL_CONNECTS")
+                    .multiple(true)
+                    .takes_value(true)
+                    .short("c")
+                    .long("connects")
+                    .help("Manual connections"),
+            )
+            .arg(
+                Arg::with_name("seed")
+                    .value_name("ADDRESSES")
+                    .multiple(true)
+                    .takes_value(true)
+                    .short("s")
+                    .long("seed")
+                    .help("Connect to the seed node"),
+            )
+            .arg(
+                Arg::with_name("log")
+                    .value_name("LOG_PATH")
+                    .takes_value(true)
+                    .long("log")
+                    .help("Log file path"),
+            )
+            .arg(
+                Arg::with_name("username")
+                    .value_name("USERNAME")
+                    .short("u")
+                    .long("username")
+                    .help("node's username"),
+            )
+            .arg(
+                Arg::with_name("channel")
+                    .value_name("CHANNEL")
+                    .short("h")
+                    .long("channel")
+                    .help("switch to one of available channels"),
+            )
+            .subcommand(
+                SubCommand::with_name("newchannel")
+                    .about("add new channel")
+                    .arg(
+                        Arg::with_name("name")
+                            .long("channelname")
+                            .required(true)
+                            .value_name("CHANNELNAME")
+                            .help("name for the new channel"),
+                    )
+                    .arg(
+                        Arg::with_name("address")
+                            .long("channeladdress")
+                            .required(true)
+                            .value_name("CHANNELADDRESS")
+                            .help("address for the new channel"),
+                    ),
+            )
+            .get_matches();
+
+        let mut accept_addr: Option<SocketAddr> = None;
+        if let Some(addr) = mat.value_of("accept") {
+            accept_addr = Some(addr.parse()?);
+        }
+
+        let mut connection_slots = 0;
+        if let Some(slots) = mat.value_of("slots") {
+            connection_slots = slots.parse()?;
+        };
+
+        let mut seed_addresses: Vec<SocketAddr> = vec![];
+        if let Some(seed_addrs) = mat.values_of("seed") {
+            seed_addresses = Self::collect_addrs(seed_addrs.collect::<Vec<&str>>());
+        };
+
+        let mut manual_connects: Vec<SocketAddr> = vec![];
+        if let Some(man_connects) = mat.values_of("connects") {
+            manual_connects = Self::collect_addrs(man_connects.collect::<Vec<&str>>());
+        };
+
+        let mut username = None;
+
+        if let Some(uname) = mat.value_of("username") {
+            username = Some(String::from(uname));
+        }
+
+        let mut channel_name = None;
+
+        if let Some(chan) = mat.value_of("channel") {
+            channel_name = Some(String::from(chan));
+        }
+
+        let mut new_channel: Option<Channel> = None;
+
+        if let Some(newch) = mat.subcommand_matches("newchannel") {
+            let mut new_channel_name = String::new();
+            let mut new_channel_address = String::new();
+            if let Some(channelname) = newch.value_of("name") {
+                new_channel_name = String::from(channelname);
+            }
+            if let Some(channeladdress) = newch.value_of("address") {
+                new_channel_address = String::from(channeladdress);
+            }
+            new_channel = Some(Channel::gen_new_with_addr(
+                new_channel_name,
+                new_channel_address,
+            )?);
+        }
+
+        let verbose = mat.is_present("verbose");
+
+        let log_path = Box::new(
+            if let Some(log_path) = mat.value_of("log") {
+                std::path::Path::new(log_path)
+            } else {
+                std::path::Path::new("/tmp/darkpulsenode.log")
+            }
+            .to_path_buf(),
+        );
+
+        let network_settings = Settings {
+            inbound: accept_addr,
+            outbound_connections: connection_slots,
+            seed_query_timeout_seconds: 8,
+            connect_timeout_seconds: 10,
+            channel_handshake_seconds: 4,
+            channel_heartbeat_seconds: 10,
+            external_addr: accept_addr,
+            peers: manual_connects,
+            seeds: seed_addresses,
+        };
+
+        Ok(CliOption {
+            network_settings,
+            username,
+            channel_name,
+            new_channel,
+            verbose,
+            log_path,
+        })
+    }
+
+    fn collect_addrs(addrs: Vec<&str>) -> Vec<SocketAddr> {
+        let addrs: Vec<SocketAddr> = addrs
+            .iter()
+            .map(|addr| {
+                let addr: SocketAddr = addr.parse().expect("unable to parse on of the addresses");
+                addr
+            })
+            .collect();
+
+        addrs
+    }
+}

+ 65 - 0
src/darkpulse/control_message.rs

@@ -0,0 +1,65 @@
+use std::io;
+
+use crate::serial::{Decodable, Encodable};
+use crate::Result;
+
+#[derive(Copy, Clone)]
+pub enum ControlCommand {
+    Join = 0,
+    Leave = 1,
+    Message = 2,
+}
+
+pub struct MessagePayload {
+    pub nickname: String,
+    pub text: String,
+    pub timestamp: i64,
+}
+
+pub struct ControlMessage {
+    pub control: ControlCommand,
+    pub payload: MessagePayload,
+}
+
+impl Encodable for MessagePayload {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.nickname.encode(&mut s)?;
+        len += self.text.encode(&mut s)?;
+        len += self.timestamp.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for MessagePayload {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            nickname: Decodable::decode(&mut d)?,
+            text: Decodable::decode(&mut d)?,
+            timestamp: Decodable::decode(&mut d)?,
+        })
+    }
+}
+impl Encodable for ControlMessage {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += (self.control as u8).encode(&mut s)?;
+        len += self.payload.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for ControlMessage {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        let control_code: u8 = Decodable::decode(&mut d)?;
+        let control = match control_code {
+            0 => ControlCommand::Join,
+            1 => ControlCommand::Leave,
+            _ => ControlCommand::Message,
+        };
+        Ok(Self {
+            control,
+            payload: Decodable::decode(&mut d)?,
+        })
+    }
+}

+ 173 - 0
src/darkpulse/dbsql.rs

@@ -0,0 +1,173 @@
+use std::collections::HashMap;
+use std::convert::TryInto;
+use std::fs::File;
+use std::io::prelude::*;
+
+use rusqlite::{params, Connection};
+
+use crate::Result;
+
+use super::{net::messages::SlabMessage, CiphertextHash,utility::default_config_dir, 
+    channel::Channel};
+
+
+#[derive(Debug)]
+pub struct Dbsql {
+    connection: Connection,
+    username: String,
+}
+
+impl Dbsql {
+    pub fn new() -> Result<Dbsql> {
+        let path = default_config_dir()?.join("data.db");
+        let connection = Connection::open(path)?;
+        let username = String::new();
+        Ok(Dbsql {
+            connection,
+            username,
+        })
+    }
+
+    pub fn start(&mut self) -> Result<()> {
+        let schemas = Self::read_schemas_from_file("../../sql/darkpulse_schema.sql")?;
+        self.connection.execute_batch(schemas.as_str())?;
+
+        Ok(())
+    }
+
+    pub fn add_slab(&self, slab: &SlabMessage, channel_id: &u32) -> Result<()> {
+        self.connection.execute(
+            "INSERT OR IGNORE INTO slab (nonce, cipher_text, cipher_text_hash, channel_id) VALUES (?1, ?2, ?3, ?4)",
+            params![&slab.nonce[..], &slab.ciphertext[..], &slab.cipher_hash()[..], channel_id],
+        )?;
+        Ok(())
+    }
+
+    pub fn add_username(&self, username: &String) -> Result<()> {
+        self.connection.execute(
+            "INSERT OR IGNORE INTO node (username) VALUES (?1)",
+            params![username],
+        )?;
+        Ok(())
+    }
+
+    pub fn get_channel_slabs(&self, id: u32) -> Result<HashMap<CiphertextHash, SlabMessage>> {
+        let stmt = format!("SELECT * FROM slab WHERE channel_id={}", id);
+        let mut stmt = self.connection.prepare(&stmt)?;
+
+        let mut slabs: HashMap<CiphertextHash, SlabMessage> = HashMap::new();
+        let slab_iter = stmt.query_map(params![], |row| {
+            let nonce: Vec<u8> = row.get(1)?;
+            let nonce = nonce
+                .as_slice()
+                .try_into()
+                .expect("error when converting vector to slice with size [u8; 12]");
+
+            let ciphertext = row.get(2)?;
+
+            Ok(SlabMessage { nonce, ciphertext })
+        })?;
+
+        for slab in slab_iter {
+            let slab = slab?;
+            slabs.insert(slab.cipher_hash(), slab);
+        }
+        Ok(slabs)
+    }
+
+    pub fn add_channel(&self, channel: &Channel) -> Result<()> {
+        self.connection.execute(
+            "INSERT OR IGNORE INTO channel (channel_name, channel_secret, address) VALUES (?1, ?2, ?3)",
+            params![
+            &channel.get_channel_name(),
+            &channel.get_channel_secret()[..],
+            &channel.get_channel_address()
+            ],
+        )?;
+        Ok(())
+    }
+
+    pub fn delete_channel(&self, channel_name: &String) -> Result<()> {
+        self.connection.execute(
+            "DELETE FROM channel WHERE channel_name = (?1)",
+            params![channel_name,],
+        )?;
+        Ok(())
+    }
+
+    fn read_schemas_from_file(path: &str) -> Result<String> {
+        let mut file = File::open(path)?;
+        let mut schemas = String::new();
+        file.read_to_string(&mut schemas)?;
+        Ok(schemas)
+    }
+
+    pub fn get_slabs(&mut self) -> Result<HashMap<CiphertextHash, SlabMessage>> {
+        let mut slabs = HashMap::new();
+        let mut stmt = self.connection.prepare("SELECT * FROM slab")?;
+        let slab_iter = stmt.query_map(params![], |row| {
+            let nonce: Vec<u8> = row.get(1)?;
+
+            let nonce: [u8; 12] = nonce
+                .as_slice()
+                .try_into()
+                .expect("error when converting vector to slice with size [u8; 12]");
+
+            let ciphertext = row.get(2)?;
+
+            Ok(SlabMessage { nonce, ciphertext })
+        })?;
+
+        for slab in slab_iter {
+            let slab = slab?;
+            slabs.insert(slab.cipher_hash(), slab);
+        }
+
+        Ok(slabs)
+    }
+
+    pub fn get_channels(&self) -> Result<Vec<Channel>> {
+        let mut channels = Vec::new();
+        let mut stmt = self.connection.prepare("SELECT * FROM channel")?;
+        let channel_iter = stmt.query_map(params![], |row| {
+            let channel_id = row.get(0)?;
+            let channel_name = row.get(1)?;
+            let channel_secret: Vec<u8> = row.get(2)?;
+
+            let channel_secret: [u8; 32] = channel_secret
+                .as_slice()
+                .try_into()
+                .expect("error when converting vector to slice with size [u8; 32]");
+
+            let address = row.get(3)?;
+            Ok(Channel::new(
+                    channel_name,
+                    channel_secret,
+                    address,
+                    channel_id,
+            ))
+        })?;
+
+        for channel in channel_iter {
+            let channel = channel?;
+            channels.push(channel);
+        }
+
+        Ok(channels.clone())
+    }
+
+    pub fn get_username(&self) -> Result<String> {
+        let mut username = String::new();
+        let mut stmt3 = self.connection.prepare("SELECT * FROM node")?;
+        let mut uname_iter = stmt3.query_map(params![], |row| {
+            let username: String = row.get(1)?;
+            Ok(username)
+        })?;
+
+        for name in uname_iter.next() {
+            username = name?;
+        }
+
+        Ok(username)
+    }
+}

+ 34 - 0
src/darkpulse/error.rs

@@ -0,0 +1,34 @@
+use crate::error::Error as DarkFiError;
+use std::fmt;
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+#[derive(Debug)]
+pub enum Error {
+    SqliteError(String),
+    DarkFiError(DarkFiError),
+}
+
+impl std::error::Error for Error {}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
+        match *self {
+            Error::SqliteError(ref e) => write!(f, "database sqlite error: {}", e),
+            Error::DarkFiError(ref e) => write!(f, "darkfi internal error : {}", e),
+        }
+    }
+}
+
+impl From<DarkFiError> for Error {
+    fn from(err: DarkFiError) -> Error {
+        Error::DarkFiError(err)
+    }
+}
+
+impl From<rusqlite::Error> for Error {
+    fn from(err: rusqlite::Error) -> Error {
+        Error::SqliteError(err.to_string())
+    }
+}
+

+ 15 - 0
src/darkpulse/mod.rs

@@ -0,0 +1,15 @@
+pub mod aes;
+pub mod channel;
+pub mod cli_option;
+pub mod control_message;
+pub mod dbsql;
+pub mod net;
+pub mod slabs_manager;
+pub mod utility;
+pub mod error;
+
+use async_std::sync::{Arc, Mutex};
+
+pub type CiphertextHash = [u8; 32];
+pub type MemPool = Arc<Mutex<Vec<(CiphertextHash, net::messages::SlabMessage)>>>;
+

+ 112 - 0
src/darkpulse/net/messages.rs

@@ -0,0 +1,112 @@
+use std::io;
+
+use crate::{
+    net::messages::Message,
+    serial::{Decodable, Encodable},
+    Result
+};
+
+use crate::darkpulse::aes::Ciphertext;
+
+#[derive(Clone)]
+pub struct GetSlabsMessage {
+    pub slabs_hash: Vec<[u8; 32]>,
+}
+
+#[derive(Clone)]
+pub struct InvMessage {
+    pub slabs_hash: Vec<[u8; 32]>,
+}
+
+#[derive(Clone)]
+pub struct SlabMessage {
+    pub nonce: [u8; 12],
+    pub ciphertext: Ciphertext,
+}
+
+#[derive(Clone)]
+pub struct SyncMessage {}
+
+impl Message for SlabMessage {
+    fn name() -> &'static str {
+        "slab"
+    }
+}
+
+impl Message for GetSlabsMessage {
+    fn name() -> &'static str {
+        "getslabs"
+    }
+}
+impl Message for InvMessage {
+    fn name() -> &'static str {
+        "inv"
+    }
+}
+impl Message for SyncMessage {
+    fn name() -> &'static str {
+        "sync"
+    }
+}
+
+impl Encodable for GetSlabsMessage {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.slabs_hash.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for GetSlabsMessage {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            slabs_hash: Decodable::decode(&mut d)?,
+        })
+    }
+}
+
+impl Encodable for SlabMessage {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.nonce.encode(&mut s)?;
+        len += self.ciphertext.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for SlabMessage {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            nonce: Decodable::decode(&mut d)?,
+            ciphertext: Decodable::decode(&mut d)?,
+        })
+    }
+}
+
+impl Encodable for InvMessage {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = 0;
+        len += self.slabs_hash.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for InvMessage {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            slabs_hash: Decodable::decode(&mut d)?,
+        })
+    }
+}
+
+impl Encodable for SyncMessage {
+    fn encode<S: io::Write>(&self, _s: S) -> Result<usize> {
+        Ok(0)
+    }
+}
+
+impl Decodable for SyncMessage {
+    fn decode<D: io::Read>(_d: D) -> Result<Self> {
+        Ok(Self {})
+    }
+}

+ 3 - 0
src/darkpulse/net/mod.rs

@@ -0,0 +1,3 @@
+pub mod messages;
+pub mod protocol_slab;
+

+ 190 - 0
src/darkpulse/net/protocol_slab.rs

@@ -0,0 +1,190 @@
+use std::sync::Arc;
+
+
+use log::*;
+use smol::Executor;
+
+use crate::error::Result as NetResult;
+use crate::serial::deserialize;
+use crate::net::{message_subscriber::MessageSubscription, protocols::ProtocolJobsManager,
+protocols::ProtocolJobsManagerPtr ,ChannelPtr};
+
+use crate::darkpulse::{aes::aes_decrypt, net::messages, control_message::ControlCommand,
+control_message::ControlMessage, slabs_manager::SlabsManagerSafe, CiphertextHash};
+
+pub struct ProtocolSlab {
+    channel: ChannelPtr,
+    slabman: SlabsManagerSafe,
+
+    sync_sub: MessageSubscription<messages::SyncMessage>,
+    inv_sub: MessageSubscription<messages::InvMessage>,
+    get_slabs_sub: MessageSubscription<messages::GetSlabsMessage>,
+    slab_sub: MessageSubscription<messages::SlabMessage>,
+
+    jobsman: ProtocolJobsManagerPtr,
+}
+
+impl ProtocolSlab {
+    pub async fn new(slabman: SlabsManagerSafe, channel: ChannelPtr) -> Arc<Self> {
+        let sync_sub = channel
+            .clone()
+            .subscribe_msg::<messages::SyncMessage>()
+            .await
+            .expect("Missing sync  dispatcher!");
+
+        let inv_sub = channel
+            .clone()
+            .subscribe_msg::<messages::InvMessage>()
+            .await
+            .expect("Missing inv  dispatcher!");
+
+        let get_slabs_sub = channel
+            .clone()
+            .subscribe_msg::<messages::GetSlabsMessage>()
+            .await
+            .expect("Missing getslabs  dispatcher!");
+
+        let slab_sub = channel
+            .clone()
+            .subscribe_msg::<messages::SlabMessage>()
+            .await
+            .expect("Missing slab  dispatcher!");
+
+        Arc::new(Self {
+            channel: channel.clone(),
+            slabman,
+            sync_sub,
+            inv_sub,
+            get_slabs_sub,
+            slab_sub,
+            jobsman: ProtocolJobsManager::new("ProtocolSlab", channel),
+        })
+    }
+
+    pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
+        debug!(target: "net", "ProtocolSlab::start() [START]");
+        self.jobsman.clone().start(executor.clone());
+
+        self.jobsman
+            .clone()
+            .spawn(self.clone().handle_receive_sync(), executor.clone())
+            .await;
+        self.jobsman
+            .clone()
+            .spawn(self.clone().handle_receive_inv(), executor.clone())
+            .await;
+
+        self.jobsman
+            .clone()
+            .spawn(self.clone().handle_receive_get_slabs(), executor.clone())
+            .await;
+        self.jobsman
+            .clone()
+            .spawn(self.clone().handle_receive_slab(), executor)
+            .await;
+
+        let _ = self.channel.send(messages::SyncMessage {}).await;
+
+        debug!(target: "net", "ProtocolSlab::start() [END]");
+    }
+
+    async fn handle_receive_sync(self: Arc<Self>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolSlab::handle_receive_sync() [START]");
+        loop {
+            let _sync_msg = self.sync_sub.receive().await?;
+            let slab_hashs = self.slabman.lock().await.get_slabs_hash();
+            let inv_msg = messages::InvMessage {
+                slabs_hash: slab_hashs.clone(),
+            };
+            self.channel.send(inv_msg).await?;
+            info!("receive sync message!");
+        }
+    }
+
+    async fn handle_receive_inv(self: Arc<Self>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolSlab::handle_receive_inv() [START]");
+        loop {
+            let inv_msg = self.inv_sub.receive().await?;
+            let mut list_of_hash: Vec<CiphertextHash> = vec![];
+            let slabs_hash = self.slabman.lock().await.get_slabs_hash();
+            for slab in inv_msg.slabs_hash.iter() {
+                if !slabs_hash.contains(slab) {
+                    list_of_hash.push(slab.clone());
+                }
+            }
+            let getslabs_msg = messages::GetSlabsMessage {
+                slabs_hash: list_of_hash,
+            };
+            self.channel.send(getslabs_msg).await?;
+            info!("receive inv message!");
+        }
+    }
+
+    async fn handle_receive_get_slabs(self: Arc<Self>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolSlab::handle_receive_get_slabs() [START]");
+        loop {
+            let get_slabs_msg = self.get_slabs_sub.receive().await?;
+            for slab_hash in get_slabs_msg.slabs_hash.iter() {
+                let slabman = self.slabman.lock().await;
+                let slab = slabman.get_slab(&slab_hash);
+                if let Some(slab) = slab {
+                    self.channel.send(slab.clone()).await?;
+                }
+            }
+            info!("receive getslabs message!");
+        }
+    }
+
+    async fn handle_receive_slab(self: Arc<Self>) -> NetResult<()> {
+        debug!(target: "net", "ProtocolSlab::handle_receive_slab() [START]");
+        loop {
+            let slab_msg = self.slab_sub.receive().await?;
+            info!("receive slab message!");
+
+            let channels = self.slabman.lock().await.get_channels().unwrap_or(vec![]);
+
+            let slab = messages::SlabMessage {
+                nonce: slab_msg.nonce,
+                ciphertext: slab_msg.ciphertext.clone(),
+            };
+
+            for channel in channels.iter() {
+                match aes_decrypt(
+                    &channel.get_channel_secret(),
+                    &slab_msg.nonce,
+                    &slab_msg.ciphertext,
+                ) {
+                    Some(plaintext) => {
+                        self.slabman
+                            .lock()
+                            .await
+                            .add_new_slab(slab.clone())
+                            .await
+                            .expect("error during adding new slab to database");
+
+                        let des_plaintext: ControlMessage = deserialize(&plaintext[..])
+                            .expect("error during deserializing the message");
+
+                        match des_plaintext.control {
+                            ControlCommand::Join => {
+                                info!("{} joined the group", des_plaintext.payload.nickname);
+                            }
+                            ControlCommand::Leave => {
+                                info!("{} left the group", des_plaintext.payload.nickname);
+                            }
+                            ControlCommand::Message => {
+                                info!(
+                                    "{} -> {}: {}",
+                                    des_plaintext.payload.timestamp,
+                                    des_plaintext.payload.nickname,
+                                    des_plaintext.payload.text
+                                );
+                            }
+                        }
+                    }
+                    None => {}
+                }
+            }
+        }
+    }
+}

+ 1 - 0
src/darkpulse/net/protocols/mod.rs

@@ -0,0 +1 @@
+pub mod protocol_slab;

+ 124 - 0
src/darkpulse/slabs_manager.rs

@@ -0,0 +1,124 @@
+use std::collections::HashMap;
+use std::sync::Arc;
+
+use log::*;
+use sha2::{Digest, Sha256};
+
+use crate:: Result;
+
+use super::{dbsql, net::messages::SlabMessage, channel::Channel, CiphertextHash, aes::Ciphertext};
+
+pub fn cipher_hash(ciphertext: &Ciphertext) -> CiphertextHash {
+    let mut cipher_hash = [0u8; 32];
+    let mut hasher = Sha256::new();
+    for chunk in ciphertext.chunks(32) {
+        hasher.update(chunk);
+    }
+    cipher_hash.copy_from_slice(&hasher.finalize());
+    cipher_hash
+}
+
+impl SlabMessage {
+    pub fn cipher_hash(&self) -> CiphertextHash {
+        cipher_hash(&self.ciphertext)
+    }
+}
+
+pub type SlabsManagerSafe = Arc<async_std::sync::Mutex<SlabsManager>>;
+
+pub struct SlabsManager {
+    slabs: HashMap<CiphertextHash, SlabMessage>,
+    notify_update: async_channel::Sender<CiphertextHash>,
+    main_channel: Channel,
+    db: dbsql::Dbsql,
+}
+
+impl SlabsManager {
+    pub async fn new(
+        db: dbsql::Dbsql,
+        notify_update: async_channel::Sender<CiphertextHash>,
+        main_channel: Channel,
+    ) -> SlabsManagerSafe {
+        let mut slabs: HashMap<CiphertextHash, SlabMessage> = HashMap::new();
+
+        if let Some(channel_id) = main_channel.get_channel_id() {
+            slabs = db.get_channel_slabs(channel_id.clone()).unwrap_or(slabs);
+        }
+
+        Arc::new(async_std::sync::Mutex::new(SlabsManager {
+            slabs,
+            notify_update,
+            main_channel,
+            db,
+        }))
+    }
+
+    pub fn get_slabs_hash(&self) -> Vec<CiphertextHash> {
+        self.slabs.keys().cloned().collect()
+    }
+    pub fn height(&self) -> u32 {
+        self.slabs.len() as u32
+    }
+    pub fn has_cipher_hash(&self, cipher_hash: &CiphertextHash) -> bool {
+        self.slabs.contains_key(cipher_hash)
+    }
+
+    pub async fn add_new_slab(&mut self, slab: SlabMessage) -> Result<()> {
+        info!("received Slab message.");
+        self.slabs.insert(slab.cipher_hash(), slab.clone());
+
+        if let Some(channel_id) = self.main_channel.get_channel_id() {
+            self.db.add_slab(&slab, channel_id)?;
+        }
+
+        self.notify_update.send(slab.cipher_hash()).await?;
+        Ok(())
+    }
+
+    pub fn set_main_channel(&mut self, main_channel: Channel) {
+        self.main_channel = main_channel;
+        self.switch_main_channel();
+    }
+
+    pub fn switch_main_channel(&mut self) {
+        let default_slabs: HashMap<CiphertextHash, SlabMessage> = HashMap::new();
+
+        if let Some(channel_id) = self.main_channel.get_channel_id() {
+            self.slabs = self
+                .db
+                .get_channel_slabs(channel_id.clone())
+                .unwrap_or(default_slabs);
+        }
+    }
+
+    pub fn get_channels(&mut self) -> Result<Vec<Channel>> {
+        self.db.get_channels()
+    }
+
+    pub fn add_new_channel(&mut self, new_channel: &Channel) -> Result<()> {
+        self.db.add_channel(new_channel)?;
+        Ok(())
+    }
+
+    pub fn delete_channel(&mut self, channel_id: &String) -> Result<()> {
+        self.db.delete_channel(channel_id)?;
+        Ok(())
+    }
+
+    pub fn add_username(&mut self, username: &String) -> Result<()> {
+        self.db.add_username(username)?;
+        Ok(())
+    }
+
+    pub fn get_main_channel(&self) -> Channel {
+        self.main_channel.clone()
+    }
+
+    pub fn get_slab(&self, cipher_hash: &CiphertextHash) -> Option<&SlabMessage> {
+        self.slabs.get(cipher_hash)
+    }
+
+    pub fn get_slabs(&self) -> &HashMap<CiphertextHash, SlabMessage> {
+        &self.slabs
+    }
+}

+ 181 - 0
src/darkpulse/utility.rs

@@ -0,0 +1,181 @@
+use std::fs::OpenOptions;
+use std::io::prelude::*;
+use std::net::SocketAddr;
+use std::path::PathBuf;
+use std::sync::atomic::AtomicU64;
+use std::sync::Arc;
+use std::time::{SystemTime, UNIX_EPOCH};
+
+use async_executor::Executor;
+use futures::prelude::*;
+use log::*;
+
+use super::{aes::aes_encrypt, dbsql, net::messages, net::protocol_slab::ProtocolSlab,
+control_message::ControlMessage, control_message::ControlCommand, channel::Channel,
+slabs_manager::SlabsManagerSafe, control_message::MessagePayload};
+
+
+use crate::{ serial::{serialize, deserialize}, net::ChannelPtr, Result};
+
+pub type AddrsStorage = Arc<async_std::sync::Mutex<Vec<SocketAddr>>>;
+
+pub type Clock = Arc<AtomicU64>;
+
+pub fn get_current_time() -> u64 {
+    let start = SystemTime::now();
+    let since_the_epoch = start
+        .duration_since(UNIX_EPOCH)
+        .expect("Incorrect system clock: time went backwards");
+    let in_ms =
+        since_the_epoch.as_secs() * 1000 + since_the_epoch.subsec_nanos() as u64 / 1_000_000;
+    return in_ms;
+}
+
+pub fn save_to_addrs_store(stored_addrs: &Vec<SocketAddr>) -> Result<()> {
+    let path = default_config_dir()?.join("addrs.add");
+    let mut writer = OpenOptions::new().write(true).create(true).open(path)?;
+    let buffer = serialize(stored_addrs);
+    writer.write_all(&buffer)?;
+    Ok(())
+}
+
+pub fn default_config_dir() -> Result<PathBuf> {
+    let mut path = PathBuf::new();
+
+    if let Some(home_dir) = dirs::home_dir() {
+        path = home_dir;
+    };
+
+    let path = path.join(".darkpulse/");
+    if !path.exists() {
+        match std::fs::create_dir(&path) {
+            Err(err) => {
+                eprintln!("error: Creating config dir: {}", err);
+                std::process::exit(-1);
+            }
+            Ok(()) => (),
+        }
+    }
+
+    Ok(path)
+}
+
+pub fn load_stored_addrs() -> Result<Vec<SocketAddr>> {
+    let path = default_config_dir()?.join("addrs.add");
+    println!("{:?}", path);
+    let mut reader = OpenOptions::new()
+        .read(true)
+        .write(true)
+        .create(true)
+        .open(path)?;
+    let mut buffer = Vec::new();
+    reader.read_to_end(&mut buffer)?;
+    if !buffer.is_empty() {
+        let addrs: Vec<SocketAddr> = deserialize(&buffer)?;
+        Ok(addrs)
+    } else {
+        Ok(vec![])
+    }
+}
+
+pub async fn pack_slab(
+    channel_secret: &[u8; 32],
+    username: String,
+    message: String,
+    control_command: ControlCommand,
+) -> Result<messages::SlabMessage> {
+    let nonce: [u8; 12] = rand::random();
+    let timestamp = chrono::offset::Utc::now();
+    let timestamp: i64 = timestamp.timestamp_millis() / 1000;
+
+    let msg_payload = MessagePayload {
+        nickname: username.clone(),
+        text: message,
+        timestamp,
+    };
+
+    let control_message = ControlMessage {
+        control: control_command,
+        payload: msg_payload,
+    };
+
+    let ser_message = serialize(&control_message);
+
+    let ciphertext = aes_encrypt(channel_secret, &nonce, &ser_message[..])
+        .expect("error during encrypting the message");
+
+    let slab = messages::SlabMessage { nonce, ciphertext };
+
+    Ok(slab)
+}
+
+pub fn setup_username(newname: Option<String>, db: &dbsql::Dbsql) -> Result<String> {
+    let mut _username: String = String::new();
+    match newname {
+        Some(nm) => {
+            _username = nm.clone();
+            db.add_username(&nm).unwrap();
+        }
+        None => {
+            _username = db.get_username()?;
+            if _username.is_empty() {
+                _username = String::from("username");
+            }
+        }
+    }
+    Ok(_username)
+}
+
+pub async fn read_line<R: AsyncBufRead + Unpin>(reader: &mut R) -> Result<String> {
+    let mut buf = String::new();
+    let _ = reader.read_line(&mut buf).await?;
+    Ok(buf.trim().to_string())
+}
+
+pub fn choose_channel(db: &dbsql::Dbsql, channel_name: Option<String>) -> Result<Channel> {
+    let channels = db.get_channels()?;
+    let mut main_channel = Channel::gen_new(String::from("test_channel"));
+    if channels.len() > 0 {
+        match channel_name {
+            Some(name) => {
+                main_channel = channels
+                    .iter()
+                    .filter(|ch| ch.get_channel_name() == &name)
+                    .next()
+                    .expect(format!("there is no channel with the name {}: ", name).as_str())
+                    .clone();
+                }
+            None => {
+                main_channel = channels.first().unwrap().clone();
+            }
+        }
+    } else {
+        error!("there are no channels available");
+        db.add_channel(&main_channel)?;
+    }
+    Ok(main_channel)
+}
+
+pub async fn setup_network_channel(
+    executor: Arc<Executor<'_>>,
+    channel: ChannelPtr,
+    slabman: SlabsManagerSafe,
+) {
+    let message_subsytem = channel.get_message_subsystem();
+
+    message_subsytem
+        .add_dispatch::<messages::SyncMessage>()
+        .await;
+    message_subsytem
+        .add_dispatch::<messages::InvMessage>()
+        .await;
+    message_subsytem
+        .add_dispatch::<messages::GetSlabsMessage>()
+        .await;
+    message_subsytem
+        .add_dispatch::<messages::SlabMessage>()
+        .await;
+
+    let protocol_slab = ProtocolSlab::new(slabman, channel.clone()).await;
+    protocol_slab.clone().start(executor.clone()).await;
+}

+ 7 - 0
src/error.rs

@@ -227,3 +227,10 @@ impl From<halo2::plonk::Error> for Error {
         Error::PlonkError(format!("{:?}", err))
     }
 }
+
+#[cfg(feature = "darkpulse")]
+impl From<rusqlite::Error> for Error {
+    fn from(err: rusqlite::Error) -> Error {
+        Error::SqlxError(err.to_string())
+    }
+}

+ 3 - 0
src/lib.rs

@@ -19,4 +19,7 @@ pub mod vm;
 pub mod vm_serial;
 pub mod wallet;
 
+#[cfg(feature = "darkpulse")]
+pub mod darkpulse;
+
 pub use crate::error::{Error, Result};