use crate::{
actors::{
lua_vm::messages::SendWarning,
queue::messages::{Dequeue, GetLength},
scanmgr::{
error::{Error, ScanMgrResult},
ScanMgr,
},
user_engine::messages::ScanBytes,
},
userscript_api::{
fs_api::path_obj::PathObj,
scanmgr_api::scanresult::{DataItemResult, ScanResult},
},
};
use kameo::message::{Context, Message};
use std::path::PathBuf;
pub struct InvokeScan;
impl Message<InvokeScan> for ScanMgr {
type Reply = ScanMgrResult<Vec<ScanResult>>;
async fn handle(&mut self, _: InvokeScan, _: Context<'_, Self, Self::Reply>) -> Self::Reply {
let Some(lua_vm) = self.lua_ref.upgrade() else {
return Err(Error::NoLuaVm);
};
let Some(queue) = self.queue_ref.upgrade() else {
return Err(Error::NoQueue);
};
let Some(user_engine) = self.user_engine_ref.upgrade() else {
return Err(Error::NoUserEngine);
};
let mut scan_results: Vec<ScanResult> = Vec::with_capacity(16384);
while queue.ask(GetLength).await.expect("should be infallible") > 0 {
let (name, path, content) = match queue.ask(Dequeue).await {
Ok((name, path, content)) => (name, path, content),
Err(err) => {
let warning: String = format!("failed to load data item: {err}");
lua_vm
.tell(SendWarning::Complete(warning))
.await
.expect("should be infallible");
continue;
}
};
let Ok(results) = user_engine.ask(ScanBytes::from(content)).await else {
let warning: String = format!("failed to scan data item `{name}`.\n HINT: is the path accessible?\n {path:?}");
lua_vm
.tell(SendWarning::Complete(warning))
.await
.expect("should be infallible");
continue;
};
for engine_name in results {
let name: String = name.clone();
let path: Option<PathObj> = path.clone().map(|path: PathBuf| PathObj(path));
let result = ScanResult {
engine: engine_name,
item: DataItemResult { name, path },
};
scan_results.push(result);
}
}
Ok(scan_results)
}
}