fix: plugin in windows

This commit is contained in:
leookun
2026-08-30 20:57:02 +08:00
parent a5bbe67845
commit 453c120740
5 changed files with 48 additions and 5 deletions
+36 -5
View File
@@ -70,11 +70,7 @@ impl PluginDataStore {
.await?;
file.sync_all().await?;
drop(file);
#[cfg(windows)]
if path.exists() {
tokio::fs::remove_file(&path).await?;
}
tokio::fs::rename(&temporary, &path).await?;
replace_file(&temporary, &path).await?;
set_file_permissions(&path)?;
Ok(())
}
@@ -106,6 +102,41 @@ impl PluginDataStore {
}
}
/// 原子替换目标文件。Windows 上 rename 不覆盖已存在文件,且目标可能被
/// 杀毒软件或索引器短暂锁定(拒绝访问/共享冲突),需删除后重试。
async fn replace_file(temporary: &Path, path: &Path) -> Result<()> {
#[cfg(windows)]
{
const ACCESS_DENIED: i32 = 5;
const SHARING_VIOLATION: i32 = 32;
let mut attempts = 0;
loop {
if path.exists() {
let _ = tokio::fs::remove_file(path).await;
}
match tokio::fs::rename(temporary, path).await {
Ok(()) => return Ok(()),
Err(error)
if attempts < 10
&& matches!(
error.raw_os_error(),
Some(ACCESS_DENIED | SHARING_VIOLATION)
) =>
{
attempts += 1;
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
}
Err(error) => return Err(error.into()),
}
}
}
#[cfg(not(windows))]
{
tokio::fs::rename(temporary, path).await?;
Ok(())
}
}
fn validate_component(value: &str, label: &str) -> Result<()> {
if value.is_empty()
|| value.len() > 128
+1
View File
@@ -107,6 +107,7 @@ impl PluginDefinitionLoader {
) -> Result<PluginModuleDefinition> {
let entry_url = file_url(entry)?;
let mut command = tokio::process::Command::new(executable);
super::detach_console(&mut command);
command
.arg("run")
.arg("--quiet")
+1
View File
@@ -207,6 +207,7 @@ fn extract_runtime_archive(archive: &Path, output: &Path, executable_name: &str)
async fn validate_runtime(executable: &Path, cancellation: &CancellationToken) -> Result<()> {
let mut command = tokio::process::Command::new(executable);
super::detach_console(&mut command);
command
.arg("--version")
.stdin(Stdio::null())
+9
View File
@@ -21,3 +21,12 @@ pub use descriptor::{
pub use registry::{ImportResponse, OAuthBeginResponse, OAuthPollResponse, PluginRegistry};
pub use runtime::{PluginRuntime, PluginRuntimePhase, PluginRuntimeState, PluginRuntimeStatus};
pub(crate) use wire::llm_request as plugin_llm_request;
/// Windows 下阻止 Deno 子进程弹出控制台窗口(CREATE_NO_WINDOW)。
#[cfg(windows)]
fn detach_console(command: &mut tokio::process::Command) {
command.creation_flags(0x0800_0000);
}
#[cfg(not(windows))]
fn detach_console(_command: &mut tokio::process::Command) {}
+1
View File
@@ -223,6 +223,7 @@ impl PluginWorker {
async fn spawn(&self) -> Result<WorkerProcess> {
let entry_url = file_url(&self.inner.entry)?;
let mut command = tokio::process::Command::new(&self.inner.executable);
super::detach_console(&mut command);
command
.arg("run")
.arg("--quiet")