Skip to Content

Plugin File Client Usage Guide

Overview

The PluginFileClient provides essential file operations designed specifically for plugin developers using MVEL, JavaScript, or Python. It offers simple, secure methods for file I/O, JSON/CSV handling, and directory operations with built-in error handling and sandboxing.

Key Features

  • Simplified API: Only essential methods for data processing
  • Script-Friendly: Designed for MVEL, JavaScript, and Python developers
  • Secure by Design: Sandboxed operations with path validation
  • Atomic Writes: Data integrity for configuration and export files
  • JSON/CSV Support: Built-in support for common data formats
  • Error Handling: Consistent error reporting without exceptions

Core API Methods

File Operations (6 methods)

  • read(String filePath) - Read text file content
  • write(String filePath, String content) - Write text to file
  • write(String filePath, String content, boolean append) - Write or append text
  • append(String filePath, String content) - Append to file (convenience method)
  • delete(String filePath) - Delete a file
  • exists(String filePath) - Check if file exists

JSON Operations (3 methods)

  • readJson(String filePath) - Read and parse JSON file
  • writeJson(String filePath, Object data) - Write object as JSON
  • appendJson(String filePath, Object element) - Append to JSON array

CSV Operations (3 methods)

  • readCsv(String filePath) - Read CSV with headers
  • writeCsv(String filePath, List headers, List<List> rows, boolean append) - Write CSV data
  • appendCsv(String filePath, List<List> rows) - Append rows to CSV

Directory Operations (2 methods)

  • createDir(String dirPath) - Create directory with parents
  • listFiles(String dirPath) - List files in directory

Path Utilities (2 methods)

  • joinPath(String... parts) - Build platform-independent paths
  • getFileName(String filePath) - Extract filename from path

Basic Usage Examples

Simple File Operations

// MVEL - Read configuration content = files.read("config.txt") if (content.isSuccess()) { configText = content.getAsString() log.info("Config loaded: " + configText) } // Write processing data result = files.write("output.txt", "Item processed: " + itemId) if (result.isSuccess()) { log.info("Data written successfully") } // Append to log file files.append("process.log", "Event: " + eventId + "\n")
// JavaScript - File operations with error handling const content = files.read("data.txt"); if (content.isSuccess()) { console.log("File content:", content.getAsString()); } else { console.error("Read failed:", content.getErrorMessage()); } // Append to event log const logEntry = `[${new Date()}] Item ${itemId} processed\n`; files.append("events.log", logEntry);
# Python - Check and write file if not files.exists("output.csv"): # Create new file with headers headers = ["item_id", "timestamp", "event_count"] files.writeCsv("output.csv", headers, [], False) # Append data files.append("debug.log", f"Processing item {item_id}\n")

JSON Operations

// MVEL - Read configuration configResult = files.readJson("config.json") if (configResult.isSuccess()) { config = configResult.getData() apiUrl = config.get("api_url") timeout = config.get("timeout") } // Export data eventData = { "id": eventId, "timestamp": System.currentTimeMillis(), "count": eventCount } files.writeJson("events/" + eventId + ".json", eventData) // Append to event log event = { "type": "item_processed", "item_id": itemId, "time": System.currentTimeMillis() } files.appendJson("events.json", event)
// JavaScript - Configuration and logging const settings = files.readJson("settings.json"); if (settings.isSuccess()) { const config = settings.getData(); const network = config.network || "mainnet"; console.log(`Connected to ${network}`); } // Log event const event = { id: eventData.getId(), amount: eventData.getValue(), timestamp: Date.now() }; files.appendJson("events.json", event);
# Python - JSON data export summary = { "period": current_period, "items_processed": item_count, "total_events": event_count, "timestamp": System.currentTimeMillis() } files.writeJson(f"summaries/period_{current_period}.json", summary) # Append to audit log audit_entry = { "action": "export_completed", "period": current_period, "records": record_count } files.appendJson("audit.json", audit_entry)

CSV Operations

// MVEL - Export event data headers = ["event_id", "item_id", "amount", "fee"] rows = [] for (event : events) { row = [ event.getId(), String.valueOf(itemId), String.valueOf(event.getAmount()), String.valueOf(event.getFee()) ] rows.add(row) } // Write new CSV file files.writeCsv("transactions.csv", headers, rows, false) // Or append to existing CSV files.appendCsv("all_transactions.csv", rows)
// JavaScript - Read and process CSV const csvResult = files.readCsv("addresses.csv"); if (csvResult.isSuccess()) { const records = csvResult.getData(); console.log(`Processing ${records.length} addresses`); records.forEach(record => { const address = record.address; const balance = record.balance; // Process each address }); } // Append new data const newRows = [ [newAddress, newBalance.toString(), "0"], [anotherAddress, anotherBalance.toString(), "1"] ]; files.appendCsv("addresses.csv", newRows);
# Python - CSV export with append headers = ["epoch", "slot", "block_hash", "tx_count"] # Write headers if new file if not files.exists("blocks.csv"): files.writeCsv("blocks.csv", headers, [], False) # Append block data row = [ str(epoch_number), str(slot_number), block_hash, str(transaction_count) ] files.appendCsv("blocks.csv", [row])

Directory Operations

// MVEL - Organize output by date dateDir = "exports/" + new java.text.SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date()) files.createDir(dateDir) files.writeJson(dateDir + "/block_" + blockNumber + ".json", blockData) // List and process files listing = files.listFiles("imports/") if (listing.isSuccess()) { fileList = listing.getFiles() log.info("Found " + fileList.size() + " files to process") for (fileInfo : fileList) { if (fileInfo.getName().endsWith(".json")) { // Process JSON file data = files.readJson("imports/" + fileInfo.getName()) // ... } } }
// JavaScript - Batch processing files.createDir("processed"); const listing = files.listFiles("pending/"); if (listing.isSuccess()) { const files = listing.getFiles(); const jsonFiles = listing.filterByExtension("json"); console.log(`Processing ${jsonFiles.length} JSON files`); jsonFiles.forEach(file => { const result = files.readJson(`pending/${file.getName()}`); if (result.isSuccess()) { // Process and move to processed directory const data = result.getData(); // ... process data ... files.writeJson(`processed/${file.getName()}`, data); files.delete(`pending/${file.getName()}`); } }); }
# Python - Directory organization # Create directory structure files.createDir("data/blocks") files.createDir("data/transactions") files.createDir("data/addresses") # List and count files listing = files.listFiles("data/blocks/") if listing.isSuccess(): file_count = len(listing.getFiles()) print(f"Total blocks stored: {file_count}")

Path Operations

// MVEL - Build paths safely basePath = "exports" yearMonth = new java.text.SimpleDateFormat("yyyy/MM").format(new java.util.Date()) fileName = "block_" + blockNumber + ".json" // Cross-platform path construction fullPath = files.joinPath(basePath, yearMonth, fileName) files.createDir(files.joinPath(basePath, yearMonth)) files.writeJson(fullPath, blockData)
// JavaScript - Path manipulation const exportDir = "exports"; const date = new Date().toISOString().split('T')[0]; const filename = `transactions_${date}.csv`; const fullPath = files.joinPath(exportDir, date, filename); const dirPath = files.joinPath(exportDir, date); files.createDir(dirPath); files.writeCsv(fullPath, headers, rows, false); // Extract filename for logging const savedFile = files.getFileName(fullPath); console.log(`Data saved to: ${savedFile}`);

Best Practices

1. Always Check Operation Results

const result = files.read("important.json"); if (!result.isSuccess()) { console.error(`Failed to read file: ${result.getErrorMessage()}`); return; // Handle error appropriately } const data = result.getAsString();

2. Use Path Utilities for Cross-Platform Compatibility

// Good - works on all platforms const logPath = files.joinPath("logs", "2024", "01", "app.log"); // Avoid - platform-specific // const logPath = "logs/2024/01/app.log"; // Unix only // const logPath = "logs\\2024\\01\\app.log"; // Windows only

3. Choose Appropriate Write Mode

// For configuration and complete data - use write (overwrites) files.writeJson("config.json", settings); // For logs and continuous data - use append files.append("transaction.log", logEntry); files.appendJson("events.json", eventData); files.appendCsv("metrics.csv", newRows);

4. Organize Data with Directories

// Create logical directory structure files.createDir("data/blocks"); files.createDir("data/transactions"); files.createDir("logs/daily"); // Use date-based organization for time-series data const dateDir = new Date().toISOString().split('T')[0]; files.createDir(files.joinPath("exports", dateDir));

5. Handle Missing Files Gracefully

// Check existence before reading if (files.exists("state.json")) { const state = files.readJson("state.json"); // Resume from saved state } else { // Initialize new state const newState = { startBlock: 0, processed: 0 }; files.writeJson("state.json", newState); }

Security Features

The file client includes built-in security measures:

  1. Sandboxing: All file operations are confined to a designated sandbox directory
  2. Path Validation: Prevents directory traversal attacks
  3. No Dangerous Operations: No recursive deletion, file movement, or archive extraction
  4. Safe Defaults: Conservative permissions and error handling

Error Handling

All operations return a FileOperationResult with consistent error handling:

const result = files.readJson("data.json"); if (result.isSuccess()) { const data = result.getData(); // For JSON/CSV operations // or const text = result.getAsString(); // For text operations // Process data... } else { const error = result.getErrorMessage(); console.error(`Operation failed: ${error}`); }
Last updated on