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

ambee/giterated

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

MOre pre vtable changes

Amber - ⁨1⁩ year ago

parent: tbd commit: ⁨9cfa135

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