1use std::path::PathBuf;
2
3use libloading::Library;
4use tokio::task::JoinHandle;
5use url::Url;
6
7use crate::prelude::*;
8
9pub trait UrlPlugin: Send {
10 #[allow(clippy::new_ret_no_self)]
11 fn new() -> JoinHandle<Result<Box<dyn UrlPlugin>>>
12 where
13 Self: Sized;
14
15 fn load(
16 &self,
17 url: Url,
18 inputs: Inputs,
19 outputs: Outputs,
20 configuration: serde_yml::Value,
21 ) -> JoinHandle<Result<RuntimeNode>>;
22}
23
24pub type DynamicallyLinkedUrlPluginInstance = fn() -> JoinHandle<Result<Box<dyn UrlPlugin>>>;
25
26pub struct DynamicallyLinkedUrlPlugin {
27 handle: Box<dyn UrlPlugin>, _library: Library,
29}
30
31pub enum RuntimeUrlPlugin {
32 StaticallyLinked(Box<dyn UrlPlugin>),
33 DynamicallyLinked(DynamicallyLinkedUrlPlugin),
34}
35
36impl RuntimeUrlPlugin {
37 pub async fn new_statically_linked<T: UrlPlugin + 'static>() -> Result<Self> {
38 Ok(Self::StaticallyLinked(
39 T::new()
40 .await
41 .wrap_err("Failed to await for statically linked url plugin")?
42 .wrap_err("Failed to create statically linked url plugin")?,
43 ))
44 }
45
46 pub async fn new_dynamically_linked(path: PathBuf) -> Result<Self> {
47 let library = unsafe { Library::new(path)? };
48 let constructor = unsafe {
49 library
50 .get::<*mut DynamicallyLinkedUrlPluginInstance>(b"FLARROW_URL_PLUGIN")?
51 .read()
52 };
53
54 Ok(RuntimeUrlPlugin::DynamicallyLinked(
55 DynamicallyLinkedUrlPlugin {
56 _library: library,
57 handle: (constructor)()
58 .await
59 .wrap_err("Failed to await for dynamically linked url plugin")?
60 .wrap_err("Failed to create dynamically linked url plugin")?,
61 },
62 ))
63 }
64
65 pub fn load(
66 &self,
67 url: Url,
68 inputs: Inputs,
69 outputs: Outputs,
70 configuration: serde_yml::Value,
71 ) -> JoinHandle<Result<RuntimeNode>> {
72 match self {
73 RuntimeUrlPlugin::StaticallyLinked(plugin) => {
74 plugin.load(url, inputs, outputs, configuration)
75 }
76 RuntimeUrlPlugin::DynamicallyLinked(plugin) => {
77 plugin.handle.load(url, inputs, outputs, configuration)
78 }
79 }
80 }
81}