style: format code and reorganize imports across rfsclient codebase
This commit is contained in:
		| @@ -1,5 +1,5 @@ | ||||
| use sal_rfs_client::RfsClient; | ||||
| use sal_rfs_client::types::{ClientConfig, Credentials}; | ||||
| use sal_rfs_client::RfsClient; | ||||
|  | ||||
| #[tokio::main] | ||||
| async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
| @@ -12,10 +12,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         }), | ||||
|         timeout_seconds: 30, | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     let mut client = RfsClient::new(config); | ||||
|     println!("Client created with authentication credentials"); | ||||
|      | ||||
|  | ||||
|     // Authenticate with the server | ||||
|     client.authenticate().await?; | ||||
|     if client.is_authenticated() { | ||||
| @@ -30,13 +30,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         credentials: None, | ||||
|         timeout_seconds: 30, | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     let client_no_auth = RfsClient::new(config_no_auth); | ||||
|     println!("Client created without authentication credentials"); | ||||
|      | ||||
|  | ||||
|     // Check health endpoint (doesn't require authentication) | ||||
|     let health = client_no_auth.health_check().await?; | ||||
|     println!("Server health: {:?}", health); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| use sal_rfs_client::RfsClient; | ||||
| use sal_rfs_client::types::{ClientConfig, Credentials}; | ||||
| use openapi::models::{VerifyBlock, VerifyBlocksRequest}; | ||||
| use sal_rfs_client::types::{ClientConfig, Credentials}; | ||||
| use sal_rfs_client::RfsClient; | ||||
|  | ||||
| #[tokio::main] | ||||
| async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
| @@ -13,45 +13,52 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         }), | ||||
|         timeout_seconds: 60, | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     let mut client = RfsClient::new(config); | ||||
|      | ||||
|  | ||||
|     // Authenticate with the server | ||||
|     client.authenticate().await?; | ||||
|     println!("Authentication successful"); | ||||
|      | ||||
|  | ||||
|     // Create a test file to upload for block testing | ||||
|     let test_file_path = "/tmp/block_test.txt"; | ||||
|     let test_content = "This is a test file for RFS client block management"; | ||||
|     std::fs::write(test_file_path, test_content)?; | ||||
|     println!("Created test file at {}", test_file_path); | ||||
|      | ||||
|  | ||||
|     // Upload the file to get blocks | ||||
|     println!("Uploading file to get blocks..."); | ||||
|     let file_hash = client.upload_file(test_file_path, None).await?; | ||||
|     println!("File uploaded with hash: {}", file_hash); | ||||
|      | ||||
|  | ||||
|     // Get blocks by file hash | ||||
|     println!("Getting blocks for file hash: {}", file_hash); | ||||
|     let blocks = client.get_blocks_by_hash(&file_hash).await?; | ||||
|     println!("Found {} blocks for the file", blocks.blocks.len()); | ||||
|      | ||||
|  | ||||
|     // Print block information | ||||
|     for (i, block_data) in blocks.blocks.iter().enumerate() { | ||||
|         println!("Block {}: Hash={}, Index={}", i, block_data.hash, block_data.index); | ||||
|         println!( | ||||
|             "Block {}: Hash={}, Index={}", | ||||
|             i, block_data.hash, block_data.index | ||||
|         ); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     // Verify blocks with complete information | ||||
|     println!("Verifying blocks..."); | ||||
|      | ||||
|  | ||||
|     // Create a list of VerifyBlock objects with complete information | ||||
|     let verify_blocks = blocks.blocks.iter().map(|block| { | ||||
|         VerifyBlock { | ||||
|             block_hash: block.hash.clone(), | ||||
|             block_index: block.index, | ||||
|             file_hash: file_hash.clone(), // Using the actual file hash | ||||
|         } | ||||
|     }).collect::<Vec<_>>(); | ||||
|     let verify_blocks = blocks | ||||
|         .blocks | ||||
|         .iter() | ||||
|         .map(|block| { | ||||
|             VerifyBlock { | ||||
|                 block_hash: block.hash.clone(), | ||||
|                 block_index: block.index, | ||||
|                 file_hash: file_hash.clone(), // Using the actual file hash | ||||
|             } | ||||
|         }) | ||||
|         .collect::<Vec<_>>(); | ||||
|  | ||||
|     // Create the request with the complete block information | ||||
|     for block in verify_blocks.iter() { | ||||
| @@ -59,27 +66,34 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         println!("Block index: {}", block.block_index); | ||||
|         println!("File hash: {}", block.file_hash); | ||||
|     } | ||||
|     let request = VerifyBlocksRequest { blocks: verify_blocks }; | ||||
|      | ||||
|     let request = VerifyBlocksRequest { | ||||
|         blocks: verify_blocks, | ||||
|     }; | ||||
|  | ||||
|     // Send the verification request | ||||
|     let verify_result = client.verify_blocks(request).await?; | ||||
|     println!("Verification result: {} missing blocks", verify_result.missing.len()); | ||||
|     println!( | ||||
|         "Verification result: {} missing blocks", | ||||
|         verify_result.missing.len() | ||||
|     ); | ||||
|     for block in verify_result.missing.iter() { | ||||
|         println!("Missing block: {}", block); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     // List blocks (list_blocks_handler) | ||||
|     println!("\n1. Listing all blocks with pagination..."); | ||||
|     let blocks_list = client.list_blocks(None).await?; | ||||
|     println!("Server has {} blocks in total", blocks_list.len()); | ||||
|     if !blocks_list.is_empty() { | ||||
|         let first_few = blocks_list.iter().take(3) | ||||
|         let first_few = blocks_list | ||||
|             .iter() | ||||
|             .take(3) | ||||
|             .map(|s| s.as_str()) | ||||
|             .collect::<Vec<_>>() | ||||
|             .join(", "); | ||||
|         println!("First few blocks: {}", first_few); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     // Check if a block exists (check_block_handler) | ||||
|     if !blocks.blocks.is_empty() { | ||||
|         let block_to_check = &blocks.blocks[0].hash; | ||||
| @@ -87,15 +101,21 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         let exists = client.check_block(block_to_check).await?; | ||||
|         println!("Block exists: {}", exists); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     // Get block downloads statistics (get_block_downloads_handler) | ||||
|     if !blocks.blocks.is_empty() { | ||||
|         let block_to_check = &blocks.blocks[0].hash; | ||||
|         println!("\n3. Getting download statistics for block: {}", block_to_check); | ||||
|         println!( | ||||
|             "\n3. Getting download statistics for block: {}", | ||||
|             block_to_check | ||||
|         ); | ||||
|         let downloads = client.get_block_downloads(block_to_check).await?; | ||||
|         println!("Block has been downloaded {} times", downloads.downloads_count); | ||||
|         println!( | ||||
|             "Block has been downloaded {} times", | ||||
|             downloads.downloads_count | ||||
|         ); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     // Get a specific block content (get_block_handler) | ||||
|     if !blocks.blocks.is_empty() { | ||||
|         let block_to_get = &blocks.blocks[0].hash; | ||||
| @@ -103,26 +123,31 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         let block_content = client.get_block(block_to_get).await?; | ||||
|         println!("Retrieved block with {} bytes", block_content.len()); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     // Get user blocks (get_user_blocks_handler) | ||||
|     println!("\n6. Listing user blocks..."); | ||||
|     let user_blocks = client.get_user_blocks(Some(1), Some(10)).await?; | ||||
|     println!("User has {} blocks (showing page 1 with 10 per page)", user_blocks.total); | ||||
|     println!( | ||||
|         "User has {} blocks (showing page 1 with 10 per page)", | ||||
|         user_blocks.total | ||||
|     ); | ||||
|     for block in user_blocks.blocks.iter().take(3) { | ||||
|         println!("  - Block: {}, Size: {}", block.hash, block.size); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     // Upload a block (upload_block_handler) | ||||
|     println!("\n7. Uploading a new test block..."); | ||||
|     let test_block_data = b"This is test block data for direct block upload"; | ||||
|     let new_file_hash = "test_file_hash_for_block_upload"; | ||||
|     let block_index = 0; | ||||
|     let block_hash = client.upload_block(new_file_hash, block_index, test_block_data.to_vec()).await?; | ||||
|     let block_hash = client | ||||
|         .upload_block(new_file_hash, block_index, test_block_data.to_vec()) | ||||
|         .await?; | ||||
|     println!("Uploaded block with hash: {}", block_hash); | ||||
|      | ||||
|  | ||||
|     // Clean up | ||||
|     std::fs::remove_file(test_file_path)?; | ||||
|     println!("Test file cleaned up"); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| use sal_rfs_client::types::{ClientConfig, Credentials, DownloadOptions, UploadOptions}; | ||||
| use sal_rfs_client::RfsClient; | ||||
| use sal_rfs_client::types::{ClientConfig, Credentials, UploadOptions, DownloadOptions}; | ||||
|  | ||||
| #[tokio::main] | ||||
| async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
| @@ -12,53 +12,55 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         }), | ||||
|         timeout_seconds: 60, | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     let mut client = RfsClient::new(config); | ||||
|      | ||||
|  | ||||
|     // Authenticate with the server | ||||
|     client.authenticate().await?; | ||||
|     println!("Authentication successful"); | ||||
|      | ||||
|  | ||||
|     // Create a test file to upload | ||||
|     let test_file_path = "/tmp/test_upload.txt"; | ||||
|     std::fs::write(test_file_path, "This is a test file for RFS client upload")?; | ||||
|     println!("Created test file at {}", test_file_path); | ||||
|      | ||||
|  | ||||
|     // Upload the file with options | ||||
|     println!("Uploading file..."); | ||||
|     let upload_options = UploadOptions { | ||||
|         chunk_size: Some(1024 * 1024), // 1MB chunks | ||||
|         verify: true, | ||||
|     }; | ||||
|      | ||||
|     let file_hash = client.upload_file(test_file_path, Some(upload_options)).await?; | ||||
|  | ||||
|     let file_hash = client | ||||
|         .upload_file(test_file_path, Some(upload_options)) | ||||
|         .await?; | ||||
|     println!("File uploaded with hash: {}", file_hash); | ||||
|      | ||||
|  | ||||
|     // Download the file | ||||
|     let download_path = "/tmp/test_download.txt"; | ||||
|     println!("Downloading file to {}...", download_path); | ||||
|      | ||||
|     let download_options = DownloadOptions { | ||||
|         verify: true, | ||||
|     }; | ||||
|      | ||||
|     client.download_file(&file_hash, download_path, Some(download_options)).await?; | ||||
|  | ||||
|     let download_options = DownloadOptions { verify: true }; | ||||
|  | ||||
|     client | ||||
|         .download_file(&file_hash, download_path, Some(download_options)) | ||||
|         .await?; | ||||
|     println!("File downloaded to {}", download_path); | ||||
|      | ||||
|  | ||||
|     // Verify the downloaded file matches the original | ||||
|     let original_content = std::fs::read_to_string(test_file_path)?; | ||||
|     let downloaded_content = std::fs::read_to_string(download_path)?; | ||||
|      | ||||
|  | ||||
|     if original_content == downloaded_content { | ||||
|         println!("File contents match! Download successful."); | ||||
|     } else { | ||||
|         println!("ERROR: File contents do not match!"); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     // Clean up test files | ||||
|     std::fs::remove_file(test_file_path)?; | ||||
|     std::fs::remove_file(download_path)?; | ||||
|     println!("Test files cleaned up"); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| use sal_rfs_client::RfsClient; | ||||
| use sal_rfs_client::types::{ClientConfig, Credentials, FlistOptions, WaitOptions}; | ||||
| use sal_rfs_client::RfsClient; | ||||
|  | ||||
| #[tokio::main] | ||||
| async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
| @@ -13,17 +13,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         }), | ||||
|         timeout_seconds: 60, | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     let mut client = RfsClient::new(config); | ||||
|      | ||||
|  | ||||
|     // Authenticate with the server | ||||
|     client.authenticate().await?; | ||||
|     println!("Authentication successful"); | ||||
|      | ||||
|  | ||||
|     println!("\n1. CREATE FLIST - Creating an FList from a Docker image"); | ||||
|     let image_name = "alpine:latest"; | ||||
|     println!("Creating FList for image: {}", image_name); | ||||
|      | ||||
|  | ||||
|     // Use FlistOptions to specify additional parameters | ||||
|     let options = FlistOptions { | ||||
|         auth: None, | ||||
| @@ -34,13 +34,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         identity_token: None, | ||||
|         registry_token: None, | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     // Create the FList and handle potential conflict error | ||||
|     let job_id = match client.create_flist(&image_name, Some(options)).await { | ||||
|         Ok(id) => { | ||||
|             println!("FList creation started with job ID: {}", id); | ||||
|             Some(id) | ||||
|         }, | ||||
|         } | ||||
|         Err(e) => { | ||||
|             if e.to_string().contains("Conflict") { | ||||
|                 println!("FList already exists"); | ||||
| @@ -50,51 +50,55 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     // 2. Check FList state if we have a job ID | ||||
|     if let Some(job_id) = &job_id { | ||||
|         println!("\n2. GET FLIST STATE - Checking FList creation state"); | ||||
|         let state = client.get_flist_state(job_id).await?; | ||||
|         println!("Current FList state: {:?}", state.flist_state); | ||||
|          | ||||
|  | ||||
|         // 3. Wait for FList creation with progress reporting | ||||
|         println!("\n3. WAIT FOR FLIST CREATION - Waiting for FList to be created with progress reporting"); | ||||
|         let wait_options = WaitOptions { | ||||
|             timeout_seconds: 60,  // Shorter timeout for the example | ||||
|             timeout_seconds: 60, // Shorter timeout for the example | ||||
|             poll_interval_ms: 1000, | ||||
|             progress_callback: Some(Box::new(|state| { | ||||
|                 println!("Progress: FList state is now {:?}", state); | ||||
|                 // No return value needed (returns unit type) | ||||
|             })), | ||||
|         }; | ||||
|          | ||||
|  | ||||
|         // Wait for the FList to be created (with a timeout) | ||||
|         match client.wait_for_flist_creation(job_id, Some(wait_options)).await { | ||||
|         match client | ||||
|             .wait_for_flist_creation(job_id, Some(wait_options)) | ||||
|             .await | ||||
|         { | ||||
|             Ok(final_state) => { | ||||
|                 println!("FList creation completed with state: {:?}", final_state); | ||||
|             }, | ||||
|             } | ||||
|             Err(e) => { | ||||
|                 println!("Error waiting for FList creation: {}", e); | ||||
|                 // Continue with the example even if waiting fails | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     // 4. List all available FLists | ||||
|     println!("\n4. LIST FLISTS - Listing all available FLists"); | ||||
|      | ||||
|  | ||||
|     // Variable to store the FList path for preview and download | ||||
|     let mut flist_path_for_preview: Option<String> = None; | ||||
|      | ||||
|  | ||||
|     match client.list_flists().await { | ||||
|         Ok(flists) => { | ||||
|             println!("Found {} FList categories", flists.len()); | ||||
|              | ||||
|  | ||||
|             for (category, files) in &flists { | ||||
|                 println!("Category: {}", category); | ||||
|                 for file in files.iter().take(2) { // Show only first 2 files per category | ||||
|                 for file in files.iter().take(2) { | ||||
|                     // Show only first 2 files per category | ||||
|                     println!("  - {} (size: {} bytes)", file.name, file.size); | ||||
|                      | ||||
|  | ||||
|                     // Save the first FList path for preview | ||||
|                     if flist_path_for_preview.is_none() { | ||||
|                         let path = format!("{}/{}/{}", parent_dir, category, file.name); | ||||
| @@ -105,7 +109,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|                     println!("  - ... and {} more files", files.len() - 2); | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|  | ||||
|             // 5. Preview an FList if we found one | ||||
|             if let Some(ref flist_path) = flist_path_for_preview { | ||||
|                 println!("\n5. PREVIEW FLIST - Previewing FList: {}", flist_path); | ||||
| @@ -114,57 +118,59 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|                         println!("FList preview for {}:", flist_path); | ||||
|                         println!("  - Checksum: {}", preview.checksum); | ||||
|                         println!("  - Metadata: {}", preview.metadata); | ||||
|                          | ||||
|  | ||||
|                         // Display content (list of strings) | ||||
|                         if !preview.content.is_empty() { | ||||
|                             println!("  - Content entries:"); | ||||
|                             for (i, entry) in preview.content.iter().enumerate().take(5) { | ||||
|                                 println!("    {}. {}", i+1, entry); | ||||
|                                 println!("    {}. {}", i + 1, entry); | ||||
|                             } | ||||
|                             if preview.content.len() > 5 { | ||||
|                                 println!("    ... and {} more entries", preview.content.len() - 5); | ||||
|                             } | ||||
|                         } | ||||
|                     }, | ||||
|                     } | ||||
|                     Err(e) => println!("Error previewing FList: {}", e), | ||||
|                 } | ||||
|             } else { | ||||
|                 println!("No FLists available for preview"); | ||||
|             } | ||||
|         }, | ||||
|         } | ||||
|         Err(e) => println!("Error listing FLists: {}", e), | ||||
|     } | ||||
|      | ||||
|  | ||||
|     // 6. DOWNLOAD FLIST - Downloading an FList to a local file | ||||
|     if let Some(ref flist_path) = flist_path_for_preview { | ||||
|         println!("\n6. DOWNLOAD FLIST - Downloading FList: {}", flist_path); | ||||
|          | ||||
|  | ||||
|         // Create a temporary output path for the downloaded FList | ||||
|         let output_path = "/tmp/downloaded_flist.fl"; | ||||
|          | ||||
|  | ||||
|         match client.download_flist(flist_path, output_path).await { | ||||
|             Ok(_) => { | ||||
|                 println!("FList successfully downloaded to {}", output_path); | ||||
|                  | ||||
|  | ||||
|                 // Get file size | ||||
|                 match std::fs::metadata(output_path) { | ||||
|                     Ok(metadata) => println!("Downloaded file size: {} bytes", metadata.len()), | ||||
|                     Err(e) => println!("Error getting file metadata: {}", e), | ||||
|                 } | ||||
|             }, | ||||
|             } | ||||
|             Err(e) => println!("Error downloading FList: {}", e), | ||||
|         } | ||||
|     } else { | ||||
|         println!("\n6. DOWNLOAD FLIST - No FList available for download"); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     println!("\nAll FList operations demonstrated:"); | ||||
|     println!("1. create_flist - Create a new FList from a Docker image"); | ||||
|     println!("2. get_flist_state - Check the state of an FList creation job"); | ||||
|     println!("3. wait_for_flist_creation - Wait for an FList to be created with progress reporting"); | ||||
|     println!( | ||||
|         "3. wait_for_flist_creation - Wait for an FList to be created with progress reporting" | ||||
|     ); | ||||
|     println!("4. list_flists - List all available FLists"); | ||||
|     println!("5. preview_flist - Preview the content of an FList"); | ||||
|     println!("6. download_flist - Download an FList to a local file"); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| use sal_rfs_client::RfsClient; | ||||
| use sal_rfs_client::types::{ClientConfig, Credentials, WaitOptions}; | ||||
| use openapi::models::FlistState; | ||||
| use sal_rfs_client::types::{ClientConfig, Credentials, WaitOptions}; | ||||
| use sal_rfs_client::RfsClient; | ||||
|  | ||||
| #[tokio::main] | ||||
| async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
| @@ -13,49 +13,52 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         }), | ||||
|         timeout_seconds: 60, | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     let mut client = RfsClient::new(config); | ||||
|      | ||||
|  | ||||
|     // Authenticate with the server | ||||
|     client.authenticate().await?; | ||||
|     println!("Authentication successful"); | ||||
|      | ||||
|  | ||||
|     // Create an FList from a Docker image | ||||
|     let image_name = "redis:latest"; | ||||
|     println!("Creating FList for image: {}", image_name); | ||||
|      | ||||
|  | ||||
|     let job_id = client.create_flist(&image_name, None).await?; | ||||
|     println!("FList creation started with job ID: {}", job_id); | ||||
|      | ||||
|  | ||||
|     // Set up options for waiting with progress reporting | ||||
|     let options = WaitOptions { | ||||
|         timeout_seconds: 600,  // 10 minutes timeout | ||||
|         timeout_seconds: 600,   // 10 minutes timeout | ||||
|         poll_interval_ms: 2000, // Check every 2 seconds | ||||
|         progress_callback: Some(Box::new(|state| { | ||||
|             match state { | ||||
|                 FlistState::FlistStateInProgress(info) => { | ||||
|                     println!("Progress: {:.1}% - {}", info.in_progress.progress, info.in_progress.msg); | ||||
|                 }, | ||||
|                 FlistState::FlistStateStarted(_) => { | ||||
|                     println!("FList creation started..."); | ||||
|                 }, | ||||
|                 FlistState::FlistStateAccepted(_) => { | ||||
|                     println!("FList creation request accepted..."); | ||||
|                 }, | ||||
|                 _ => println!("State: {:?}", state), | ||||
|         progress_callback: Some(Box::new(|state| match state { | ||||
|             FlistState::FlistStateInProgress(info) => { | ||||
|                 println!( | ||||
|                     "Progress: {:.1}% - {}", | ||||
|                     info.in_progress.progress, info.in_progress.msg | ||||
|                 ); | ||||
|             } | ||||
|             FlistState::FlistStateStarted(_) => { | ||||
|                 println!("FList creation started..."); | ||||
|             } | ||||
|             FlistState::FlistStateAccepted(_) => { | ||||
|                 println!("FList creation request accepted..."); | ||||
|             } | ||||
|             _ => println!("State: {:?}", state), | ||||
|         })), | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     // Wait for the FList to be created | ||||
|     println!("Waiting for FList creation to complete..."); | ||||
|      | ||||
|  | ||||
|     // Use ? operator to propagate errors properly | ||||
|     let state = client.wait_for_flist_creation(&job_id, Some(options)).await | ||||
|     let state = client | ||||
|         .wait_for_flist_creation(&job_id, Some(options)) | ||||
|         .await | ||||
|         .map_err(|e| -> Box<dyn std::error::Error> { Box::new(e) })?; | ||||
|      | ||||
|  | ||||
|     println!("FList created successfully!"); | ||||
|     println!("Final state: {:?}", state); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|   | ||||
| @@ -1,24 +1,23 @@ | ||||
| use bytes::Bytes; | ||||
| use std::collections::HashMap; | ||||
| use std::path::Path; | ||||
| use std::sync::Arc; | ||||
| use std::collections::HashMap; | ||||
| use bytes::Bytes; | ||||
|  | ||||
| use openapi::{ | ||||
|     apis::{ | ||||
|         authentication_api, block_management_api, flist_management_api, | ||||
|         file_management_api, system_api, website_serving_api, | ||||
|         configuration::Configuration, | ||||
|         authentication_api, block_management_api, configuration::Configuration, | ||||
|         file_management_api, flist_management_api, system_api, website_serving_api, | ||||
|         Error as OpenApiError, | ||||
|     }, | ||||
|     models::{ | ||||
|         SignInBody, ListBlocksParams, | ||||
|         VerifyBlocksRequest, VerifyBlocksResponse, FlistBody, UserBlocksResponse, BlockDownloadsResponse, | ||||
|         BlocksResponse, PreviewResponse, FileInfo, FlistState, FlistStateResponse, | ||||
|         BlockDownloadsResponse, BlocksResponse, FileInfo, FlistBody, FlistState, | ||||
|         FlistStateResponse, ListBlocksParams, PreviewResponse, SignInBody, UserBlocksResponse, | ||||
|         VerifyBlocksRequest, VerifyBlocksResponse, | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| use crate::error::{RfsError, Result, map_openapi_error}; | ||||
| use crate::types::{ClientConfig, UploadOptions, DownloadOptions, FlistOptions, WaitOptions}; | ||||
| use crate::error::{map_openapi_error, Result, RfsError}; | ||||
| use crate::types::{ClientConfig, DownloadOptions, FlistOptions, UploadOptions, WaitOptions}; | ||||
|  | ||||
| /// Main client for interacting with the RFS server | ||||
| #[derive(Clone)] | ||||
| @@ -33,16 +32,18 @@ impl RfsClient { | ||||
|     pub fn new(client_config: ClientConfig) -> Self { | ||||
|         // Create a custom reqwest client with timeout configuration | ||||
|         let client = reqwest::Client::builder() | ||||
|             .timeout(std::time::Duration::from_secs(client_config.timeout_seconds)) | ||||
|             .timeout(std::time::Duration::from_secs( | ||||
|                 client_config.timeout_seconds, | ||||
|             )) | ||||
|             .build() | ||||
|             .unwrap_or_default(); | ||||
|          | ||||
|  | ||||
|         // Create OpenAPI configuration with our custom client | ||||
|         let mut config = Configuration::new(); | ||||
|         config.base_path = client_config.base_url.clone(); | ||||
|         config.user_agent = Some(format!("rfs-client/0.1.0")); | ||||
|         config.user_agent = Some("rfs-client/0.1.0".to_string()); | ||||
|         config.client = client; | ||||
|          | ||||
|  | ||||
|         Self { | ||||
|             config: Arc::new(config), | ||||
|             client_config, | ||||
| @@ -70,22 +71,26 @@ impl RfsClient { | ||||
|             if let Some(token) = Some(result.access_token) { | ||||
|                 // Create a custom reqwest client with timeout configuration | ||||
|                 let client = reqwest::Client::builder() | ||||
|                     .timeout(std::time::Duration::from_secs(self.client_config.timeout_seconds)) | ||||
|                     .timeout(std::time::Duration::from_secs( | ||||
|                         self.client_config.timeout_seconds, | ||||
|                     )) | ||||
|                     .build() | ||||
|                     .unwrap_or_default(); | ||||
|                  | ||||
|  | ||||
|                 // Create a new configuration with the auth token and timeout | ||||
|                 let mut new_config = Configuration::new(); | ||||
|                 new_config.base_path = self.client_config.base_url.clone(); | ||||
|                 new_config.user_agent = Some(format!("rfs-client/0.1.0")); | ||||
|                 new_config.user_agent = Some("rfs-client/0.1.0".to_string()); | ||||
|                 new_config.bearer_access_token = Some(token.clone()); | ||||
|                 new_config.client = client; | ||||
|                  | ||||
|  | ||||
|                 self.config = Arc::new(new_config); | ||||
|                 self.auth_token = Some(token); | ||||
|                 Ok(()) | ||||
|             } else { | ||||
|                 Err(RfsError::AuthError("No token received from server".to_string())) | ||||
|                 Err(RfsError::AuthError( | ||||
|                     "No token received from server".to_string(), | ||||
|                 )) | ||||
|             } | ||||
|         } else { | ||||
|             Err(RfsError::AuthError("No credentials provided".to_string())) | ||||
| @@ -102,62 +107,79 @@ impl RfsClient { | ||||
|         let result = system_api::health_check_handler(&self.config) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         Ok(result.msg) | ||||
|     } | ||||
|  | ||||
|     /// Upload a file to the RFS server | ||||
|     pub async fn upload_file<P: AsRef<Path>>(&self, file_path: P, options: Option<UploadOptions>) -> Result<String> { | ||||
|     pub async fn upload_file<P: AsRef<Path>>( | ||||
|         &self, | ||||
|         file_path: P, | ||||
|         options: Option<UploadOptions>, | ||||
|     ) -> Result<String> { | ||||
|         let file_path = file_path.as_ref(); | ||||
|         let _options = options.unwrap_or_default(); | ||||
|          | ||||
|  | ||||
|         // Check if file exists | ||||
|         if !file_path.exists() { | ||||
|             return Err(RfsError::FileSystemError(format!("File not found: {}", file_path.display()))); | ||||
|             return Err(RfsError::FileSystemError(format!( | ||||
|                 "File not found: {}", | ||||
|                 file_path.display() | ||||
|             ))); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         // Use the OpenAPI client to upload the file | ||||
|         let result = file_management_api::upload_file_handler(&self.config, file_path.to_path_buf()) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|         let result = | ||||
|             file_management_api::upload_file_handler(&self.config, file_path.to_path_buf()) | ||||
|                 .await | ||||
|                 .map_err(map_openapi_error)?; | ||||
|  | ||||
|         // Extract the file hash from the response | ||||
|         Ok(result.file_hash.clone()) | ||||
|     } | ||||
|  | ||||
|     /// Download a file from the RFS server | ||||
|     pub async fn download_file<P: AsRef<Path>>(&self, file_id: &str, output_path: P, options: Option<DownloadOptions>) -> Result<()> { | ||||
|     pub async fn download_file<P: AsRef<Path>>( | ||||
|         &self, | ||||
|         file_id: &str, | ||||
|         output_path: P, | ||||
|         options: Option<DownloadOptions>, | ||||
|     ) -> Result<()> { | ||||
|         let output_path = output_path.as_ref(); | ||||
|         let _options = options.unwrap_or_default(); | ||||
|          | ||||
|  | ||||
|         // Create parent directories if needed | ||||
|         if let Some(parent) = output_path.parent() { | ||||
|             std::fs::create_dir_all(parent) | ||||
|                 .map_err(|e| RfsError::FileSystemError(format!("Failed to create directory: {}", e)))?; | ||||
|             std::fs::create_dir_all(parent).map_err(|e| { | ||||
|                 RfsError::FileSystemError(format!("Failed to create directory: {}", e)) | ||||
|             })?; | ||||
|         } | ||||
|          | ||||
|  | ||||
|         // Create a FileDownloadRequest with the filename from the output path | ||||
|         let file_name = output_path.file_name() | ||||
|         let file_name = output_path | ||||
|             .file_name() | ||||
|             .and_then(|n| n.to_str()) | ||||
|             .unwrap_or("downloaded_file") | ||||
|             .to_string(); | ||||
|              | ||||
|  | ||||
|         let download_request = openapi::models::FileDownloadRequest::new(file_name); | ||||
|          | ||||
|  | ||||
|         // Download the file | ||||
|         let response = file_management_api::get_file_handler(&self.config, file_id, download_request) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|         let response = | ||||
|             file_management_api::get_file_handler(&self.config, file_id, download_request) | ||||
|                 .await | ||||
|                 .map_err(map_openapi_error)?; | ||||
|  | ||||
|         // Read the response body | ||||
|         let bytes = response.bytes() | ||||
|         let bytes = response | ||||
|             .bytes() | ||||
|             .await | ||||
|             .map_err(|e| RfsError::RequestError(e))?; | ||||
|          | ||||
|             .map_err(RfsError::RequestError)?; | ||||
|  | ||||
|         // Write the file to disk | ||||
|         std::fs::write(output_path, bytes) | ||||
|             .map_err(|e| RfsError::FileSystemError(format!("Failed to write file: {}", e)))?; | ||||
|          | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @@ -168,29 +190,38 @@ impl RfsClient { | ||||
|         let result = block_management_api::list_blocks_handler(&self.config, page, per_page) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         Ok(result.blocks) | ||||
|     } | ||||
|  | ||||
|     /// Verify blocks | ||||
|     pub async fn verify_blocks(&self, request: VerifyBlocksRequest) -> Result<VerifyBlocksResponse> { | ||||
|     pub async fn verify_blocks( | ||||
|         &self, | ||||
|         request: VerifyBlocksRequest, | ||||
|     ) -> Result<VerifyBlocksResponse> { | ||||
|         let result = block_management_api::verify_blocks_handler(&self.config, request) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         Ok(result) | ||||
|     } | ||||
|  | ||||
|     /// Create a new FList from a Docker image | ||||
|     pub async fn create_flist(&self, image_name: &str, options: Option<FlistOptions>) -> Result<String> { | ||||
|     pub async fn create_flist( | ||||
|         &self, | ||||
|         image_name: &str, | ||||
|         options: Option<FlistOptions>, | ||||
|     ) -> Result<String> { | ||||
|         // Ensure the client is authenticated | ||||
|         if !self.is_authenticated() { | ||||
|             return Err(RfsError::AuthError("Authentication required for creating FLists".to_string())); | ||||
|             return Err(RfsError::AuthError( | ||||
|                 "Authentication required for creating FLists".to_string(), | ||||
|             )); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         // Create FList body with the required fields | ||||
|         let mut flist = FlistBody::new(image_name.to_string()); | ||||
|          | ||||
|  | ||||
|         // Apply options if provided | ||||
|         if let Some(opts) = options { | ||||
|             flist.username = opts.username.map(Some); | ||||
| @@ -201,12 +232,12 @@ impl RfsClient { | ||||
|             flist.identity_token = opts.identity_token.map(Some); | ||||
|             flist.registry_token = opts.registry_token.map(Some); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         // Call the API to create the FList | ||||
|         let result = flist_management_api::create_flist_handler(&self.config, flist) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         // Return the job ID | ||||
|         Ok(result.id) | ||||
|     } | ||||
| @@ -215,66 +246,80 @@ impl RfsClient { | ||||
|     pub async fn get_flist_state(&self, job_id: &str) -> Result<FlistStateResponse> { | ||||
|         // Ensure the client is authenticated | ||||
|         if !self.is_authenticated() { | ||||
|             return Err(RfsError::AuthError("Authentication required for accessing FList state".to_string())); | ||||
|             return Err(RfsError::AuthError( | ||||
|                 "Authentication required for accessing FList state".to_string(), | ||||
|             )); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         // Call the API to get the FList state | ||||
|         let result = flist_management_api::get_flist_state_handler(&self.config, job_id) | ||||
|                 .await | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         Ok(result) | ||||
|     } | ||||
|      | ||||
|  | ||||
|     /// Wait for an FList to be created | ||||
|     ///  | ||||
|     /// | ||||
|     /// This method polls the FList state until it reaches a terminal state (Created or Failed) | ||||
|     /// or until the timeout is reached. | ||||
|     pub async fn wait_for_flist_creation(&self, job_id: &str, options: Option<WaitOptions>) -> Result<FlistStateResponse> { | ||||
|     pub async fn wait_for_flist_creation( | ||||
|         &self, | ||||
|         job_id: &str, | ||||
|         options: Option<WaitOptions>, | ||||
|     ) -> Result<FlistStateResponse> { | ||||
|         let options = options.unwrap_or_default(); | ||||
|         let deadline = std::time::Instant::now() + std::time::Duration::from_secs(options.timeout_seconds); | ||||
|          | ||||
|         let deadline = | ||||
|             std::time::Instant::now() + std::time::Duration::from_secs(options.timeout_seconds); | ||||
|  | ||||
|         loop { | ||||
|             // Check if we've exceeded the timeout | ||||
|             if std::time::Instant::now() > deadline { | ||||
|                 return Err(RfsError::TimeoutError(format!( | ||||
|                     "Timed out waiting for FList creation after {} seconds",  | ||||
|                     "Timed out waiting for FList creation after {} seconds", | ||||
|                     options.timeout_seconds | ||||
|                 ))); | ||||
|             } | ||||
|              | ||||
|  | ||||
|             // Get the current state | ||||
|             let state_result = self.get_flist_state(job_id).await; | ||||
|              | ||||
|  | ||||
|             match state_result { | ||||
|                 Ok(state) => { | ||||
|                     // Call progress callback if provided | ||||
|                     if let Some(ref callback) = options.progress_callback { | ||||
|                         callback(state.flist_state.as_ref()); | ||||
|                     } | ||||
|                      | ||||
|  | ||||
|                     // Check if we've reached a terminal state | ||||
|                     match state.flist_state.as_ref() { | ||||
|                         FlistState::FlistStateCreated(_) => { | ||||
|                             // Success! FList was created | ||||
|                             return Ok(state); | ||||
|                         }, | ||||
|                         } | ||||
|                         FlistState::FlistStateFailed(error_msg) => { | ||||
|                             // Failure! FList creation failed | ||||
|                             return Err(RfsError::FListError(format!("FList creation failed: {}", error_msg))); | ||||
|                         }, | ||||
|                             return Err(RfsError::FListError(format!( | ||||
|                                 "FList creation failed: {}", | ||||
|                                 error_msg | ||||
|                             ))); | ||||
|                         } | ||||
|                         _ => { | ||||
|                             // Still in progress, continue polling | ||||
|                             tokio::time::sleep(std::time::Duration::from_millis(options.poll_interval_ms)).await; | ||||
|                             tokio::time::sleep(std::time::Duration::from_millis( | ||||
|                                 options.poll_interval_ms, | ||||
|                             )) | ||||
|                             .await; | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|                 } | ||||
|                 Err(e) => { | ||||
|                     // If we get a 404 error, it might be because the FList job is still initializing | ||||
|                     // Just wait and retry | ||||
|                     println!("Warning: Error checking FList state: {}", e); | ||||
|                     println!("Retrying in {} ms...", options.poll_interval_ms); | ||||
|                     tokio::time::sleep(std::time::Duration::from_millis(options.poll_interval_ms)).await; | ||||
|                     tokio::time::sleep(std::time::Duration::from_millis(options.poll_interval_ms)) | ||||
|                         .await; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -294,7 +339,7 @@ impl RfsClient { | ||||
|         let result = block_management_api::get_block_downloads_handler(&self.config, hash) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         Ok(result) | ||||
|     } | ||||
|  | ||||
| @@ -303,10 +348,12 @@ impl RfsClient { | ||||
|         let response = block_management_api::get_block_handler(&self.config, hash) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|         let bytes = response.bytes().await | ||||
|             .map_err(|e| RfsError::RequestError(e))?; | ||||
|          | ||||
|  | ||||
|         let bytes = response | ||||
|             .bytes() | ||||
|             .await | ||||
|             .map_err(RfsError::RequestError)?; | ||||
|  | ||||
|         Ok(bytes) | ||||
|     } | ||||
|  | ||||
| @@ -315,16 +362,20 @@ impl RfsClient { | ||||
|         let result = block_management_api::get_blocks_by_hash_handler(&self.config, hash) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         Ok(result) | ||||
|     } | ||||
|  | ||||
|     /// Get blocks uploaded by the current user | ||||
|     pub async fn get_user_blocks(&self, page: Option<i32>, per_page: Option<i32>) -> Result<UserBlocksResponse> { | ||||
|     pub async fn get_user_blocks( | ||||
|         &self, | ||||
|         page: Option<i32>, | ||||
|         per_page: Option<i32>, | ||||
|     ) -> Result<UserBlocksResponse> { | ||||
|         let result = block_management_api::get_user_blocks_handler(&self.config, page, per_page) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         Ok(result) | ||||
|     } | ||||
|  | ||||
| @@ -333,11 +384,12 @@ impl RfsClient { | ||||
|         // Create a temporary file to hold the block data | ||||
|         let temp_dir = std::env::temp_dir(); | ||||
|         let temp_file_path = temp_dir.join(format!("{}-{}", file_hash, idx)); | ||||
|          | ||||
|  | ||||
|         // Write the data to the temporary file | ||||
|         std::fs::write(&temp_file_path, &data) | ||||
|             .map_err(|e| RfsError::FileSystemError(format!("Failed to write temporary block file: {}", e)))?; | ||||
|          | ||||
|         std::fs::write(&temp_file_path, &data).map_err(|e| { | ||||
|             RfsError::FileSystemError(format!("Failed to write temporary block file: {}", e)) | ||||
|         })?; | ||||
|  | ||||
|         // Upload the block | ||||
|         let result = block_management_api::upload_block_handler( | ||||
|             &self.config, | ||||
| @@ -347,12 +399,12 @@ impl RfsClient { | ||||
|         ) | ||||
|         .await | ||||
|         .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         // Clean up the temporary file | ||||
|         if let Err(e) = std::fs::remove_file(temp_file_path) { | ||||
|             eprintln!("Warning: Failed to remove temporary block file: {}", e); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         // Return the hash from the response | ||||
|         Ok(result.hash) | ||||
|     } | ||||
| @@ -362,7 +414,7 @@ impl RfsClient { | ||||
|         let result = flist_management_api::list_flists_handler(&self.config) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         Ok(result) | ||||
|     } | ||||
|  | ||||
| @@ -371,7 +423,7 @@ impl RfsClient { | ||||
|         let result = flist_management_api::preview_flist_handler(&self.config, flist_path) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         Ok(result) | ||||
|     } | ||||
|  | ||||
| @@ -380,7 +432,7 @@ impl RfsClient { | ||||
|         let result = website_serving_api::serve_website_handler(&self.config, website_id, path) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         Ok(result) | ||||
|     } | ||||
|  | ||||
| @@ -389,25 +441,30 @@ impl RfsClient { | ||||
|         let result = system_api::health_check_handler(&self.config) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|  | ||||
|         Ok(result.msg) | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// Download an FList file | ||||
|     ///  | ||||
|     /// | ||||
|     /// This method downloads an FList from the server and saves it to the specified path. | ||||
|     pub async fn download_flist<P: AsRef<Path>>(&self, flist_path: &str, output_path: P) -> Result<()> { | ||||
|     pub async fn download_flist<P: AsRef<Path>>( | ||||
|         &self, | ||||
|         flist_path: &str, | ||||
|         output_path: P, | ||||
|     ) -> Result<()> { | ||||
|         let response = flist_management_api::serve_flists(&self.config, flist_path) | ||||
|             .await | ||||
|             .map_err(map_openapi_error)?; | ||||
|          | ||||
|         let bytes = response.bytes().await | ||||
|             .map_err(|e| RfsError::RequestError(e))?; | ||||
|          | ||||
|  | ||||
|         let bytes = response | ||||
|             .bytes() | ||||
|             .await | ||||
|             .map_err(RfsError::RequestError)?; | ||||
|  | ||||
|         std::fs::write(output_path, &bytes) | ||||
|             .map_err(|e| RfsError::FileSystemError(e.to_string()))?; | ||||
|          | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										153
									
								
								packages/clients/rfsclient/src/diff.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								packages/clients/rfsclient/src/diff.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | ||||
| diff --git a/packages/clients/rfsclient/src/rhai.rs b/packages/clients/rfsclient/src/rhai.rs | ||||
| index fd686ba..b19c50f 100644 | ||||
| --- a/packages/clients/rfsclient/src/rhai.rs | ||||
| +++ b/packages/clients/rfsclient/src/rhai.rs | ||||
| @@ -17,6 +17,14 @@ lazy_static! { | ||||
|      static ref RUNTIME: Mutex<Option<Runtime>> = Mutex::new(None); | ||||
|  } | ||||
|   | ||||
| +/// Overload: list blocks with explicit pagination integers | ||||
| +fn rfs_list_blocks_with_pagination( | ||||
| +    page: rhai::INT, | ||||
| +    per_page: rhai::INT, | ||||
| +) -> Result<String, Box<EvalAltResult>> { | ||||
| +    rfs_list_blocks(Some(page), Some(per_page)) | ||||
| +} | ||||
| + | ||||
|  /// Wrapper around RfsClient to make it thread-safe for global usage | ||||
|  struct RfsClientWrapper { | ||||
|      client: Mutex<RfsClient>, | ||||
| @@ -47,6 +55,8 @@ pub fn register_rfs_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult> | ||||
|       | ||||
|      // Register block management functions | ||||
|      engine.register_fn("rfs_list_blocks", rfs_list_blocks); | ||||
| +    // Overload accepting explicit integer pagination params | ||||
| +    engine.register_fn("rfs_list_blocks", rfs_list_blocks_with_pagination); | ||||
|      engine.register_fn("rfs_upload_block", rfs_upload_block); | ||||
|      engine.register_fn("rfs_check_block", rfs_check_block); | ||||
|      engine.register_fn("rfs_get_block_downloads", rfs_get_block_downloads); | ||||
| diff --git a/packages/clients/rfsclient/tests/rhai_integration_tests.rs b/packages/clients/rfsclient/tests/rhai_integration_tests.rs | ||||
| index 2c90001..cc38f4a 100644 | ||||
| --- a/packages/clients/rfsclient/tests/rhai_integration_tests.rs | ||||
| +++ b/packages/clients/rfsclient/tests/rhai_integration_tests.rs | ||||
| @@ -114,8 +114,7 @@ fn test_rfs_flist_management_integration() { | ||||
|          Err(e) => { | ||||
|              let error_msg = e.to_string(); | ||||
|              println!("FList preview error: {}", error_msg); | ||||
| -             | ||||
| -            // Check if it's an authentication error (shouldn't happen with valid creds) | ||||
| +            // Authentication should not fail in this integration test | ||||
|              if error_msg.contains("Authentication") { | ||||
|                  panic!("❌ Authentication should work with valid credentials: {}", error_msg); | ||||
|              } else { | ||||
| @@ -141,6 +140,7 @@ fn test_rfs_create_flist_integration() { | ||||
|      let create_script = format!(r#" | ||||
|          rfs_create_client("{}", "{}", "{}", 30); | ||||
|          rfs_authenticate(); | ||||
| +        if !rfs_is_authenticated() {{ throw "Not authenticated after rfs_authenticate()"; }} | ||||
|          rfs_create_flist("busybox:latest", "docker.io", "", "") | ||||
|      "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD); | ||||
|       | ||||
| @@ -466,10 +466,10 @@ fn test_rfs_list_blocks_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|       | ||||
|      let result: bool = engine.eval(&create_script)?; | ||||
|      assert!(result, "Failed to create RFS client"); | ||||
| -    // Test listing blocks with default pagination - using optional parameters | ||||
| +    // Test listing blocks with explicit pagination parameters | ||||
|      let list_script = r#" | ||||
| -        let result = rfs_list_blocks(); | ||||
| -        if typeof(result) != "string" { | ||||
| +        let result = rfs_list_blocks(1, 50); | ||||
| +        if result.type_of() != "string" { | ||||
|              throw "Expected string result "; | ||||
|          } | ||||
|          true | ||||
| @@ -506,7 +506,7 @@ fn test_rfs_download_block_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|      let download_script = format!( | ||||
|          r#" | ||||
|          let result = rfs_download_block("test_block_hash", '{}', false); | ||||
| -        if typeof(result) != "string" {{ | ||||
| +        if result.type_of() != "string" {{ | ||||
|              throw "Expected string result"; | ||||
|          }} | ||||
|          true | ||||
| @@ -540,9 +540,9 @@ fn test_rfs_verify_blocks_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|       | ||||
|      // Test verifying blocks with a test hash | ||||
|      let verify_script = r#" | ||||
| -        let hashes = '["test_block_hash"]'; | ||||
| +        let hashes = "[\"test_block_hash\"]"; | ||||
|          let result = rfs_verify_blocks(hashes); | ||||
| -        if typeof(result) != "string" { | ||||
| +        if result.type_of() != "string" { | ||||
|              throw "Expected string result"; | ||||
|          } | ||||
|          true | ||||
| @@ -574,16 +574,29 @@ fn test_rfs_get_block_info_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|      // Test getting block info with a test hash | ||||
|      let info_script = r#" | ||||
|          let result = rfs_get_blocks_by_hash("test_block_hash"); | ||||
| -        if typeof(result) != "string" { | ||||
| +        if result.type_of() != "string" { | ||||
|              throw "Expected string result"; | ||||
|          } | ||||
|          true | ||||
|      "#; | ||||
|       | ||||
| -    let result: bool = engine.eval(info_script)?; | ||||
| -    assert!(result, "Failed to get block info"); | ||||
| -     | ||||
| -    Ok(()) | ||||
| +    match engine.eval::<bool>(info_script) { | ||||
| +        Ok(result) => { | ||||
| +            assert!(result, "Failed to get block info"); | ||||
| +            Ok(()) | ||||
| +        } | ||||
| +        Err(e) => { | ||||
| +            let error_msg = e.to_string(); | ||||
| +            println!("Block info error (may be expected): {}", error_msg); | ||||
| +            assert!( | ||||
| +                error_msg.contains("404") || | ||||
| +                error_msg.contains("not found") || | ||||
| +                error_msg.contains("OpenAPI") || | ||||
| +                error_msg.contains("RFS error") | ||||
| +            ); | ||||
| +            Ok(()) | ||||
| +        } | ||||
| +    } | ||||
|  } | ||||
|   | ||||
|  // ============================================================================= | ||||
| @@ -614,10 +627,10 @@ fn test_rfs_download_file_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|      // Test downloading a file (assuming test file hash exists) | ||||
|      let download_script = format!( | ||||
|          r#" | ||||
| -        let options = #{{ verify: false }}; | ||||
| -        let result = rfs_download_file("test_file_hash", '{}', options); | ||||
| -        if typeof(result) != "string" {{ | ||||
| -            throw "Expected string result"; | ||||
| +        // rfs_download_file returns unit and throws on error | ||||
| +        let result = rfs_download_file("test_file_hash", '{}', false); | ||||
| +        if result.type_of() != "()" {{ | ||||
| +            throw "Expected unit return"; | ||||
|          }} | ||||
|          true | ||||
|      "#, | ||||
| @@ -839,7 +852,7 @@ fn test_rfs_download_flist_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|      let download_script = format!( | ||||
|          r#" | ||||
|          let result = rfs_download_flist("flists/test/test.fl", '{}'); | ||||
| -        if typeof(result) != "string" {{ | ||||
| +        if result.type_of() != "string" {{ | ||||
|              throw "Expected string result"; | ||||
|          }} | ||||
|          true | ||||
| @@ -874,7 +887,7 @@ fn test_rfs_wait_for_flist_creation_wrapper() -> Result<(), Box<dyn std::error:: | ||||
|      // Test waiting for FList creation with a test job ID | ||||
|      let wait_script = r#" | ||||
|          let result = rfs_wait_for_flist_creation("test_job_id", 10, 1000); | ||||
| -        if typeof(result) != "string" { | ||||
| +        if result.type_of() != "string" { | ||||
|              throw "Expected string result"; | ||||
|          } | ||||
|          true | ||||
| @@ -3,8 +3,8 @@ | ||||
|  | ||||
| pub mod client; | ||||
| pub mod error; | ||||
| pub mod types; | ||||
| pub mod rhai; | ||||
| pub mod types; | ||||
|  | ||||
| pub use client::RfsClient; | ||||
| pub use error::RfsError; | ||||
|   | ||||
| @@ -24,7 +24,9 @@ struct RfsClientWrapper { | ||||
|  | ||||
| impl RfsClientWrapper { | ||||
|     fn new(client: RfsClient) -> Self { | ||||
|         Self { client: Mutex::new(client) } | ||||
|         Self { | ||||
|             client: Mutex::new(client), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -44,7 +46,7 @@ pub fn register_rfs_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult> | ||||
|     engine.register_fn("rfs_get_system_info", rfs_get_system_info); | ||||
|     engine.register_fn("rfs_is_authenticated", rfs_is_authenticated); | ||||
|     engine.register_fn("rfs_health_check", rfs_health_check); | ||||
|      | ||||
|  | ||||
|     // Register block management functions | ||||
|     engine.register_fn("rfs_list_blocks", rfs_list_blocks); | ||||
|     engine.register_fn("rfs_list_blocks", rfs_list_blocks); | ||||
| @@ -55,11 +57,11 @@ pub fn register_rfs_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult> | ||||
|     engine.register_fn("rfs_get_block", rfs_get_block); | ||||
|     engine.register_fn("rfs_get_blocks_by_hash", rfs_get_blocks_by_hash); | ||||
|     engine.register_fn("rfs_get_user_blocks", rfs_get_user_blocks); | ||||
|      | ||||
|  | ||||
|     // Register file operations functions | ||||
|     engine.register_fn("rfs_upload_file", rfs_upload_file); | ||||
|     engine.register_fn("rfs_download_file", rfs_download_file); | ||||
|      | ||||
|  | ||||
|     // Register FList management functions | ||||
|     engine.register_fn("rfs_create_flist", rfs_create_flist); | ||||
|     engine.register_fn("rfs_list_flists", rfs_list_flists); | ||||
| @@ -67,10 +69,10 @@ pub fn register_rfs_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult> | ||||
|     engine.register_fn("rfs_preview_flist", rfs_preview_flist); | ||||
|     engine.register_fn("rfs_download_flist", rfs_download_flist); | ||||
|     engine.register_fn("rfs_wait_for_flist_creation", rfs_wait_for_flist_creation); | ||||
|      | ||||
|  | ||||
|     // Register Website functions | ||||
|     engine.register_fn("rfs_get_website", rfs_get_website); | ||||
|      | ||||
|  | ||||
|     // Register System and Utility functions | ||||
|     engine.register_fn("rfs_is_authenticated", rfs_is_authenticated); | ||||
|     engine.register_fn("rfs_health_check", rfs_health_check); | ||||
| @@ -250,7 +252,7 @@ pub fn rfs_authenticate() -> Result<bool, Box<EvalAltResult>> { | ||||
| } | ||||
|  | ||||
| /// Check if the client is authenticated with the RFS server | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// `true` if authenticated, `false` otherwise | ||||
| fn rfs_is_authenticated() -> Result<bool, Box<EvalAltResult>> { | ||||
| @@ -261,7 +263,7 @@ fn rfs_is_authenticated() -> Result<bool, Box<EvalAltResult>> { | ||||
|             rhai::Position::NONE, | ||||
|         )) | ||||
|     })?; | ||||
|      | ||||
|  | ||||
|     Ok(client.is_authenticated()) | ||||
| } | ||||
|  | ||||
| @@ -300,7 +302,7 @@ pub fn rfs_get_system_info() -> Result<String, Box<EvalAltResult>> { | ||||
| } | ||||
|  | ||||
| /// Check the health status of the RFS server | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// The health status as a string | ||||
| fn rfs_health_check() -> Result<String, Box<EvalAltResult>> { | ||||
| @@ -321,10 +323,8 @@ fn rfs_health_check() -> Result<String, Box<EvalAltResult>> { | ||||
|         )) | ||||
|     })?; | ||||
|  | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.health_check().await | ||||
|     }); | ||||
|      | ||||
|     let result = runtime.block_on(async { client.health_check().await }); | ||||
|  | ||||
|     result.map_err(|e| { | ||||
|         Box::new(EvalAltResult::ErrorRuntime( | ||||
|             format!("Health check failed: {}", e).into(), | ||||
| @@ -338,11 +338,11 @@ fn rfs_health_check() -> Result<String, Box<EvalAltResult>> { | ||||
| // ============================================================================= | ||||
|  | ||||
| /// List all blocks with optional filtering | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `page` - Optional page number (1-based) | ||||
| /// * `per_page` - Optional number of items per page | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// JSON string containing block information | ||||
| fn rfs_list_blocks_impl( | ||||
| @@ -368,20 +368,18 @@ fn rfs_list_blocks_impl( | ||||
|  | ||||
|     // Create ListBlocksParams with optional page and per_page | ||||
|     let mut params = openapi::models::ListBlocksParams::new(); | ||||
|      | ||||
|  | ||||
|     // Convert Rhai INT to i32 for the API and set the parameters | ||||
|     if let Some(p) = page.and_then(|p| p.try_into().ok()) { | ||||
|         params.page = Some(Some(p)); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     if let Some(pp) = per_page.and_then(|p| p.try_into().ok()) { | ||||
|         params.per_page = Some(Some(pp)); | ||||
|     } | ||||
|  | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.list_blocks(Some(params)).await | ||||
|     }); | ||||
|      | ||||
|     let result = runtime.block_on(async { client.list_blocks(Some(params)).await }); | ||||
|  | ||||
|     match result { | ||||
|         Ok(blocks) => { | ||||
|             // Convert blocks to JSON string for Rhai | ||||
| @@ -400,10 +398,10 @@ fn rfs_list_blocks_impl( | ||||
| } | ||||
|  | ||||
| /// Check if a block exists | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `hash` - The hash of the block to check | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// `true` if the block exists, `false` otherwise | ||||
| fn rfs_check_block(hash: &str) -> Result<bool, Box<EvalAltResult>> { | ||||
| @@ -424,10 +422,8 @@ fn rfs_check_block(hash: &str) -> Result<bool, Box<EvalAltResult>> { | ||||
|         )) | ||||
|     })?; | ||||
|  | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.check_block(hash).await | ||||
|     }); | ||||
|      | ||||
|     let result = runtime.block_on(async { client.check_block(hash).await }); | ||||
|  | ||||
|     result.map_err(|e| { | ||||
|         Box::new(EvalAltResult::ErrorRuntime( | ||||
|             format!("Failed to check block: {}", e).into(), | ||||
| @@ -437,10 +433,10 @@ fn rfs_check_block(hash: &str) -> Result<bool, Box<EvalAltResult>> { | ||||
| } | ||||
|  | ||||
| /// Get block download statistics | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `hash` - The hash of the block | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// JSON string containing download statistics | ||||
| fn rfs_get_block_downloads(hash: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| @@ -461,10 +457,8 @@ fn rfs_get_block_downloads(hash: &str) -> Result<String, Box<EvalAltResult>> { | ||||
|         )) | ||||
|     })?; | ||||
|  | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.get_block_downloads(hash).await | ||||
|     }); | ||||
|      | ||||
|     let result = runtime.block_on(async { client.get_block_downloads(hash).await }); | ||||
|  | ||||
|     match result { | ||||
|         Ok(stats) => { | ||||
|             // Convert stats to JSON string for Rhai | ||||
| @@ -483,10 +477,10 @@ fn rfs_get_block_downloads(hash: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| } | ||||
|  | ||||
| /// Verify blocks | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `hashes` - JSON array of block hashes to verify | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// JSON string containing verification results | ||||
| fn rfs_verify_blocks(hashes: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| @@ -525,16 +519,14 @@ fn rfs_verify_blocks(hashes: &str) -> Result<String, Box<EvalAltResult>> { | ||||
|         .into_iter() | ||||
|         .map(|block_hash| openapi::models::VerifyBlock { | ||||
|             block_hash: block_hash.clone(), | ||||
|             block_index: 0,  // Default to 0 if not specified | ||||
|             file_hash: block_hash,  // Using the same hash as file_hash for now | ||||
|             block_index: 0,        // Default to 0 if not specified | ||||
|             file_hash: block_hash, // Using the same hash as file_hash for now | ||||
|         }) | ||||
|         .collect(); | ||||
|  | ||||
|     let request = openapi::models::VerifyBlocksRequest::new(verify_blocks); | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.verify_blocks(request).await | ||||
|     }); | ||||
|      | ||||
|     let result = runtime.block_on(async { client.verify_blocks(request).await }); | ||||
|  | ||||
|     match result { | ||||
|         Ok(verification) => { | ||||
|             // Convert verification to JSON string for Rhai | ||||
| @@ -553,10 +545,10 @@ fn rfs_verify_blocks(hashes: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| } | ||||
|  | ||||
| /// Get a block by hash | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `hash` - The hash of the block to retrieve | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// The block data as a byte array | ||||
| fn rfs_get_block(hash: &str) -> Result<rhai::Blob, Box<EvalAltResult>> { | ||||
| @@ -577,12 +569,10 @@ fn rfs_get_block(hash: &str) -> Result<rhai::Blob, Box<EvalAltResult>> { | ||||
|         )) | ||||
|     })?; | ||||
|  | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.get_block(hash).await | ||||
|     }); | ||||
|      | ||||
|     let result = runtime.block_on(async { client.get_block(hash).await }); | ||||
|  | ||||
|     match result { | ||||
|         Ok(bytes) => Ok(bytes.to_vec().into()), | ||||
|         Ok(bytes) => Ok(bytes.to_vec()), | ||||
|         Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime( | ||||
|             format!("Failed to get block: {}", e).into(), | ||||
|             rhai::Position::NONE, | ||||
| @@ -591,10 +581,10 @@ fn rfs_get_block(hash: &str) -> Result<rhai::Blob, Box<EvalAltResult>> { | ||||
| } | ||||
|  | ||||
| /// Get blocks by file hash or block hash | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `hash` - The file hash or block hash to look up | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// JSON string containing block information | ||||
| fn rfs_get_blocks_by_hash(hash: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| @@ -615,10 +605,8 @@ fn rfs_get_blocks_by_hash(hash: &str) -> Result<String, Box<EvalAltResult>> { | ||||
|         )) | ||||
|     })?; | ||||
|  | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.get_blocks_by_hash(hash).await | ||||
|     }); | ||||
|      | ||||
|     let result = runtime.block_on(async { client.get_blocks_by_hash(hash).await }); | ||||
|  | ||||
|     match result { | ||||
|         Ok(blocks) => { | ||||
|             // Convert blocks to JSON string for Rhai | ||||
| @@ -637,11 +625,11 @@ fn rfs_get_blocks_by_hash(hash: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| } | ||||
|  | ||||
| /// Get blocks uploaded by the current user | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `page` - Optional page number (1-based) | ||||
| /// * `per_page` - Optional number of items per page | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// JSON string containing user's blocks information | ||||
| fn rfs_get_user_blocks_impl( | ||||
| @@ -669,10 +657,8 @@ fn rfs_get_user_blocks_impl( | ||||
|     let page_i32 = page.and_then(|p| p.try_into().ok()); | ||||
|     let per_page_i32 = per_page.and_then(|p| p.try_into().ok()); | ||||
|  | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.get_user_blocks(page_i32, per_page_i32).await | ||||
|     }); | ||||
|      | ||||
|     let result = runtime.block_on(async { client.get_user_blocks(page_i32, per_page_i32).await }); | ||||
|  | ||||
|     match result { | ||||
|         Ok(user_blocks) => { | ||||
|             // Convert user blocks to JSON string for Rhai | ||||
| @@ -691,15 +677,19 @@ fn rfs_get_user_blocks_impl( | ||||
| } | ||||
|  | ||||
| /// Upload a block to the RFS server | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `file_hash` - The hash of the file this block belongs to | ||||
| /// * `index` - The index of the block in the file | ||||
| /// * `data` - The block data as a byte array | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// The hash of the uploaded block | ||||
| fn rfs_upload_block(file_hash: &str, index: rhai::INT, data: rhai::Blob) -> Result<String, Box<EvalAltResult>> { | ||||
| fn rfs_upload_block( | ||||
|     file_hash: &str, | ||||
|     index: rhai::INT, | ||||
|     data: rhai::Blob, | ||||
| ) -> Result<String, Box<EvalAltResult>> { | ||||
|     let runtime_mutex = get_runtime()?; | ||||
|     let runtime_guard = runtime_mutex.lock().map_err(|e| { | ||||
|         Box::new(EvalAltResult::ErrorRuntime( | ||||
| @@ -718,15 +708,14 @@ fn rfs_upload_block(file_hash: &str, index: rhai::INT, data: rhai::Blob) -> Resu | ||||
|     })?; | ||||
|  | ||||
|     // Convert index to i64 for the API | ||||
|     let index_i64 = index as i64; | ||||
|      | ||||
|     let index_i64 = index; | ||||
|  | ||||
|     // Convert the blob to Vec<u8> | ||||
|     let data_vec = data.to_vec(); | ||||
|  | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.upload_block(file_hash, index_i64, data_vec).await | ||||
|     }); | ||||
|      | ||||
|     let result = | ||||
|         runtime.block_on(async { client.upload_block(file_hash, index_i64, data_vec).await }); | ||||
|  | ||||
|     result.map_err(|e| { | ||||
|         Box::new(EvalAltResult::ErrorRuntime( | ||||
|             format!("Failed to upload block: {}", e).into(), | ||||
| @@ -747,7 +736,6 @@ fn rfs_get_user_blocks(params: Map) -> Result<String, Box<EvalAltResult>> { | ||||
|     rfs_get_user_blocks_impl(page, per_page) | ||||
| } | ||||
|  | ||||
|  | ||||
| /// Rhai-facing adapter: accept params map with optional keys: page, per_page | ||||
| fn rfs_list_blocks(params: Map) -> Result<String, Box<EvalAltResult>> { | ||||
|     // Extract optional page and per_page from the map | ||||
| @@ -776,7 +764,11 @@ fn rfs_list_blocks(params: Map) -> Result<String, Box<EvalAltResult>> { | ||||
| /// # Returns | ||||
| /// | ||||
| /// * `Result<(), Box<EvalAltResult>>` - Ok(()) if download was successful, error otherwise | ||||
| fn rfs_download_file(file_id: &str, output_path: &str, verify: bool) -> Result<(), Box<EvalAltResult>> { | ||||
| fn rfs_download_file( | ||||
|     file_id: &str, | ||||
|     output_path: &str, | ||||
|     verify: bool, | ||||
| ) -> Result<(), Box<EvalAltResult>> { | ||||
|     let runtime_mutex = get_runtime()?; | ||||
|     let runtime_guard = runtime_mutex.lock().map_err(|e| { | ||||
|         Box::new(EvalAltResult::ErrorRuntime( | ||||
| @@ -795,8 +787,10 @@ fn rfs_download_file(file_id: &str, output_path: &str, verify: bool) -> Result<( | ||||
|     })?; | ||||
|  | ||||
|     let download_options = Some(DownloadOptions { verify }); | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.download_file(file_id, output_path, download_options).await  | ||||
|     let result = runtime.block_on(async { | ||||
|         client | ||||
|             .download_file(file_id, output_path, download_options) | ||||
|             .await | ||||
|     }); | ||||
|  | ||||
|     result.map_err(|e| { | ||||
| @@ -818,7 +812,11 @@ fn rfs_download_file(file_id: &str, output_path: &str, verify: bool) -> Result<( | ||||
| /// # Returns | ||||
| /// | ||||
| /// * `Result<String, Box<EvalAltResult>>` - File ID of the uploaded file | ||||
| pub fn rfs_upload_file(file_path: &str, chunk_size: rhai::INT, verify: bool) -> Result<String, Box<EvalAltResult>> { | ||||
| pub fn rfs_upload_file( | ||||
|     file_path: &str, | ||||
|     chunk_size: rhai::INT, | ||||
|     verify: bool, | ||||
| ) -> Result<String, Box<EvalAltResult>> { | ||||
|     let runtime_mutex = get_runtime()?; | ||||
|     let runtime_guard = runtime_mutex.lock().map_err(|e| { | ||||
|         Box::new(EvalAltResult::ErrorRuntime( | ||||
| @@ -838,7 +836,11 @@ pub fn rfs_upload_file(file_path: &str, chunk_size: rhai::INT, verify: bool) -> | ||||
|     })?; | ||||
|  | ||||
|     let upload_options = Some(UploadOptions { | ||||
|         chunk_size: if chunk_size > 0 { Some(chunk_size as usize) } else { None }, | ||||
|         chunk_size: if chunk_size > 0 { | ||||
|             Some(chunk_size as usize) | ||||
|         } else { | ||||
|             None | ||||
|         }, | ||||
|         verify, | ||||
|     }); | ||||
|  | ||||
| @@ -857,11 +859,11 @@ pub fn rfs_upload_file(file_path: &str, chunk_size: rhai::INT, verify: bool) -> | ||||
| // ============================================================================= | ||||
|  | ||||
| /// Get website content from the RFS server | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `website_id` - The ID of the website | ||||
| /// * `path` - The path to the content within the website | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// The website content as a string | ||||
| fn rfs_get_website(website_id: &str, path: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| @@ -882,11 +884,14 @@ fn rfs_get_website(website_id: &str, path: &str) -> Result<String, Box<EvalAltRe | ||||
|         )) | ||||
|     })?; | ||||
|  | ||||
|     let result = runtime.block_on(async {  | ||||
|     let result = runtime.block_on(async { | ||||
|         let response = client.get_website(website_id, path).await?; | ||||
|         response.text().await.map_err(|e| RfsError::RequestError(e.into())) | ||||
|         response | ||||
|             .text() | ||||
|             .await | ||||
|             .map_err(RfsError::RequestError) | ||||
|     }); | ||||
|      | ||||
|  | ||||
|     result.map_err(|e| { | ||||
|         Box::new(EvalAltResult::ErrorRuntime( | ||||
|             format!("Failed to get website content: {}", e).into(), | ||||
| @@ -900,13 +905,13 @@ fn rfs_get_website(website_id: &str, path: &str) -> Result<String, Box<EvalAltRe | ||||
| // ============================================================================= | ||||
|  | ||||
| /// Create an FList from a Docker image | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `image_name` - Docker image name (e.g., "ubuntu:20.04") | ||||
| /// * `server_address` - Optional server address (empty string if not needed) | ||||
| /// * `identity_token` - Optional identity token (empty string if not needed) | ||||
| /// * `registry_token` - Optional registry token (empty string if not needed) | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// Job ID for tracking FList creation progress | ||||
| fn rfs_create_flist( | ||||
| @@ -932,7 +937,7 @@ fn rfs_create_flist( | ||||
|             rhai::Position::NONE, | ||||
|         )) | ||||
|     })?; | ||||
|      | ||||
|  | ||||
|     // Build FList options | ||||
|     let mut options = crate::types::FlistOptions::default(); | ||||
|     if !server_address.is_empty() { | ||||
| @@ -944,9 +949,9 @@ fn rfs_create_flist( | ||||
|     if !registry_token.is_empty() { | ||||
|         options.registry_token = Some(registry_token.to_string()); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     let result = runtime.block_on(async { client.create_flist(image_name, Some(options)).await }); | ||||
|      | ||||
|  | ||||
|     result.map_err(|e| { | ||||
|         Box::new(EvalAltResult::ErrorRuntime( | ||||
|             format!("FList creation failed: {}", e).into(), | ||||
| @@ -956,7 +961,7 @@ fn rfs_create_flist( | ||||
| } | ||||
|  | ||||
| /// List all available FLists | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// JSON string containing FList information | ||||
| fn rfs_list_flists() -> Result<String, Box<EvalAltResult>> { | ||||
| @@ -977,9 +982,9 @@ fn rfs_list_flists() -> Result<String, Box<EvalAltResult>> { | ||||
|             rhai::Position::NONE, | ||||
|         )) | ||||
|     })?; | ||||
|      | ||||
|  | ||||
|     let result = runtime.block_on(async { client.list_flists().await }); | ||||
|      | ||||
|  | ||||
|     match result { | ||||
|         Ok(flists) => { | ||||
|             // Convert HashMap to JSON string for Rhai | ||||
| @@ -998,10 +1003,10 @@ fn rfs_list_flists() -> Result<String, Box<EvalAltResult>> { | ||||
| } | ||||
|  | ||||
| /// Get FList creation state by job ID | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `job_id` - Job ID returned from create_flist | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// JSON string containing FList state information | ||||
| fn rfs_get_flist_state(job_id: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| @@ -1022,9 +1027,9 @@ fn rfs_get_flist_state(job_id: &str) -> Result<String, Box<EvalAltResult>> { | ||||
|             rhai::Position::NONE, | ||||
|         )) | ||||
|     })?; | ||||
|      | ||||
|  | ||||
|     let result = runtime.block_on(async { client.get_flist_state(job_id).await }); | ||||
|      | ||||
|  | ||||
|     match result { | ||||
|         Ok(state) => { | ||||
|             // Convert state to JSON string for Rhai | ||||
| @@ -1043,10 +1048,10 @@ fn rfs_get_flist_state(job_id: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| } | ||||
|  | ||||
| /// Preview an FList's contents | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `flist_path` - Path to the FList | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// JSON string containing FList preview information | ||||
| fn rfs_preview_flist(flist_path: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| @@ -1067,9 +1072,9 @@ fn rfs_preview_flist(flist_path: &str) -> Result<String, Box<EvalAltResult>> { | ||||
|             rhai::Position::NONE, | ||||
|         )) | ||||
|     })?; | ||||
|      | ||||
|  | ||||
|     let result = runtime.block_on(async { client.preview_flist(flist_path).await }); | ||||
|      | ||||
|  | ||||
|     match result { | ||||
|         Ok(preview) => { | ||||
|             // Convert preview to JSON string for Rhai | ||||
| @@ -1088,11 +1093,11 @@ fn rfs_preview_flist(flist_path: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| } | ||||
|  | ||||
| /// Download an FList file from the RFS server | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `flist_path` - Path to the FList to download (e.g., "flists/user/example.fl") | ||||
| /// * `output_path` - Local path where the FList will be saved | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// Empty string on success, error on failure | ||||
| fn rfs_download_flist(flist_path: &str, output_path: &str) -> Result<String, Box<EvalAltResult>> { | ||||
| @@ -1113,10 +1118,8 @@ fn rfs_download_flist(flist_path: &str, output_path: &str) -> Result<String, Box | ||||
|         )) | ||||
|     })?; | ||||
|  | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.download_flist(flist_path, output_path).await | ||||
|     }); | ||||
|      | ||||
|     let result = runtime.block_on(async { client.download_flist(flist_path, output_path).await }); | ||||
|  | ||||
|     match result { | ||||
|         Ok(_) => Ok(String::new()), | ||||
|         Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime( | ||||
| @@ -1127,16 +1130,16 @@ fn rfs_download_flist(flist_path: &str, output_path: &str) -> Result<String, Box | ||||
| } | ||||
|  | ||||
| /// Wait for an FList to be created | ||||
| ///  | ||||
| /// | ||||
| /// # Arguments | ||||
| /// * `job_id` - The job ID returned by rfs_create_flist | ||||
| /// * `timeout_seconds` - Maximum time to wait in seconds (default: 300) | ||||
| /// * `poll_interval_ms` - Polling interval in milliseconds (default: 1000) | ||||
| ///  | ||||
| /// | ||||
| /// # Returns | ||||
| /// JSON string containing the final FList state | ||||
| fn rfs_wait_for_flist_creation_impl( | ||||
|     job_id: &str,  | ||||
|     job_id: &str, | ||||
|     timeout_seconds: Option<rhai::INT>, | ||||
|     poll_interval_ms: Option<rhai::INT>, | ||||
| ) -> Result<String, Box<EvalAltResult>> { | ||||
| @@ -1163,10 +1166,9 @@ fn rfs_wait_for_flist_creation_impl( | ||||
|         progress_callback: None, | ||||
|     }; | ||||
|  | ||||
|     let result = runtime.block_on(async {  | ||||
|         client.wait_for_flist_creation(job_id, Some(options)).await | ||||
|     }); | ||||
|      | ||||
|     let result = | ||||
|         runtime.block_on(async { client.wait_for_flist_creation(job_id, Some(options)).await }); | ||||
|  | ||||
|     match result { | ||||
|         Ok(state) => { | ||||
|             // Convert state to JSON string for Rhai | ||||
| @@ -1198,4 +1200,4 @@ fn rfs_wait_for_flist_creation(job_id: &str, params: Map) -> Result<String, Box< | ||||
|         .and_then(|d| d.clone().try_cast::<rhai::INT>()); | ||||
|  | ||||
|     rfs_wait_for_flist_creation_impl(job_id, timeout_seconds, poll_interval_ms) | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,7 @@ | ||||
| // Re-export common types from OpenAPI client for convenience | ||||
| pub use openapi::models::{ | ||||
|     BlockDownloadsResponse, BlocksResponse, FileInfo,  | ||||
|     FileUploadResponse, FlistBody, FlistState, Job, ListBlocksResponse, | ||||
|     PreviewResponse, ResponseResult, SignInResponse, VerifyBlocksResponse, | ||||
|     BlockDownloadsResponse, BlocksResponse, FileInfo, FileUploadResponse, FlistBody, FlistState, | ||||
|     Job, ListBlocksResponse, PreviewResponse, ResponseResult, SignInResponse, VerifyBlocksResponse, | ||||
| }; | ||||
|  | ||||
| /// Authentication credentials for the RFS server | ||||
| @@ -74,10 +73,10 @@ pub struct FlistOptions { | ||||
| pub struct WaitOptions { | ||||
|     /// Maximum time to wait in seconds | ||||
|     pub timeout_seconds: u64, | ||||
|      | ||||
|  | ||||
|     /// Polling interval in milliseconds | ||||
|     pub poll_interval_ms: u64, | ||||
|      | ||||
|  | ||||
|     /// Optional progress callback | ||||
|     pub progress_callback: Option<Box<dyn Fn(&FlistState) + Send + Sync>>, | ||||
| } | ||||
| @@ -88,7 +87,14 @@ impl std::fmt::Debug for WaitOptions { | ||||
|         f.debug_struct("WaitOptions") | ||||
|             .field("timeout_seconds", &self.timeout_seconds) | ||||
|             .field("poll_interval_ms", &self.poll_interval_ms) | ||||
|             .field("progress_callback", &if self.progress_callback.is_some() { "Some(...)" } else { "None" }) | ||||
|             .field( | ||||
|                 "progress_callback", | ||||
|                 &if self.progress_callback.is_some() { | ||||
|                     "Some(...)" | ||||
|                 } else { | ||||
|                     "None" | ||||
|                 }, | ||||
|             ) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
| @@ -107,7 +113,7 @@ impl Clone for WaitOptions { | ||||
| impl Default for WaitOptions { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             timeout_seconds: 300,  // 5 minutes default timeout | ||||
|             timeout_seconds: 300,   // 5 minutes default timeout | ||||
|             poll_interval_ms: 1000, // 1 second default polling interval | ||||
|             progress_callback: None, | ||||
|         } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| //! Integration tests for RFS client Rhai wrappers | ||||
| //! | ||||
| //! These tests verify that the Rhai wrappers work correctly with the RFS client. | ||||
| //!  | ||||
| //! | ||||
| //! Test Categories: | ||||
| //! - Unit tests: Test wrapper logic without requiring a running server | ||||
| //! - Integration tests: Test with a real RFS server (when available) | ||||
| @@ -15,7 +15,14 @@ use tempfile::NamedTempFile; | ||||
| fn is_server_running(url: &str) -> bool { | ||||
|     // Try to make a simple HTTP request to check if server is available | ||||
|     match std::process::Command::new("curl") | ||||
|         .args(["-s", "-o", "/dev/null", "-w", "%{http_code}", &format!("{}/api/v1", url)]) | ||||
|         .args([ | ||||
|             "-s", | ||||
|             "-o", | ||||
|             "/dev/null", | ||||
|             "-w", | ||||
|             "%{http_code}", | ||||
|             &format!("{}/api/v1", url), | ||||
|         ]) | ||||
|         .output() | ||||
|     { | ||||
|         Ok(output) => { | ||||
| @@ -39,15 +46,15 @@ const TEST_PASSWORD: &str = "password"; | ||||
| fn test_rhai_engine_setup() -> Result<(), Box<EvalAltResult>> { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine)?; | ||||
|      | ||||
|  | ||||
|     // Test that we can create a client successfully | ||||
|     let script = r#" | ||||
|         rfs_create_client("http://localhost:8080", "user", "password", 30) | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(script)?; | ||||
|     assert!(result); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @@ -56,15 +63,15 @@ fn test_rhai_engine_setup() -> Result<(), Box<EvalAltResult>> { | ||||
| fn test_rfs_create_client() -> Result<(), Box<EvalAltResult>> { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine)?; | ||||
|      | ||||
|  | ||||
|     let script = r#" | ||||
|         let result = rfs_create_client("http://localhost:8080", "user", "password", 30); | ||||
|         result | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(script)?; | ||||
|     assert!(result); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @@ -73,15 +80,15 @@ fn test_rfs_create_client() -> Result<(), Box<EvalAltResult>> { | ||||
| fn test_rfs_create_client_no_credentials() -> Result<(), Box<EvalAltResult>> { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine)?; | ||||
|      | ||||
|  | ||||
|     let script = r#" | ||||
|         let result = rfs_create_client("http://localhost:8080", "", "", 30); | ||||
|         result | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(script)?; | ||||
|     assert!(result); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @@ -92,36 +99,48 @@ fn test_rfs_flist_management_integration() { | ||||
|         println!("Skipping FList integration test - no server detected"); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).expect("Failed to register RFS module"); | ||||
|      | ||||
|  | ||||
|     // Test FList listing with proper credentials | ||||
|     let list_script = format!(r#" | ||||
|     let list_script = format!( | ||||
|         r#" | ||||
|         rfs_create_client("{}", "{}", "{}", 30); | ||||
|         rfs_authenticate(); | ||||
|         rfs_list_flists() | ||||
|     "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD); | ||||
|      | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|  | ||||
|     let result = engine.eval::<String>(&list_script); | ||||
|     match result { | ||||
|         Ok(flists_json) => { | ||||
|             println!("FLists retrieved: {}", flists_json); | ||||
|             // Should be valid JSON | ||||
|             assert!(serde_json::from_str::<serde_json::Value>(&flists_json).is_ok(),  | ||||
|                    "FList data should be valid JSON"); | ||||
|             assert!( | ||||
|                 serde_json::from_str::<serde_json::Value>(&flists_json).is_ok(), | ||||
|                 "FList data should be valid JSON" | ||||
|             ); | ||||
|         } | ||||
|         Err(e) => { | ||||
|             let error_msg = e.to_string(); | ||||
|             println!("FList preview error: {}", error_msg); | ||||
|              | ||||
|  | ||||
|             // Check if it's an authentication error (shouldn't happen with valid creds) | ||||
|             if error_msg.contains("Authentication") { | ||||
|                 panic!("❌ Authentication should work with valid credentials: {}", error_msg); | ||||
|                 panic!( | ||||
|                     "❌ Authentication should work with valid credentials: {}", | ||||
|                     error_msg | ||||
|                 ); | ||||
|             } else { | ||||
|                 // Other errors are acceptable (not found, permissions, etc.) | ||||
|                 println!("Server error (may be expected): {}", error_msg); | ||||
|                 assert!(error_msg.contains("OpenAPI") || error_msg.contains("FList") || error_msg.contains("not found")); | ||||
|                 assert!( | ||||
|                     error_msg.contains("OpenAPI") | ||||
|                         || error_msg.contains("FList") | ||||
|                         || error_msg.contains("not found") | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -133,23 +152,26 @@ fn test_rfs_create_flist_integration() { | ||||
|         println!("Skipping FList creation test - no server detected"); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).expect("Failed to register RFS module"); | ||||
|      | ||||
|  | ||||
|     // Test FList creation with proper authentication | ||||
|     let create_script = format!(r#" | ||||
|     let create_script = format!( | ||||
|         r#" | ||||
|         rfs_create_client("{}", "{}", "{}", 30); | ||||
|         rfs_authenticate(); | ||||
|         rfs_create_flist("busybox:latest", "docker.io", "", "") | ||||
|     "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD); | ||||
|      | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|  | ||||
|     let result = engine.eval::<String>(&create_script); | ||||
|     match result { | ||||
|         Ok(job_id) => { | ||||
|             println!("✅ FList creation job started: {}", job_id); | ||||
|             assert!(!job_id.is_empty(), "Job ID should not be empty"); | ||||
|              | ||||
|  | ||||
|             // Test getting FList state with the job ID | ||||
|             let state_script = format!("rfs_get_flist_state(\"{}\")", job_id); | ||||
|             let state_result = engine.eval::<String>(&state_script); | ||||
| @@ -166,12 +188,15 @@ fn test_rfs_create_flist_integration() { | ||||
|         Err(e) => { | ||||
|             let error_msg = e.to_string(); | ||||
|             println!("FList creation error: {}", error_msg); | ||||
|              | ||||
|  | ||||
|             // Check if it's a 409 Conflict (FList already exists) - this is acceptable | ||||
|             if error_msg.contains("409 Conflict") { | ||||
|                 println!("✅ FList already exists (409 Conflict) - this is expected behavior"); | ||||
|             } else if error_msg.contains("Authentication") { | ||||
|                 panic!("❌ Authentication should work with valid credentials: {}", error_msg); | ||||
|                 panic!( | ||||
|                     "❌ Authentication should work with valid credentials: {}", | ||||
|                     error_msg | ||||
|                 ); | ||||
|             } else { | ||||
|                 // Other server errors are acceptable (permissions, etc.) | ||||
|                 println!("Server error (may be expected): {}", error_msg); | ||||
| @@ -187,17 +212,20 @@ fn test_rfs_preview_flist_integration() { | ||||
|         println!("Skipping FList preview test - no server detected"); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).expect("Failed to register RFS module"); | ||||
|      | ||||
|  | ||||
|     // Test FList preview with proper authentication and correct path format | ||||
|     let preview_script = format!(r#" | ||||
|     let preview_script = format!( | ||||
|         r#" | ||||
|         rfs_create_client("{}", "{}", "{}", 30); | ||||
|         rfs_authenticate(); | ||||
|         rfs_preview_flist("flists/user/alpine-latest.fl") | ||||
|     "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD); | ||||
|      | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|  | ||||
|     let result = engine.eval::<String>(&preview_script); | ||||
|     match result { | ||||
|         Ok(preview_json) => { | ||||
| @@ -206,10 +234,17 @@ fn test_rfs_preview_flist_integration() { | ||||
|         } | ||||
|         Err(e) => { | ||||
|             let error_msg = e.to_string(); | ||||
|             println!("Expected FList preview error (not found/auth): {}", error_msg); | ||||
|             println!( | ||||
|                 "Expected FList preview error (not found/auth): {}", | ||||
|                 error_msg | ||||
|             ); | ||||
|             // Should be a proper server error | ||||
|             assert!(error_msg.contains("Authentication") || error_msg.contains("OpenAPI") ||  | ||||
|                    error_msg.contains("FList") || error_msg.contains("not found")); | ||||
|             assert!( | ||||
|                 error_msg.contains("Authentication") | ||||
|                     || error_msg.contains("OpenAPI") | ||||
|                     || error_msg.contains("FList") | ||||
|                     || error_msg.contains("not found") | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -219,12 +254,12 @@ fn test_rfs_preview_flist_integration() { | ||||
| fn test_rfs_get_system_info_wrapper() { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).unwrap(); | ||||
|      | ||||
|  | ||||
|     let script = r#" | ||||
|         rfs_create_client("http://localhost:8080", "", "", 30); | ||||
|         rfs_get_system_info() | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result = engine.eval::<String>(script); | ||||
|     match result { | ||||
|         Ok(info) => { | ||||
| @@ -246,12 +281,12 @@ fn test_rfs_get_system_info_wrapper() { | ||||
| fn test_rfs_authenticate_wrapper() { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).unwrap(); | ||||
|      | ||||
|  | ||||
|     let script = r#" | ||||
|         rfs_create_client("http://localhost:8080", "user", "password", 30); | ||||
|         rfs_authenticate() | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result = engine.eval::<bool>(script); | ||||
|     match result { | ||||
|         Ok(success) => { | ||||
| @@ -273,17 +308,20 @@ fn test_rfs_authenticate_wrapper() { | ||||
| fn test_rfs_upload_file_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine)?; | ||||
|      | ||||
|  | ||||
|     // Create a temporary file for testing | ||||
|     let temp_file = NamedTempFile::new()?; | ||||
|     fs::write(&temp_file, b"test content")?; | ||||
|     let file_path = temp_file.path().to_string_lossy(); | ||||
|      | ||||
|     let script = format!(r#" | ||||
|  | ||||
|     let script = format!( | ||||
|         r#" | ||||
|         rfs_create_client("http://localhost:8080", "", "", 30); | ||||
|         rfs_upload_file("{}", 0, false) | ||||
|     "#, file_path); | ||||
|      | ||||
|     "#, | ||||
|         file_path | ||||
|     ); | ||||
|  | ||||
|     let result = engine.eval::<String>(&script); | ||||
|     match result { | ||||
|         Ok(upload_result) => { | ||||
| @@ -298,7 +336,7 @@ fn test_rfs_upload_file_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|             assert!(error_msg.contains("RFS error") || error_msg.contains("OpenAPI")); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @@ -307,7 +345,7 @@ fn test_rfs_upload_file_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
| fn test_complete_rhai_script() { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).unwrap(); | ||||
|      | ||||
|  | ||||
|     let script = r#" | ||||
|         // Create client | ||||
|         let client_created = rfs_create_client("http://localhost:8080", "user", "password", 60); | ||||
| @@ -315,7 +353,7 @@ fn test_complete_rhai_script() { | ||||
|         // Return success if we got this far | ||||
|         client_created | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(script).unwrap(); | ||||
|     assert!(result); | ||||
| } | ||||
| @@ -325,17 +363,17 @@ fn test_complete_rhai_script() { | ||||
| fn test_error_handling() { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).unwrap(); | ||||
|      | ||||
|  | ||||
|     // Test calling a protected endpoint without authentication - should fail | ||||
|     // Note: get_system_info is NOT protected, but create_flist IS protected | ||||
|     let script = r#" | ||||
|         rfs_create_client("http://localhost:8080", "", "", 30); | ||||
|         rfs_create_flist("test:latest", "docker.io", "", "") | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result = engine.eval::<String>(script); | ||||
|     assert!(result.is_err()); | ||||
|      | ||||
|  | ||||
|     // Check that the error message contains authentication error | ||||
|     let error_msg = result.unwrap_err().to_string(); | ||||
|     println!("Expected authentication error: {}", error_msg); | ||||
| @@ -347,23 +385,26 @@ fn test_error_handling() { | ||||
| fn test_rfs_is_authenticated_wrapper() { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).unwrap(); | ||||
|      | ||||
|  | ||||
|     // Test without authenticating first | ||||
|     let script1 = r#" | ||||
|         rfs_create_client("http://localhost:8080", "", "", 30); | ||||
|         rfs_is_authenticated() | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result1 = engine.eval::<bool>(script1).unwrap(); | ||||
|     assert!(!result1, "Should not be authenticated before calling authenticate()"); | ||||
|      | ||||
|     assert!( | ||||
|         !result1, | ||||
|         "Should not be authenticated before calling authenticate()" | ||||
|     ); | ||||
|  | ||||
|     // Test after authenticating (may still fail if server requires valid credentials) | ||||
|     let script2 = r#" | ||||
|         rfs_create_client("http://localhost:8080", "user", "password", 30); | ||||
|         rfs_authenticate(); | ||||
|         rfs_is_authenticated() | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result2 = engine.eval::<bool>(script2); | ||||
|     match result2 { | ||||
|         Ok(auth_status) => { | ||||
| @@ -382,12 +423,12 @@ fn test_rfs_is_authenticated_wrapper() { | ||||
| fn test_rfs_health_check_wrapper() { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).unwrap(); | ||||
|      | ||||
|  | ||||
|     let script = r#" | ||||
|         rfs_create_client("http://localhost:8080", "", "", 30); | ||||
|         rfs_health_check() | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result = engine.eval::<String>(script); | ||||
|     match result { | ||||
|         Ok(health_status) => { | ||||
| @@ -400,9 +441,9 @@ fn test_rfs_health_check_wrapper() { | ||||
|             println!("Health check error (may be expected): {}", error_msg); | ||||
|             // Acceptable errors if server is not running or requires auth | ||||
|             assert!( | ||||
|                 error_msg.contains("RFS error") ||  | ||||
|                 error_msg.contains("OpenAPI") || | ||||
|                 error_msg.contains("failed") | ||||
|                 error_msg.contains("RFS error") | ||||
|                     || error_msg.contains("OpenAPI") | ||||
|                     || error_msg.contains("failed") | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| @@ -415,17 +456,20 @@ fn test_rfs_get_website_wrapper() { | ||||
|         println!("Skipping website test - no server detected"); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).unwrap(); | ||||
|      | ||||
|  | ||||
|     // Test with a non-existent website (should fail gracefully) | ||||
|     let script = format!(r#" | ||||
|     let script = format!( | ||||
|         r#" | ||||
|         rfs_create_client("{}", "{}", "{}", 30); | ||||
|         rfs_authenticate(); | ||||
|         rfs_get_website("nonexistent-website", "index.html") | ||||
|     "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD); | ||||
|      | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|  | ||||
|     let result = engine.eval::<String>(&script); | ||||
|     match result { | ||||
|         Ok(content) => { | ||||
| @@ -437,10 +481,10 @@ fn test_rfs_get_website_wrapper() { | ||||
|             let error_msg = e.to_string(); | ||||
|             println!("Expected website error: {}", error_msg); | ||||
|             assert!( | ||||
|                 error_msg.contains("404") ||  | ||||
|                 error_msg.contains("not found") || | ||||
|                 error_msg.contains("OpenAPI") || | ||||
|                 error_msg.contains("RFS error") | ||||
|                 error_msg.contains("404") | ||||
|                     || error_msg.contains("not found") | ||||
|                     || error_msg.contains("OpenAPI") | ||||
|                     || error_msg.contains("RFS error") | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| @@ -455,7 +499,7 @@ fn test_rfs_get_website_wrapper() { | ||||
| fn test_rfs_list_blocks_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine)?; | ||||
|      | ||||
|  | ||||
|     // Create a client first | ||||
|     let create_script = format!( | ||||
|         r#" | ||||
| @@ -463,10 +507,10 @@ fn test_rfs_list_blocks_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(&create_script)?; | ||||
|     assert!(result, "Failed to create RFS client"); | ||||
|      | ||||
|  | ||||
|     // Authenticate before invoking operations that require it | ||||
|     let auth_script = r#" | ||||
|         rfs_authenticate() | ||||
| @@ -481,10 +525,10 @@ fn test_rfs_list_blocks_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         } | ||||
|         true | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(list_script)?; | ||||
|     assert!(result, "Failed to list blocks"); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @@ -493,7 +537,7 @@ fn test_rfs_list_blocks_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
| fn test_rfs_download_block_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine)?; | ||||
|      | ||||
|  | ||||
|     // Create a client first | ||||
|     let create_script = format!( | ||||
|         r#" | ||||
| @@ -501,18 +545,18 @@ fn test_rfs_download_block_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(&create_script)?; | ||||
|     assert!(result, "Failed to create RFS client"); | ||||
|      | ||||
|  | ||||
|     // Authenticate before invoking operations that require it | ||||
|     let authed: bool = engine.eval(r#" rfs_authenticate() "#)?; | ||||
|     assert!(authed, "Authentication failed in download wrapper test"); | ||||
|      | ||||
|  | ||||
|     // Create a temporary file for download | ||||
|     let temp_file = NamedTempFile::new()?; | ||||
|     let temp_path = temp_file.path().to_str().unwrap(); | ||||
|      | ||||
|  | ||||
|     // Test downloading a block (assuming test block hash exists) | ||||
|     let download_script = format!( | ||||
|         r#" | ||||
| @@ -522,13 +566,13 @@ fn test_rfs_download_block_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         }} | ||||
|         true | ||||
|     "#, | ||||
|         temp_path.replace('\\', "\\\\")  // Escape backslashes for Windows paths | ||||
|         temp_path.replace('\\', "\\\\") // Escape backslashes for Windows paths | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     // This might fail if the test block doesn't exist, but we're testing the wrapper, not the actual download | ||||
|     let result: bool = engine.eval(&download_script).unwrap_or_else(|_| true); | ||||
|     assert!(result, "Failed to execute download block script"); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @@ -537,7 +581,7 @@ fn test_rfs_download_block_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
| fn test_rfs_verify_blocks_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine)?; | ||||
|      | ||||
|  | ||||
|     // Create a client first | ||||
|     let create_script = format!( | ||||
|         r#" | ||||
| @@ -545,10 +589,10 @@ fn test_rfs_verify_blocks_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(&create_script)?; | ||||
|     assert!(result, "Failed to create RFS client"); | ||||
|      | ||||
|  | ||||
|     // Test verifying blocks with a test hash | ||||
|     let verify_script = r#" | ||||
|         let hashes = "[\"test_block_hash\"]"; | ||||
| @@ -558,10 +602,10 @@ fn test_rfs_verify_blocks_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         }} | ||||
|         true | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(verify_script)?; | ||||
|     assert!(result, "Failed to verify blocks"); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @@ -570,7 +614,7 @@ fn test_rfs_verify_blocks_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
| fn test_rfs_get_block_info_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine)?; | ||||
|      | ||||
|  | ||||
|     // Create a client first | ||||
|     let create_script = format!( | ||||
|         r#" | ||||
| @@ -578,10 +622,10 @@ fn test_rfs_get_block_info_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(&create_script)?; | ||||
|     assert!(result, "Failed to create RFS client"); | ||||
|      | ||||
|  | ||||
|     // Test getting block info with a test hash | ||||
|     let info_script = r#" | ||||
|         let result = rfs_get_blocks_by_hash("test_block_hash"); | ||||
| @@ -590,7 +634,7 @@ fn test_rfs_get_block_info_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         } | ||||
|         true | ||||
|     "#; | ||||
|      | ||||
|  | ||||
|     match engine.eval::<bool>(info_script) { | ||||
|         Ok(result) => { | ||||
|             assert!(result, "Failed to get block info"); | ||||
| @@ -600,10 +644,10 @@ fn test_rfs_get_block_info_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|             let error_msg = e.to_string(); | ||||
|             println!("Block info error (may be expected): {}", error_msg); | ||||
|             assert!( | ||||
|                 error_msg.contains("404") || | ||||
|                 error_msg.contains("not found") || | ||||
|                 error_msg.contains("OpenAPI") || | ||||
|                 error_msg.contains("RFS error") | ||||
|                 error_msg.contains("404") | ||||
|                     || error_msg.contains("not found") | ||||
|                     || error_msg.contains("OpenAPI") | ||||
|                     || error_msg.contains("RFS error") | ||||
|             ); | ||||
|             Ok(()) | ||||
|         } | ||||
| @@ -619,7 +663,7 @@ fn test_rfs_get_block_info_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
| fn test_rfs_download_file_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine)?; | ||||
|      | ||||
|  | ||||
|     // Create a client first | ||||
|     let create_script = format!( | ||||
|         r#" | ||||
| @@ -627,14 +671,14 @@ fn test_rfs_download_file_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(&create_script)?; | ||||
|     assert!(result, "Failed to create RFS client"); | ||||
|      | ||||
|  | ||||
|     // Create a temporary file for download | ||||
|     let temp_file = NamedTempFile::new()?; | ||||
|     let temp_path = temp_file.path().to_str().unwrap(); | ||||
|      | ||||
|  | ||||
|     // Test downloading a file (assuming test file hash exists) | ||||
|     let download_script = format!( | ||||
|         r#" | ||||
| @@ -645,13 +689,13 @@ fn test_rfs_download_file_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         }} | ||||
|         true | ||||
|     "#, | ||||
|         temp_path.replace('\\', "\\\\")  // Escape backslashes for Windows paths | ||||
|         temp_path.replace('\\', "\\\\") // Escape backslashes for Windows paths | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     // This might fail if the test file doesn't exist, but we're testing the wrapper | ||||
|     let result: bool = engine.eval(&download_script).unwrap_or_else(|_| true); | ||||
|     assert!(result, "Failed to execute download file script"); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @@ -678,7 +722,7 @@ fn test_flist_operations_workflow() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let temp_dir = tempfile::tempdir()?; | ||||
|     let output_path = temp_dir.path().join("downloaded_flist.fl"); | ||||
|     let output_path_str = output_path.to_str().unwrap(); | ||||
|      | ||||
|  | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).expect("Failed to register RFS module"); | ||||
|  | ||||
| @@ -808,19 +852,19 @@ fn test_flist_operations_workflow() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     // Add a helper function to parse JSON in Rhai | ||||
|     engine.register_fn("parse_json", |json_str: &str| -> String { | ||||
|         // Just return the JSON string as is - Rhai can work with it directly | ||||
|         json_str.to_string() | ||||
|     }); | ||||
|      | ||||
|  | ||||
|     // Execute the script | ||||
|     match engine.eval::<bool>(&script) { | ||||
|         Ok(success) => { | ||||
|             assert!(success, "FList operations workflow test failed"); | ||||
|             Ok(()) | ||||
|         }, | ||||
|         } | ||||
|         Err(e) => { | ||||
|             println!("Error in FList operations workflow test: {}", e); | ||||
|             // Don't fail the test if the server doesn't have the expected data | ||||
| @@ -843,7 +887,7 @@ fn test_flist_operations_workflow() -> Result<(), Box<dyn std::error::Error>> { | ||||
| fn test_rfs_download_flist_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine)?; | ||||
|      | ||||
|  | ||||
|     // Create a client first | ||||
|     let create_script = format!( | ||||
|         r#" | ||||
| @@ -851,14 +895,14 @@ fn test_rfs_download_flist_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(&create_script)?; | ||||
|     assert!(result, "Failed to create RFS client"); | ||||
|      | ||||
|  | ||||
|     // Create a temporary file for download | ||||
|     let temp_file = NamedTempFile::new()?; | ||||
|     let temp_path = temp_file.path().to_str().unwrap(); | ||||
|      | ||||
|  | ||||
|     // Test downloading an FList (assuming test flist exists) | ||||
|     let download_script = format!( | ||||
|         r#" | ||||
| @@ -868,13 +912,13 @@ fn test_rfs_download_flist_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|         }} | ||||
|         true | ||||
|     "#, | ||||
|         temp_path.replace('\\', "\\\\")  // Escape backslashes for Windows paths | ||||
|         temp_path.replace('\\', "\\\\") // Escape backslashes for Windows paths | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     // This might fail if the test flist doesn't exist, but we're testing the wrapper | ||||
|     let result: bool = engine.eval(&download_script).unwrap_or_else(|_| true); | ||||
|     assert!(result, "Failed to execute download flist script"); | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @@ -883,7 +927,7 @@ fn test_rfs_download_flist_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
| fn test_rfs_wait_for_flist_creation_wrapper() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine)?; | ||||
|      | ||||
|  | ||||
|     // Create a client first | ||||
|     let create_script = format!( | ||||
|         r#" | ||||
| @@ -891,14 +935,14 @@ fn test_rfs_wait_for_flist_creation_wrapper() -> Result<(), Box<dyn std::error:: | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     let result: bool = engine.eval(&create_script)?; | ||||
|     assert!(result, "Failed to create RFS client"); | ||||
|      | ||||
|  | ||||
|     // Authenticate before invoking operations that require it | ||||
|     let authed: bool = engine.eval(r#" rfs_authenticate() "#)?; | ||||
|     assert!(authed, "Authentication failed in wait wrapper test"); | ||||
|      | ||||
|  | ||||
|     // Intentionally use a dummy job id and assert the wrapper returns a meaningful error | ||||
|     let wait_script = r#" | ||||
|         // This call should fail because the job id is dummy; we want to see the error path | ||||
| @@ -907,13 +951,20 @@ fn test_rfs_wait_for_flist_creation_wrapper() -> Result<(), Box<dyn std::error:: | ||||
|  | ||||
|     let eval_res = engine.eval::<String>(wait_script); | ||||
|     match eval_res { | ||||
|         Ok(s) => panic!("Expected failure for dummy job id, but got success with result: {}", s), | ||||
|         Ok(s) => panic!( | ||||
|             "Expected failure for dummy job id, but got success with result: {}", | ||||
|             s | ||||
|         ), | ||||
|         Err(e) => { | ||||
|             let msg = e.to_string(); | ||||
|             assert!(msg.contains("Operation timed out"), "Unexpected error message: {}", msg); | ||||
|             assert!( | ||||
|                 msg.contains("Operation timed out"), | ||||
|                 "Unexpected error message: {}", | ||||
|                 msg | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @@ -925,18 +976,24 @@ fn test_rfs_wait_for_flist_creation_wrapper() -> Result<(), Box<dyn std::error:: | ||||
| #[test] | ||||
| fn test_rfs_get_system_info_with_server() { | ||||
|     if !is_server_running(TEST_SERVER_URL) { | ||||
|         println!("Skipping integration test - no RFS server running at {}", TEST_SERVER_URL); | ||||
|         println!( | ||||
|             "Skipping integration test - no RFS server running at {}", | ||||
|             TEST_SERVER_URL | ||||
|         ); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).unwrap(); | ||||
|      | ||||
|     let script = format!(r#" | ||||
|  | ||||
|     let script = format!( | ||||
|         r#" | ||||
|         rfs_create_client("{}", "", "", 30); | ||||
|         rfs_get_system_info() | ||||
|     "#, TEST_SERVER_URL); | ||||
|      | ||||
|     "#, | ||||
|         TEST_SERVER_URL | ||||
|     ); | ||||
|  | ||||
|     let result = engine.eval::<String>(&script); | ||||
|     match result { | ||||
|         Ok(info) => { | ||||
| @@ -954,19 +1011,25 @@ fn test_rfs_get_system_info_with_server() { | ||||
| #[test] | ||||
| fn test_rfs_authenticate_with_server() { | ||||
|     if !is_server_running(TEST_SERVER_URL) { | ||||
|         println!("Skipping integration test - no RFS server running at {}", TEST_SERVER_URL); | ||||
|         println!( | ||||
|             "Skipping integration test - no RFS server running at {}", | ||||
|             TEST_SERVER_URL | ||||
|         ); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).unwrap(); | ||||
|      | ||||
|  | ||||
|     // Test with dummy credentials (will likely fail, but tests the flow) | ||||
|     let script = format!(r#" | ||||
|     let script = format!( | ||||
|         r#" | ||||
|         rfs_create_client("{}", "{}", "{}", 30); | ||||
|         rfs_authenticate() | ||||
|     "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD); | ||||
|      | ||||
|     "#, | ||||
|         TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD | ||||
|     ); | ||||
|  | ||||
|     let result = engine.eval::<bool>(&script); | ||||
|     match result { | ||||
|         Ok(success) => { | ||||
| @@ -974,7 +1037,10 @@ fn test_rfs_authenticate_with_server() { | ||||
|             assert!(success); | ||||
|         } | ||||
|         Err(e) => { | ||||
|             println!("Expected authentication failure with dummy credentials: {}", e); | ||||
|             println!( | ||||
|                 "Expected authentication failure with dummy credentials: {}", | ||||
|                 e | ||||
|             ); | ||||
|             // This is expected with dummy credentials | ||||
|             assert!(e.to_string().contains("Authentication failed")); | ||||
|         } | ||||
| @@ -985,14 +1051,18 @@ fn test_rfs_authenticate_with_server() { | ||||
| #[test] | ||||
| fn test_complete_workflow_with_server() { | ||||
|     if !is_server_running(TEST_SERVER_URL) { | ||||
|         println!("Skipping integration test - no RFS server running at {}", TEST_SERVER_URL); | ||||
|         println!( | ||||
|             "Skipping integration test - no RFS server running at {}", | ||||
|             TEST_SERVER_URL | ||||
|         ); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     let mut engine = Engine::new(); | ||||
|     register_rfs_module(&mut engine).unwrap(); | ||||
|      | ||||
|     let script = format!(r#" | ||||
|  | ||||
|     let script = format!( | ||||
|         r#" | ||||
|         // Create client | ||||
|         let client_created = rfs_create_client("{}", "", "", 60); | ||||
|         print("Client created: " + client_created); | ||||
| @@ -1003,8 +1073,10 @@ fn test_complete_workflow_with_server() { | ||||
|          | ||||
|         // Return success | ||||
|         client_created && info_result.len() > 0 | ||||
|     "#, TEST_SERVER_URL); | ||||
|      | ||||
|     "#, | ||||
|         TEST_SERVER_URL | ||||
|     ); | ||||
|  | ||||
|     let result = engine.eval::<bool>(&script); | ||||
|     match result { | ||||
|         Ok(success) => { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user