fix: Cleanup by sending a command and kill when dropped (#1945)

* fix: Cleanup by sending a command and kill when dropped

* chore: Fix the loadModule run command

* fix: cleans up failed health

* refactor long-running

* chore: Fixes?"

* refactor

* run iso ci on pr

* fix debuild

* fix tests

* switch to libc kill

* kill process by parent

* fix graceful shutdown

* recurse submodules

* fix compat build

* feat: Add back in the timeout

* chore: add the missing types for the unnstable

* inherited logs

Co-authored-by: J M <Blu-J@users.noreply.github.com>

* fix deleted code

Co-authored-by: Aiden McClelland <me@drbonez.dev>
Co-authored-by: J M <Blu-J@users.noreply.github.com>
This commit is contained in:
J M
2022-11-18 19:19:04 -07:00
committed by Aiden McClelland
parent eec8c41e20
commit a3d1b2d671
39 changed files with 1866 additions and 1845 deletions

View File

@@ -11,6 +11,8 @@ futures = "0.3.21"
models = { path = "../models" }
pin-project = "1.0.11"
serde = { version = "1.0", features = ["derive", "rc"] }
serde_json = "1.0"
tokio = { version = "1.19.2", features = ["full"] }
tokio-stream = { version = "0.1.9", features = ["io-util", "sync"] }
tracing = "0.1.35"
tracing = "0.1.35"
yajrc = { version = "*", git = "https://github.com/dr-bonez/yajrc.git", branch = "develop" }

View File

@@ -10,9 +10,11 @@ use tokio::sync::oneshot;
use tokio::task::{JoinError, JoinHandle, LocalSet};
mod byte_replacement_reader;
mod rpc_client;
mod rsync;
mod script_dir;
pub use byte_replacement_reader::*;
pub use rpc_client::RpcClient;
pub use rsync::*;
pub use script_dir::*;

View File

@@ -0,0 +1,116 @@
use std::collections::BTreeMap;
use std::sync::atomic::AtomicUsize;
use std::sync::{Arc, Weak};
use models::{Error, ErrorKind, ResultExt};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader};
use tokio::sync::{oneshot, Mutex};
use yajrc::{Id, RpcError, RpcMethod, RpcRequest, RpcResponse};
use crate::NonDetachingJoinHandle;
type DynWrite = Box<dyn AsyncWrite + Unpin + Send + Sync + 'static>;
type ResponseMap = BTreeMap<Id, oneshot::Sender<Result<Value, RpcError>>>;
pub struct RpcClient {
id: AtomicUsize,
_handler: NonDetachingJoinHandle<()>,
writable: Weak<Mutex<(DynWrite, ResponseMap)>>,
}
impl RpcClient {
pub fn new<
W: AsyncWrite + Unpin + Send + Sync + 'static,
R: AsyncRead + Unpin + Send + Sync + 'static,
>(
writer: W,
reader: R,
) -> Self {
let writer: DynWrite = Box::new(writer);
let writable = Arc::new(Mutex::new((writer, ResponseMap::new())));
let weak_writable = Arc::downgrade(&writable);
RpcClient {
id: AtomicUsize::new(0),
_handler: tokio::spawn(async move {
let mut lines = BufReader::new(reader).lines();
while let Some(line) = lines.next_line().await.transpose() {
let mut w = writable.lock().await;
match line.map_err(Error::from).and_then(|l| {
serde_json::from_str::<RpcResponse>(&l)
.with_kind(ErrorKind::Deserialization)
}) {
Ok(l) => {
if let Some(id) = l.id {
if let Some(res) = w.1.remove(&id) {
if let Err(e) = res.send(l.result) {
tracing::warn!(
"RpcClient Response for Unknown ID: {:?}",
e
);
}
} else {
tracing::warn!(
"RpcClient Response for Unknown ID: {:?}",
l.result
);
}
} else {
tracing::info!("RpcClient Notification: {:?}", l);
}
}
Err(e) => {
tracing::error!("RpcClient Error: {}", e);
tracing::debug!("{:?}", e);
}
}
}
})
.into(),
writable: weak_writable,
}
}
pub async fn request<T: RpcMethod>(
&self,
method: T,
params: T::Params,
) -> Result<T::Response, RpcError>
where
T: Serialize,
T::Params: Serialize,
T::Response: for<'de> Deserialize<'de>,
{
if let Some(w) = self.writable.upgrade() {
let mut w = w.lock().await;
let id = Id::Number(
self.id
.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
.into(),
);
w.0.write_all(
(serde_json::to_string(&RpcRequest {
id: Some(id.clone()),
method,
params,
})? + "\n")
.as_bytes(),
)
.await
.map_err(|e| {
let mut err = yajrc::INTERNAL_ERROR.clone();
err.data = Some(json!(e.to_string()));
err
})?;
let (send, recv) = oneshot::channel();
w.1.insert(id, send);
drop(w);
if let Ok(val) = recv.await {
return Ok(serde_json::from_value(val?)?);
}
}
let mut err = yajrc::INTERNAL_ERROR.clone();
err.data = Some(json!("RpcClient thread has terminated"));
Err(err)
}
}

View File

@@ -1,13 +1,14 @@
use color_eyre::eyre::eyre;
use std::path::Path;
use crate::{const_true, ByteReplacementReader, NonDetachingJoinHandle};
use color_eyre::eyre::eyre;
use models::{Error, ErrorKind};
use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader};
use tokio::process::{Child, Command};
use tokio::sync::watch;
use tokio_stream::wrappers::WatchStream;
use crate::{const_true, ByteReplacementReader, NonDetachingJoinHandle};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RsyncOptions {