This commit is contained in:
Tsuki 2024-08-25 15:58:17 +08:00
parent 58947b9aa1
commit 2aecd72b8a
4 changed files with 163 additions and 242 deletions

View File

@ -14,11 +14,35 @@ use abi_stable::{
}, },
}; };
use parser::{Record, ValueResult}; use parser::{Record, ValueResult};
use radarg_plugin_interface::{ use radarg_plugin_interface::{
CoordType, Error, Loc3, MetaData, Plugin, PluginId, PluginMod, PluginMod_Ref, PluginResult, DataLoaderPlugin, DataLoaderPlugin_TO, Error, GridDataInfo, LoadedData, PluginId, PluginMod,
PluginResultType, PluginType, Plugin_TO, PluginMod_Ref, ProbeDataType, RadarGridData, VecResult,
}; };
macro_rules! data_rvec {
($data:ident, $({$parsed_vec:tt => $abi_stable_rvec:tt}),+) => {
match $data {
$(
ValueResult::$parsed_vec(data) => VecResult::$abi_stable_rvec(RVec::from(data)),
)+
}
};
}
macro_rules! data_type {
($datetype:ident, $({ $($name:literal)|+ => $type:tt }),+) => {
match $datetype {
$(
$($name)|+ => ProbeDataType::$type,
)+
_ => ProbeDataType::Unknown
}
};
}
#[export_root_module] #[export_root_module]
fn instantiate_root_module() -> PluginMod_Ref { fn instantiate_root_module() -> PluginMod_Ref {
PluginMod { new }.leak_into_prefix() PluginMod { new }.leak_into_prefix()
@ -28,182 +52,90 @@ struct ETWSLoader {
id: PluginId, id: PluginId,
} }
fn calculate_coverage(lat_deg: f64, lon_deg: f64, radius_km: f64) -> (f64, f64, f64, f64) { impl DataLoaderPlugin for ETWSLoader {
let center = Point::new(lon_deg, lat_deg);
// 计算四个方向(北、南、东、西)的点
let north = center.haversine_destination(0.0, radius_km);
let south = center.haversine_destination(180.0, radius_km);
let east = center.haversine_destination(90.0, radius_km);
let west = center.haversine_destination(270.0, radius_km);
let min_lat = south.y();
let max_lat = north.y();
let min_lon = west.x();
let max_lon = east.x();
(min_lat, max_lat, min_lon, max_lon)
}
impl Plugin for ETWSLoader {
fn plugin_id(&self) -> &PluginId { fn plugin_id(&self) -> &PluginId {
&self.id &self.id
} }
fn load(&self, path: RStr<'_>) -> RResult<PluginResult, Error> where { fn load(&self, path: RStr<'_>) -> RResult<RVec<LoadedData>, Error> where {
let mut lat_range = [0.0, 0.0];
let mut lon_range = [0.0, 0.0];
if let Ok(record) = Record::parse_from_path(path.to_string()) { if let Ok(record) = Record::parse_from_path(path.to_string()) {
let result_blocks = record let result = record
.blocks .blocks
.into_iter() .into_iter()
.map(|b| { .map(|b| {
let (dimension_len, data) = match b.data { let data = b.data;
ValueResult::I16(data) => ( let converted_data = data_rvec!(
data.len(), data,
radarg_plugin_interface::VecResult::I16(RVec::from(data)), {I16 => I16},
), {F32 => F32},
ValueResult::F32(data) => ( {F64 => F64},
data.len(), {I32 => I32},
radarg_plugin_interface::VecResult::F32(RVec::from(data)), {U32 => U32},
), {I64 => I64},
ValueResult::F64(data) => ( {U64 => U64},
data.len(), {I8 => I8},
radarg_plugin_interface::VecResult::F64(RVec::from(data)), {U8 => U8}
), );
ValueResult::I32(data) => (
data.len(),
radarg_plugin_interface::VecResult::I32(RVec::from(data)),
),
ValueResult::U32(data) => (
data.len(),
radarg_plugin_interface::VecResult::U32(RVec::from(data)),
),
ValueResult::I64(data) => (
data.len(),
radarg_plugin_interface::VecResult::I64(RVec::from(data)),
),
ValueResult::U64(data) => (
data.len(),
radarg_plugin_interface::VecResult::U64(RVec::from(data)),
),
ValueResult::I8(data) => (
data.len(),
radarg_plugin_interface::VecResult::I8(RVec::from(data)),
),
ValueResult::U8(data) => (
data.len(),
radarg_plugin_interface::VecResult::U8(RVec::from(data)),
),
};
let dimension_des = b.info.dimension_des;
let c = if dimension_des.contains(&format!("lat")) {
let len = b.info.dimension_values.len();
let lon = b.info.dimension_values.get(len - 1).unwrap(); let dimension_values = convert_nested_vec_to_rvec(b.info.dimension_values);
let lat = b.info.dimension_values.get(len - 2).unwrap(); let dimension_size = convert_vec_to_rvec(
b.info
lon_range = [lon[0], lon[lon.len() - 1]]; .dimension_size
lat_range = [lat[0], lat[lat.len() - 1]];
CoordType::Cartesian
} else if dimension_des.contains(&format!("ele"))
|| dimension_des.contains(&format!("el"))
|| dimension_des.contains(&format!("elevation"))
{
let (min_lat, max_lat, min_lon, max_lon) = calculate_coverage(
b.info.radar_lat.unwrap(),
b.info.radar_lon.unwrap(),
b.info.dimension_end[2],
);
lon_range = [min_lon, max_lon];
lat_range = [min_lat, max_lat];
CoordType::Polar(
Loc3 {
x: b.info.radar_lon.unwrap(),
y: b.info.radar_lat.unwrap(),
z: b.info.radar_alt.unwrap(),
},
b.info.dimension_end[2],
)
} else {
CoordType::Other
};
let shape = match b.info.dimension_size.len() {
1 => radarg_plugin_interface::DataShape::Vector,
2 => {
// let lat = b.info.dimension_values.get(0).unwrap();
// let lon = b.info.dimension_values.get(1).unwrap();
// lat_range = [lat[0], lat[lat.len() - 1]];
// lon_range = [lon[0], lon[lon.len() - 1]];
radarg_plugin_interface::DataShape::Matrix
}
_ => {
// let lat = b.info.dimension_values.get(1).unwrap();
// let lon = b.info.dimension_values.get(2).unwrap();
// lat_range = [lat[0], lat[lat.len() - 1]];
// lon_range = [lon[0], lon[lon.len() - 1]];
radarg_plugin_interface::DataShape::Cube
}
};
let data_type = match b.info.value_name.as_str() {
"ET" => PluginResultType::ET,
"VIL" => PluginResultType::VIL,
"EB" => PluginResultType::EB,
"DBZ" => PluginResultType::DBZ,
"CR" => PluginResultType::DBZ,
"R" => PluginResultType::R,
"V" => PluginResultType::V,
"ZDR" => PluginResultType::ZDR,
"PHIDP" => PluginResultType::PHIDP,
"KDP" => PluginResultType::KDP,
"CC" => PluginResultType::CC,
"HCA" => PluginResultType::HCA,
"QPE" => PluginResultType::QPE,
"QPF" => PluginResultType::QPF,
"FR" => PluginResultType::DBZ,
_ => PluginResultType::Unknown,
};
radarg_plugin_interface::Block {
data: data,
shape,
size: RVec::from(b.info.dimension_size)
.into_iter() .into_iter()
.map(|p| p as usize) .map(|p| p as usize)
.collect::<RVec<_>>(), .collect::<Vec<_>>(),
datetime: record.filetime.timestamp(), );
dimensions: RVec::from(vec![RString::from("time")]), let dimension_names = convert_vec_to_rvec(
coord_type: c, b.info
dimension_values: RVec::from( .dimension_des
b.info .into_iter()
.dimension_values .map(RString::from)
.into_iter() .collect::<Vec<_>>(),
.map(|p| RVec::from(p)) );
.collect::<Vec<_>>(),
), let fill_value = b.info.fill_value;
fill_value: b.info.fill_value, let value_name = RString::from(b.info.value_name);
data_type, let value_description = RString::from(b.info.value_des);
} let datetime = record.filetime.timestamp();
let value_key = value_name.as_str();
let data_type = data_type!(
value_key,
{ "ET" => ET },
{ "DBZ" | "CR" | "FR" | "R" => DBZ},
{ "VIL" => VIL},
{ "EB" => EB},
{ "V" => V},
{ "ZDR" => ZDR},
{ "PHIDP" => PHIDP},
{ "KDP" => KDP},
{ "CC" =>CC},
{ "HCA" => HCA},
{ "QPE" => QPE},
{ "QPF" => QPF}
);
let grid_info = GridDataInfo {
shape: dimension_size,
dimensions: dimension_values,
dimension_names,
fill_value,
datetime: RSome(datetime),
value_description: RSome(value_description),
maybe_probe_data_type: RSome(data_type),
value_name,
dimension_description: "Wrong".into(),
};
LoadedData::RadarGridData(RadarGridData {
data: converted_data,
info: grid_info,
})
}) })
.collect::<RVec<_>>(); .collect::<RVec<_>>();
let meta = MetaData { ROk(result)
datetime: RSome(record.filetime.timestamp()),
site_info: RNone,
lon_range: RSome(lon_range),
lat_range: RSome(lat_range),
data_format: RSome("Eastone Washon Radar".into()),
other_info: RNone,
};
ROk(PluginResult {
datetime: RString::from(record.filetime.format("%Y%m%d%H%M").to_string()),
blocks: result_blocks,
meta,
})
} else { } else {
RErr(Error::UnsupportedFormat) RErr(Error::UnsupportedFormat)
} }
@ -211,6 +143,7 @@ impl Plugin for ETWSLoader {
fn plugin_info(&self) -> radarg_plugin_interface::PluginInfo where { fn plugin_info(&self) -> radarg_plugin_interface::PluginInfo where {
radarg_plugin_interface::PluginInfo { radarg_plugin_interface::PluginInfo {
plugin_type: "DataLoader".into(),
name: "ETWS_Loader".into(), name: "ETWS_Loader".into(),
version: "0.1.0".into(), version: "0.1.0".into(),
author: "Tsuki".into(), author: "Tsuki".into(),
@ -220,10 +153,22 @@ impl Plugin for ETWSLoader {
} }
} }
fn convert_iter_to_rvec<T>(raw: impl Iterator<Item = T>) -> RVec<T> {
RVec::from(raw.collect::<Vec<_>>())
}
fn convert_vec_to_rvec<T>(raw: Vec<T>) -> RVec<T> {
RVec::from(raw)
}
fn convert_nested_vec_to_rvec<T>(raw: Vec<Vec<T>>) -> RVec<RVec<T>> {
RVec::from(raw.into_iter().map(RVec::from).collect::<Vec<_>>())
}
#[sabi_extern_fn] #[sabi_extern_fn]
pub fn new(plugin_id: PluginId) -> RResult<PluginType, Error> { pub fn new(plugin_id: PluginId) -> RResult<dyn DataLoaderPlugin, Error> {
let this = ETWSLoader { id: plugin_id }; let this = ETWSLoader { id: plugin_id };
ROk(Plugin_TO::from_value(this, TD_Opaque)) ROk(DataLoaderPlugin_TO::from_value(this, TD_Opaque))
} }
// 测试模块 // 测试模块

View File

@ -2,9 +2,12 @@ pub mod data;
use data::GridData; use data::GridData;
use quick_cache::sync::Cache; use quick_cache::sync::Cache;
use radarg_plugin_interface::Plugin;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use crate::PLUGIN_MANAGER;
pub type Value<T> = Arc<T>; pub type Value<T> = Arc<T>;
pub enum Data { pub enum Data {
@ -24,12 +27,15 @@ impl DataPool {
pub fn get_or_load(&self, path: impl Into<PathBuf>) -> Result<Value<Data>, ()> { pub fn get_or_load(&self, path: impl Into<PathBuf>) -> Result<Value<Data>, ()> {
self.pool.get_or_insert_async(&path.into(), async { self.pool.get_or_insert_async(&path.into(), async {
let path = path.into(); // let path = path.into();
let data = match path.extension().and_then(|ext| ext.to_str()) {
Some("grid") => Data::GridData(GridData::load(&path).await.unwrap()), for data_loader in PLUGIN_MANAGER.data_loader_plugin().iter() {
_ => panic!("Unsupported file type"), let path: PathBuf = path.into();
}; if let Ok(data) = data_loader.load(path.as_os_str().to_str().unwrap().into()) {
Ok(Arc::new(data)) return Ok(Arc::new(Data::GridData(GridData::new(data))));
}
}
Err(())
}) })
} }
} }

View File

@ -93,4 +93,12 @@ impl PluginManager {
.find(|(id, _)| id.named == name) .find(|(id, _)| id.named == name)
.map(|(_, p)| p) .map(|(_, p)| p)
} }
pub fn data_loader_plugin(&self) -> Vec<&Plugin_TO<'static, RBox<()>>> {
self.registered_plugins
.iter()
.filter(|p| p.1.plugin_info().plugin_type == "DataLoader")
.map(|p| p.1)
.collect()
}
} }

View File

@ -12,38 +12,30 @@ pub use self::error::Error;
/// The identifier for a plugin. /// The identifier for a plugin.
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, PartialEq, Eq, StableAbi, Hash)] #[derive(Debug, Clone, PartialEq, Eq, StableAbi, Hash)]
#[sabi(impl_InterfaceType(Sync, Send, Debug, Debug, Hash))]
pub struct PluginId { pub struct PluginId {
pub named: RCowStr<'static>, pub named: RCowStr<'static>,
/// The number of the instance of this Plugin.
pub instance: u64, pub instance: u64,
} }
// Plugin Can be loaded from a file path
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, StableAbi, Copy)] #[derive(Clone, Debug, StableAbi)]
#[sabi(impl_InterfaceType(Sync, Send, Debug, Debug))] pub enum LoadedData {
pub struct Loc3 { RadarGridData(RadarGridData),
pub x: f64, JsonData,
pub y: f64, PlainText(RString),
pub z: f64, Binary(RVec<u8>),
}
#[repr(C)]
#[derive(StableAbi, Clone, Debug)]
pub struct RadarGridData {
pub data: VecResult,
pub info: GridDataInfo,
} }
pub type Range = f64;
#[repr(C)]
#[derive(StableAbi, Clone, Debug, Copy)]
#[sabi(impl_InterfaceType(Sync, Send, Debug, Debug))]
pub enum CoordType {
Polar(Loc3, Range),
Cartesian,
Other,
}
pub type PluginType = Plugin_TO<'static, RBox<()>>;
#[repr(C)] #[repr(C)]
#[derive(StableAbi, Clone, Debug)] #[derive(StableAbi, Clone, Debug)]
#[sabi(impl_InterfaceType(Sync, Send, Debug))]
pub enum VecResult { pub enum VecResult {
I64(RVec<i64>), I64(RVec<i64>),
F64(RVec<f64>), F64(RVec<f64>),
@ -58,29 +50,22 @@ pub enum VecResult {
} }
#[repr(C)] #[repr(C)]
#[derive(StableAbi, Clone, Copy, Debug)] #[derive(StableAbi, Clone, Debug)]
#[sabi(impl_InterfaceType(Sync, Send, Debug))] pub struct GridDataInfo {
pub enum DataShape { pub shape: RVec<usize>,
Vector, pub dimensions: RVec<RVec<f64>>,
Matrix, pub dimension_names: RVec<RString>,
Cube, pub fill_value: f64,
}
#[repr(C)]
#[derive(Debug, StableAbi, Clone)]
pub struct MetaData {
pub datetime: ROption<i64>, pub datetime: ROption<i64>,
pub site_info: ROption<RString>, pub value_description: ROption<RString>,
pub lat_range: ROption<[f64; 2]>, pub value_name: RString,
pub lon_range: ROption<[f64; 2]>, pub maybe_probe_data_type: ROption<ProbeDataType>,
pub data_format: ROption<RString>, pub dimension_description: RString,
pub other_info: ROption<RString>,
} }
#[repr(C)] #[repr(C)]
#[derive(StableAbi, Clone, Copy, Debug)] #[derive(StableAbi, Clone, Copy, Debug)]
#[sabi(impl_InterfaceType(Sync, Send, Debug))] pub enum ProbeDataType {
pub enum PluginResultType {
// Single // Single
R, R,
V, V,
@ -102,34 +87,11 @@ pub enum PluginResultType {
Unknown, Unknown,
} }
#[repr(C)]
#[derive(StableAbi, Clone, Debug)]
#[sabi(impl_InterfaceType(Sync, Send, Debug))]
pub struct PluginResult {
pub datetime: RString,
pub meta: MetaData,
pub blocks: RVec<Block>,
}
#[repr(C)]
#[derive(StableAbi, Clone, Debug)]
#[sabi(impl_InterfaceType(Sync, Send, Debug))]
pub struct Block {
pub data: VecResult,
pub shape: DataShape,
pub size: RVec<usize>,
pub coord_type: CoordType,
pub datetime: i64,
pub dimensions: RVec<RString>,
pub dimension_values: RVec<RVec<f64>>,
pub fill_value: f64,
pub data_type: PluginResultType,
}
#[repr(C)] #[repr(C)]
#[derive(Debug, StableAbi)] #[derive(Debug, StableAbi)]
#[sabi(impl_InterfaceType(Sync, Send, Debug))] #[sabi(impl_InterfaceType(Sync, Send, Debug))]
pub struct PluginInfo { pub struct PluginInfo {
pub plugin_type: RStr<'static>,
pub name: RStr<'static>, pub name: RStr<'static>,
pub version: RStr<'static>, pub version: RStr<'static>,
pub author: RStr<'static>, pub author: RStr<'static>,
@ -137,10 +99,11 @@ pub struct PluginInfo {
pub url: ROption<RStr<'static>>, pub url: ROption<RStr<'static>>,
} }
pub type PluginType = DataLoaderPlugin_TO<'static, RBox<()>>;
#[sabi_trait] #[sabi_trait]
#[sabi(impl_InterfaceType(Sync, Send, Debug))] pub trait DataLoaderPlugin: Send + Sync {
pub trait Plugin: Send + Sync { fn load(&self, path: RStr<'_>) -> RResult<RVec<LoadedData>, Error>;
fn load(&self, path: RStr<'_>) -> RResult<PluginResult, Error>;
fn plugin_id(&self) -> &PluginId; fn plugin_id(&self) -> &PluginId;
fn plugin_info(&self) -> PluginInfo; fn plugin_info(&self) -> PluginInfo;
} }
@ -151,7 +114,6 @@ pub trait Plugin: Send + Sync {
/// call <PluginMod as RootModule>::load_from_directory(some_directory_path) /// call <PluginMod as RootModule>::load_from_directory(some_directory_path)
#[repr(C)] #[repr(C)]
#[derive(StableAbi)] #[derive(StableAbi)]
#[sabi(impl_InterfaceType(Sync, Send, Debug))]
#[sabi(kind(Prefix(prefix_ref = PluginMod_Ref)))] #[sabi(kind(Prefix(prefix_ref = PluginMod_Ref)))]
#[sabi(missing_field(panic))] #[sabi(missing_field(panic))]
pub struct PluginMod { pub struct PluginMod {
@ -173,7 +135,7 @@ pub struct PluginMod {
impl RootModule for PluginMod_Ref { impl RootModule for PluginMod_Ref {
declare_root_module_statics! {PluginMod_Ref} declare_root_module_statics! {PluginMod_Ref}
const BASE_NAME: &'static str = "plugin"; const BASE_NAME: &'static str = "data_loader_plugin";
const NAME: &'static str = "plugin"; const NAME: &'static str = "data_loader_plugin";
const VERSION_STRINGS: VersionStrings = package_version_strings!(); const VERSION_STRINGS: VersionStrings = package_version_strings!();
} }