use giterated_abi::{result::FfiError, value_ex::FfiValueUntyped, vtable::runtime::RuntimeHandle}; use giterated_models::{ error::OperationError, object::ObjectOperationPair, operation::GiteratedOperation, settings::GetSetting, value::GetValue, }; use tracing::{debug_span, trace, trace_span}; use super::{ObjectSettingPair, ObjectValuePair, RuntimeHandlers}; /// A wrapper for operation handling that enforces handling rules. /// /// # Handler Resolution /// In order, handler resolution will be attempted as follows: /// /// | Index | object_kind | operation_kind | Special Case? | /// |-------|-------------|-----------------|---------------| /// | 1 | `any` | `typed` | No | /// | 2 | `typed` | `any` | No | /// | 3 | `any` | `any` | No | /// | 4 | `any` | `GetValue` | ⚠️ Yes ⚠️ | /// | 5 | `any` | `GetSetting` | ⚠️ Yes ⚠️ | /// | 6 | `any` | `SetSetting` | ⚠️ Yes ⚠️ | /// | 7 | `any` | `ObjectRequest` | ⚠️ Yes ⚠️ | /// | 8 | `typed` | `typed` | No | pub struct OperationHandlerRules<'a> { object_kind: &'a str, operation_name: &'a str, handlers: &'a RuntimeHandlers, } impl<'o> OperationHandlerRules<'o> { pub fn new( object_kind: &'o str, operation_name: &'o str, handlers: &'o RuntimeHandlers, ) -> Self { Self { object_kind, operation_name, handlers, } } pub async fn handle( &self, runtime: &RuntimeHandle, object: &str, operation_payload: &[u8], ) -> Result> { // object_kind: `any` // operation_kind: `typed` if let Some(_handler) = self .handlers .operation_handlers .get(&ObjectOperationPair::new("any", self.operation_name)) { todo!() } // object_kind: `typed` // operation_kind: `any` if let Some(_handler) = self .handlers .operation_handlers .get(&ObjectOperationPair::new(self.object_kind, "any")) {} // object_kind: `any` // operation_kind: `any` if let Some(_handler) = self .handlers .operation_handlers .get(&ObjectOperationPair::new("any", "any")) {} // ⚠️ Special Case ⚠️ // object_kind: `any` // operation_kind: `GetValue` if self.operation_name == "get_value" { let operation: GetValue = todo!(); let _guard = trace_span!( "get_value handler resolving", object = self.object_kind, value = operation.value_name ) .entered(); if let Some((domain, callback)) = self.handlers.value_getters.get( &ObjectValuePair::new(self.object_kind, &operation.value_name), ) { trace_span!( "get_value handler.", object = self.object_kind, value_name = operation.value_name ); let object_vtable = domain .object_vtable(self.object_kind) .ok_or_else(|| OperationError::Unhandled)?; trace!("Resolved object vtable for {}", self.object_kind); let _value_vtable = domain .value_vtable(self.object_kind, &operation.value_name) .ok_or_else(|| OperationError::Unhandled)?; trace!( "Resolved value vtable for {}::{}", self.object_kind, operation.value_name ); // let object = unsafe { (object_vtable.from_str)(object) } // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; // let _guard = debug_span!("get_value handler"); // let result = unsafe { // (callback.func)( // callback.callback_ptr, // runtime_state, // &domain.plugin.state, // object, // ) // } // .await; // match result { // Ok(value) => return Ok(value.into()), // Err(_err) => todo!(), // } todo!() } else { trace!("Failed to resolve handler."); } } // ⚠️ Special Case ⚠️ // object_kind: `any` // operation_kind: `GetSetting` if self.operation_name == "get_setting" { let operation: GetSetting = todo!(); let _guard = trace_span!( "get_setting handler resolving", object = self.object_kind, setting = operation.setting_name ) .entered(); if let Some((domain, callback)) = self.handlers.setting_getters.get( &ObjectSettingPair::new(self.object_kind, &operation.setting_name), ) { trace_span!( "get_setting handler.", object = self.object_kind, setting_name = operation.setting_name ); let object_vtable = domain .object_vtable(self.object_kind) .ok_or_else(|| OperationError::Unhandled)?; trace!("Resolved object vtable for {}", self.object_kind); let _setting_vtable = domain .setting_vtable(self.object_kind, &operation.setting_name) .ok_or_else(|| OperationError::Unhandled)?; trace!("Resolved setting vtable for {}", operation.setting_name); todo!() // let object = unsafe { (object_vtable.from_str)(object) } // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; // let _guard = debug_span!("get_value handler"); // let result = unsafe { // (callback.func())( // callback.callback_ptr, // runtime_state, // &domain.plugin.state, // object, // ) // } // .await; // match result { // Ok(value) => { // let vtable = unsafe { (value.vtable.get_setting_vtable)() }; // let return_value: Value = serde_json::from_slice(unsafe { // (value.vtable.serialize)(value).unwrap().as_ref() // }) // .unwrap(); // todo!() // // return Ok(unsafe { // // AnySuccess::from_raw( // // FFIBox::from_box(Box::new(return_value)).untyped(), // // vtable, // // ) // // }); // } // Err(_err) => todo!(), // } } else { trace!("Failed to resolve handler."); } } // ⚠️ Special Case ⚠️ // object_kind: `any` // operation_kind: `SetSetting` self.operation_name == "set_setting"; // ⚠️ Special Case ⚠️ // object_kind: `any` // operation_kind: `ObjectRequest` self.operation_name == "object_request"; // object_kind: `typed` // operation_kind: `typed` if let Some((domain, handler)) = self.handlers .operation_handlers .get(&ObjectOperationPair::new( self.object_kind, self.operation_name, )) { let _guard = trace_span!("typed_typed handler resolved").entered(); let object_vtable = domain .object_vtable(self.object_kind) .ok_or_else(|| OperationError::Unhandled)?; trace!("Resolved object vtable for {}", self.object_kind); let operation_vtable = domain .operation_vtable(self.object_kind, self.operation_name) .ok_or_else(|| OperationError::Unhandled)?; trace!( "Resolved operation vtable for {}::{}", self.object_kind, self.operation_name ); todo!() // let object = unsafe { (object_vtable.from_str)(object) } // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; // let operation = unsafe { (operation_vtable.deserialize)(operation_payload) } // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; // trace!("Parsed operation data"); // let _guard = debug_span!("calling handler").entered(); // let result = unsafe { // (handler.func)( // handler.callback_ptr, // runtime_state, // &domain.plugin.state, // object, // operation, // ) // }; // return result.await; } Err(OperationError::Unhandled) } }