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

ambee/giterated

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

Huge refactor to prep for moving the daemon over to the plugin architecture

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨5df753c

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