This commit is contained in:
John Smith
2021-12-10 20:14:33 -05:00
parent 7e967b22af
commit c5113623be
24 changed files with 596 additions and 262 deletions

View File

@@ -160,6 +160,25 @@ impl veilid_server::Server for VeilidServerImpl {
Promise::ok(())
}
fn debug(
&mut self,
params: veilid_server::DebugParams,
mut results: veilid_server::DebugResults,
) -> Promise<(), ::capnp::Error> {
trace!("VeilidServerImpl::attach");
let veilid_api = self.veilid_api.clone();
let what = pry!(pry!(params.get()).get_what()).to_owned();
Promise::from_future(async move {
let output = veilid_api
.debug(what)
.await
.map_err(|e| ::capnp::Error::failed(format!("{:?}", e)))?;
results.get().set_output(output.as_str());
Ok(())
})
}
}
// --- Client API Server-Side ---------------------------------
@@ -268,9 +287,11 @@ impl ClientApi {
}
}
pub fn handle_state_change(self: Rc<Self>, changed: veilid_core::VeilidStateChange) {
trace!("state changed: {:?}", changed);
fn send_request_to_all_clients<F, T>(self: Rc<Self>, request: F)
where
F: Fn(u64, &mut RegistrationHandle) -> ::capnp::capability::RemotePromise<T>,
T: capnp::traits::Pipelined + for<'a> capnp::traits::Owned<'a> + 'static + Unpin,
{
// Send status update to each registered client
let registration_map = self.inner.borrow().registration_map.clone();
let registration_map1 = registration_map.clone();
@@ -278,17 +299,16 @@ impl ClientApi {
for (&id, mut registration) in regs.iter_mut() {
if registration.requests_in_flight > 5 {
debug!(
"too many requests in flight for status updates: {}",
"too many requests in flight: {}",
registration.requests_in_flight
);
}
registration.requests_in_flight += 1;
// Make a state changed request
let mut request = registration.client.state_changed_request();
let rpc_changed = request.get().init_changed();
ClientApi::convert_state_changed(&changed, rpc_changed);
let request_promise = request(id, registration);
let registration_map2 = registration_map1.clone();
async_std::task::spawn_local(request.send().promise.map(move |r| match r {
async_std::task::spawn_local(request_promise.promise.map(move |r| match r {
Ok(_) => {
if let Some(ref mut s) =
registration_map2.borrow_mut().registrations.get_mut(&id)
@@ -304,6 +324,23 @@ impl ClientApi {
}
}
pub fn handle_state_change(self: Rc<Self>, changed: veilid_core::VeilidStateChange) {
self.send_request_to_all_clients(|_id, registration| {
let mut request = registration.client.state_changed_request();
let rpc_changed = request.get().init_changed();
ClientApi::convert_state_changed(&changed, rpc_changed);
request.send()
});
}
pub fn handle_client_log(self: Rc<Self>, message: String) {
self.send_request_to_all_clients(|_id, registration| {
let mut request = registration.client.log_message_request();
request.get().set_message(&message);
request.send()
});
}
pub fn run(self: Rc<Self>, bind_addrs: Vec<SocketAddr>) {
// Create client api VeilidServer
let veilid_server_impl = VeilidServerImpl::new(self.inner.borrow().veilid_api.clone());

View File

@@ -0,0 +1,48 @@
use async_std::channel::{bounded, Receiver, RecvError, Sender, TrySendError};
use std::sync::Arc;
#[derive(Debug)]
struct ClientLogChannelInner {
sender: Sender<String>,
receiver: Receiver<String>,
}
#[derive(Debug, Clone)]
pub struct ClientLogChannel {
inner: Arc<ClientLogChannelInner>,
}
impl ClientLogChannel {
pub fn new() -> Self {
let (sender, receiver) = bounded(1);
Self {
inner: Arc::new(ClientLogChannelInner { sender, receiver }),
}
}
pub async fn recv(&self) -> Result<String, RecvError> {
self.inner.receiver.recv().await
}
}
impl std::io::Write for ClientLogChannel {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
if let Err(e) = self
.inner
.sender
.try_send(String::from_utf8_lossy(buf).to_string())
{
match e {
TrySendError::Full(_) => Err(std::io::Error::from(std::io::ErrorKind::WouldBlock)),
TrySendError::Closed(_) => {
Err(std::io::Error::from(std::io::ErrorKind::BrokenPipe))
}
}
} else {
Ok(buf.len())
}
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}

View File

@@ -3,6 +3,7 @@
#![deny(unused_must_use)]
mod client_api;
mod client_log_channel;
mod settings;
#[allow(clippy::all)]

View File

@@ -29,6 +29,9 @@ logging:
path: ""
append: true
level: "info"
client:
enable: false
level: "info"
testing:
subnode_index: 0
core:
@@ -283,6 +286,12 @@ pub struct File {
pub level: LogLevel,
}
#[derive(Debug, Deserialize)]
pub struct Client {
pub enabled: bool,
pub level: LogLevel,
}
#[derive(Debug, Deserialize)]
pub struct ClientApi {
pub enabled: bool,
@@ -293,6 +302,7 @@ pub struct ClientApi {
pub struct Logging {
pub terminal: Terminal,
pub file: File,
pub client: Client,
}
#[derive(Debug, Deserialize)]
@@ -928,6 +938,8 @@ mod tests {
assert_eq!(s.logging.file.path, "");
assert_eq!(s.logging.file.append, true);
assert_eq!(s.logging.file.level, LogLevel::Info);
assert_eq!(s.logging.client.enabled, true);
assert_eq!(s.logging.client.level, LogLevel::Info);
assert_eq!(s.testing.subnode_index, 0);
assert_eq!(
s.core.tablestore.directory,

View File

@@ -1,8 +1,10 @@
#[cfg(unix)]
use crate::client_api;
use crate::client_log_channel::*;
use crate::settings;
use async_std::channel::{bounded, Receiver, Sender};
use clap::{App, Arg};
use futures::*;
use lazy_static::*;
use log::*;
use parking_lot::Mutex;
@@ -187,7 +189,7 @@ pub async fn main() -> Result<(), String> {
// Set up loggers
let mut logs: Vec<Box<dyn SharedLogger>> = Vec::new();
let mut client_log_channel: Option<ClientLogChannel> = None;
let mut cb = ConfigBuilder::new();
cb.add_filter_ignore_str("async_std");
cb.add_filter_ignore_str("async_io");
@@ -228,6 +230,15 @@ pub async fn main() -> Result<(), String> {
logfile,
))
}
if settingsr.logging.client.enabled {
let clog = ClientLogChannel::new();
client_log_channel = Some(clog.clone());
logs.push(WriteLogger::new(
settings::convert_loglevel(settingsr.logging.file.level),
cb.build(),
clog,
))
}
CombinedLogger::init(logs).map_err(|e| format!("failed to init logs: {}", e))?;
// Create Veilid Core
@@ -280,12 +291,27 @@ pub async fn main() -> Result<(), String> {
let capi_jh = async_std::task::spawn_local(async move {
trace!("state change processing started");
while let Ok(change) = receiver.recv().await {
if let Some(c) = capi2.borrow_mut().as_mut().cloned() {
if let Some(c) = capi2.borrow().as_ref().cloned() {
c.handle_state_change(change);
}
}
trace!("state change processing stopped");
});
// Handle log messages on main thread for capnproto rpc
let capi2 = capi.clone();
let capi_jh2 = if let Some(client_log_channel) = client_log_channel {
Some(async_std::task::spawn_local(async move {
trace!("client logging started");
while let Ok(message) = client_log_channel.recv().await {
if let Some(c) = capi2.borrow().as_ref().cloned() {
c.handle_client_log(message);
}
}
trace!("client logging stopped")
}))
} else {
None
};
// Auto-attach if desired
if auto_attach {
@@ -313,8 +339,11 @@ pub async fn main() -> Result<(), String> {
// Shut down Veilid API
veilid_api.shutdown().await;
// Wait for statechanged handler to exit
// Wait for client api handlers to exit
capi_jh.await;
if let Some(capi_jh2) = capi_jh2 {
capi_jh2.await;
}
Ok(())
}