2025-11-08 15:13:22 +09:00
|
|
|
//! Provider registry: selects concrete providers for core resources (e.g. FileBox).
|
2025-11-08 17:04:21 +09:00
|
|
|
//! SSOT (Single Source of Truth) for provider selection via ProviderFactory registration.
|
2025-11-08 15:13:22 +09:00
|
|
|
|
2025-11-08 17:04:21 +09:00
|
|
|
use std::sync::{Arc, Mutex, OnceLock};
|
2025-11-08 15:13:22 +09:00
|
|
|
|
|
|
|
|
use crate::boxes::file::provider::FileIo;
|
|
|
|
|
use crate::boxes::file::core_ro::CoreRoFileIo;
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub enum FileBoxMode { Auto, CoreRo, PluginOnly }
|
|
|
|
|
|
2025-11-08 17:04:21 +09:00
|
|
|
/// Factory for creating FileIo providers
|
|
|
|
|
pub trait ProviderFactory: Send + Sync {
|
|
|
|
|
fn box_name(&self) -> &str;
|
|
|
|
|
fn create_provider(&self) -> Arc<dyn FileIo>;
|
|
|
|
|
fn is_available(&self) -> bool;
|
|
|
|
|
fn priority(&self) -> i32 {
|
|
|
|
|
0 // Default priority (higher = preferred)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Global registry of provider factories
|
|
|
|
|
static PROVIDER_FACTORIES: OnceLock<Mutex<Vec<Arc<dyn ProviderFactory>>>> = OnceLock::new();
|
|
|
|
|
|
|
|
|
|
/// Register a provider factory (called by builtin/dynamic loaders)
|
|
|
|
|
pub fn register_provider_factory(factory: Arc<dyn ProviderFactory>) {
|
|
|
|
|
let registry = PROVIDER_FACTORIES.get_or_init(|| Mutex::new(Vec::new()));
|
|
|
|
|
registry.lock().unwrap().push(factory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Read FileBox mode from environment variables
|
2025-11-08 15:13:22 +09:00
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub fn read_filebox_mode_from_env() -> FileBoxMode {
|
|
|
|
|
match std::env::var("NYASH_FILEBOX_MODE").unwrap_or_else(|_| "auto".to_string()).as_str() {
|
|
|
|
|
"core-ro" => FileBoxMode::CoreRo,
|
|
|
|
|
"plugin-only" => FileBoxMode::PluginOnly,
|
|
|
|
|
_ => {
|
|
|
|
|
if std::env::var("NYASH_DISABLE_PLUGINS").as_deref() == Ok("1") {
|
|
|
|
|
FileBoxMode::CoreRo
|
|
|
|
|
} else { FileBoxMode::Auto }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-08 17:04:21 +09:00
|
|
|
/// Select provider based on mode and registered factories (SSOT)
|
2025-11-08 15:13:22 +09:00
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
2025-11-08 17:04:21 +09:00
|
|
|
let registry = PROVIDER_FACTORIES.get();
|
|
|
|
|
let quiet_pipe = crate::config::env::env_bool("NYASH_JSON_ONLY");
|
|
|
|
|
|
2025-11-08 15:13:22 +09:00
|
|
|
match mode {
|
2025-11-08 17:04:21 +09:00
|
|
|
FileBoxMode::Auto => {
|
|
|
|
|
// Try: dynamic/builtin (by priority) → core-ro fallback
|
|
|
|
|
if let Some(reg) = registry {
|
|
|
|
|
let mut factories: Vec<_> = reg.lock().unwrap()
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|f| f.box_name() == "FileBox" && f.is_available())
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
// Sort by priority (descending)
|
|
|
|
|
factories.sort_by(|a, b| b.priority().cmp(&a.priority()));
|
|
|
|
|
|
|
|
|
|
if let Some(factory) = factories.first() {
|
|
|
|
|
if !quiet_pipe {
|
|
|
|
|
eprintln!("[provider-registry] FileBox: using registered provider (priority={})", factory.priority());
|
|
|
|
|
}
|
|
|
|
|
return factory.create_provider();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fallback to core-ro
|
|
|
|
|
if !quiet_pipe {
|
|
|
|
|
eprintln!("[provider-registry] FileBox: using core-ro fallback");
|
|
|
|
|
}
|
|
|
|
|
Arc::new(CoreRoFileIo::new())
|
|
|
|
|
}
|
|
|
|
|
FileBoxMode::PluginOnly => {
|
|
|
|
|
// Try only registered providers, Fail-Fast if none available
|
|
|
|
|
if let Some(reg) = registry {
|
|
|
|
|
let mut factories: Vec<_> = reg.lock().unwrap()
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|f| f.box_name() == "FileBox" && f.is_available())
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
factories.sort_by(|a, b| b.priority().cmp(&a.priority()));
|
|
|
|
|
|
|
|
|
|
if let Some(factory) = factories.first() {
|
|
|
|
|
if !quiet_pipe {
|
|
|
|
|
eprintln!("[provider-registry] FileBox: using plugin-only provider (priority={})", factory.priority());
|
|
|
|
|
}
|
|
|
|
|
return factory.create_provider();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
panic!("FileBox plugin-only mode: no provider registered. Set NYASH_FILEBOX_MODE=auto or NYASH_FILEBOX_MODE=core-ro to use fallback.");
|
|
|
|
|
}
|
|
|
|
|
FileBoxMode::CoreRo => {
|
|
|
|
|
// Always use core-ro, ignore registry
|
|
|
|
|
if !quiet_pipe {
|
|
|
|
|
eprintln!("[provider-registry] FileBox: using core-ro (forced)");
|
|
|
|
|
}
|
2025-11-08 15:13:22 +09:00
|
|
|
Arc::new(CoreRoFileIo::new())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|