initial import of main veilid core
This commit is contained in:
179
veilid-core/src/intf/wasm/network/mod.rs
Normal file
179
veilid-core/src/intf/wasm/network/mod.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
mod protocol;
|
||||
|
||||
use crate::intf::*;
|
||||
use crate::network_manager::*;
|
||||
use crate::routing_table::*;
|
||||
use crate::*;
|
||||
use protocol::ws::WebsocketProtocolHandler;
|
||||
pub use protocol::*;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
struct NetworkInner {
|
||||
network_manager: NetworkManager,
|
||||
stop_network: Eventual,
|
||||
network_needs_restart: bool,
|
||||
//join_handle: TryJoin?
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Network {
|
||||
inner: Arc<Mutex<NetworkInner>>,
|
||||
}
|
||||
|
||||
impl Network {
|
||||
fn new_inner(network_manager: NetworkManager) -> NetworkInner {
|
||||
NetworkInner {
|
||||
network_manager: network_manager,
|
||||
stop_network: Eventual::new(),
|
||||
network_needs_restart: false,
|
||||
//join_handle: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(network_manager: NetworkManager) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(Mutex::new(Self::new_inner(network_manager))),
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
async fn send_data_to_existing_connection(
|
||||
&self,
|
||||
descriptor: &ConnectionDescriptor,
|
||||
data: Vec<u8>,
|
||||
) -> Result<Option<Vec<u8>>, String> {
|
||||
match descriptor.protocol_type() {
|
||||
ProtocolType::UDP => return Err("no support for udp protocol".to_owned()),
|
||||
ProtocolType::TCP => return Err("no support for tcp protocol".to_owned()),
|
||||
ProtocolType::WS | ProtocolType::WSS => {
|
||||
// find an existing connection in the connection table if one exists
|
||||
let network_manager = self.inner.lock().network_manager.clone();
|
||||
if let Some(entry) = network_manager
|
||||
.connection_table()
|
||||
.get_connection(&descriptor)
|
||||
{
|
||||
// connection exists, send over it
|
||||
entry
|
||||
.conn
|
||||
.send(data)
|
||||
.await
|
||||
.map_err(|_| "failed to send ws message".to_owned())?;
|
||||
// Data was consumed
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
// connection or local socket didn't exist, we'll need to use dialinfo to create one
|
||||
// Pass the data back out so we don't own it any more
|
||||
Ok(Some(data))
|
||||
}
|
||||
|
||||
pub async fn send_data_unbound_to_dial_info(
|
||||
&self,
|
||||
dial_info: &DialInfo,
|
||||
data: Vec<u8>,
|
||||
) -> Result<(), String> {
|
||||
let network_manager = self.inner.lock().network_manager.clone();
|
||||
|
||||
match &dial_info {
|
||||
DialInfo::UDP(_) => return Err("no support for UDP protocol".to_owned()),
|
||||
DialInfo::TCP(_) => return Err("no support for TCP protocol".to_owned()),
|
||||
DialInfo::WS(_) => Err("WS protocol does not support unbound messages".to_owned()),
|
||||
DialInfo::WSS(_) => Err("WSS protocol does not support unbound messages".to_owned()),
|
||||
}
|
||||
}
|
||||
pub async fn send_data_to_dial_info(
|
||||
&self,
|
||||
dial_info: &DialInfo,
|
||||
data: Vec<u8>,
|
||||
) -> Result<(), String> {
|
||||
let network_manager = self.inner.lock().network_manager.clone();
|
||||
|
||||
let conn = match &dial_info {
|
||||
DialInfo::UDP(_) => return Err("no support for UDP protocol".to_owned()),
|
||||
DialInfo::TCP(_) => return Err("no support for TCP protocol".to_owned()),
|
||||
DialInfo::WS(_) => WebsocketProtocolHandler::connect(network_manager, dial_info)
|
||||
.await
|
||||
.map_err(|_| "failed to connect to WS dial info".to_owned())?,
|
||||
DialInfo::WSS(_) => WebsocketProtocolHandler::connect(network_manager, dial_info)
|
||||
.await
|
||||
.map_err(|_| "failed to connect to WSS dial info".to_owned())?,
|
||||
};
|
||||
|
||||
conn.send(data)
|
||||
.await
|
||||
.map_err(|_| "failed to send data to dial info".to_owned())
|
||||
}
|
||||
|
||||
pub async fn send_data(&self, node_ref: NodeRef, data: Vec<u8>) -> Result<(), String> {
|
||||
let dial_info = node_ref.dial_info();
|
||||
let descriptor = node_ref.last_connection();
|
||||
|
||||
// First try to send data to the last socket we've seen this peer on
|
||||
let di_data = if let Some(descriptor) = descriptor {
|
||||
match self
|
||||
.clone()
|
||||
.send_data_to_existing_connection(&descriptor, data)
|
||||
.await?
|
||||
{
|
||||
None => {
|
||||
return Ok(());
|
||||
}
|
||||
Some(d) => d,
|
||||
}
|
||||
} else {
|
||||
data
|
||||
};
|
||||
|
||||
// If that fails, try to make a connection or reach out to the peer via its dial info
|
||||
if let Some(di) = dial_info {
|
||||
self.clone().send_data_to_dial_info(&di, di_data).await
|
||||
} else {
|
||||
Err("couldn't send data, no dial info or peer address".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
pub async fn startup(&self) -> Result<(), String> {
|
||||
//let network_manager = self.inner.lock().network_manager.clone();
|
||||
//let config_shared = network_manager.core().config();
|
||||
//let config = config_shared.get();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn needs_restart(&self) -> bool {
|
||||
self.inner.lock().network_needs_restart
|
||||
}
|
||||
|
||||
pub async fn shutdown(&self) {
|
||||
trace!("stopping network");
|
||||
|
||||
// Reset state
|
||||
let network_manager = self.inner.lock().network_manager.clone();
|
||||
let routing_table = network_manager.routing_table();
|
||||
|
||||
// Drop all dial info
|
||||
routing_table.clear_local_dial_info();
|
||||
routing_table.clear_public_dial_info();
|
||||
|
||||
// Cancels all async background tasks by dropping join handles
|
||||
*self.inner.lock() = Self::new_inner(network_manager);
|
||||
|
||||
trace!("network stopped");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
pub fn get_network_class(&self) -> NetworkClass {
|
||||
// xxx eventually detect tor browser?
|
||||
return NetworkClass::WebApp;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
pub async fn tick(&self) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
48
veilid-core/src/intf/wasm/network/protocol/mod.rs
Normal file
48
veilid-core/src/intf/wasm/network/protocol/mod.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
pub mod wrtc;
|
||||
pub mod ws;
|
||||
|
||||
use crate::veilid_api::ProtocolType;
|
||||
use crate::xx::*;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct DummyNetworkConnection {}
|
||||
|
||||
impl DummyNetworkConnection {
|
||||
pub fn protocol_type(&self) -> ProtocolType {
|
||||
ProtocolType::UDP
|
||||
}
|
||||
pub fn send(&self, _message: Vec<u8>) -> SystemPinBoxFuture<Result<(), ()>> {
|
||||
Box::pin(async { Ok(()) })
|
||||
}
|
||||
pub fn recv(&self) -> SystemPinBoxFuture<Result<Vec<u8>, ()>> {
|
||||
Box::pin(async { Ok(Vec::new()) })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum NetworkConnection {
|
||||
Dummy(DummyNetworkConnection),
|
||||
WS(ws::WebsocketNetworkConnection),
|
||||
//WebRTC(wrtc::WebRTCNetworkConnection),
|
||||
}
|
||||
|
||||
impl NetworkConnection {
|
||||
pub fn protocol_type(&self) -> ProtocolType {
|
||||
match self {
|
||||
Self::Dummy(d) => d.protocol_type(),
|
||||
Self::WS(w) => w.protocol_type(),
|
||||
}
|
||||
}
|
||||
pub fn send(&self, message: Vec<u8>) -> SystemPinBoxFuture<Result<(), ()>> {
|
||||
match self {
|
||||
Self::Dummy(d) => d.send(message),
|
||||
Self::WS(w) => w.send(message),
|
||||
}
|
||||
}
|
||||
pub fn recv(&self) -> SystemPinBoxFuture<Result<Vec<u8>, ()>> {
|
||||
match self {
|
||||
Self::Dummy(d) => d.recv(),
|
||||
Self::WS(w) => w.recv(),
|
||||
}
|
||||
}
|
||||
}
|
0
veilid-core/src/intf/wasm/network/protocol/wrtc.rs
Normal file
0
veilid-core/src/intf/wasm/network/protocol/wrtc.rs
Normal file
116
veilid-core/src/intf/wasm/network/protocol/ws.rs
Normal file
116
veilid-core/src/intf/wasm/network/protocol/ws.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
use crate::intf::*;
|
||||
use crate::network_manager::{NetworkManager, MAX_MESSAGE_SIZE};
|
||||
use crate::*;
|
||||
use alloc::fmt;
|
||||
use futures_util::stream::StreamExt;
|
||||
use web_sys::WebSocket;
|
||||
use ws_stream_wasm::*;
|
||||
|
||||
struct WebsocketNetworkConnectionInner {
|
||||
_ws_meta: WsMeta,
|
||||
ws_stream: WsStream,
|
||||
ws: WebSocket,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WebsocketNetworkConnection {
|
||||
tls: bool,
|
||||
inner: Arc<Mutex<WebsocketNetworkConnectionInner>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for WebsocketNetworkConnection {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", core::any::type_name::<Self>())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for WebsocketNetworkConnection {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.tls == other.tls && Arc::as_ptr(&self.inner) == Arc::as_ptr(&other.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for WebsocketNetworkConnection {}
|
||||
|
||||
impl WebsocketNetworkConnection {
|
||||
pub fn new(tls: bool, ws_meta: WsMeta, ws_stream: WsStream) -> Self {
|
||||
let ws = ws_stream.wrapped().clone();
|
||||
Self {
|
||||
tls: tls,
|
||||
inner: Arc::new(Mutex::new(WebsocketNetworkConnectionInner {
|
||||
_ws_meta: ws_meta,
|
||||
ws_stream: ws_stream,
|
||||
ws: ws,
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebsocketNetworkConnection {
|
||||
pub fn protocol_type(&self) -> ProtocolType {
|
||||
if self.tls {
|
||||
ProtocolType::WSS
|
||||
} else {
|
||||
ProtocolType::WS
|
||||
}
|
||||
}
|
||||
pub fn send(&self, message: Vec<u8>) -> SystemPinBoxFuture<Result<(), ()>> {
|
||||
let inner = self.inner.clone();
|
||||
Box::pin(async move {
|
||||
if message.len() > MAX_MESSAGE_SIZE {
|
||||
return Err(());
|
||||
}
|
||||
inner.lock().ws.send_with_u8_array(&message).map_err(drop)
|
||||
})
|
||||
}
|
||||
pub fn recv(&self) -> SystemPinBoxFuture<Result<Vec<u8>, ()>> {
|
||||
let inner = self.inner.clone();
|
||||
Box::pin(async move {
|
||||
let out = match inner.lock().ws_stream.next().await {
|
||||
Some(WsMessage::Binary(v)) => v,
|
||||
_ => {
|
||||
trace!("websocket recv failed");
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
if out.len() > MAX_MESSAGE_SIZE {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
///
|
||||
|
||||
pub struct WebsocketProtocolHandler {}
|
||||
|
||||
impl WebsocketProtocolHandler {
|
||||
pub async fn connect(
|
||||
network_manager: NetworkManager,
|
||||
dial_info: &DialInfo,
|
||||
) -> Result<NetworkConnection, ()> {
|
||||
let url = dial_info.to_url_string(None);
|
||||
let (tls, host, port, protocol_type) = match dial_info {
|
||||
DialInfo::WS(ws) => (false, ws.fqdn.clone(), ws.port, ProtocolType::WS),
|
||||
DialInfo::WSS(wss) => (true, wss.fqdn.clone(), wss.port, ProtocolType::WSS),
|
||||
_ => return Err(()),
|
||||
};
|
||||
|
||||
let peer_addr = PeerAddress::new(Address::from_str(&host)?, port, protocol_type);
|
||||
|
||||
let (ws, wsio) = match WsMeta::connect(url, None).await {
|
||||
Ok(conn) => conn,
|
||||
Err(_) => return Err(()),
|
||||
};
|
||||
|
||||
let conn = NetworkConnection::WS(WebsocketNetworkConnection::new(tls, ws, wsio));
|
||||
network_manager
|
||||
.on_new_connection(ConnectionDescriptor::new_no_local(peer_addr), conn.clone())
|
||||
.await?;
|
||||
|
||||
Ok(conn)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user