JavaScript is disabled, refresh for a better experience. ambee/giterated

ambee/giterated

Git repository hosting, collaboration, and discovery for the Fediverse.

So. Much. Work.

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨b05f964

⁨giterated-plugins/giterated-plugin/src/handle.rs⁩ - ⁨7336⁩ bytes
Raw
1 use std::{collections::HashMap, marker::PhantomData, path::Path, sync::Arc};
2
3 use anyhow::Error;
4 use dlopen2::wrapper::Container;
5 use semver::Version;
6 use tracing::{debug, trace};
7
8 use crate::{
9 callback::{OperationHandlerCallback, SettingGetterCallback, ValueGetterCallback},
10 new_stack::{
11 ObjectOperationPair, ObjectSettingPair, ObjectValuePair, PluginMeta, PluginState,
12 RuntimeHandlers, TypeMetadata,
13 },
14 FFISettingMeta, FFIValueChangeHandler, FFIValueMeta, GiteratedPluginApi, InitializationVTable,
15 ObjectVtable, OperationVTable, SettingVtable, ValueVTable,
16 };
17
18 #[derive(Clone)]
19 pub struct PluginHandle {
20 pub meta: PluginMeta,
21 pub raw: Arc<Container<GiteratedPluginApi>>,
22 pub initialization: Arc<PluginInitializationState>,
23 pub state: PluginState,
24 }
25
26 impl PluginHandle {
27 pub fn from_dylib(path: &str) -> Result<Self, CreationError> {
28 let mut handle = unsafe { Container::load(path) }?;
29
30 // Initialize the raw handle
31 let init_state = Self::initialize_raw_handle(&mut handle)?;
32
33 let metadata = Self::get_meta(&mut handle)?;
34
35 let initalization = Self::initialize_registration(&mut handle)?;
36
37 trace!(
38 "Loaded plugin {} (Version: {})",
39 metadata.name,
40 metadata.version
41 );
42
43 Ok(Self {
44 raw: Arc::new(handle),
45 meta: metadata,
46 initialization: Arc::new(initalization),
47 state: init_state,
48 })
49 }
50
51 /// Builds the Plugin's Substack.
52 ///
53 /// Builds the Plugin into a substack, which can then be provided to the Giterated Runtime.
54 pub fn build_substack(&mut self) -> Result<(), Error> {
55 todo!()
56 }
57
58 fn get_meta(handle: &mut Container<GiteratedPluginApi>) -> Result<PluginMeta, CreationError> {
59 let meta = unsafe { handle.plugin_meta() };
60
61 let name = unsafe { std::slice::from_raw_parts(meta.name, meta.name_len) };
62 let version = unsafe { std::slice::from_raw_parts(meta.version, meta.version_len) };
63
64 let name = std::str::from_utf8(name).unwrap();
65 let version = std::str::from_utf8(version).unwrap();
66
67 Ok(PluginMeta {
68 name: String::from(name),
69 version: Version::parse(version).unwrap(),
70 })
71 }
72
73 pub fn initialize_registration(
74 handle: &mut Container<GiteratedPluginApi>,
75 ) -> Result<PluginInitializationState, CreationError> {
76 debug!("Initializing plugin registration...");
77 let mut builder = PluginInitializationTable::default();
78
79 // SAFETY: The lifetime of the returned type is only valid as long
80 // as the builder that returned it lives
81 let func_table = unsafe { builder.func_table() };
82
83 let state = Box::new(PluginInitializationState::new());
84
85 unsafe { handle.load_initialization_vtable(&func_table) };
86 let state = unsafe { handle.initialize_registration(Box::into_raw(state)) };
87
88 debug!("Plugin handle initialized!");
89 Ok(unsafe { *Box::from_raw(state) })
90 }
91
92 fn initialize_raw_handle(
93 handle: &mut Container<GiteratedPluginApi>,
94 ) -> Result<PluginState, CreationError> {
95 debug!("Initializing plugin handle...");
96
97 let state = unsafe { handle.initialize() };
98
99 debug!("Plugin handle initialized!");
100
101 Ok(state)
102 }
103 }
104
105 #[derive(Debug, thiserror::Error)]
106 pub enum CreationError {
107 #[error("an error occured opening the library {0}")]
108 LoadingLibrary(#[from] dlopen2::Error),
109 }
110
111 pub struct PluginSubstackBuilder {}
112
113 #[derive(Default)]
114 pub struct PluginInitializationState {
115 pub type_metadata: TypeMetadata,
116 pub operation_handlers: HashMap<ObjectOperationPair<'static>, OperationHandlerCallback>,
117 pub value_getters: HashMap<ObjectValuePair<'static>, ValueGetterCallback>,
118 pub setting_getters: HashMap<ObjectSettingPair<'static>, SettingGetterCallback>,
119 }
120
121 impl PluginInitializationState {
122 pub fn new() -> Self {
123 Self::default()
124 }
125 }
126
127 #[derive(Default)]
128 pub struct PluginInitializationTable<'a> {
129 _marker: PhantomData<&'a ()>,
130 }
131
132 impl<'a> PluginInitializationTable<'a> {
133 pub unsafe fn func_table(&mut self) -> InitializationVTable {
134 InitializationVTable {
135 register_value_change,
136 register_object,
137 register_operation,
138 register_setting,
139 register_value,
140 operation_handler,
141 value_getter,
142 setting_getter,
143 }
144 }
145 }
146
147 unsafe extern "C" fn register_value_change(
148 state: *mut PluginInitializationState,
149 object_kind: &str,
150 value_name: &str,
151 vtable: FFIValueChangeHandler,
152 ) {
153 todo!()
154 }
155
156 unsafe extern "C" fn register_object(
157 state: *mut PluginInitializationState,
158 object_kind: &'static str,
159 vtable: ObjectVtable,
160 ) {
161 let mut state = Box::from_raw(state);
162
163 state.type_metadata.register_object(object_kind, vtable);
164
165 Box::into_raw(state);
166 }
167
168 unsafe extern "C" fn register_operation(
169 state: *mut PluginInitializationState,
170 object_kind: &'static str,
171 operation_name: &'static str,
172 vtable: OperationVTable,
173 ) {
174 let mut state = Box::from_raw(state);
175
176 state
177 .type_metadata
178 .register_operation(object_kind, operation_name, vtable);
179
180 Box::into_raw(state);
181 }
182
183 unsafe extern "C" fn register_setting(
184 state: *mut PluginInitializationState,
185 object_kind: &'static str,
186 setting_name: &'static str,
187 vtable: SettingVtable,
188 ) {
189 let mut state = Box::from_raw(state);
190
191 state
192 .type_metadata
193 .register_setting(object_kind, setting_name, vtable);
194
195 Box::into_raw(state);
196 }
197
198 unsafe extern "C" fn register_value(
199 state: *mut PluginInitializationState,
200 object_kind: &'static str,
201 value_name: &'static str,
202 vtable: ValueVTable,
203 ) {
204 let mut state = Box::from_raw(state);
205
206 state
207 .type_metadata
208 .register_value(object_kind, value_name, vtable);
209
210 Box::into_raw(state);
211 }
212
213 unsafe extern "C" fn operation_handler(
214 state: *mut PluginInitializationState,
215 object_kind: &'static str,
216 operation_name: &'static str,
217 handler: OperationHandlerCallback,
218 ) {
219 let mut state = Box::from_raw(state);
220
221 trace!("Operation handler for {}::{}", object_kind, operation_name);
222
223 state.operation_handlers.insert(
224 ObjectOperationPair::new(object_kind, operation_name),
225 handler,
226 );
227
228 Box::into_raw(state);
229 }
230
231 unsafe extern "C" fn value_getter(
232 state: *mut PluginInitializationState,
233 object_kind: &'static str,
234 value_name: &'static str,
235 handler: ValueGetterCallback,
236 ) {
237 let mut state = Box::from_raw(state);
238
239 trace!("Value getter for {}::{}", object_kind, value_name);
240
241 state
242 .value_getters
243 .insert(ObjectValuePair::new(object_kind, value_name), handler);
244
245 Box::into_raw(state);
246 }
247
248 unsafe extern "C" fn setting_getter(
249 state: *mut PluginInitializationState,
250 object_kind: &'static str,
251 setting_name: &'static str,
252 handler: SettingGetterCallback,
253 ) {
254 let mut state = Box::from_raw(state);
255
256 trace!("Setting getter for {}::{}", object_kind, setting_name);
257
258 state
259 .setting_getters
260 .insert(ObjectSettingPair::new(object_kind, setting_name), handler);
261
262 Box::into_raw(state);
263 }
264