use crate::vfs::{vercel_kv_vfs::VercelKvVfs, VfsError};
use log::{debug, error, info, warn}; use once_cell::sync::Lazy;
use std::io;
use std::path::Path;
use tokio::sync::Mutex; use crate::vfs::VirtualFileSystem;
static VFS: Lazy<Mutex<Option<VercelKvVfs>>> = Lazy::new(|| Mutex::new(None));
pub async fn get_vfs() -> Result<VercelKvVfs, io::Error> {
let mut vfs_guard = VFS.lock().await;
if vfs_guard.is_none() {
info!("Initializing VercelKvVfs..."); let vfs = VercelKvVfs::new().map_err(|e| {
error!("VFS initialization failed: {}", e);
io::Error::new(io::ErrorKind::Other, format!("VFS init failed: {}", e))
})?;
*vfs_guard = Some(vfs);
info!("VercelKvVfs initialized successfully."); }
vfs_guard.as_ref().cloned().ok_or_else(|| {
error!("Attempted to use VFS before initialization");
io::Error::new(io::ErrorKind::Other, "VFS not initialized")
})
}
fn map_vfs_error(e: VfsError) -> io::Error {
debug!("Mapping VfsError to io::Error: {:?}", e);
match e {
VfsError::NotFound(msg) => io::Error::new(io::ErrorKind::NotFound, msg),
VfsError::ConfigError(msg) => io::Error::new(io::ErrorKind::InvalidInput, msg),
VfsError::StorageError(msg) => io::Error::new(io::ErrorKind::Other, msg),
VfsError::NetworkError(msg) => io::Error::new(io::ErrorKind::NotConnected, msg),
VfsError::IoError(err) => err,
VfsError::IsDirectory(msg) => io::Error::new(io::ErrorKind::Other, msg),
VfsError::NotDirectory(msg) => io::Error::new(io::ErrorKind::Other, msg),
VfsError::PermissionDenied(msg) => io::Error::new(io::ErrorKind::PermissionDenied, msg),
VfsError::AlreadyExists(msg) => io::Error::new(io::ErrorKind::AlreadyExists, msg),
VfsError::NotSupported(msg) => io::Error::new(io::ErrorKind::Unsupported, msg),
VfsError::InvalidPath(msg) => io::Error::new(io::ErrorKind::InvalidInput, msg),
VfsError::Other(msg) => io::Error::new(io::ErrorKind::Other, msg),
}
}
pub async fn read_file(path: &str) -> Result<String, io::Error> {
let vfs = get_vfs().await?;
let bytes_result = vfs.read_file(path).await;
match bytes_result {
Ok(bytes) => String::from_utf8(bytes).map_err(|e| {
error!("Failed to convert bytes to UTF-8 for {}: {}", path, e);
io::Error::new(io::ErrorKind::InvalidData, e)
}),
Err(e) => {
warn!("VFS read_file failed for {}: {:?}", path, e);
Err(map_vfs_error(e))
}
}
}
pub async fn read_file_async(path: &str) -> Result<String, io::Error> {
read_file(path).await }
pub async fn file_exists(path: &str) -> bool {
match get_vfs().await {
Ok(vfs) => {
debug!("Got VFS instance. Calling vfs.exists...");
match vfs.exists(path).await {
Ok(exists) => {
debug!("VFS exists check for {} returned: {}", path, exists);
exists
}
Err(e) => {
warn!("VFS exists check failed for {}: {}", path, e);
false }
}
}
Err(e) => {
error!("Failed to get VFS for existence check on {}: {}", path, e);
false
}
}
}
async fn file_get<P: AsRef<Path>>(path: P, _base_path: Option<&str>) -> io::Result<String> {
let path_ref = path.as_ref();
debug!("file_get called for path: {:?}", path_ref);
let path_str = path_ref.to_str().ok_or_else(|| {
error!("File path {:?} is not a valid UTF-8 string", path_ref);
io::Error::new(
io::ErrorKind::InvalidInput,
"File path is not a valid UTF-8 string",
)
})?;
debug!("Delegating file_get to read_file for path: {}", path_str);
read_file(path_str).await
}
pub async fn copy_file(src: &str, dst: &str) -> io::Result<()> {
debug!("copy_file called from src: {} to dst: {}", src, dst);
debug!("Attempting to get VFS instance...");
let vfs = get_vfs().await?;
debug!("Reading source file {} using VFS...", src);
let content_result = vfs.read_file(src).await;
let content = match content_result {
Ok(content) => {
debug!(
"Successfully read {} bytes from source: {}",
content.len(),
src
);
content
}
Err(e) => {
warn!("Failed to read source file {} during copy: {:?}", src, e);
return Err(map_vfs_error(e));
}
};
debug!("Writing content to destination file {} using VFS...", dst);
let write_result = vfs.write_file(dst, content).await;
match write_result {
Ok(_) => {
debug!("Successfully wrote to destination: {}", dst);
Ok(())
}
Err(e) => {
error!("Failed to write to destination file {}: {:?}", dst, e);
Err(map_vfs_error(e))
}
}
}
pub async fn file_get_async<P: AsRef<Path>>(
path: P,
base_path: Option<&str>,
) -> io::Result<String> {
let path_ref = path.as_ref();
file_get(path_ref, base_path).await
}
pub async fn get_file_attributes(path: &str) -> io::Result<crate::vfs::FileAttributes> {
debug!("get_file_attributes called for path: {}", path);
debug!("Attempting to get VFS instance...");
let vfs = get_vfs().await?;
debug!("Got VFS instance. Calling read_file_attributes...");
match vfs.read_file_attributes(path).await {
Ok(attributes) => {
debug!(
"Successfully got attributes for path: {}, size: {}",
path, attributes.size
);
Ok(attributes)
}
Err(e) => {
warn!("VFS read_file_attributes failed for {}: {:?}", path, e);
Err(map_vfs_error(e))
}
}
}
pub async fn create_directory(path: &str) -> io::Result<()> {
debug!("create_directory called for path: {}", path);
debug!("Attempting to get VFS instance...");
let vfs = get_vfs().await?;
debug!("Got VFS instance. Calling create_directory...");
match vfs.create_directory(path).await {
Ok(_) => {
debug!("Successfully created directory: {}", path);
Ok(())
}
Err(e) => {
warn!("VFS create_directory failed for {}: {:?}", path, e);
Err(map_vfs_error(e))
}
}
}