mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
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:
@@ -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" }
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
|
||||
116
libs/helpers/src/rpc_client.rs
Normal file
116
libs/helpers/src/rpc_client.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user