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

ambee/giterated

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

Spinning

Amber - ⁨1⁩ year ago

parent: tbd commit: ⁨1788060

⁨giterated-runtime/src/lib.rs⁩ - ⁨12111⁩ bytes
Raw
1 mod operation_walker;
2 pub mod plugin;
3
4 use std::{collections::HashMap, sync::Arc};
5
6 use anyhow::Error;
7 use dlopen2::wrapper::Container;
8 use giterated_abi::{
9 callback::{
10 operation::OperationHandlerCallback,
11 setting::{SettingChangeCallback, SettingGetterCallback},
12 value::{ValueChangeCallback, ValueGetterCallback},
13 CallbackPtr,
14 },
15 plugin::GiteratedPluginAbi,
16 vtable::{operation::Operation, plugin::Plugin, Object, Setting, VTable, Value},
17 };
18 use giterated_core::types::TypeMetadata;
19 use giterated_models::{
20 error::OperationError,
21 object::{GiteratedObject, ObjectOperationPair},
22 operation::GiteratedOperation,
23 settings::ObjectSettingPair,
24 value::ObjectValuePair,
25 };
26 use operation_walker::OperationHandlerRules;
27 use plugin::initialization::PluginInitializationState;
28 use tracing::{debug, debug_span, trace, trace_span, warn};
29
30 pub use giterated_abi::vtable::runtime::RuntimeHandle;
31
32 pub struct Runtime {
33 plugins: Vec<RuntimePlugin>,
34 handlers: RuntimeHandlers,
35 }
36
37 #[derive(Clone)]
38 pub struct RuntimePlugin {
39 vtable: &'static VTable<Plugin>,
40 library: Arc<Container<GiteratedPluginAbi>>,
41 }
42
43 impl RuntimePlugin {
44 pub fn name(&self) -> &'static str {
45 todo!()
46 }
47
48 pub fn version(&self) -> &'static str {
49 todo!()
50 }
51
52 pub fn metadata(&self) -> &TypeMetadata {
53 todo!()
54 }
55 }
56
57 impl Runtime {
58 pub fn new() -> Box<Self> {
59 Box::new(Self {
60 plugins: vec![],
61 handlers: RuntimeHandlers::default(),
62 })
63 }
64
65 pub fn state(self: &Box<Self>) -> RuntimeHandle {
66 RuntimeHandle
67 }
68
69 pub fn load_dylib(&mut self, path: impl AsRef<str>) -> Result<(), Error> {
70 let path = path.as_ref();
71
72 let _guard = debug_span!("loading dylib", path = debug(path)).entered();
73
74 let library: Container<GiteratedPluginAbi> = unsafe { Container::load(path) }?;
75
76 let vtable = unsafe { library.__get_plugin_vtable() };
77
78 self.plugins.push(RuntimePlugin {
79 vtable,
80 library: Arc::new(library),
81 });
82
83 Ok(())
84 }
85
86 pub fn insert_plugin(
87 &mut self,
88 plugin: RuntimePlugin,
89 mut initialization: PluginInitializationState,
90 ) {
91 let _guard = debug_span!("inserting plugin", meta = debug(&plugin.name())).entered();
92
93 for (pair, callback) in initialization.operation_handlers.drain() {
94 let _guard =
95 trace_span!("processing operation handler callbacks", pair = debug(pair)).entered();
96
97 if self
98 .handlers
99 .operation_handlers
100 .insert(pair, (RuntimeDomain::from_plugin(&plugin), callback))
101 .is_some()
102 {
103 warn!("Warning! Insertion of handler for overwrote a previous handler.")
104 }
105
106 trace!("Insertion of operation handler successful")
107 }
108
109 for (pair, callback) in initialization.value_getters.drain() {
110 let _guard =
111 trace_span!("processing value getter callbacks", pair = debug(pair)).entered();
112
113 if self
114 .handlers
115 .value_getters
116 .insert(pair, (RuntimeDomain::from_plugin(&plugin), callback))
117 .is_some()
118 {
119 warn!("Warning! Insertion of handler for overwrote a previous handler.")
120 }
121
122 trace!("Insertion of operation handler successful")
123 }
124
125 for (pair, callback) in initialization.setting_getters {
126 let _guard =
127 trace_span!("processing setting getter callbacks", pair = debug(pair)).entered();
128
129 if self
130 .handlers
131 .setting_getters
132 .insert(pair, (RuntimeDomain::from_plugin(&plugin), callback))
133 .is_some()
134 {
135 warn!("Warning! Insertion of setting handler for overwrote a previous handler.")
136 }
137
138 trace!("Insertion of setting handler successful")
139 }
140
141 self.plugins.push(plugin);
142 }
143
144 pub fn init(self: Box<Self>) {
145 todo!()
146 // unsafe { giterated_static_runtime::initialize_runtime(Box::into_raw(self).cast::<()>()) }
147 }
148
149 // pub async fn handle(
150 // &self,
151 // object_kind: &str,
152 // operation_name: &str,
153 // object: &str,
154 // operation_payload: &[u8],
155 // operation_state: &OperationState,
156 // ) -> Result<AnySuccess, OperationError<AnyFailure>> {
157 // let rules = self.handlers.handle_operation(object_kind, operation_name);
158
159 // let state = self.state(operation_state);
160
161 // rules.handle(&state, object, operation_payload).await
162 // }
163
164 pub fn handle_typed<O: GiteratedObject, D: GiteratedOperation<O>>(
165 &self,
166 _object: O,
167 _operation: D,
168 ) -> Result<D::Success, OperationError<D::Failure>> {
169 todo!()
170 }
171 }
172
173 pub struct RuntimeDomain {
174 plugin: RuntimePlugin,
175 }
176
177 impl RuntimeDomain {
178 pub fn from_plugin(plugin: &RuntimePlugin) -> Self {
179 Self {
180 plugin: plugin.clone(),
181 }
182 }
183
184 pub fn object_vtable(&self, object_kind: &str) -> Option<&'static VTable<Object>> {
185 self.plugin.metadata().objects.get(object_kind).copied()
186 }
187
188 pub fn operation_vtable(
189 &self,
190 object_kind: &str,
191 operation_name: &str,
192 ) -> Option<&'static VTable<Operation>> {
193 self.plugin
194 .metadata()
195 .operations
196 .get(&ObjectOperationPair::new(object_kind, operation_name))
197 .copied()
198 }
199
200 pub fn setting_vtable(
201 &self,
202 object_kind: &str,
203 setting_name: &str,
204 ) -> Option<&'static VTable<Setting>> {
205 self.plugin
206 .metadata()
207 .settings
208 .get(&ObjectSettingPair::new(object_kind, setting_name))
209 .copied()
210 }
211
212 pub fn value_vtable(
213 &self,
214 object_kind: &str,
215 value_name: &str,
216 ) -> Option<&'static VTable<Value>> {
217 self.plugin
218 .metadata()
219 .values
220 .get(&ObjectValuePair::new(object_kind, value_name))
221 .copied()
222 }
223 }
224
225 #[repr(C)]
226 pub struct FFIPluginMeta {
227 pub name: *const u8,
228 pub name_len: usize,
229 pub version: *const u8,
230 pub version_len: usize,
231 }
232
233 // pub struct RuntimePlugin {
234 // handle: PluginHandle,
235 // type_metadata: Arc<TypeMetadata>,
236 // }
237
238 impl RuntimePlugin {
239 // pub fn plugin_meta(&self) -> PluginMeta {
240 // let meta = unsafe { self.handle.raw.plugin_meta() };
241
242 // let name = unsafe { std::slice::from_raw_parts(meta.name, meta.name_len) };
243 // let version = unsafe { std::slice::from_raw_parts(meta.version, meta.version_len) };
244
245 // let name = std::str::from_utf8(name).unwrap();
246 // let version = std::str::from_utf8(version).unwrap();
247
248 // PluginMeta {
249 // name: String::from(name),
250 // version: Version::parse(version).unwrap(),
251 // }
252 // }
253 }
254
255 // #[derive(WrapperApi)]
256 // pub struct GiteratedPluginApi {
257 // plugin_meta: unsafe extern "C" fn() -> FFIPluginMeta,
258 // load_host_vtable: unsafe extern "C" fn(vtable: &HostVTable),
259 // load_initialization_vtable: unsafe extern "C" fn(vtable: &'static VTable<Initialization>),
260 // initialize: unsafe extern "C" fn(runtime_state: *const RuntimeState) -> PluginState,
261 // initialize_registration: unsafe extern "C" fn(
262 // init_state: *mut PluginInitializationState,
263 // ) -> *mut PluginInitializationState,
264 // load_type_metadata: unsafe extern "C" fn(metadata: *mut ()),
265 // }
266 #[derive(Default)]
267 pub struct RuntimeHandlers {
268 operation_handlers: HashMap<
269 ObjectOperationPair<'static>,
270 (RuntimeDomain, CallbackPtr<OperationHandlerCallback>),
271 >,
272 value_getters:
273 HashMap<ObjectValuePair<'static>, (RuntimeDomain, CallbackPtr<ValueGetterCallback>)>,
274 setting_getters:
275 HashMap<ObjectSettingPair<'static>, (RuntimeDomain, CallbackPtr<SettingGetterCallback>)>,
276 value_change:
277 HashMap<ObjectValuePair<'static>, (RuntimeDomain, CallbackPtr<ValueChangeCallback>)>,
278 setting_change:
279 HashMap<ObjectSettingPair<'static>, (RuntimeDomain, CallbackPtr<SettingChangeCallback>)>,
280 }
281
282 unsafe impl Send for RuntimeHandlers {}
283 unsafe impl Sync for RuntimeHandlers {}
284
285 impl RuntimeHandlers {
286 pub fn operation_handler(
287 &mut self,
288 pair: ObjectOperationPair<'static>,
289 handler: CallbackPtr<OperationHandlerCallback>,
290 domain: RuntimeDomain,
291 ) {
292 trace!(
293 "Inserting operation handler for {}::{}",
294 pair.object_kind,
295 pair.operation_name
296 );
297
298 // There can only be one handler per operation (at least for now?), send a warning if
299 // a newly registered handler overwrites the previous handler.
300 if self
301 .operation_handlers
302 .insert(pair, (domain, handler))
303 .is_some()
304 {
305 debug!("Warning! A newly inserted operation handler for {}::{} overwrites a previous handler.", pair.object_kind, pair.operation_name);
306 }
307 }
308
309 pub fn value_getter(
310 &mut self,
311 pair: ObjectValuePair<'static>,
312 handler: CallbackPtr<ValueGetterCallback>,
313 domain: RuntimeDomain,
314 ) {
315 trace!(
316 "Inserting value getter for {}::{}",
317 pair.object_kind,
318 pair.value_name
319 );
320
321 if self.value_getters.insert(pair, (domain, handler)).is_some() {
322 debug!(
323 "Warning! A newly inserted value getter for {}::{} overwrites a previous handler.",
324 pair.object_kind, pair.value_name
325 );
326 }
327 }
328
329 pub fn setting_getter(
330 &mut self,
331 pair: ObjectSettingPair<'static>,
332 handler: CallbackPtr<SettingGetterCallback>,
333 domain: RuntimeDomain,
334 ) {
335 trace!(
336 "Inserting setting getter for {}::{}",
337 pair.object_kind,
338 pair.setting_name
339 );
340
341 if self
342 .setting_getters
343 .insert(pair, (domain, handler))
344 .is_some()
345 {
346 debug!("Warning! A newly inserted setting getter for {}::{} overwrites a previous handler.", pair.object_kind, pair.setting_name);
347 }
348 }
349
350 pub fn value_change(
351 &mut self,
352 pair: ObjectValuePair<'static>,
353 handler: CallbackPtr<ValueChangeCallback>,
354 domain: RuntimeDomain,
355 ) {
356 trace!(
357 "Inserting value change handler for {}::{}",
358 pair.object_kind,
359 pair.value_name
360 );
361
362 if self.value_change.insert(pair, (domain, handler)).is_some() {
363 debug!("Warning! A newly inserted value change handler for {}::{} overwrites a previous handler.", pair.object_kind, pair.value_name);
364 panic!("Not intended");
365 }
366 }
367
368 pub fn setting_change(
369 &mut self,
370 pair: ObjectSettingPair<'static>,
371 handler: CallbackPtr<SettingChangeCallback>,
372 domain: RuntimeDomain,
373 ) {
374 trace!(
375 "Inserting setting change handler for {}::{}",
376 pair.object_kind,
377 pair.setting_name
378 );
379
380 if self
381 .setting_change
382 .insert(pair, (domain, handler))
383 .is_some()
384 {
385 debug!("Warning! A newly inserted setting change handler for {}::{} overwrites a previous handler.", pair.object_kind, pair.setting_name);
386 panic!("Not intended");
387 }
388 }
389 }
390
391 impl RuntimeHandlers {
392 pub fn handle_operation<'o>(
393 &'o self,
394 object_kind: &'o str,
395 operation_name: &'o str,
396 ) -> OperationHandlerRules<'o> {
397 OperationHandlerRules::new(object_kind, operation_name, self)
398 }
399 }
400
401 pub trait StaticRuntimeExt {
402 fn from_static() -> Self;
403 }
404
405 impl StaticRuntimeExt for RuntimeHandle {
406 fn from_static() -> Self {
407 todo!()
408 }
409 }
410