executor work
This commit is contained in:
@@ -10,6 +10,11 @@ license = "LGPL-2.0-or-later OR MPL-2.0 OR (MIT AND BSD-3-Clause)"
|
||||
name = "veilid-cli"
|
||||
path = "src/main.rs"
|
||||
|
||||
[features]
|
||||
default = [ "rt-tokio" ]
|
||||
rt-async-std = [ "async-std", "veilid-core/rt-async-std" ]
|
||||
rt-tokio = [ "tokio", "tokio-util", "veilid-core/rt-tokio" ]
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
cursive = { path = "../external/cursive/cursive", default-features = false, features = ["ncurses-backend", "toml", "rt-async-std"]}
|
||||
|
||||
@@ -17,9 +22,10 @@ cursive = { path = "../external/cursive/cursive", default-features = false, feat
|
||||
cursive = { path = "../external/cursive/cursive", default-features = false, features = ["crossterm-backend", "toml", "rt-async-std"]}
|
||||
|
||||
[dependencies]
|
||||
async-std = { version = "^1.9", features = ["unstable", "attributes"] }
|
||||
async-tungstenite = { version = "^0.8", features = ["async-std-runtime"] }
|
||||
async_executors = { version = "^0", default-features = false, features = [ "async_std" ]}
|
||||
async-std = { version = "^1.9", features = ["unstable", "attributes"], optional = true }
|
||||
tokio = { version = "^1", features = ["full"], optional = true }
|
||||
tokio-util = { version = "^0", features = ["compat"], optional = true}
|
||||
async-tungstenite = { version = "^0.8" }
|
||||
cursive-flexi-logger-view = { path = "../external/cursive-flexi-logger-view" }
|
||||
cursive_buffered_backend = { path = "../external/cursive_buffered_backend" }
|
||||
# cursive-multiplex = "0.4.0"
|
||||
@@ -41,7 +47,7 @@ bugsalot = "^0"
|
||||
flexi_logger = { version = "^0", features = ["use_chrono_for_offset"] }
|
||||
thiserror = "^1"
|
||||
crossbeam-channel = "^0"
|
||||
veilid-core = { path = "../veilid-core" }
|
||||
veilid-core = { path = "../veilid-core", default_features = false}
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "^0"
|
||||
|
@@ -1,9 +1,8 @@
|
||||
use crate::command_processor::*;
|
||||
use crate::tools::*;
|
||||
use crate::veilid_client_capnp::*;
|
||||
use async_executors::{AsyncStd, LocalSpawnHandleExt};
|
||||
use capnp::capability::Promise;
|
||||
use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, Disconnector, RpcSystem};
|
||||
use futures::io::AsyncReadExt;
|
||||
use std::cell::RefCell;
|
||||
use std::net::SocketAddr;
|
||||
use std::rc::Rc;
|
||||
@@ -140,9 +139,7 @@ impl ClientApiConnection {
|
||||
));
|
||||
}
|
||||
|
||||
let rpc_jh = AsyncStd
|
||||
.spawn_handle_local(rpc_system)
|
||||
.map_err(|e| format!("failed to spawn rpc system: {}", e))?;
|
||||
let rpc_jh = spawn_local(rpc_system);
|
||||
|
||||
// Send the request and get the state object and the registration object
|
||||
let response = request
|
||||
@@ -173,23 +170,43 @@ impl ClientApiConnection {
|
||||
// object mapping from the server which we need for the update backchannel
|
||||
|
||||
// Wait until rpc system completion or disconnect was requested
|
||||
rpc_jh
|
||||
.await
|
||||
.map_err(|e| format!("client RPC system error: {}", e))
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature="rt-async-std")] {
|
||||
rpc_jh
|
||||
.await
|
||||
.map_err(|e| format!("client RPC system error: {}", e))
|
||||
} else if #[cfg(feature="rt-tokio")] {
|
||||
rpc_jh
|
||||
.await
|
||||
.map_err(|e| format!("join error: {}", e))?
|
||||
.map_err(|e| format!("client RPC system error: {}", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_connection(&mut self) -> Result<(), String> {
|
||||
trace!("ClientApiConnection::handle_connection");
|
||||
let connect_addr = self.inner.borrow().connect_addr.unwrap();
|
||||
// Connect the TCP socket
|
||||
let stream = async_std::net::TcpStream::connect(connect_addr)
|
||||
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
|
||||
let (reader, writer) = stream.split();
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature="rt-async-std")] {
|
||||
let (reader, writer) = stream.split();
|
||||
} else if #[cfg(feature="rt-tokio")] {
|
||||
let (reader, writer) = stream.into_split();
|
||||
let reader = reader.compat();
|
||||
let writer = writer.compat_write();
|
||||
}
|
||||
}
|
||||
|
||||
let rpc_network = Box::new(twoparty::VatNetwork::new(
|
||||
reader,
|
||||
writer,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
use crate::client_api_connection::*;
|
||||
use crate::settings::Settings;
|
||||
use crate::tools::*;
|
||||
use crate::ui::*;
|
||||
use async_std::prelude::FutureExt;
|
||||
use log::*;
|
||||
use std::cell::*;
|
||||
use std::net::SocketAddr;
|
||||
@@ -116,7 +116,7 @@ debug - send a debugging command to the Veilid server
|
||||
trace!("CommandProcessor::cmd_shutdown");
|
||||
let mut capi = self.capi();
|
||||
let ui = self.ui();
|
||||
async_std::task::spawn_local(async move {
|
||||
spawn_detached_local(async move {
|
||||
if let Err(e) = capi.server_shutdown().await {
|
||||
error!("Server command 'shutdown' failed to execute: {}", e);
|
||||
}
|
||||
@@ -129,7 +129,7 @@ debug - send a debugging command to the Veilid server
|
||||
trace!("CommandProcessor::cmd_attach");
|
||||
let mut capi = self.capi();
|
||||
let ui = self.ui();
|
||||
async_std::task::spawn_local(async move {
|
||||
spawn_detached_local(async move {
|
||||
if let Err(e) = capi.server_attach().await {
|
||||
error!("Server command 'attach' failed to execute: {}", e);
|
||||
}
|
||||
@@ -142,7 +142,7 @@ debug - send a debugging command to the Veilid server
|
||||
trace!("CommandProcessor::cmd_detach");
|
||||
let mut capi = self.capi();
|
||||
let ui = self.ui();
|
||||
async_std::task::spawn_local(async move {
|
||||
spawn_detached_local(async move {
|
||||
if let Err(e) = capi.server_detach().await {
|
||||
error!("Server command 'detach' failed to execute: {}", e);
|
||||
}
|
||||
@@ -155,7 +155,7 @@ debug - send a debugging command to the Veilid server
|
||||
trace!("CommandProcessor::cmd_disconnect");
|
||||
let mut capi = self.capi();
|
||||
let ui = self.ui();
|
||||
async_std::task::spawn_local(async move {
|
||||
spawn_detached_local(async move {
|
||||
capi.disconnect().await;
|
||||
ui.send_callback(callback);
|
||||
});
|
||||
@@ -166,7 +166,7 @@ debug - send a debugging command to the Veilid server
|
||||
trace!("CommandProcessor::cmd_debug");
|
||||
let mut capi = self.capi();
|
||||
let ui = self.ui();
|
||||
async_std::task::spawn_local(async move {
|
||||
spawn_detached_local(async move {
|
||||
match capi.server_debug(rest.unwrap_or_default()).await {
|
||||
Ok(output) => ui.display_string_dialog("Debug Output", output, callback),
|
||||
Err(e) => {
|
||||
@@ -248,9 +248,7 @@ debug - send a debugging command to the Veilid server
|
||||
debug!("Connection lost, retrying in 2 seconds");
|
||||
{
|
||||
let waker = self.inner_mut().connection_waker.instance_clone(());
|
||||
waker
|
||||
.race(async_std::task::sleep(Duration::from_millis(2000)))
|
||||
.await;
|
||||
let _ = timeout(Duration::from_millis(2000), waker).await;
|
||||
}
|
||||
self.inner_mut().connection_waker.reset();
|
||||
first = false;
|
||||
@@ -306,7 +304,7 @@ debug - send a debugging command to the Veilid server
|
||||
// pub fn stop_connection(&mut self) {
|
||||
// self.inner_mut().reconnect = false;
|
||||
// let mut capi = self.capi().clone();
|
||||
// async_std::task::spawn_local(async move {
|
||||
// spawn_detached(async move {
|
||||
// capi.disconnect().await;
|
||||
// });
|
||||
// }
|
||||
@@ -327,7 +325,7 @@ debug - send a debugging command to the Veilid server
|
||||
trace!("CommandProcessor::attach");
|
||||
let mut capi = self.capi();
|
||||
|
||||
async_std::task::spawn_local(async move {
|
||||
spawn_detached_local(async move {
|
||||
if let Err(e) = capi.server_attach().await {
|
||||
error!("Server command 'attach' failed to execute: {}", e);
|
||||
}
|
||||
@@ -338,7 +336,7 @@ debug - send a debugging command to the Veilid server
|
||||
trace!("CommandProcessor::detach");
|
||||
let mut capi = self.capi();
|
||||
|
||||
async_std::task::spawn_local(async move {
|
||||
spawn_detached_local(async move {
|
||||
if let Err(e) = capi.server_detach().await {
|
||||
error!("Server command 'detach' failed to execute: {}", e);
|
||||
}
|
||||
|
@@ -3,16 +3,17 @@
|
||||
|
||||
use veilid_core::xx::*;
|
||||
|
||||
use async_std::prelude::*;
|
||||
use clap::{Arg, ColorChoice, Command};
|
||||
use flexi_logger::*;
|
||||
use std::ffi::OsStr;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::path::Path;
|
||||
use tools::*;
|
||||
|
||||
mod client_api_connection;
|
||||
mod command_processor;
|
||||
mod settings;
|
||||
mod tools;
|
||||
mod ui;
|
||||
|
||||
#[allow(clippy::all)]
|
||||
@@ -60,8 +61,7 @@ fn parse_command_line(default_config_path: &OsStr) -> Result<clap::ArgMatches, S
|
||||
Ok(matches)
|
||||
}
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() -> Result<(), String> {
|
||||
fn main() -> Result<(), String> {
|
||||
// Get command line options
|
||||
let default_config_path = settings::Settings::get_default_config_path();
|
||||
let matches = parse_command_line(default_config_path.as_os_str())?;
|
||||
@@ -170,17 +170,29 @@ async fn main() -> Result<(), String> {
|
||||
comproc.set_server_address(server_addr);
|
||||
let mut comproc2 = comproc.clone();
|
||||
let connection_future = comproc.connection_manager();
|
||||
// Start UI
|
||||
let ui_future = async_std::task::spawn_local(async move {
|
||||
sivui.run_async().await;
|
||||
|
||||
// When UI quits, close connection and command processor cleanly
|
||||
comproc2.quit();
|
||||
capi.disconnect().await;
|
||||
// Start async
|
||||
block_on(async move {
|
||||
// Start UI
|
||||
let ui_future = async move {
|
||||
sivui.run_async().await;
|
||||
|
||||
// When UI quits, close connection and command processor cleanly
|
||||
comproc2.quit();
|
||||
capi.disconnect().await;
|
||||
};
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature="rt-async-std")] {
|
||||
use async_std::prelude::*;
|
||||
// Wait for ui and connection to complete
|
||||
let _ = ui_future.join(connection_future).await;
|
||||
} else if #[cfg(feature="rt-tokio")] {
|
||||
// Wait for ui and connection to complete
|
||||
let _ = tokio::join!(ui_future, connection_future);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for ui and connection to complete
|
||||
ui_future.join(connection_future).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
40
veilid-cli/src/tools.rs
Normal file
40
veilid-cli/src/tools.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use cfg_if::*;
|
||||
use core::future::Future;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature="rt-async-std")] {
|
||||
pub use async_std::task::JoinHandle;
|
||||
pub use async_std::net::TcpStream;
|
||||
pub use async_std::future::TimeoutError;
|
||||
pub fn spawn_local<F: Future<Output = T> + 'static, T: 'static>(f: F) -> JoinHandle<T> {
|
||||
async_std::task::spawn_local(f)
|
||||
}
|
||||
pub fn spawn_detached_local<F: Future<Output = T> + 'static, T: 'static>(f: F) {
|
||||
let _ = async_std::task::spawn_local(f);
|
||||
}
|
||||
pub use async_std::task::sleep;
|
||||
pub use async_std::future::timeout;
|
||||
pub fn block_on<F: Future<Output = T>, T>(f: F) -> T {
|
||||
async_std::task::block_on(f)
|
||||
}
|
||||
} else if #[cfg(feature="rt-tokio")] {
|
||||
pub use tokio::task::JoinHandle;
|
||||
pub use tokio::net::TcpStream;
|
||||
pub use tokio_util::compat::*;
|
||||
pub use tokio::time::error::Elapsed as TimeoutError;
|
||||
pub fn spawn_local<F: Future<Output = T> + 'static, T: 'static>(f: F) -> JoinHandle<T> {
|
||||
tokio::task::spawn_local(f)
|
||||
}
|
||||
pub fn spawn_detached_local<F: Future<Output = T> + 'static, T: 'static>(f: F) {
|
||||
let _ = tokio::task::spawn_local(f);
|
||||
}
|
||||
pub use tokio::time::sleep;
|
||||
pub use tokio::time::timeout;
|
||||
pub fn block_on<F: Future<Output = T>, T>(f: F) -> T {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let local = tokio::task::LocalSet::new();
|
||||
local.block_on(&rt, f)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user