use crate::grant_file_access;
use crate::rong_file::RongFile;
use rong::*;
use std::path::PathBuf;
use tokio::io::AsyncWriteExt;
fn resolve_dest(dest: &JSValue) -> JSResult<PathBuf> {
if dest.is_string() {
let path: String = dest.clone().to_rust()?;
return grant_file_access(&path);
}
if let Some(obj) = dest.clone().into_object()
&& let Ok(rf) = obj.borrow::<RongFile>()
{
return Ok(rf.resolved().clone());
}
Err(HostError::new(
rong::error::E_INVALID_ARG,
"destination must be a string path or RongFile",
)
.with_name("TypeError")
.into())
}
async fn rong_write(_ctx: JSContext, dest: JSValue, data: JSValue) -> JSResult<f64> {
let resolved = resolve_dest(&dest)?;
if data.is_string() {
let text: String = data.to_rust()?;
let bytes = text.as_bytes();
let len = bytes.len();
let mut file = tokio::fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&resolved)
.await
.map_err(|e| HostError::new("FS_IO", format!("Failed to open file: {}", e)))?;
file.write_all(bytes)
.await
.map_err(|e| HostError::new("FS_IO", format!("Write failed: {}", e)))?;
file.flush()
.await
.map_err(|e| HostError::new("FS_IO", format!("Flush failed: {}", e)))?;
return Ok(len as f64);
}
if data.is_array_buffer() {
let ab: JSArrayBuffer = data.to_rust()?;
let bytes = ab.as_slice();
let len = bytes.len();
let mut file = tokio::fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&resolved)
.await
.map_err(|e| HostError::new("FS_IO", format!("Failed to open file: {}", e)))?;
file.write_all(bytes)
.await
.map_err(|e| HostError::new("FS_IO", format!("Write failed: {}", e)))?;
file.flush()
.await
.map_err(|e| HostError::new("FS_IO", format!("Flush failed: {}", e)))?;
return Ok(len as f64);
}
if let Some(obj) = data.clone().into_object() {
let source = {
if let Ok(rf) = obj.borrow::<RongFile>() {
Some(rf.resolved().clone())
} else {
None
}
};
if let Some(source) = source {
let bytes_copied = tokio::fs::copy(&source, &resolved)
.await
.map_err(|e| HostError::new("FS_IO", format!("Failed to copy file: {}", e)))?;
return Ok(bytes_copied as f64);
}
if let Some(ta) = AnyJSTypedArray::from_object(obj)
&& let Some(bytes) = ta.as_bytes()
{
let len = bytes.len();
let mut file = tokio::fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&resolved)
.await
.map_err(|e| HostError::new("FS_IO", format!("Failed to open file: {}", e)))?;
file.write_all(bytes)
.await
.map_err(|e| HostError::new("FS_IO", format!("Write failed: {}", e)))?;
file.flush()
.await
.map_err(|e| HostError::new("FS_IO", format!("Flush failed: {}", e)))?;
return Ok(len as f64);
}
}
Err(HostError::new(
rong::error::E_INVALID_ARG,
"data must be a string, ArrayBuffer, TypedArray, or RongFile",
)
.with_name("TypeError")
.into())
}
pub(crate) fn init(ctx: &JSContext) -> JSResult<()> {
let rong = ctx.host_namespace();
let write_fn = JSFunc::new(ctx, rong_write)?.name("write")?;
rong.set("write", write_fn)?;
Ok(())
}