/* This file is part of DarkFi (https://dark.fi) * * Copyright (C) 2020-2023 Dyne.org foundation * * 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 . */ use std::fmt; use async_std::sync::{Arc, Mutex}; use log::{info, warn}; use rand::rngs::OsRng; use smol::channel::Receiver; use structopt_toml::StructOptToml; use darkfi::{ async_daemonize, net, rpc::server::listen_and_serve, system::{Subscriber, SubscriberPtr}, util::{file::save_json_file, path::expand_path}, Result, }; pub mod buffers; pub mod crypto; pub mod irc; pub mod model; pub mod privmsg; pub mod protocol_privmsg; pub mod protocol_privmsg2; pub mod rpc; pub mod settings; pub mod view; use crate::{ buffers::SeenIds, irc::IrcServer, privmsg::Privmsg, protocol_privmsg::ProtocolPrivmsg, rpc::JsonRpcInterface, settings::{Args, ChannelInfo, CONFIG_FILE, CONFIG_FILE_CONTENTS}, }; #[derive(serde::Serialize)] struct KeyPair { private_key: String, public_key: String, } impl fmt::Display for KeyPair { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Public key: {}\nPrivate key: {}", self.public_key, self.private_key) } } struct Ircd { notify_clients: SubscriberPtr, } impl Ircd { fn new() -> Self { let notify_clients = Subscriber::new(); Self { notify_clients } } async fn start( &self, settings: &Args, seen: Arc>, p2p: net::P2pPtr, p2p_receiver: Receiver, executor: Arc>, ) -> Result<()> { let notify_clients = self.notify_clients.clone(); executor .spawn(async move { while let Ok(msg) = p2p_receiver.recv().await { notify_clients.notify(msg).await; } }) .detach(); let irc_server = IrcServer::new( settings.clone(), seen.clone(), p2p.clone(), self.notify_clients.clone(), ) .await?; let executor_cloned = executor.clone(); executor .spawn(async move { irc_server.start(executor_cloned.clone()).await.unwrap(); }) .detach(); Ok(()) } } async_daemonize!(realmain); async fn realmain(settings: Args, executor: Arc>) -> Result<()> { let seen = Arc::new(Mutex::new(SeenIds::new())); if settings.gen_secret { let secret_key = crypto_box::SecretKey::generate(&mut OsRng); let encoded = bs58::encode(secret_key.as_bytes()); println!("{}", encoded.into_string()); return Ok(()) } if settings.gen_keypair { let secret_key = crypto_box::SecretKey::generate(&mut OsRng); let pub_key = secret_key.public_key(); let prv_encoded = bs58::encode(secret_key.as_bytes()).into_string(); let pub_encoded = bs58::encode(pub_key.as_bytes()).into_string(); let kp = KeyPair { private_key: prv_encoded, public_key: pub_encoded }; if settings.output.is_some() { let datastore = expand_path(&settings.output.unwrap())?; save_json_file(&datastore, &kp)?; } else { println!("Generated KeyPair:\n{}", kp); } return Ok(()) } if settings.secret.is_some() { let secret = settings.secret.clone().unwrap(); let bytes: [u8; 32] = bs58::decode(secret).into_vec()?.try_into().unwrap(); let secret = crypto_box::SecretKey::from(bytes); let pubkey = secret.public_key(); let pub_encoded = bs58::encode(pubkey.as_bytes()).into_string(); if settings.output.is_some() { let datastore = expand_path(&settings.output.unwrap())?; save_json_file(&datastore, &pub_encoded)?; } else { println!("Public key recoverd: {}", pub_encoded); } return Ok(()) } // // P2p setup // let mut net_settings = settings.net.clone(); net_settings.app_version = Some(option_env!("CARGO_PKG_VERSION").unwrap_or("").to_string()); let (p2p_send_channel, p2p_recv_channel) = smol::channel::unbounded::(); let p2p = net::P2p::new(net_settings.into()).await; let p2p2 = p2p.clone(); let registry = p2p.protocol_registry(); let seen_c = seen.clone(); registry .register(net::SESSION_ALL, move |channel, p2p| { let sender = p2p_send_channel.clone(); let seen = seen_c.clone(); async move { ProtocolPrivmsg::init(channel, sender, p2p, seen).await } }) .await; p2p.clone().start(executor.clone()).await?; let executor_cloned = executor.clone(); executor_cloned.spawn(p2p.clone().run(executor.clone())).detach(); // RPC interface let rpc_listen_addr = settings.rpc_listen.clone(); let rpc_interface = Arc::new(JsonRpcInterface { addr: rpc_listen_addr.clone(), p2p: p2p.clone() }); let _ex = executor.clone(); executor .spawn(async move { listen_and_serve(rpc_listen_addr, rpc_interface, _ex).await }) .detach(); // // IRC instance // let ircd = Ircd::new(); ircd.start(&settings, seen, p2p, p2p_recv_channel, executor.clone()).await?; // Run once receive exit signal let (signal, shutdown) = smol::channel::bounded::<()>(1); ctrlc::set_handler(move || { warn!(target: "ircd", "ircd start Exit Signal"); // cleaning up tasks running in the background async_std::task::block_on(signal.send(())).unwrap(); }) .unwrap(); // Wait for SIGINT shutdown.recv().await?; print!("\r"); info!("Caught termination signal, cleaning up and exiting..."); p2p2.stop().await; Ok(()) }