Rust implementation of NextGraph, a Decentralized and local-first web 3.0 ecosystem https://nextgraph.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nextgraph-rs/p2p-broker/src/server_ws.rs

215 lines
7.1 KiB

/*
* Copyright (c) 2022-2023 Niko Bonnieure, Par le Peuple, NextGraph.org developers
* All rights reserved.
* Licensed under the Apache License, Version 2.0
* <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
* or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
* at your option. All files in the project carrying such
* notice may not be copied, modified, or distributed except
* according to those terms.
*/
2 years ago
//! WebSocket implementation of the Broker
use crate::interfaces::*;
use crate::types::*;
2 years ago
use async_std::net::{TcpListener, TcpStream};
use async_std::sync::Mutex;
use async_std::task;
use async_tungstenite::accept_async;
use async_tungstenite::tungstenite::protocol::Message;
use futures::{SinkExt, StreamExt};
use p2p_client_ws::remote_ws::ConnectionWebSocket;
use p2p_net::broker::*;
use p2p_net::connection::IAccept;
use p2p_net::types::IP;
use p2p_net::utils::Sensitive;
use p2p_repo::log::*;
use p2p_repo::types::{PrivKey, PubKey};
use p2p_repo::utils::generate_keypair;
use std::collections::HashSet;
2 years ago
use std::fs;
use std::net::SocketAddr;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::ops::Deref;
use std::path::{Path, PathBuf};
2 years ago
use std::sync::Arc;
use std::{thread, time};
use stores_lmdb::kcv_store::LmdbKCVStore;
use stores_lmdb::repo_store::LmdbRepoStore;
use tempfile::Builder;
2 years ago
pub async fn accept(tcp: TcpStream, peer_priv_key: Sensitive<[u8; 32]>, peer_pub_key: PubKey) {
let sock_addr = tcp.peer_addr().unwrap();
let ip = sock_addr.ip();
let mut ws = accept_async(tcp).await.unwrap();
let cws = ConnectionWebSocket {};
let base = cws.accept(peer_priv_key, peer_pub_key, ws).await.unwrap();
//TODO FIXME get remote_peer_id from ConnectionBase (once it is available)
let (priv_key, pub_key) = generate_keypair();
let remote_peer_id = pub_key;
let res = BROKER
.write()
.await
.accept(base, IP::try_from(&ip).unwrap(), None, remote_peer_id)
.await;
}
pub async fn run_server_accept_one(
addr: &str,
port: u16,
peer_priv_key: Sensitive<[u8; 32]>,
peer_pub_key: PubKey,
) -> std::io::Result<()> {
let addrs = format!("{}:{}", addr, port);
let root = tempfile::Builder::new().prefix("ngd").tempdir().unwrap();
let master_key: [u8; 32] = [0; 32];
std::fs::create_dir_all(root.path()).unwrap();
log_debug!("data directory: {}", root.path().to_str().unwrap());
let store = LmdbKCVStore::open(root.path(), master_key);
let socket = TcpListener::bind(addrs.as_str()).await?;
log_debug!("Listening on {}", addrs.as_str());
let mut connections = socket.incoming();
let tcp = connections.next().await.unwrap()?;
accept(tcp, peer_priv_key, peer_pub_key).await;
Ok(())
}
use p2p_net::utils::U8Array;
pub async fn run_server_v0(
peer_priv_key: Sensitive<[u8; 32]>,
peer_pub_key: PubKey,
wallet_master_key: Sensitive<[u8; 32]>,
config: DaemonConfigV0,
mut path: PathBuf,
) -> Result<(), ()> {
// check config
let mut should_run = false;
for overlay_conf in config.overlays_configs {
if overlay_conf.core != BrokerOverlayPermission::Nobody
|| overlay_conf.server != BrokerOverlayPermission::Nobody
{
should_run = true;
break;
}
}
if !should_run {
log_err!("There isn't any overlay_config that should run as core or server. Check your config. cannot start");
return Err(());
}
let listeners: HashSet<String> = HashSet::new();
for listener in &config.listeners {
let mut id = listener.interface_name.clone();
id.push('@');
id.push_str(&listener.port.to_string());
if listeners.contains(&id) {
log_err!(
"The listener {} is defined twice. Check your config file. cannot start",
id
);
return Err(());
}
}
//let root = tempfile::Builder::new().prefix("ngd").tempdir().unwrap();
path.push("storage");
std::fs::create_dir_all(path.clone()).unwrap();
//log::info!("Home directory is {}");
// TODO: open wallet
let master_key: [u8; 32] = [0; 32];
let store = LmdbKCVStore::open(&path, master_key);
let interfaces = get_interface();
let mut listeners: Vec<TcpListener> = vec![];
for listener in config.listeners {
match find_name(&interfaces, &listener.interface_name) {
None => {
log_err!(
"The interface {} does not exist on your host. Check your config file. cannot start",
listener.interface_name
);
return Err(());
}
Some(interface) => {
let mut ips: Vec<SocketAddr> = interface
.ipv4
.iter()
.filter_map(|ip| {
if interface.if_type.is_ipv4_valid_for_type(&ip.addr) {
Some(SocketAddr::new(IpAddr::V4(ip.addr), listener.port))
} else {
None
}
})
.collect();
if ips.len() == 0 {
log_err!(
"The interface {} does not have any IPv4 address. cannot start",
listener.interface_name
);
return Err(());
}
if listener.ipv6 {
let mut ipv6s: Vec<SocketAddr> = interface
.ipv6
.iter()
.filter_map(|ip| {
if interface.if_type.is_ipv6_valid_for_type(&ip.addr) {
Some(SocketAddr::new(IpAddr::V6(ip.addr), listener.port))
} else {
None
}
})
.collect();
ips.append(&mut ipv6s);
}
let ips_string = ips
.iter()
.map(|ip| ip.to_string())
.collect::<Vec<String>>()
.join(", ");
let listener = TcpListener::bind(ips.as_slice()).await.map_err(|e| {
log_err!(
"cannot bind to {} with addresses {} : {}",
interface.name,
ips_string,
e.to_string()
)
})?;
log_info!("Listening on {} {}", interface.name, ips_string);
listeners.push(listener);
}
}
}
// select on all listeners
let mut incoming = futures::stream::select_all(
listeners
.into_iter()
.map(TcpListener::into_incoming)
.map(Box::pin),
);
// Iterate over all incoming connections
while let Some(tcp) = incoming.next().await {
accept(
tcp.unwrap(),
Sensitive::<[u8; 32]>::from_slice(peer_priv_key.deref()),
peer_pub_key,
)
.await;
}
Ok(())
}