pub type InitedVehicleValidator = Box; pub struct InitedVehicleValidators { pub multiplayer: std::sync::Arc, pub custom_game: std::sync::Arc, pub singleplayer: std::sync::Arc, pub campaigns: std::sync::Arc>, } pub fn validators_from_conf(conf: &oj_rc_core::persist::config::VehicleValidators, parsers: &oj_rc_core::cubes::CubeParsers, plugins_path: impl AsRef) -> InitedVehicleValidators { let plugins_path = plugins_path.as_ref(); InitedVehicleValidators { multiplayer: std::sync::Arc::new(validator_from_conf(&conf.multiplayer, parsers, plugins_path)), custom_game: std::sync::Arc::new(validator_from_conf(&conf.multiplayer, parsers, plugins_path)), singleplayer: std::sync::Arc::new(validator_from_conf(&conf.singleplayer, parsers, plugins_path)), campaigns: std::sync::Arc::new( conf.campaigns.iter() .map(|(campaign_id, validator)| (campaign_id.to_owned(), validator_from_conf(validator, parsers, plugins_path))) .collect() ), } } fn validator_from_conf(conf: &oj_rc_core::persist::VehicleValidator, parsers: &oj_rc_core::cubes::CubeParsers, plugins_path: impl AsRef) -> InitedVehicleValidator { match conf { oj_rc_core::persist::VehicleValidator::None => Box::new(AlwaysValid) as _, oj_rc_core::persist::VehicleValidator::Cpu { min, max } => Box::new(CpuRange { range: *min..=*max, parser: parsers.cpu_counter(), }) as _, oj_rc_core::persist::VehicleValidator::All { all } => Box::new(All::init(all, parsers, plugins_path)) as _, oj_rc_core::persist::VehicleValidator::Any { any } => Box::new(Any::init(any, parsers, plugins_path)) as _, oj_rc_core::persist::VehicleValidator::Custom { path } => { let full_path = plugins_path.as_ref().join(path); log::warn!("Custom vehicle validator plugin {} is experimental and insecure", full_path.display()); let result = oj_rc_plugins::vehicle_validation::VehicleValidatorCPlugin::new(&full_path); match result { Ok(c_plugin) => Box::new(c_plugin) as _, Err(e) => { log::error!("Failed to load custom vehicle validator plugin {}: {} (crashing!)", full_path.display(), e); panic!("Failed to load custom vehicle validator plugin {}: {}", full_path.display(), e) } } }, } } struct AlwaysValid; impl oj_rc_plugins::vehicle_validation::VehicleValidatorPlugin for AlwaysValid { fn validate(&self, _cube_data: &[u8], _colour_data: &[u8]) -> oj_rc_plugins::vehicle_validation::ValidationResultCode { oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok } } impl oj_rc_plugins::Plugin for AlwaysValid {} struct CpuRange { range: std::ops::RangeInclusive, parser: std::sync::Arc, } impl oj_rc_plugins::vehicle_validation::VehicleValidatorPlugin for CpuRange { fn validate(&self, cube_data: &[u8], _colour_data: &[u8]) -> oj_rc_plugins::vehicle_validation::ValidationResultCode { let cpu_info = self.parser.calculate_cpu(&mut std::io::Cursor::new(cube_data)); if self.range.contains(&(cpu_info.total - cpu_info.cosmetic)) { oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok } else { oj_rc_plugins::vehicle_validation::ValidationResultCode::Invalid } } } impl oj_rc_plugins::Plugin for CpuRange {} struct All(Vec); impl All { fn init(items: &[oj_rc_core::persist::VehicleValidator], parsers: &oj_rc_core::cubes::CubeParsers, plugins_path: impl AsRef) -> Self { let plugins_path = plugins_path.as_ref(); All( items.iter() .map(|item| validator_from_conf(item, parsers, plugins_path)) .collect() ) } } impl oj_rc_plugins::vehicle_validation::VehicleValidatorPlugin for All { fn validate(&self, cube_data: &[u8], colour_data: &[u8]) -> oj_rc_plugins::vehicle_validation::ValidationResultCode { self.0.iter() .filter_map(|item| { let code = item.validate(cube_data, colour_data); if matches!(code, oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok) { None } else { Some(code) } }) .next() .unwrap_or(oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok) } } impl oj_rc_plugins::Plugin for All {} struct Any(Vec); impl Any { fn init(items: &[oj_rc_core::persist::VehicleValidator], parsers: &oj_rc_core::cubes::CubeParsers, plugins_path: impl AsRef) -> Self { let plugins_path = plugins_path.as_ref(); Any( items.iter() .map(|item| validator_from_conf(item, parsers, plugins_path)) .collect() ) } } impl oj_rc_plugins::vehicle_validation::VehicleValidatorPlugin for Any { fn validate(&self, cube_data: &[u8], colour_data: &[u8]) -> oj_rc_plugins::vehicle_validation::ValidationResultCode { self.0.iter() .map_while(|item| { let code = item.validate(cube_data, colour_data); if matches!(code, oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok) { None } else { Some(code) } }) .next() .unwrap_or(oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok) } } impl oj_rc_plugins::Plugin for Any {}