checkpoint
This commit is contained in:
parent
317f036598
commit
59c14f3b22
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -6160,6 +6160,7 @@ dependencies = [
|
|||||||
"cursive_table_view",
|
"cursive_table_view",
|
||||||
"directories",
|
"directories",
|
||||||
"flexi_logger",
|
"flexi_logger",
|
||||||
|
"flume",
|
||||||
"futures",
|
"futures",
|
||||||
"hex",
|
"hex",
|
||||||
"json",
|
"json",
|
||||||
@ -6168,10 +6169,11 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
|
"stop-token",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio 1.28.2",
|
"tokio 1.28.2",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"veilid-core",
|
"veilid-tools",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -12,8 +12,8 @@ path = "src/main.rs"
|
|||||||
[features]
|
[features]
|
||||||
default = [ "rt-tokio" ]
|
default = [ "rt-tokio" ]
|
||||||
macos = [ "cursive/ncurses-backend" ]
|
macos = [ "cursive/ncurses-backend" ]
|
||||||
rt-async-std = [ "async-std", "veilid-core/rt-async-std", "cursive/rt-async-std" ]
|
rt-async-std = [ "async-std", "veilid-tools/rt-async-std", "cursive/rt-async-std" ]
|
||||||
rt-tokio = [ "tokio", "tokio-util", "veilid-core/rt-tokio", "cursive/rt-tokio" ]
|
rt-tokio = [ "tokio", "tokio-util", "veilid-tools/rt-tokio", "cursive/rt-tokio" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-std = { version = "^1.9", features = ["unstable", "attributes"], optional = true }
|
async-std = { version = "^1.9", features = ["unstable", "attributes"], optional = true }
|
||||||
@ -41,8 +41,10 @@ flexi_logger = { version = "^0", features = ["use_chrono_for_offset"] }
|
|||||||
thiserror = "^1"
|
thiserror = "^1"
|
||||||
crossbeam-channel = "^0"
|
crossbeam-channel = "^0"
|
||||||
hex = "^0"
|
hex = "^0"
|
||||||
veilid-core = { path = "../veilid-core" }
|
veilid-tools = { path = "../veilid-tools", default-features = false }
|
||||||
json = "^0"
|
json = "^0"
|
||||||
|
stop-token = { version = "^0", default-features = false }
|
||||||
|
flume = { version = "^0", features = ["async"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = "^0"
|
serial_test = "^0"
|
||||||
|
@ -1,94 +1,66 @@
|
|||||||
use crate::command_processor::*;
|
use crate::command_processor::*;
|
||||||
use crate::tools::*;
|
use crate::tools::*;
|
||||||
use futures::future::FutureExt;
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use veilid_core::tools::*;
|
use stop_token::{future::FutureExt as _, StopSource, StopToken};
|
||||||
use veilid_core::*;
|
|
||||||
|
|
||||||
fn map_to_internal_error<T: ToString>(e: T) -> VeilidAPIError {
|
use veilid_tools::*;
|
||||||
VeilidAPIError::Internal {
|
cfg_if! {
|
||||||
message: e.to_string(),
|
if #[cfg(feature="rt-async-std")] {
|
||||||
|
use async_std::io::prelude::BufReadExt;
|
||||||
|
use async_std::io::WriteExt;
|
||||||
|
use async_std::io::BufReader;
|
||||||
|
} else if #[cfg(feature="rt-tokio")] {
|
||||||
|
use tokio::io::AsyncBufReadExt;
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
use tokio::io::BufReader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_api_result<T: DeserializeOwned + fmt::Debug>(
|
// fn map_to_internal_error<T: ToString>(e: T) -> VeilidAPIError {
|
||||||
reader: &api_result::Reader,
|
// VeilidAPIError::Internal {
|
||||||
) -> VeilidAPIResult<T> {
|
// message: e.to_string(),
|
||||||
match reader.which().map_err(map_to_internal_error)? {
|
// }
|
||||||
api_result::Which::Ok(v) => {
|
// }
|
||||||
let ok_val = v.map_err(map_to_internal_error)?;
|
|
||||||
let res: T = veilid_core::deserialize_json(ok_val).map_err(map_to_internal_error)?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
api_result::Which::Err(e) => {
|
|
||||||
let err_val = e.map_err(map_to_internal_error)?;
|
|
||||||
let res: VeilidAPIError =
|
|
||||||
veilid_core::deserialize_json(err_val).map_err(map_to_internal_error)?;
|
|
||||||
Err(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VeilidClientImpl {
|
// fn decode_api_result<T: DeserializeOwned + fmt::Debug>(
|
||||||
comproc: CommandProcessor,
|
// reader: &api_result::Reader,
|
||||||
}
|
// ) -> VeilidAPIResult<T> {
|
||||||
|
// match reader.which().map_err(map_to_internal_error)? {
|
||||||
|
// api_result::Which::Ok(v) => {
|
||||||
|
// let ok_val = v.map_err(map_to_internal_error)?;
|
||||||
|
// let res: T = veilid_core::deserialize_json(ok_val).map_err(map_to_internal_error)?;
|
||||||
|
// Ok(res)
|
||||||
|
// }
|
||||||
|
// api_result::Which::Err(e) => {
|
||||||
|
// let err_val = e.map_err(map_to_internal_error)?;
|
||||||
|
// let res: VeilidAPIError =
|
||||||
|
// veilid_core::deserialize_json(err_val).map_err(map_to_internal_error)?;
|
||||||
|
// Err(res)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
impl VeilidClientImpl {
|
// struct VeilidClientImpl {
|
||||||
pub fn new(comproc: CommandProcessor) -> Self {
|
// comproc: CommandProcessor,
|
||||||
Self { comproc }
|
// }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl veilid_client::Server for VeilidClientImpl {
|
// impl VeilidClientImpl {
|
||||||
fn update(
|
// pub fn new(comproc: CommandProcessor) -> Self {
|
||||||
&mut self,
|
// Self { comproc }
|
||||||
params: veilid_client::UpdateParams,
|
// }
|
||||||
_results: veilid_client::UpdateResults,
|
// }
|
||||||
) -> Promise<(), ::capnp::Error> {
|
|
||||||
let veilid_update = pry!(pry!(params.get()).get_veilid_update());
|
|
||||||
let veilid_update: VeilidUpdate = pry_result!(deserialize_json(veilid_update));
|
|
||||||
|
|
||||||
match veilid_update {
|
// }
|
||||||
VeilidUpdate::Log(log) => {
|
|
||||||
self.comproc.update_log(log);
|
|
||||||
}
|
|
||||||
VeilidUpdate::AppMessage(msg) => {
|
|
||||||
self.comproc.update_app_message(msg);
|
|
||||||
}
|
|
||||||
VeilidUpdate::AppCall(call) => {
|
|
||||||
self.comproc.update_app_call(call);
|
|
||||||
}
|
|
||||||
VeilidUpdate::Attachment(attachment) => {
|
|
||||||
self.comproc.update_attachment(attachment);
|
|
||||||
}
|
|
||||||
VeilidUpdate::Network(network) => {
|
|
||||||
self.comproc.update_network_status(network);
|
|
||||||
}
|
|
||||||
VeilidUpdate::Config(config) => {
|
|
||||||
self.comproc.update_config(config);
|
|
||||||
}
|
|
||||||
VeilidUpdate::RouteChange(route) => {
|
|
||||||
self.comproc.update_route(route);
|
|
||||||
}
|
|
||||||
VeilidUpdate::Shutdown => self.comproc.update_shutdown(),
|
|
||||||
VeilidUpdate::ValueChange(value_change) => {
|
|
||||||
self.comproc.update_value_change(value_change);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise::ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ClientApiConnectionInner {
|
struct ClientApiConnectionInner {
|
||||||
comproc: CommandProcessor,
|
comproc: CommandProcessor,
|
||||||
connect_addr: Option<SocketAddr>,
|
connect_addr: Option<SocketAddr>,
|
||||||
disconnector: Option<Disconnector<rpc_twoparty_capnp::Side>>,
|
server: Option<flume::Sender<String>>,
|
||||||
server: Option<Rc<RefCell<veilid_server::Client>>>,
|
|
||||||
server_settings: Option<String>,
|
server_settings: Option<String>,
|
||||||
|
disconnector: Option<StopSource>,
|
||||||
disconnect_requested: bool,
|
disconnect_requested: bool,
|
||||||
cancel_eventual: Eventual,
|
cancel_eventual: Eventual,
|
||||||
}
|
}
|
||||||
@ -106,9 +78,9 @@ impl ClientApiConnection {
|
|||||||
inner: Rc::new(RefCell::new(ClientApiConnectionInner {
|
inner: Rc::new(RefCell::new(ClientApiConnectionInner {
|
||||||
comproc,
|
comproc,
|
||||||
connect_addr: None,
|
connect_addr: None,
|
||||||
disconnector: None,
|
|
||||||
server: None,
|
server: None,
|
||||||
server_settings: None,
|
server_settings: None,
|
||||||
|
disconnector: None,
|
||||||
disconnect_requested: false,
|
disconnect_requested: false,
|
||||||
cancel_eventual: Eventual::new(),
|
cancel_eventual: Eventual::new(),
|
||||||
})),
|
})),
|
||||||
@ -123,196 +95,272 @@ impl ClientApiConnection {
|
|||||||
eventual.resolve(); // don't need to await this
|
eventual.resolve(); // don't need to await this
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_veilid_state<'a>(
|
// async fn process_veilid_state<'a>(
|
||||||
&'a mut self,
|
// &'a mut self,
|
||||||
veilid_state: VeilidState,
|
// veilid_state: VeilidState,
|
||||||
) -> Result<(), String> {
|
// ) -> Result<(), String> {
|
||||||
let mut inner = self.inner.borrow_mut();
|
// let mut inner = self.inner.borrow_mut();
|
||||||
inner.comproc.update_attachment(veilid_state.attachment);
|
// inner.comproc.update_attachment(veilid_state.attachment);
|
||||||
inner.comproc.update_network_status(veilid_state.network);
|
// inner.comproc.update_network_status(veilid_state.network);
|
||||||
inner.comproc.update_config(veilid_state.config);
|
// inner.comproc.update_config(veilid_state.config);
|
||||||
Ok(())
|
// Ok(())
|
||||||
}
|
// }
|
||||||
|
|
||||||
async fn spawn_rpc_system(
|
async fn process_update(&self, update: json::JsonValue) {
|
||||||
&mut self,
|
let comproc = self.inner.borrow().comproc.clone();
|
||||||
connect_addr: SocketAddr,
|
let Some(kind) = update["kind"].as_str() else {
|
||||||
mut rpc_system: RpcSystem<rpc_twoparty_capnp::Side>,
|
comproc.log_message(format!("missing update kind: {}", update));
|
||||||
) -> Result<(), String> {
|
return;
|
||||||
let mut request;
|
|
||||||
{
|
|
||||||
let mut inner = self.inner.borrow_mut();
|
|
||||||
|
|
||||||
// Get the bootstrap server connection object
|
|
||||||
inner.server = Some(Rc::new(RefCell::new(
|
|
||||||
rpc_system.bootstrap(rpc_twoparty_capnp::Side::Server),
|
|
||||||
)));
|
|
||||||
|
|
||||||
// Store our disconnector future for later (must happen after bootstrap, contrary to documentation)
|
|
||||||
inner.disconnector = Some(rpc_system.get_disconnector());
|
|
||||||
|
|
||||||
// Get a client object to pass to the server for status update callbacks
|
|
||||||
let client = capnp_rpc::new_client(VeilidClientImpl::new(inner.comproc.clone()));
|
|
||||||
|
|
||||||
// Register our client and get a registration object back
|
|
||||||
request = inner
|
|
||||||
.server
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.register_request();
|
|
||||||
request.get().set_veilid_client(client);
|
|
||||||
|
|
||||||
inner
|
|
||||||
.comproc
|
|
||||||
.set_connection_state(ConnectionState::Connected(
|
|
||||||
connect_addr,
|
|
||||||
std::time::SystemTime::now(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let rpc_jh = spawn_local(rpc_system);
|
|
||||||
|
|
||||||
let reg_res: Result<registration::Client, String> = (async {
|
|
||||||
// Send the request and get the state object and the registration object
|
|
||||||
let response = request
|
|
||||||
.send()
|
|
||||||
.promise
|
|
||||||
.await
|
|
||||||
.map_err(|e| format!("failed to send register request: {}", e))?;
|
|
||||||
let response = response
|
|
||||||
.get()
|
|
||||||
.map_err(|e| format!("failed to get register response: {}", e))?;
|
|
||||||
|
|
||||||
// Get the registration object, which drops our connection when it is dropped
|
|
||||||
let registration = response
|
|
||||||
.get_registration()
|
|
||||||
.map_err(|e| format!("failed to get registration object: {}", e))?;
|
|
||||||
|
|
||||||
// Get the initial veilid state
|
|
||||||
let veilid_state = response
|
|
||||||
.get_state()
|
|
||||||
.map_err(|e| format!("failed to get initial veilid state: {}", e))?;
|
|
||||||
|
|
||||||
// Set up our state for the first time
|
|
||||||
let veilid_state: VeilidState = deserialize_json(veilid_state)
|
|
||||||
.map_err(|e| format!("failed to get deserialize veilid state: {}", e))?;
|
|
||||||
self.process_veilid_state(veilid_state).await?;
|
|
||||||
|
|
||||||
// Save server settings
|
|
||||||
let server_settings = response
|
|
||||||
.get_settings()
|
|
||||||
.map_err(|e| format!("failed to get initial veilid server settings: {}", e))?
|
|
||||||
.to_owned();
|
|
||||||
self.inner.borrow_mut().server_settings = Some(server_settings.clone());
|
|
||||||
|
|
||||||
// Don't drop the registration, doing so will remove the client
|
|
||||||
// object mapping from the server which we need for the update backchannel
|
|
||||||
Ok(registration)
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let _registration = match reg_res {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(e) => {
|
|
||||||
rpc_jh.abort().await;
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
match kind {
|
||||||
// Wait until rpc system completion or disconnect was requested
|
"Log" => {
|
||||||
let res = rpc_jh.await;
|
comproc.update_log(update);
|
||||||
res.map_err(|e| format!("client RPC system error: {}", e))
|
}
|
||||||
|
"AppMessage" => {
|
||||||
|
comproc.update_app_message(update);
|
||||||
|
}
|
||||||
|
"AppCall" => {
|
||||||
|
comproc.update_app_call(update);
|
||||||
|
}
|
||||||
|
"Attachment" => {
|
||||||
|
comproc.update_attachment(update);
|
||||||
|
}
|
||||||
|
"Network" => {
|
||||||
|
comproc.update_network_status(update);
|
||||||
|
}
|
||||||
|
"Config" => {
|
||||||
|
comproc.update_config(update);
|
||||||
|
}
|
||||||
|
"RouteChange" => {
|
||||||
|
comproc.update_route(update);
|
||||||
|
}
|
||||||
|
"Shutdown" => comproc.update_shutdown(),
|
||||||
|
"ValueChange" => {
|
||||||
|
comproc.update_value_change(update);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
comproc.log_message(format!("unknown update kind: {}", update));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// async fn spawn_rpc_system(
|
||||||
|
// &mut self,
|
||||||
|
// connect_addr: SocketAddr,
|
||||||
|
// mut rpc_system: RpcSystem<rpc_twoparty_capnp::Side>,
|
||||||
|
// ) -> Result<(), String> {
|
||||||
|
// let mut request;
|
||||||
|
// {
|
||||||
|
// let mut inner = self.inner.borrow_mut();
|
||||||
|
|
||||||
|
// // Get the bootstrap server connection object
|
||||||
|
// inner.server = Some(Rc::new(RefCell::new(
|
||||||
|
// rpc_system.bootstrap(rpc_twoparty_capnp::Side::Server),
|
||||||
|
// )));
|
||||||
|
|
||||||
|
// // Store our disconnector future for later (must happen after bootstrap, contrary to documentation)
|
||||||
|
// inner.disconnector = Some(rpc_system.get_disconnector());
|
||||||
|
|
||||||
|
// // Get a client object to pass to the server for status update callbacks
|
||||||
|
// let client = capnp_rpc::new_client(VeilidClientImpl::new(inner.comproc.clone()));
|
||||||
|
|
||||||
|
// // Register our client and get a registration object back
|
||||||
|
// request = inner
|
||||||
|
// .server
|
||||||
|
// .as_ref()
|
||||||
|
// .unwrap()
|
||||||
|
// .borrow_mut()
|
||||||
|
// .register_request();
|
||||||
|
// request.get().set_veilid_client(client);
|
||||||
|
|
||||||
|
// inner
|
||||||
|
// .comproc
|
||||||
|
// .set_connection_state(ConnectionState::Connected(
|
||||||
|
// connect_addr,
|
||||||
|
// std::time::SystemTime::now(),
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let rpc_jh = spawn_local(rpc_system);
|
||||||
|
|
||||||
|
// let reg_res: Result<registration::Client, String> = (async {
|
||||||
|
// // Send the request and get the state object and the registration object
|
||||||
|
// let response = request
|
||||||
|
// .send()
|
||||||
|
// .promise
|
||||||
|
// .await
|
||||||
|
// .map_err(|e| format!("failed to send register request: {}", e))?;
|
||||||
|
// let response = response
|
||||||
|
// .get()
|
||||||
|
// .map_err(|e| format!("failed to get register response: {}", e))?;
|
||||||
|
|
||||||
|
// // Get the registration object, which drops our connection when it is dropped
|
||||||
|
// let registration = response
|
||||||
|
// .get_registration()
|
||||||
|
// .map_err(|e| format!("failed to get registration object: {}", e))?;
|
||||||
|
|
||||||
|
// // Get the initial veilid state
|
||||||
|
// let veilid_state = response
|
||||||
|
// .get_state()
|
||||||
|
// .map_err(|e| format!("failed to get initial veilid state: {}", e))?;
|
||||||
|
|
||||||
|
// // Set up our state for the first time
|
||||||
|
// let veilid_state: VeilidState = deserialize_json(veilid_state)
|
||||||
|
// .map_err(|e| format!("failed to get deserialize veilid state: {}", e))?;
|
||||||
|
// self.process_veilid_state(veilid_state).await?;
|
||||||
|
|
||||||
|
// // Save server settings
|
||||||
|
// let server_settings = response
|
||||||
|
// .get_settings()
|
||||||
|
// .map_err(|e| format!("failed to get initial veilid server settings: {}", e))?
|
||||||
|
// .to_owned();
|
||||||
|
// self.inner.borrow_mut().server_settings = Some(server_settings.clone());
|
||||||
|
|
||||||
|
// // Don't drop the registration, doing so will remove the client
|
||||||
|
// // object mapping from the server which we need for the update backchannel
|
||||||
|
// Ok(registration)
|
||||||
|
// })
|
||||||
|
// .await;
|
||||||
|
|
||||||
|
// let _registration = match reg_res {
|
||||||
|
// Ok(v) => v,
|
||||||
|
// Err(e) => {
|
||||||
|
// rpc_jh.abort().await;
|
||||||
|
// return Err(e);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Wait until rpc system completion or disconnect was requested
|
||||||
|
// let res = rpc_jh.await;
|
||||||
|
// res.map_err(|e| format!("client RPC system error: {}", e))
|
||||||
|
// }
|
||||||
|
|
||||||
async fn handle_connection(&mut self, connect_addr: SocketAddr) -> Result<(), String> {
|
async fn handle_connection(&mut self, connect_addr: SocketAddr) -> Result<(), String> {
|
||||||
trace!("ClientApiConnection::handle_connection");
|
trace!("ClientApiConnection::handle_connection");
|
||||||
|
|
||||||
self.inner.borrow_mut().connect_addr = Some(connect_addr);
|
let stop_token = {
|
||||||
|
let stop_source = StopSource::new();
|
||||||
|
let token = stop_source.token();
|
||||||
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
inner.connect_addr = Some(connect_addr);
|
||||||
|
inner.disconnector = Some(stop_source);
|
||||||
|
token
|
||||||
|
};
|
||||||
|
|
||||||
// Connect the TCP socket
|
// Connect the TCP socket
|
||||||
let stream = TcpStream::connect(connect_addr)
|
let stream = TcpStream::connect(connect_addr)
|
||||||
.await
|
.await
|
||||||
.map_err(map_to_string)?;
|
.map_err(map_to_string)?;
|
||||||
|
|
||||||
// If it succeed, disable nagle algorithm
|
// If it succeed, disable nagle algorithm
|
||||||
stream.set_nodelay(true).map_err(map_to_string)?;
|
stream.set_nodelay(true).map_err(map_to_string)?;
|
||||||
|
|
||||||
// Create the VAT network
|
// Split the stream
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature="rt-async-std")] {
|
if #[cfg(feature="rt-async-std")] {
|
||||||
use futures::AsyncReadExt;
|
use futures::AsyncReadExt;
|
||||||
let (reader, writer) = stream.split();
|
let (reader, writer) = stream.split();
|
||||||
|
let mut reader = BufReader::new(reader);
|
||||||
} else if #[cfg(feature="rt-tokio")] {
|
} else if #[cfg(feature="rt-tokio")] {
|
||||||
pub use tokio_util::compat::*;
|
|
||||||
let (reader, writer) = stream.into_split();
|
let (reader, writer) = stream.into_split();
|
||||||
let reader = reader.compat();
|
let mut reader = BufReader::new(reader);
|
||||||
let writer = writer.compat_write();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let rpc_network = Box::new(twoparty::VatNetwork::new(
|
// Process lines
|
||||||
reader,
|
let mut line = String::new();
|
||||||
writer,
|
while let Ok(r) = reader
|
||||||
rpc_twoparty_capnp::Side::Client,
|
.read_line(&mut line)
|
||||||
Default::default(),
|
.timeout_at(stop_token.clone())
|
||||||
));
|
.await
|
||||||
|
{
|
||||||
// Create the rpc system
|
match r {
|
||||||
let rpc_system = RpcSystem::new(rpc_network, None);
|
Ok(size) => {
|
||||||
|
// Exit on EOF
|
||||||
// Process the rpc system until we decide we're done
|
if size == 0 {
|
||||||
match self.spawn_rpc_system(connect_addr, rpc_system).await {
|
// Disconnected
|
||||||
Ok(()) => {}
|
return Err("Connection closed".to_owned());
|
||||||
Err(e) => {
|
}
|
||||||
error!("Failed to spawn client RPC system: {}", e);
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// Disconnected
|
||||||
|
return Err("Connection lost".to_owned());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Drop the server and disconnector too (if we still have it)
|
// Unmarshal json
|
||||||
let mut inner = self.inner.borrow_mut();
|
let j = match json::parse(line.trim()) {
|
||||||
let disconnect_requested = inner.disconnect_requested;
|
Ok(v) => v,
|
||||||
inner.server_settings = None;
|
Err(e) => {
|
||||||
inner.server = None;
|
error!("failed to parse server response: {}", e);
|
||||||
inner.disconnector = None;
|
continue;
|
||||||
inner.disconnect_requested = false;
|
|
||||||
inner.connect_addr = None;
|
|
||||||
|
|
||||||
if !disconnect_requested {
|
|
||||||
// Connection lost
|
|
||||||
Err("Connection lost".to_owned())
|
|
||||||
} else {
|
|
||||||
// Connection finished
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cancellable<T>(&mut self, p: Promise<T, capnp::Error>) -> Promise<T, capnp::Error>
|
|
||||||
where
|
|
||||||
T: 'static,
|
|
||||||
{
|
|
||||||
let (mut cancel_instance, cancel_eventual) = {
|
|
||||||
let inner = self.inner.borrow();
|
|
||||||
(
|
|
||||||
inner.cancel_eventual.instance_empty().fuse(),
|
|
||||||
inner.cancel_eventual.clone(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let mut p = p.fuse();
|
|
||||||
|
|
||||||
Promise::from_future(async move {
|
|
||||||
let out = select! {
|
|
||||||
a = p => {
|
|
||||||
a
|
|
||||||
},
|
|
||||||
_ = cancel_instance => {
|
|
||||||
Err(capnp::Error::failed("cancelled".into()))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
drop(cancel_instance);
|
|
||||||
cancel_eventual.reset();
|
if j["type"] == "Update" {
|
||||||
out
|
self.process_update(j).await;
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection finished
|
||||||
|
Ok(())
|
||||||
|
|
||||||
|
// let rpc_network = Box::new(twoparty::VatNetwork::new(
|
||||||
|
// reader,
|
||||||
|
// writer,
|
||||||
|
// rpc_twoparty_capnp::Side::Client,
|
||||||
|
// Default::default(),
|
||||||
|
// ));
|
||||||
|
|
||||||
|
// // Create the rpc system
|
||||||
|
// let rpc_system = RpcSystem::new(rpc_network, None);
|
||||||
|
|
||||||
|
// // Process the rpc system until we decide we're done
|
||||||
|
// match self.spawn_rpc_system(connect_addr, rpc_system).await {
|
||||||
|
// Ok(()) => {}
|
||||||
|
// Err(e) => {
|
||||||
|
// error!("Failed to spawn client RPC system: {}", e);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Drop the server and disconnector too (if we still have it)
|
||||||
|
// let mut inner = self.inner.borrow_mut();
|
||||||
|
// let disconnect_requested = inner.disconnect_requested;
|
||||||
|
// inner.server_settings = None;
|
||||||
|
// inner.server = None;
|
||||||
|
// inner.disconnector = None;
|
||||||
|
// inner.disconnect_requested = false;
|
||||||
|
// inner.connect_addr = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn cancellable<T>(&mut self, p: Promise<T, capnp::Error>) -> Promise<T, capnp::Error>
|
||||||
|
// where
|
||||||
|
// T: 'static,
|
||||||
|
// {
|
||||||
|
// let (mut cancel_instance, cancel_eventual) = {
|
||||||
|
// let inner = self.inner.borrow();
|
||||||
|
// (
|
||||||
|
// inner.cancel_eventual.instance_empty().fuse(),
|
||||||
|
// inner.cancel_eventual.clone(),
|
||||||
|
// )
|
||||||
|
// };
|
||||||
|
// let mut p = p.fuse();
|
||||||
|
|
||||||
|
// Promise::from_future(async move {
|
||||||
|
// let out = select! {
|
||||||
|
// a = p => {
|
||||||
|
// a
|
||||||
|
// },
|
||||||
|
// _ = cancel_instance => {
|
||||||
|
// Err(capnp::Error::failed("cancelled".into()))
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// drop(cancel_instance);
|
||||||
|
// cancel_eventual.reset();
|
||||||
|
// out
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
pub async fn server_attach(&mut self) -> Result<(), String> {
|
pub async fn server_attach(&mut self) -> Result<(), String> {
|
||||||
trace!("ClientApiConnection::server_attach");
|
trace!("ClientApiConnection::server_attach");
|
||||||
let server = {
|
let server = {
|
||||||
|
@ -5,8 +5,7 @@ use std::cell::*;
|
|||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use veilid_core::tools::*;
|
use veilid_tools::*;
|
||||||
use veilid_core::*;
|
|
||||||
|
|
||||||
pub fn convert_loglevel(s: &str) -> Result<VeilidConfigLogLevel, String> {
|
pub fn convert_loglevel(s: &str) -> Result<VeilidConfigLogLevel, String> {
|
||||||
match s.to_ascii_lowercase().as_str() {
|
match s.to_ascii_lowercase().as_str() {
|
||||||
@ -387,7 +386,11 @@ reply - reply to an AppCall not handled directly by the server
|
|||||||
// calls into ui
|
// calls into ui
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
|
|
||||||
pub fn update_attachment(&mut self, attachment: veilid_core::VeilidStateAttachment) {
|
pub fn log_message(&mut self, message: String) {
|
||||||
|
self.inner().ui.add_node_event(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_attachment(&mut self, attachment: json::JsonValue) {
|
||||||
self.inner_mut().ui.set_attachment_state(
|
self.inner_mut().ui.set_attachment_state(
|
||||||
attachment.state,
|
attachment.state,
|
||||||
attachment.public_internet_ready,
|
attachment.public_internet_ready,
|
||||||
@ -424,17 +427,17 @@ reply - reply to an AppCall not handled directly by the server
|
|||||||
self.inner().ui.add_node_event(out);
|
self.inner().ui.add_node_event(out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn update_value_change(&mut self, value_change: veilid_core::VeilidValueChange) {
|
pub fn update_value_change(&mut self, value_change: json::JsonValue) {
|
||||||
let out = format!("Value change: {:?}", value_change);
|
let out = format!("Value change: {:?}", value_change.as_str().unwrap_or("???"));
|
||||||
self.inner().ui.add_node_event(out);
|
self.inner().ui.add_node_event(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_log(&mut self, log: veilid_core::VeilidLog) {
|
pub fn update_log(&mut self, log: json::JsonValue) {
|
||||||
self.inner().ui.add_node_event(format!(
|
self.inner().ui.add_node_event(format!(
|
||||||
"{}: {}{}",
|
"{}: {}{}",
|
||||||
log.log_level,
|
log["log_level"].as_str().unwrap_or("???"),
|
||||||
log.message,
|
log["message"].as_str().unwrap_or("???"),
|
||||||
if let Some(bt) = log.backtrace {
|
if let Some(bt) = log["backtrace"].as_str() {
|
||||||
format!("\nBacktrace:\n{}", bt)
|
format!("\nBacktrace:\n{}", bt)
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
"".to_owned()
|
||||||
@ -442,7 +445,7 @@ reply - reply to an AppCall not handled directly by the server
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_app_message(&mut self, msg: veilid_core::VeilidAppMessage) {
|
pub fn update_app_message(&mut self, msg: json::JsonValue) {
|
||||||
// check is message body is ascii printable
|
// check is message body is ascii printable
|
||||||
let mut printable = true;
|
let mut printable = true;
|
||||||
for c in msg.message() {
|
for c in msg.message() {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
use crate::tools::*;
|
use crate::tools::*;
|
||||||
use veilid_core::tools::*;
|
use veilid_tools::*;
|
||||||
|
|
||||||
use clap::{Arg, ColorChoice, Command};
|
use clap::{Arg, ColorChoice, Command};
|
||||||
use flexi_logger::*;
|
use flexi_logger::*;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use cursive_table_view::*;
|
use cursive_table_view::*;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use veilid_core::*;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum PeerTableColumn {
|
pub enum PeerTableColumn {
|
||||||
|
@ -12,12 +12,11 @@ use cursive::Cursive;
|
|||||||
use cursive::CursiveRunnable;
|
use cursive::CursiveRunnable;
|
||||||
use cursive_flexi_logger_view::{CursiveLogWriter, FlexiLoggerView};
|
use cursive_flexi_logger_view::{CursiveLogWriter, FlexiLoggerView};
|
||||||
//use cursive_multiplex::*;
|
//use cursive_multiplex::*;
|
||||||
use log::*;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use veilid_core::*;
|
use veilid_tools::*;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
@ -50,20 +49,20 @@ impl<T> Dirty<T> {
|
|||||||
pub type UICallback = Box<dyn Fn(&mut Cursive) + Send>;
|
pub type UICallback = Box<dyn Fn(&mut Cursive) + Send>;
|
||||||
|
|
||||||
struct UIState {
|
struct UIState {
|
||||||
attachment_state: Dirty<AttachmentState>,
|
attachment_state: Dirty<String>,
|
||||||
public_internet_ready: Dirty<bool>,
|
public_internet_ready: Dirty<bool>,
|
||||||
local_network_ready: Dirty<bool>,
|
local_network_ready: Dirty<bool>,
|
||||||
network_started: Dirty<bool>,
|
network_started: Dirty<bool>,
|
||||||
network_down_up: Dirty<(f32, f32)>,
|
network_down_up: Dirty<(f32, f32)>,
|
||||||
connection_state: Dirty<ConnectionState>,
|
connection_state: Dirty<ConnectionState>,
|
||||||
peers_state: Dirty<Vec<PeerTableData>>,
|
peers_state: Dirty<Vec<json::JsonValue>>,
|
||||||
node_id: Dirty<String>,
|
node_id: Dirty<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIState {
|
impl UIState {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
attachment_state: Dirty::new(AttachmentState::Detached),
|
attachment_state: Dirty::new("Detached".to_owned()),
|
||||||
public_internet_ready: Dirty::new(false),
|
public_internet_ready: Dirty::new(false),
|
||||||
local_network_ready: Dirty::new(false),
|
local_network_ready: Dirty::new(false),
|
||||||
network_started: Dirty::new(false),
|
network_started: Dirty::new(false),
|
||||||
@ -239,15 +238,16 @@ impl UI {
|
|||||||
s.find_name("peers").unwrap()
|
s.find_name("peers").unwrap()
|
||||||
}
|
}
|
||||||
fn render_attachment_state(inner: &mut UIInner) -> String {
|
fn render_attachment_state(inner: &mut UIInner) -> String {
|
||||||
let att = match inner.ui_state.attachment_state.get() {
|
let att = match inner.ui_state.attachment_state.get().as_str() {
|
||||||
AttachmentState::Detached => "[----]",
|
"Detached" => "[----]",
|
||||||
AttachmentState::Attaching => "[/ ]",
|
"Attaching" => "[/ ]",
|
||||||
AttachmentState::AttachedWeak => "[| ]",
|
"AttachedWeak" => "[| ]",
|
||||||
AttachmentState::AttachedGood => "[|| ]",
|
"AttachedGood" => "[|| ]",
|
||||||
AttachmentState::AttachedStrong => "[||| ]",
|
"AttachedStrong" => "[||| ]",
|
||||||
AttachmentState::FullyAttached => "[||||]",
|
"FullyAttached" => "[||||]",
|
||||||
AttachmentState::OverAttached => "[++++]",
|
"OverAttached" => "[++++]",
|
||||||
AttachmentState::Detaching => "[////]",
|
"Detaching" => "[////]",
|
||||||
|
_ => "[????]",
|
||||||
};
|
};
|
||||||
let pi = if *inner.ui_state.public_internet_ready.get() {
|
let pi = if *inner.ui_state.public_internet_ready.get() {
|
||||||
"+P"
|
"+P"
|
||||||
@ -272,15 +272,16 @@ impl UI {
|
|||||||
}
|
}
|
||||||
fn render_button_attach<'a>(inner: &mut UIInner) -> (&'a str, bool) {
|
fn render_button_attach<'a>(inner: &mut UIInner) -> (&'a str, bool) {
|
||||||
if let ConnectionState::Connected(_, _) = inner.ui_state.connection_state.get() {
|
if let ConnectionState::Connected(_, _) = inner.ui_state.connection_state.get() {
|
||||||
match inner.ui_state.attachment_state.get() {
|
match inner.ui_state.attachment_state.get().as_str() {
|
||||||
AttachmentState::Detached => ("Attach", true),
|
"Detached" => ("Attach", true),
|
||||||
AttachmentState::Attaching => ("Detach", true),
|
"Attaching" => ("Detach", true),
|
||||||
AttachmentState::AttachedWeak => ("Detach", true),
|
"AttachedWeak" => ("Detach", true),
|
||||||
AttachmentState::AttachedGood => ("Detach", true),
|
"AttachedGood" => ("Detach", true),
|
||||||
AttachmentState::AttachedStrong => ("Detach", true),
|
"AttachedStrong" => ("Detach", true),
|
||||||
AttachmentState::FullyAttached => ("Detach", true),
|
"FullyAttached" => ("Detach", true),
|
||||||
AttachmentState::OverAttached => ("Detach", true),
|
"OverAttached" => ("Detach", true),
|
||||||
AttachmentState::Detaching => ("Detach", false),
|
"Detaching" => ("Detach", false),
|
||||||
|
_ => ("???", false),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(" ---- ", false)
|
(" ---- ", false)
|
||||||
@ -412,15 +413,17 @@ impl UI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_button_attach_pressed(s: &mut Cursive) {
|
fn on_button_attach_pressed(s: &mut Cursive) {
|
||||||
let action: Option<bool> = match Self::inner_mut(s).ui_state.attachment_state.get() {
|
let action: Option<bool> = match Self::inner_mut(s).ui_state.attachment_state.get().as_str()
|
||||||
AttachmentState::Detached => Some(true),
|
{
|
||||||
AttachmentState::Attaching => Some(false),
|
"Detached" => Some(true),
|
||||||
AttachmentState::AttachedWeak => Some(false),
|
"Attaching" => Some(false),
|
||||||
AttachmentState::AttachedGood => Some(false),
|
"AttachedWeak" => Some(false),
|
||||||
AttachmentState::AttachedStrong => Some(false),
|
"AttachedGood" => Some(false),
|
||||||
AttachmentState::FullyAttached => Some(false),
|
"AttachedStrong" => Some(false),
|
||||||
AttachmentState::OverAttached => Some(false),
|
"FullyAttached" => Some(false),
|
||||||
AttachmentState::Detaching => None,
|
"OverAttached" => Some(false),
|
||||||
|
"Detaching" => None,
|
||||||
|
_ => None,
|
||||||
};
|
};
|
||||||
let mut cmdproc = Self::command_processor(s);
|
let mut cmdproc = Self::command_processor(s);
|
||||||
if let Some(a) = action {
|
if let Some(a) = action {
|
||||||
|
@ -140,8 +140,5 @@ pub use wasm::*;
|
|||||||
pub mod tests;
|
pub mod tests;
|
||||||
|
|
||||||
// For iOS tests
|
// For iOS tests
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn main_rs() {
|
pub extern "C" fn main_rs() {}
|
||||||
// start game code here
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user