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

ambee/giterated

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

Wow!

Amber - ⁨1⁩ year ago

parent: tbd commit: ⁨6530104

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