MCP: an agent's folders hold for file loads through the app and for a design's font files (#1112)
doc.open and the STEP/mesh imports run on the file loader's worker with the request's path scope, and a font named by file path in a design is checked against the scope before it is read.
This commit is contained in:
1 parent
6de8f6db95
commit
c469adf456
8 files changed
+122
-30
No files matched your search
@@ -37,11 +37,13 @@ pub struct Request {
|
||||
pub kind: Kind,
|
||||
/// A control-channel caller waiting for the command's reply.
|
||||
pub reply: Option<Sender<ControlResponse>>,
|
||||
/// The folders that caller's agent may use: the worker reads the file inside them.
|
||||
pub scope: Option<solidcraft_engine::io::vfs::PathScope>,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
pub fn new(path: &str, kind: Kind) -> Self {
|
||||
Request { path: path.into(), kind, reply: None }
|
||||
Request { path: path.into(), kind, reply: None, scope: None }
|
||||
}
|
||||
fn insert(&self) -> bool {
|
||||
self.kind == Kind::Insert
|
||||
@@ -180,7 +182,14 @@ pub fn control(app: &mut SolveApp, req: crate::control::ControlRequest) -> Optio
|
||||
_ => return Some(req),
|
||||
};
|
||||
let Some(path) = req.params.get("params").and_then(|p| p.get("path")).and_then(Value::as_str) else { return Some(req) };
|
||||
let _ = begin_request(app, Request { path: path.into(), kind, reply: Some(req.reply.clone()) });
|
||||
let scope = match crate::control::request_scope(app, &req.params) {
|
||||
Ok(scope) => scope,
|
||||
Err(e) => {
|
||||
let _ = req.reply.send(json!({"ok": false, "error": e}));
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let _ = begin_request(app, Request { path: path.into(), kind, reply: Some(req.reply.clone()), scope });
|
||||
None
|
||||
}
|
||||
|
||||
@@ -238,6 +247,7 @@ fn start(app: &mut SolveApp) {
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
let (preview_tx, preview_rx) = std::sync::mpsc::channel();
|
||||
let (command, params) = request.command();
|
||||
let scope = request.scope.clone();
|
||||
let thumbnail = request.kind == Kind::Open;
|
||||
let spawned = std::thread::Builder::new().name("file-load".into()).spawn(move || {
|
||||
let preview_began = std::time::Instant::now();
|
||||
@@ -256,9 +266,10 @@ fn start(app: &mut SolveApp) {
|
||||
}
|
||||
}));
|
||||
}
|
||||
let result =
|
||||
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| compute(scratch, command, ¶ms, thumbnail, &worker_phase, &worker_progress)))
|
||||
.unwrap_or_else(|_| Err("the file operation failed; the current design is unchanged".into()));
|
||||
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||
compute(scratch, command, ¶ms, scope, thumbnail, &worker_phase, &worker_progress)
|
||||
}))
|
||||
.unwrap_or_else(|_| Err("the file operation failed; the current design is unchanged".into()));
|
||||
let _ = tx.send(result);
|
||||
});
|
||||
match spawned {
|
||||
@@ -364,15 +375,26 @@ fn preview_work_fits(scene: &solidcraft_engine::render::Scene, camera: &solidcra
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn compute(mut session: Session, command: &str, params: &Value, thumbnail: bool, phase: &AtomicU8, progress: &Arc<Progress>) -> Job {
|
||||
fn compute(
|
||||
mut session: Session,
|
||||
command: &str,
|
||||
params: &Value,
|
||||
scope: Option<solidcraft_engine::io::vfs::PathScope>,
|
||||
thumbnail: bool,
|
||||
phase: &AtomicU8,
|
||||
progress: &Arc<Progress>,
|
||||
) -> Job {
|
||||
let profile = solidcraft_engine::geom::env::var_os("PROFILE_OPEN").is_some();
|
||||
let began = std::time::Instant::now();
|
||||
let cancelled = || Err("file operation cancelled".to_string());
|
||||
if progress.is_cancelled() {
|
||||
return cancelled();
|
||||
}
|
||||
// The timeline's rebuild reports each feature and stops at the next one after Cancel.
|
||||
let result = solidcraft_engine::doc::progress::watch(progress.clone(), || session.execute(command, params)).map_err(|e| e.to_string())?;
|
||||
// The timeline's rebuild reports each feature and stops at the next one after Cancel. An
|
||||
// agent's scope is per thread, so it is set again here.
|
||||
let result =
|
||||
solidcraft_engine::io::vfs::scoped(scope, || solidcraft_engine::doc::progress::watch(progress.clone(), || session.execute(command, params)))
|
||||
.map_err(|e| e.to_string())?;
|
||||
if progress.is_cancelled() {
|
||||
return cancelled();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user