2024-03-28 22:38:21 +00:00
|
|
|
use std::{collections::HashMap, sync::Arc};
|
|
|
|
|
2024-03-28 07:36:48 +00:00
|
|
|
use anyhow::Result;
|
2024-03-28 22:38:21 +00:00
|
|
|
use bytes::{Buf, BytesMut};
|
|
|
|
use krata::idm::protocol::IdmPacket;
|
2024-03-28 07:36:48 +00:00
|
|
|
use kratart::channel::ChannelService;
|
2024-03-28 22:38:21 +00:00
|
|
|
use log::{error, warn};
|
|
|
|
use prost::Message;
|
|
|
|
use tokio::{
|
|
|
|
sync::{
|
|
|
|
mpsc::{Receiver, Sender},
|
|
|
|
Mutex,
|
|
|
|
},
|
|
|
|
task::JoinHandle,
|
|
|
|
};
|
|
|
|
|
|
|
|
type ListenerMap = Arc<Mutex<HashMap<u32, Sender<(u32, IdmPacket)>>>>;
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct DaemonIdmHandle {
|
|
|
|
listeners: ListenerMap,
|
|
|
|
task: Arc<JoinHandle<()>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct DaemonIdmSubscribeHandle {
|
|
|
|
domid: u32,
|
|
|
|
listeners: ListenerMap,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DaemonIdmSubscribeHandle {
|
|
|
|
pub async fn unsubscribe(&self) -> Result<()> {
|
|
|
|
let mut guard = self.listeners.lock().await;
|
|
|
|
let _ = guard.remove(&self.domid);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DaemonIdmHandle {
|
|
|
|
pub async fn subscribe(
|
|
|
|
&self,
|
|
|
|
domid: u32,
|
|
|
|
sender: Sender<(u32, IdmPacket)>,
|
|
|
|
) -> Result<DaemonIdmSubscribeHandle> {
|
|
|
|
let mut guard = self.listeners.lock().await;
|
|
|
|
guard.insert(domid, sender);
|
|
|
|
Ok(DaemonIdmSubscribeHandle {
|
|
|
|
domid,
|
|
|
|
listeners: self.listeners.clone(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for DaemonIdmHandle {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
if Arc::strong_count(&self.task) <= 1 {
|
|
|
|
self.task.abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-28 07:36:48 +00:00
|
|
|
|
|
|
|
pub struct DaemonIdm {
|
2024-03-28 22:38:21 +00:00
|
|
|
listeners: ListenerMap,
|
2024-03-28 07:36:48 +00:00
|
|
|
receiver: Receiver<(u32, Vec<u8>)>,
|
|
|
|
task: JoinHandle<()>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DaemonIdm {
|
|
|
|
pub async fn new() -> Result<DaemonIdm> {
|
|
|
|
let (service, receiver) = ChannelService::new("krata-channel".to_string()).await?;
|
|
|
|
let task = service.launch().await?;
|
2024-03-28 22:38:21 +00:00
|
|
|
let listeners = Arc::new(Mutex::new(HashMap::new()));
|
|
|
|
Ok(DaemonIdm {
|
|
|
|
receiver,
|
|
|
|
task,
|
|
|
|
listeners,
|
|
|
|
})
|
2024-03-28 07:36:48 +00:00
|
|
|
}
|
|
|
|
|
2024-03-28 22:38:21 +00:00
|
|
|
pub async fn launch(mut self) -> Result<DaemonIdmHandle> {
|
|
|
|
let listeners = self.listeners.clone();
|
|
|
|
let task = tokio::task::spawn(async move {
|
|
|
|
let mut buffers: HashMap<u32, BytesMut> = HashMap::new();
|
|
|
|
if let Err(error) = self.process(&mut buffers).await {
|
2024-03-28 07:36:48 +00:00
|
|
|
error!("failed to process idm: {}", error);
|
|
|
|
}
|
2024-03-28 22:38:21 +00:00
|
|
|
});
|
|
|
|
Ok(DaemonIdmHandle {
|
|
|
|
listeners,
|
|
|
|
task: Arc::new(task),
|
|
|
|
})
|
2024-03-28 07:36:48 +00:00
|
|
|
}
|
|
|
|
|
2024-03-28 22:38:21 +00:00
|
|
|
async fn process(&mut self, buffers: &mut HashMap<u32, BytesMut>) -> Result<()> {
|
2024-03-28 07:36:48 +00:00
|
|
|
loop {
|
2024-03-28 22:38:21 +00:00
|
|
|
let Some((domid, data)) = self.receiver.recv().await else {
|
2024-03-28 07:36:48 +00:00
|
|
|
break;
|
|
|
|
};
|
2024-03-28 22:38:21 +00:00
|
|
|
|
|
|
|
let buffer = buffers.entry(domid).or_insert_with_key(|_| BytesMut::new());
|
|
|
|
buffer.extend_from_slice(&data);
|
|
|
|
if buffer.len() < 2 {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let size = (buffer[0] as u16 | (buffer[1] as u16) << 8) as usize;
|
|
|
|
let needed = size + 2;
|
|
|
|
if buffer.len() < needed {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let mut packet = buffer.split_to(needed);
|
|
|
|
packet.advance(2);
|
|
|
|
match IdmPacket::decode(packet) {
|
|
|
|
Ok(packet) => {
|
|
|
|
let guard = self.listeners.lock().await;
|
|
|
|
if let Some(sender) = guard.get(&domid) {
|
|
|
|
if let Err(error) = sender.try_send((domid, packet)) {
|
|
|
|
warn!("dropped idm packet from domain {}: {}", domid, error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(packet) => {
|
|
|
|
warn!("received invalid packet from domain {}: {}", domid, packet);
|
|
|
|
}
|
|
|
|
}
|
2024-03-28 07:36:48 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for DaemonIdm {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.task.abort();
|
|
|
|
}
|
|
|
|
}
|