mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-12 04:42:16 +00:00
desktop: use tokio::fs for Sora and Midjourney file I/O (Sonar S7493) (#2804)
## Summary
Replaces blocking `std::fs` calls inside `async fn`s in the desktop
crate with `tokio::fs`. SonarCloud reports these as **rust:S7493** ("use
an asynchronous file API instead of this blocking file operation"). This
PR resolves 17 of the 26 desktop findings.
| File (under `crates/desktop/artcraft/src/services/`) | Findings |
Change |
|----------------------------------------------------------------|----------|----------------------------------------------------------------------------|
| `sora/state/read_sora_credentials_from_disk_with_upgrade.rs` | 10 |
`read_to_string` and `OpenOptions`+`write_all`+`flush` →
`tokio::fs::{read_to_string, write}` |
| `sora/state/initialize_sora_jwt_bearer_token.rs` | 2 |
`std::fs::{read_to_string, write}` → `tokio::fs` |
| `sora/state/sora_credential_manager.rs` (`call_sentinel_refresh`) | 2
| `OpenOptions`+`write_all`+`flush` → `tokio::fs::write` |
| `midjourney/utils/download_midjourney_image.rs` | 2 |
`File::create`+`write_all` → `tokio::fs::write` |
| `midjourney/threads/upload_midjourney_batch.rs` | 1 |
`std::fs::remove_file` → `tokio::fs::remove_file(..).await` |
`tokio::fs::write` creates or truncates the file and writes everything.
That is the same as the
`OpenOptions::new().create(true).write(true).truncate(true)` +
`write_all` + `flush` sequence it replaces. The synchronous helpers in
`sora_credential_manager.rs` (`persist_*_to_disk`) are not `async`, are
not flagged, and are left unchanged. The `.exists()` guards are also
left as they are. The desktop crate already depends on `tokio` with the
`fs` feature, so no manifest or lockfile changes.
## Not included (overlap with open PRs)
The remaining 9 desktop S7493 findings are in files that open PRs are
rewriting. They are left alone to avoid conflicting changes:
- `core/utils/simple_http_download.rs`,
`sora/.../handle_successful_generations.rs`,
`worldlabs/threads/worldlabs_marble_task_polling.rs`: #2777 (fail
downloads on non-2xx responses).
- `core/threads/.../fal/handle_fal_complete.rs`: #2550, #2373.
- `core/utils/auto_download.rs`: #2785, #2686, #2393.
The api_clients findings are in #2803.
## Testing
- Each changed file parses with `rustfmt --check`. The formatting diffs
it reports already exist on `main`, and no files were reformatted.
- **I could not build the desktop crate locally.** `cargo check -p
artcraft` stops at `libdbus-sys` because the build machine lacks the
GTK, WebKit and D-Bus system libraries Tauri needs. Please rely on CI
for compilation before marking this ready.
- No new tests are added. This is a behaviour-preserving switch to
non-blocking I/O, so no test fails before the change and passes after
it, and these paths have no existing offline tests.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
<!-- coderabbit-ai-generated:v1 -->
## Summary by CodeRabbit
* **Chores**
* Updated background handling for saved images, checkpoints, and account
credentials. Existing cleanup, credential processing, and error
reporting behavior remain unchanged.
* These maintenance updates do not change the app’s available features
or how people interact with it.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
1 parent
1b99c184ef
commit
c3fa0453a4
5 files changed
+13
-45
No files matched your search
@@ -119,7 +119,7 @@ pub(super) async fn upload_midjourney_batch(maybe_app_handle: Option<&AppHandle>
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(err) = std::fs::remove_file(MidjourneyUploadCheckpoint::path(app_data_root, local_task)) {
|
||||
if let Err(err) = tokio::fs::remove_file(MidjourneyUploadCheckpoint::path(app_data_root, local_task)).await {
|
||||
log::warn!("Could not remove completed Midjourney upload checkpoint: {}", err);
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -2,8 +2,6 @@ use crate::core::state::data_dir::app_data_root::AppDataRoot;
|
||||
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
|
||||
use errors::AnyhowResult;
|
||||
use midjourney_client::utils::get_image_url::get_image_url;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use url::Url;
|
||||
use midjourney_client::utils::image_downloader_client::ImageDownloaderClient;
|
||||
@@ -28,8 +26,7 @@ pub async fn download_midjourney_image(
|
||||
let download_filename = format!("{}_{}.{}", job_id, index, ext);
|
||||
let download_path = tempdir.join(download_filename);
|
||||
|
||||
let mut file = File::create(&download_path)?;
|
||||
file.write_all(&image_bytes)?;
|
||||
tokio::fs::write(&download_path, &image_bytes).await?;
|
||||
|
||||
Ok(download_path)
|
||||
}
|
||||
@@ -14,7 +14,7 @@ pub async fn initialize_sora_jwt_bearer_token(app_data_root: &AppDataRoot) -> An
|
||||
return Ok(()); // Bearer token already exists.
|
||||
}
|
||||
|
||||
let cookie = std::fs::read_to_string(app_data_root.get_sora_cookie_file_path())?
|
||||
let cookie = tokio::fs::read_to_string(app_data_root.get_sora_cookie_file_path()).await?
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
@@ -22,7 +22,7 @@ pub async fn initialize_sora_jwt_bearer_token(app_data_root: &AppDataRoot) -> An
|
||||
|
||||
let bearer = generate_bearer_jwt_with_cookie(&cookie).await?;
|
||||
|
||||
std::fs::write(app_data_root.get_sora_bearer_token_file_path(), bearer)?;
|
||||
tokio::fs::write(app_data_root.get_sora_bearer_token_file_path(), bearer).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+8
-30
@@ -8,8 +8,7 @@ use openai_sora_client::creds::sora_jwt_bearer_token::SoraJwtBearerToken;
|
||||
use openai_sora_client::creds::sora_sentinel::SoraSentinel;
|
||||
use openai_sora_client::creds::sora_sentinel_token::SoraSentinelToken;
|
||||
use openai_sora_client::recipes::maybe_upgrade_or_renew_session::maybe_upgrade_or_renew_session;
|
||||
use std::fs::{read_to_string, OpenOptions};
|
||||
use std::io::Write;
|
||||
use tokio::fs::{read_to_string, write};
|
||||
|
||||
pub async fn read_sora_credentials_from_disk_with_upgrade(app_data_root: &AppDataRoot) -> AnyhowResult<SoraCredentialSet> {
|
||||
let cookie_file = app_data_root.get_sora_cookie_file_path();
|
||||
@@ -21,7 +20,7 @@ pub async fn read_sora_credentials_from_disk_with_upgrade(app_data_root: &AppDat
|
||||
return Err(anyhow!("Cookie file does not exist: {:?}", cookie_file));
|
||||
}
|
||||
|
||||
let value = read_to_string(cookie_file)?
|
||||
let value = read_to_string(cookie_file).await?
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
@@ -32,14 +31,14 @@ pub async fn read_sora_credentials_from_disk_with_upgrade(app_data_root: &AppDat
|
||||
let mut sentinel_token = None;
|
||||
|
||||
if bearer_file.exists() {
|
||||
let value = read_to_string(&bearer_file)?
|
||||
let value = read_to_string(&bearer_file).await?
|
||||
.trim()
|
||||
.to_string();
|
||||
bearer = Some(SoraJwtBearerToken::new(value)?);
|
||||
}
|
||||
|
||||
if legacy_sentinel_file.exists() {
|
||||
let value = read_to_string(&legacy_sentinel_file)?
|
||||
let value = read_to_string(&legacy_sentinel_file).await?
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
@@ -47,7 +46,7 @@ pub async fn read_sora_credentials_from_disk_with_upgrade(app_data_root: &AppDat
|
||||
}
|
||||
|
||||
if sentinel_token_file.exists() {
|
||||
let value = read_to_string(&sentinel_token_file)?
|
||||
let value = read_to_string(&sentinel_token_file).await?
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
@@ -73,14 +72,7 @@ pub async fn read_sora_credentials_from_disk_with_upgrade(app_data_root: &AppDat
|
||||
info!("Persisting bearer token value...");
|
||||
let value = bearer.token_str();
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&bearer_file)?;
|
||||
|
||||
file.write_all(value.as_bytes())?;
|
||||
file.flush()?;
|
||||
write(&bearer_file, value.as_bytes()).await?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,14 +81,7 @@ pub async fn read_sora_credentials_from_disk_with_upgrade(app_data_root: &AppDat
|
||||
info!("Persisting sentinel value...");
|
||||
let value = sentinel.get_sentinel();
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&legacy_sentinel_file)?;
|
||||
|
||||
file.write_all(value.as_bytes())?;
|
||||
file.flush()?;
|
||||
write(&legacy_sentinel_file, value.as_bytes()).await?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,14 +90,7 @@ pub async fn read_sora_credentials_from_disk_with_upgrade(app_data_root: &AppDat
|
||||
info!("Persisting sentinel token...");
|
||||
let value = sentinel_token.to_persistent_storage_json()?;
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&sentinel_token_file)?;
|
||||
|
||||
file.write_all(value.as_bytes())?;
|
||||
file.flush()?;
|
||||
write(&sentinel_token_file, value.as_bytes()).await?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,14 +162,7 @@ impl SoraCredentialManager {
|
||||
|
||||
self.holder.set_credentials(&creds)?;
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(self.app_data_root.get_sora_legacy_sentinel_file_path())?;
|
||||
|
||||
file.write_all(sentinel.as_bytes())?;
|
||||
file.flush()?;
|
||||
tokio::fs::write(self.app_data_root.get_sora_legacy_sentinel_file_path(), sentinel.as_bytes()).await?;
|
||||
|
||||
Ok(creds)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user