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",
|
||||
"directories",
|
||||
"flexi_logger",
|
||||
"flume",
|
||||
"futures",
|
||||
"hex",
|
||||
"json",
|
||||
@ -6168,10 +6169,11 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serial_test",
|
||||
"stop-token",
|
||||
"thiserror",
|
||||
"tokio 1.28.2",
|
||||
"tokio-util",
|
||||
"veilid-core",
|
||||
"veilid-tools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -12,8 +12,8 @@ path = "src/main.rs"
|
||||
[features]
|
||||
default = [ "rt-tokio" ]
|
||||
macos = [ "cursive/ncurses-backend" ]
|
||||
rt-async-std = [ "async-std", "veilid-core/rt-async-std", "cursive/rt-async-std" ]
|
||||
rt-tokio = [ "tokio", "tokio-util", "veilid-core/rt-tokio", "cursive/rt-tokio" ]
|
||||
rt-async-std = [ "async-std", "veilid-tools/rt-async-std", "cursive/rt-async-std" ]
|
||||
rt-tokio = [ "tokio", "tokio-util", "veilid-tools/rt-tokio", "cursive/rt-tokio" ]
|
||||
|
||||
[dependencies]
|
||||
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"
|
||||
crossbeam-channel = "^0"
|
||||
hex = "^0"
|
||||
veilid-core = { path = "../veilid-core" }
|
||||
veilid-tools = { path = "../veilid-tools", default-features = false }
|
||||
json = "^0"
|
||||
stop-token = { version = "^0", default-features = false }
|
||||
flume = { version = "^0", features = ["async"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "^0"
|
||||
|
@ -1,94 +1,66 @@
|
||||
use crate::command_processor::*;
|
||||
use crate::tools::*;
|
||||
use futures::future::FutureExt;
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::cell::RefCell;
|
||||
use std::net::SocketAddr;
|
||||
use std::rc::Rc;
|
||||
use veilid_core::tools::*;
|
||||
use veilid_core::*;
|
||||
use stop_token::{future::FutureExt as _, StopSource, StopToken};
|
||||
|
||||
fn map_to_internal_error<T: ToString>(e: T) -> VeilidAPIError {
|
||||
VeilidAPIError::Internal {
|
||||
message: e.to_string(),
|
||||
use veilid_tools::*;
|
||||
cfg_if! {
|
||||
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>(
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
// fn map_to_internal_error<T: ToString>(e: T) -> VeilidAPIError {
|
||||
// VeilidAPIError::Internal {
|
||||
// message: e.to_string(),
|
||||
// }
|
||||
// }
|
||||
|
||||
struct VeilidClientImpl {
|
||||
comproc: CommandProcessor,
|
||||
}
|
||||
// fn decode_api_result<T: DeserializeOwned + fmt::Debug>(
|
||||
// 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 {
|
||||
pub fn new(comproc: CommandProcessor) -> Self {
|
||||
Self { comproc }
|
||||
}
|
||||
}
|
||||
// struct VeilidClientImpl {
|
||||
// comproc: CommandProcessor,
|
||||
// }
|
||||
|
||||
impl veilid_client::Server for VeilidClientImpl {
|
||||
fn update(
|
||||
&mut self,
|
||||
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));
|
||||
// impl VeilidClientImpl {
|
||||
// pub fn new(comproc: CommandProcessor) -> Self {
|
||||
// Self { comproc }
|
||||
// }
|
||||
// }
|
||||
|
||||
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 {
|
||||
comproc: CommandProcessor,
|
||||
connect_addr: Option<SocketAddr>,
|
||||
disconnector: Option<Disconnector<rpc_twoparty_capnp::Side>>,
|
||||
server: Option<Rc<RefCell<veilid_server::Client>>>,
|
||||
server: Option<flume::Sender<String>>,
|
||||
server_settings: Option<String>,
|
||||
disconnector: Option<StopSource>,
|
||||
disconnect_requested: bool,
|
||||
cancel_eventual: Eventual,
|
||||
}
|
||||
@ -106,9 +78,9 @@ impl ClientApiConnection {
|
||||
inner: Rc::new(RefCell::new(ClientApiConnectionInner {
|
||||
comproc,
|
||||
connect_addr: None,
|
||||
disconnector: None,
|
||||
server: None,
|
||||
server_settings: None,
|
||||
disconnector: None,
|
||||
disconnect_requested: false,
|
||||
cancel_eventual: Eventual::new(),
|
||||
})),
|
||||
@ -123,196 +95,272 @@ impl ClientApiConnection {
|
||||
eventual.resolve(); // don't need to await this
|
||||
}
|
||||
|
||||
async fn process_veilid_state<'a>(
|
||||
&'a mut self,
|
||||
veilid_state: VeilidState,
|
||||
) -> Result<(), String> {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
inner.comproc.update_attachment(veilid_state.attachment);
|
||||
inner.comproc.update_network_status(veilid_state.network);
|
||||
inner.comproc.update_config(veilid_state.config);
|
||||
Ok(())
|
||||
}
|
||||
// async fn process_veilid_state<'a>(
|
||||
// &'a mut self,
|
||||
// veilid_state: VeilidState,
|
||||
// ) -> Result<(), String> {
|
||||
// let mut inner = self.inner.borrow_mut();
|
||||
// inner.comproc.update_attachment(veilid_state.attachment);
|
||||
// inner.comproc.update_network_status(veilid_state.network);
|
||||
// inner.comproc.update_config(veilid_state.config);
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
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);
|
||||
}
|
||||
async fn process_update(&self, update: json::JsonValue) {
|
||||
let comproc = self.inner.borrow().comproc.clone();
|
||||
let Some(kind) = update["kind"].as_str() else {
|
||||
comproc.log_message(format!("missing update kind: {}", update));
|
||||
return;
|
||||
};
|
||||
|
||||
// Wait until rpc system completion or disconnect was requested
|
||||
let res = rpc_jh.await;
|
||||
res.map_err(|e| format!("client RPC system error: {}", e))
|
||||
match kind {
|
||||
"Log" => {
|
||||
comproc.update_log(update);
|
||||
}
|
||||
"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> {
|
||||
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
|
||||
let stream = TcpStream::connect(connect_addr)
|
||||
.await
|
||||
.map_err(map_to_string)?;
|
||||
|
||||
// If it succeed, disable nagle algorithm
|
||||
stream.set_nodelay(true).map_err(map_to_string)?;
|
||||
|
||||
// Create the VAT network
|
||||
// Split the stream
|
||||
cfg_if! {
|
||||
if #[cfg(feature="rt-async-std")] {
|
||||
use futures::AsyncReadExt;
|
||||
let (reader, writer) = stream.split();
|
||||
let mut reader = BufReader::new(reader);
|
||||
} else if #[cfg(feature="rt-tokio")] {
|
||||
pub use tokio_util::compat::*;
|
||||
let (reader, writer) = stream.into_split();
|
||||
let reader = reader.compat();
|
||||
let writer = writer.compat_write();
|
||||
let mut reader = BufReader::new(reader);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
// Process lines
|
||||
let mut line = String::new();
|
||||
while let Ok(r) = reader
|
||||
.read_line(&mut line)
|
||||
.timeout_at(stop_token.clone())
|
||||
.await
|
||||
{
|
||||
match r {
|
||||
Ok(size) => {
|
||||
// Exit on EOF
|
||||
if size == 0 {
|
||||
// Disconnected
|
||||
return Err("Connection closed".to_owned());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
// Disconnected
|
||||
return Err("Connection lost".to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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()))
|
||||
// Unmarshal json
|
||||
let j = match json::parse(line.trim()) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!("failed to parse server response: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
drop(cancel_instance);
|
||||
cancel_eventual.reset();
|
||||
out
|
||||
})
|
||||
|
||||
if j["type"] == "Update" {
|
||||
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> {
|
||||
trace!("ClientApiConnection::server_attach");
|
||||
let server = {
|
||||
|
@ -5,8 +5,7 @@ use std::cell::*;
|
||||
use std::net::SocketAddr;
|
||||
use std::rc::Rc;
|
||||
use std::time::SystemTime;
|
||||
use veilid_core::tools::*;
|
||||
use veilid_core::*;
|
||||
use veilid_tools::*;
|
||||
|
||||
pub fn convert_loglevel(s: &str) -> Result<VeilidConfigLogLevel, String> {
|
||||
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
|
||||
////////////////////////////////////////////
|
||||
|
||||
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(
|
||||
attachment.state,
|
||||
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);
|
||||
}
|
||||
}
|
||||
pub fn update_value_change(&mut self, value_change: veilid_core::VeilidValueChange) {
|
||||
let out = format!("Value change: {:?}", value_change);
|
||||
pub fn update_value_change(&mut self, value_change: json::JsonValue) {
|
||||
let out = format!("Value change: {:?}", value_change.as_str().unwrap_or("???"));
|
||||
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!(
|
||||
"{}: {}{}",
|
||||
log.log_level,
|
||||
log.message,
|
||||
if let Some(bt) = log.backtrace {
|
||||
log["log_level"].as_str().unwrap_or("???"),
|
||||
log["message"].as_str().unwrap_or("???"),
|
||||
if let Some(bt) = log["backtrace"].as_str() {
|
||||
format!("\nBacktrace:\n{}", bt)
|
||||
} else {
|
||||
"".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
|
||||
let mut printable = true;
|
||||
for c in msg.message() {
|
||||
|
@ -3,7 +3,7 @@
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
use crate::tools::*;
|
||||
use veilid_core::tools::*;
|
||||
use veilid_tools::*;
|
||||
|
||||
use clap::{Arg, ColorChoice, Command};
|
||||
use flexi_logger::*;
|
||||
|
@ -1,7 +1,6 @@
|
||||
use super::*;
|
||||
use cursive_table_view::*;
|
||||
use std::cmp::Ordering;
|
||||
use veilid_core::*;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum PeerTableColumn {
|
||||
|
@ -12,12 +12,11 @@ use cursive::Cursive;
|
||||
use cursive::CursiveRunnable;
|
||||
use cursive_flexi_logger_view::{CursiveLogWriter, FlexiLoggerView};
|
||||
//use cursive_multiplex::*;
|
||||
use log::*;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::rc::Rc;
|
||||
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>;
|
||||
|
||||
struct UIState {
|
||||
attachment_state: Dirty<AttachmentState>,
|
||||
attachment_state: Dirty<String>,
|
||||
public_internet_ready: Dirty<bool>,
|
||||
local_network_ready: Dirty<bool>,
|
||||
network_started: Dirty<bool>,
|
||||
network_down_up: Dirty<(f32, f32)>,
|
||||
connection_state: Dirty<ConnectionState>,
|
||||
peers_state: Dirty<Vec<PeerTableData>>,
|
||||
peers_state: Dirty<Vec<json::JsonValue>>,
|
||||
node_id: Dirty<String>,
|
||||
}
|
||||
|
||||
impl UIState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
attachment_state: Dirty::new(AttachmentState::Detached),
|
||||
attachment_state: Dirty::new("Detached".to_owned()),
|
||||
public_internet_ready: Dirty::new(false),
|
||||
local_network_ready: Dirty::new(false),
|
||||
network_started: Dirty::new(false),
|
||||
@ -239,15 +238,16 @@ impl UI {
|
||||
s.find_name("peers").unwrap()
|
||||
}
|
||||
fn render_attachment_state(inner: &mut UIInner) -> String {
|
||||
let att = match inner.ui_state.attachment_state.get() {
|
||||
AttachmentState::Detached => "[----]",
|
||||
AttachmentState::Attaching => "[/ ]",
|
||||
AttachmentState::AttachedWeak => "[| ]",
|
||||
AttachmentState::AttachedGood => "[|| ]",
|
||||
AttachmentState::AttachedStrong => "[||| ]",
|
||||
AttachmentState::FullyAttached => "[||||]",
|
||||
AttachmentState::OverAttached => "[++++]",
|
||||
AttachmentState::Detaching => "[////]",
|
||||
let att = match inner.ui_state.attachment_state.get().as_str() {
|
||||
"Detached" => "[----]",
|
||||
"Attaching" => "[/ ]",
|
||||
"AttachedWeak" => "[| ]",
|
||||
"AttachedGood" => "[|| ]",
|
||||
"AttachedStrong" => "[||| ]",
|
||||
"FullyAttached" => "[||||]",
|
||||
"OverAttached" => "[++++]",
|
||||
"Detaching" => "[////]",
|
||||
_ => "[????]",
|
||||
};
|
||||
let pi = if *inner.ui_state.public_internet_ready.get() {
|
||||
"+P"
|
||||
@ -272,15 +272,16 @@ impl UI {
|
||||
}
|
||||
fn render_button_attach<'a>(inner: &mut UIInner) -> (&'a str, bool) {
|
||||
if let ConnectionState::Connected(_, _) = inner.ui_state.connection_state.get() {
|
||||
match inner.ui_state.attachment_state.get() {
|
||||
AttachmentState::Detached => ("Attach", true),
|
||||
AttachmentState::Attaching => ("Detach", true),
|
||||
AttachmentState::AttachedWeak => ("Detach", true),
|
||||
AttachmentState::AttachedGood => ("Detach", true),
|
||||
AttachmentState::AttachedStrong => ("Detach", true),
|
||||
AttachmentState::FullyAttached => ("Detach", true),
|
||||
AttachmentState::OverAttached => ("Detach", true),
|
||||
AttachmentState::Detaching => ("Detach", false),
|
||||
match inner.ui_state.attachment_state.get().as_str() {
|
||||
"Detached" => ("Attach", true),
|
||||
"Attaching" => ("Detach", true),
|
||||
"AttachedWeak" => ("Detach", true),
|
||||
"AttachedGood" => ("Detach", true),
|
||||
"AttachedStrong" => ("Detach", true),
|
||||
"FullyAttached" => ("Detach", true),
|
||||
"OverAttached" => ("Detach", true),
|
||||
"Detaching" => ("Detach", false),
|
||||
_ => ("???", false),
|
||||
}
|
||||
} else {
|
||||
(" ---- ", false)
|
||||
@ -412,15 +413,17 @@ impl UI {
|
||||
}
|
||||
|
||||
fn on_button_attach_pressed(s: &mut Cursive) {
|
||||
let action: Option<bool> = match Self::inner_mut(s).ui_state.attachment_state.get() {
|
||||
AttachmentState::Detached => Some(true),
|
||||
AttachmentState::Attaching => Some(false),
|
||||
AttachmentState::AttachedWeak => Some(false),
|
||||
AttachmentState::AttachedGood => Some(false),
|
||||
AttachmentState::AttachedStrong => Some(false),
|
||||
AttachmentState::FullyAttached => Some(false),
|
||||
AttachmentState::OverAttached => Some(false),
|
||||
AttachmentState::Detaching => None,
|
||||
let action: Option<bool> = match Self::inner_mut(s).ui_state.attachment_state.get().as_str()
|
||||
{
|
||||
"Detached" => Some(true),
|
||||
"Attaching" => Some(false),
|
||||
"AttachedWeak" => Some(false),
|
||||
"AttachedGood" => Some(false),
|
||||
"AttachedStrong" => Some(false),
|
||||
"FullyAttached" => Some(false),
|
||||
"OverAttached" => Some(false),
|
||||
"Detaching" => None,
|
||||
_ => None,
|
||||
};
|
||||
let mut cmdproc = Self::command_processor(s);
|
||||
if let Some(a) = action {
|
||||
|
@ -140,8 +140,5 @@ pub use wasm::*;
|
||||
pub mod tests;
|
||||
|
||||
// For iOS tests
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn main_rs() {
|
||||
// start game code here
|
||||
}
|
||||
pub extern "C" fn main_rs() {}
|
||||
|
Loading…
Reference in New Issue
Block a user