diff --git a/Cargo.lock b/Cargo.lock index 95b93c4..01e2105 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -489,7 +489,9 @@ dependencies = [ "giterated-models", "giterated-plugin", "giterated-plugin-sys", + "giterated-static-runtime", "serde_json", + "tokio", "tracing", "tracing-subscriber", ] @@ -559,9 +561,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" @@ -587,15 +589,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", @@ -604,21 +606,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-io", @@ -786,11 +788,14 @@ dependencies = [ "anyhow", "async-trait", "dlopen2", + "futures-util", "giterated-models", + "giterated-static-runtime", "semver", "serde", "serde_json", "thiserror", + "tokio", "tracing", ] @@ -827,6 +832,10 @@ dependencies = [ ] [[package]] +name = "giterated-static-runtime" +version = "0.1.0" + +[[package]] name = "h2" version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index d222f38..c6ebdf2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "giterated-models", "giterated-plugin", "giterated-plugin/giterated-plugin-sys", + "giterated-plugin/giterated-static-runtime", "plugins/example-plugin", "plugins/giterated-backend", "plugins/giterated-issues", diff --git a/giterated-daemon/src/client.rs b/giterated-daemon/src/client.rs index 801bf9c..7b7e4c0 100644 --- a/giterated-daemon/src/client.rs +++ b/giterated-daemon/src/client.rs @@ -5,8 +5,9 @@ use giterated_models::{ error::{IntoInternalError, OperationError}, instance::Instance, object_backend::ObjectBackend, + operation::OperationState, }; -use giterated_plugin::new_stack::{handle::RuntimeHandle, OperationState, Runtime}; +use giterated_plugin::new_stack::{handle::RuntimeHandle, Runtime}; use giterated_protocol::{ handlers::{NetworkedObject, NetworkedOperation}, AuthenticatedPayload, @@ -17,7 +18,7 @@ use tokio_tungstenite::{tungstenite::Message, WebSocketStream}; pub async fn client_wrapper( _our_instance: Instance, mut socket: WebSocketStream, - _runtime: Arc, + _runtime: Arc>, ) { loop { let message = socket.next().await; @@ -30,19 +31,15 @@ pub async fn client_wrapper( let message = message.unwrap(); let payload = match message { - Ok(message) => { - let payload = match message { - Message::Binary(payload) => payload, - Message::Ping(_) => { - let _ = socket.send(Message::Pong(vec![])).await; - continue; - } - Message::Close(_) => return, - _ => continue, - }; - - payload - } + Ok(message) => match message { + Message::Binary(payload) => payload, + Message::Ping(_) => { + let _ = socket.send(Message::Pong(vec![])).await; + continue; + } + Message::Close(_) => return, + _ => continue, + }, Err(err) => { // Connection error warn!("A connection error has occured: {:?}", err); diff --git a/giterated-daemon/src/main.rs b/giterated-daemon/src/main.rs index d9b698b..bb23a07 100644 --- a/giterated-daemon/src/main.rs +++ b/giterated-daemon/src/main.rs @@ -10,7 +10,7 @@ use tokio::{ fs::File, io::{AsyncRead, AsyncReadExt, AsyncWrite}, net::{TcpListener, TcpStream}, - sync::{Mutex, OnceCell}, + sync::Mutex, }; use tokio_tungstenite::{accept_async, WebSocketStream}; use tokio_util::task::LocalPoolHandle; @@ -42,14 +42,14 @@ async fn main() -> Result<(), Error> { sqlx::migrate!().run(&db_pool).await?; info!("Connected"); - let token_granter = Arc::new(Mutex::new(AuthenticationTokenGranter { + let _token_granter = Arc::new(Mutex::new(AuthenticationTokenGranter { config: config.clone(), instance: Instance::from_str(config["giterated"]["instance"].as_str().unwrap()).unwrap(), })); info!("Connected"); - let mut runtime = Runtime::new(); + let runtime = Runtime::new(); let runtime = Arc::new(runtime); diff --git a/giterated-models/src/ffi.rs b/giterated-models/src/ffi.rs new file mode 100644 index 0000000..59a83fd --- /dev/null +++ b/giterated-models/src/ffi.rs @@ -0,0 +1,13 @@ +pub trait ToFfi { + fn to_ffi_bytes(&self) -> Vec; +} + +pub trait FromFfi: Sized { + fn from_ffi_bytes(bytes: &[u8]) -> Option; +} + +pub trait FfiLabel { + fn prefix(&self) -> &'static str; + + fn type_label(&self) -> &'static str; +} diff --git a/giterated-models/src/instance/mod.rs b/giterated-models/src/instance/mod.rs index fd5a8d9..0a414cb 100644 --- a/giterated-models/src/instance/mod.rs +++ b/giterated-models/src/instance/mod.rs @@ -8,7 +8,6 @@ mod values; pub use operations::*; use url::Url; -pub use values::*; use crate::object::GiteratedObject; diff --git a/giterated-models/src/instance/operations.rs b/giterated-models/src/instance/operations.rs index b9e9536..716d3f2 100644 --- a/giterated-models/src/instance/operations.rs +++ b/giterated-models/src/instance/operations.rs @@ -6,7 +6,7 @@ use crate::{ error::{InstanceError, OperationError}, object::Object, object_backend::ObjectBackend, - operation::GiteratedOperation, + operation::{GiteratedOperation, OperationState}, repository::{Repository, RepositoryVisibility}, user::{Password, User}, }; @@ -104,13 +104,13 @@ impl GiteratedOperation for RepositoryCreateRequest { type Failure = InstanceError; } -impl + std::fmt::Debug> Object<'_, S, Instance, B> { +impl Object { pub async fn register_account( &mut self, email: Option<&str>, username: &str, password: &Secret, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( RegisterAccountRequest { @@ -127,7 +127,7 @@ impl + std::fmt::Debug> Object<'_, S &mut self, username: &str, password: &Secret, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( AuthenticationTokenRequest { @@ -145,7 +145,7 @@ impl + std::fmt::Debug> Object<'_, S instance: &Instance, username: &str, password: &Secret, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( AuthenticationTokenRequest { @@ -161,7 +161,7 @@ impl + std::fmt::Debug> Object<'_, S pub async fn token_extension( &mut self, token: &UserAuthenticationToken, - operation_state: &S, + operation_state: &OperationState, ) -> Result, OperationError> { self.request::( TokenExtensionRequest { @@ -179,7 +179,7 @@ impl + std::fmt::Debug> Object<'_, S visibility: &RepositoryVisibility, default_branch: &str, owner: &User, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( RepositoryCreateRequest { diff --git a/giterated-models/src/lib.rs b/giterated-models/src/lib.rs index 5b557af..87cbcc3 100644 --- a/giterated-models/src/lib.rs +++ b/giterated-models/src/lib.rs @@ -1,6 +1,7 @@ pub mod authenticated; pub mod discovery; pub mod error; +pub mod ffi; pub mod handshake; pub mod instance; pub mod message; diff --git a/giterated-models/src/object.rs b/giterated-models/src/object.rs index 2e712d6..262efdd 100644 --- a/giterated-models/src/object.rs +++ b/giterated-models/src/object.rs @@ -1,6 +1,5 @@ use std::{ fmt::{Debug, Display}, - marker::PhantomData, str::FromStr, }; @@ -9,7 +8,7 @@ use anyhow::Error; use crate::{ error::{GetValueError, OperationError}, object_backend::ObjectBackend, - operation::GiteratedOperation, + operation::{GiteratedOperation, OperationState}, settings::{GetSetting, GetSettingError, SetSetting, SetSettingError, Setting}, value::{GetValue, GiteratedObjectValue}, }; @@ -18,38 +17,26 @@ mod operations; pub use operations::*; #[derive(Debug, Clone)] -pub struct Object< - 'b, - S: Clone + Send + Sync, - O: GiteratedObject, - B: ObjectBackend + 'b + Send + Clone, -> { +pub struct Object { pub(crate) inner: O, pub(crate) backend: B, - pub(crate) _marker: PhantomData<&'b S>, } -impl<'b, S: Clone + Send + Sync, B: ObjectBackend + Send + Sync + Clone, O: GiteratedObject> - Object<'b, S, O, B> -{ +impl Object { pub fn object(&self) -> &O { &self.inner } - pub unsafe fn new_unchecked(object: O, backend: B) -> Object<'b, S, O, B> { + pub unsafe fn new_unchecked(object: O, backend: B) -> Object { Object { inner: object, backend, - _marker: PhantomData, } } } -impl< - S: Clone + Send + Sync, - O: GiteratedObject + Display, - B: ObjectBackend + Send + Sync + Clone, - > Display for Object<'_, S, O, B> +impl Display + for Object { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.inner.fmt(f) @@ -63,16 +50,10 @@ pub trait GiteratedObject: Send + Display + FromStr + Sync + Clone { fn from_object_str(object_str: &str) -> Result; } -impl< - 'b, - I: Clone + Send + Sync, - O: GiteratedObject + Clone + Debug + 'static, - B: ObjectBackend, - > Object<'b, I, O, B> -{ +impl Object { pub async fn get + Send + Debug + 'static>( &mut self, - operation_state: &I, + operation_state: &OperationState, ) -> Result> { let result = self .request( @@ -88,7 +69,7 @@ impl< pub async fn get_setting( &mut self, - operation_state: &I, + operation_state: &OperationState, ) -> Result> { self.request( GetSetting { @@ -103,7 +84,7 @@ impl< pub async fn set_setting( &mut self, setting: S, - operation_state: &I, + operation_state: &OperationState, ) -> Result<(), OperationError> { self.request( SetSetting { @@ -118,7 +99,7 @@ impl< pub async fn request + Debug + 'static>( &mut self, request: R, - operation_state: &I, + operation_state: &OperationState, ) -> Result> where R::Success: Clone, diff --git a/giterated-models/src/object/operations.rs b/giterated-models/src/object/operations.rs index 6de5011..7ec3479 100644 --- a/giterated-models/src/object/operations.rs +++ b/giterated-models/src/object/operations.rs @@ -9,7 +9,7 @@ use super::GiteratedObject; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ObjectRequest(pub String); -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct ObjectResponse(pub String); impl GiteratedOperation for ObjectRequest { diff --git a/giterated-models/src/object_backend.rs b/giterated-models/src/object_backend.rs index dc616a4..3edea81 100644 --- a/giterated-models/src/object_backend.rs +++ b/giterated-models/src/object_backend.rs @@ -1,19 +1,19 @@ use crate::{ error::OperationError, object::{GiteratedObject, Object, ObjectRequestError}, - operation::GiteratedOperation, + operation::{GiteratedOperation, OperationState}, }; use std::fmt::Debug; #[async_trait::async_trait(?Send)] -pub trait ObjectBackend: Sized + Clone + Send { +pub trait ObjectBackend: Sized + Clone + Send { async fn object_operation( &self, object: O, operation: &str, payload: D, - operation_state: &S, + operation_state: &OperationState, ) -> Result> where O: GiteratedObject + Debug + 'static, @@ -24,6 +24,6 @@ pub trait ObjectBackend: Sized + Clone + Send { async fn get_object( &self, object_str: &str, - operation_state: &S, - ) -> Result, OperationError>; + operation_state: &OperationState, + ) -> Result, OperationError>; } diff --git a/giterated-models/src/operation.rs b/giterated-models/src/operation.rs index 911a7c3..03e06fc 100644 --- a/giterated-models/src/operation.rs +++ b/giterated-models/src/operation.rs @@ -1,8 +1,8 @@ -use std::{any::type_name, fmt::Debug}; +use std::{any::type_name, collections::HashMap, fmt::Debug}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use crate::object::GiteratedObject; +use crate::{ffi::FfiLabel, object::GiteratedObject}; pub trait GiteratedOperation: Send + Sync + Serialize + DeserializeOwned @@ -26,7 +26,17 @@ impl GiteratedOperation for NetworkAnyOperation { type Failure = Vec; } -/// The internal state of an operation, used to provide authentication information -/// and the ability to make giterated calls within handlers. -#[derive(Clone)] -pub struct GiteratedOperationState(pub S); +#[derive(Clone, Debug, Default)] +pub struct OperationState { + states: HashMap>, +} + +impl FfiLabel for OperationState { + fn prefix(&self) -> &'static str { + "dev.giterated" + } + + fn type_label(&self) -> &'static str { + "operation_state" + } +} diff --git a/giterated-models/src/repository/operations.rs b/giterated-models/src/repository/operations.rs index 134e052..41f2cc6 100644 --- a/giterated-models/src/repository/operations.rs +++ b/giterated-models/src/repository/operations.rs @@ -4,7 +4,7 @@ use crate::{ error::{OperationError, RepositoryError}, object::Object, object_backend::ObjectBackend, - operation::GiteratedOperation, + operation::{GiteratedOperation, OperationState}, }; use super::{ @@ -271,13 +271,13 @@ impl GiteratedOperation for RepositoryBranchesRequest { type Failure = RepositoryError; } -impl + std::fmt::Debug> Object<'_, S, Repository, B> { +impl Object { pub async fn info( &mut self, extra_metadata: bool, rev: Option, path: Option, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( RepositoryInfoRequest { @@ -293,7 +293,7 @@ impl + std::fmt::Debug> Object<'_, S pub async fn file_from_id( &mut self, id: String, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( RepositoryFileFromIdRequest(id), @@ -306,7 +306,7 @@ impl + std::fmt::Debug> Object<'_, S &mut self, rev: Option, path: String, - operation_state: &S, + operation_state: &OperationState, ) -> Result<(RepositoryFile, String), OperationError> { self.request::( RepositoryFileFromPathRequest { rev, path }, @@ -319,7 +319,7 @@ impl + std::fmt::Debug> Object<'_, S &mut self, start_commit: String, path: String, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( RepositoryLastCommitOfFileRequest { start_commit, path }, @@ -331,7 +331,7 @@ impl + std::fmt::Debug> Object<'_, S pub async fn commit_by_id( &mut self, id: String, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( RepositoryCommitFromIdRequest(id), @@ -344,7 +344,7 @@ impl + std::fmt::Debug> Object<'_, S &mut self, old_id: String, new_id: String, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( RepositoryDiffRequest { old_id, new_id }, @@ -357,7 +357,7 @@ impl + std::fmt::Debug> Object<'_, S &mut self, old_id: String, new_id: String, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( RepositoryDiffPatchRequest { old_id, new_id }, @@ -369,7 +369,7 @@ impl + std::fmt::Debug> Object<'_, S pub async fn commit_before( &mut self, id: String, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( RepositoryCommitBeforeRequest(id), @@ -381,7 +381,7 @@ impl + std::fmt::Debug> Object<'_, S pub async fn statistics( &mut self, rev: Option, - operation_state: &S, + operation_state: &OperationState, ) -> Result> { self.request::( RepositoryStatisticsRequest { rev }, @@ -392,7 +392,7 @@ impl + std::fmt::Debug> Object<'_, S pub async fn branches( &mut self, - operation_state: &S, + operation_state: &OperationState, ) -> Result, OperationError> { self.request::(RepositoryBranchesRequest, operation_state) .await @@ -405,7 +405,7 @@ impl + std::fmt::Debug> Object<'_, S pub async fn issue_labels( &mut self, - operation_state: &S, + operation_state: &OperationState, ) -> Result, OperationError> { self.request::(RepositoryIssueLabelsRequest, operation_state) .await @@ -413,7 +413,7 @@ impl + std::fmt::Debug> Object<'_, S pub async fn issues( &mut self, - operation_state: &S, + operation_state: &OperationState, ) -> Result, OperationError> { self.request::(RepositoryIssuesRequest, operation_state) .await @@ -424,7 +424,7 @@ impl + std::fmt::Debug> Object<'_, S extra_metadata: bool, rev: Option<&str>, path: Option<&str>, - operation_state: &S, + operation_state: &OperationState, ) -> Result, OperationError> { self.request::( RepositoryFileInspectRequest { diff --git a/giterated-models/src/user/mod.rs b/giterated-models/src/user/mod.rs index 7af737e..e81b35c 100644 --- a/giterated-models/src/user/mod.rs +++ b/giterated-models/src/user/mod.rs @@ -10,7 +10,7 @@ use std::{ pub use operations::*; use secrecy::{CloneableSecret, DebugSecret, SerializableSecret, Zeroize}; use serde::{Deserialize, Serialize}; -pub use settings::*; + pub use values::*; use crate::{instance::Instance, object::GiteratedObject}; diff --git a/giterated-models/src/user/operations.rs b/giterated-models/src/user/operations.rs index 870c5ab..95de7b1 100644 --- a/giterated-models/src/user/operations.rs +++ b/giterated-models/src/user/operations.rs @@ -5,7 +5,7 @@ use crate::{ instance::Instance, object::Object, object_backend::ObjectBackend, - operation::GiteratedOperation, + operation::{GiteratedOperation, OperationState}, repository::RepositorySummary, }; @@ -22,11 +22,11 @@ impl GiteratedOperation for UserRepositoriesRequest { type Failure = UserError; } -impl + std::fmt::Debug> Object<'_, S, User, B> { +impl Object { pub async fn repositories( &mut self, instance: &Instance, - operation_state: &S, + operation_state: &OperationState, ) -> Result, OperationError> { self.request::( UserRepositoriesRequest { diff --git a/giterated-plugin/Cargo.toml b/giterated-plugin/Cargo.toml index ba50aed..4549b46 100644 --- a/giterated-plugin/Cargo.toml +++ b/giterated-plugin/Cargo.toml @@ -11,7 +11,10 @@ anyhow = "1" thiserror = "1" tracing = "0.1" giterated-models = { path = "../giterated-models" } +giterated-static-runtime = { path = "giterated-static-runtime" } semver = "*" serde_json = "1.0" async-trait = "0.1" -serde = "*" \ No newline at end of file +serde = "*" +futures-util = "0.3.30" +tokio = { version = "1.32", features = [ "full" ] } diff --git a/giterated-plugin/giterated-plugin-sys/src/lib.rs b/giterated-plugin/giterated-plugin-sys/src/lib.rs index 4dd8292..69294f6 100644 --- a/giterated-plugin/giterated-plugin-sys/src/lib.rs +++ b/giterated-plugin/giterated-plugin-sys/src/lib.rs @@ -1,7 +1,5 @@ mod local_runtime; -use std::marker::PhantomData; - use giterated_models::{ object::GiteratedObject, operation::GiteratedOperation, settings::Setting, value::GiteratedObjectValue, @@ -9,7 +7,8 @@ use giterated_models::{ use giterated_plugin::{ callback::{ CallbackPtr, IntoPluginOperationHandler, IntoPluginSettingGetter, IntoPluginSettingSetter, - IntoPluginValueGetter, OperationHandlerCallback, ValueGetterCallback, + IntoPluginValueGetter, OperationHandlerCallback, SettingGetterCallback, + ValueGetterCallback, }, handle::PluginInitializationState, new_stack::PluginState, @@ -190,28 +189,36 @@ impl<'init, S> PluginStackBuilder<'init, S> { // self // } - // pub fn setting_getter(&mut self, handler: T) -> &mut Self - // where - // O: GiteratedObject + IntoObjectVTable, - // OS: Setting + IntoSettingVTable, - // T: IntoPluginSettingGetter, - // { - // let _guard = trace_span!("register setting_getter handler").entered(); + pub fn setting_getter(&mut self, handler: T) -> &mut Self + where + O: GiteratedObject + IntoObjectVTable, + OS: Setting + IntoSettingVTable, + T: IntoPluginSettingGetter, + { + let _guard = trace_span!("register setting_getter handler").entered(); - // unsafe { - // (self.vtable.setting_getter)( - // self.init_state, - // O::object_name(), - // OS::name(), - // SettingGetterCallback::new::(handler), - // ) - // } + unsafe { + (self.vtable.setting_getter)( + self.init_state, + O::object_name(), + OS::name(), + SettingGetterCallback::new::(handler), + ) + } - // self.object::(); - // // self.setting::(); + self.object::(); - // self - // } + unsafe { + (self.vtable.register_setting)( + self.init_state, + O::object_name(), + OS::name(), + SettingVtable::new::(), + ) + }; + + self + } } pub trait ValueSettingExt { @@ -252,15 +259,17 @@ where HG: IntoPluginSettingGetter, { unsafe extern "C" fn get_value( - callback: CallbackPtr, - state: &PluginState, - object: AnyObject, + _callback: CallbackPtr, + _state: &PluginState, + _object: AnyObject, ) -> Result { - let result = HG::get_setting(callback, state, object)?; + // let result = HG::get_setting(callback, state, object)?; + + // let setting = *result.transmute_owned::(); - let setting = *result.transmute_owned::(); + todo!(); - Ok(NewAnyValue::new(setting)) + // Ok(NewAnyValue::new(setting)) } fn callback_ptr(&self) -> CallbackPtr { diff --git a/giterated-plugin/giterated-static-runtime/Cargo.toml b/giterated-plugin/giterated-static-runtime/Cargo.toml new file mode 100644 index 0000000..b7cdeab --- /dev/null +++ b/giterated-plugin/giterated-static-runtime/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "giterated-static-runtime" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/giterated-plugin/giterated-static-runtime/src/lib.rs b/giterated-plugin/giterated-static-runtime/src/lib.rs new file mode 100644 index 0000000..8f8df02 --- /dev/null +++ b/giterated-plugin/giterated-static-runtime/src/lib.rs @@ -0,0 +1,16 @@ +use std::{mem::MaybeUninit, ptr::NonNull}; + +struct RuntimePointer(NonNull<()>); + +unsafe impl Send for RuntimePointer {} +unsafe impl Sync for RuntimePointer {} + +static mut GITERATED_RUNTIME: MaybeUninit = MaybeUninit::zeroed(); + +pub unsafe fn initialize_runtime(runtime_pointer: *mut ()) { + GITERATED_RUNTIME.write(RuntimePointer(NonNull::new(runtime_pointer).unwrap())); +} + +pub unsafe fn get_runtime_reference() -> NonNull<()> { + GITERATED_RUNTIME.assume_init_read().0 +} diff --git a/giterated-plugin/src/callback/mod.rs b/giterated-plugin/src/callback/mod.rs index 38225a3..1689dba 100644 --- a/giterated-plugin/src/callback/mod.rs +++ b/giterated-plugin/src/callback/mod.rs @@ -1,5 +1,12 @@ mod operation; -use std::sync::Arc; + +use giterated_models::{ + error::OperationError, + object::{GiteratedObject, Object, ObjectRequestError}, + object_backend::ObjectBackend, + operation::{GiteratedOperation, OperationState}, +}; +use std::fmt::Debug; pub use operation::*; mod value; @@ -7,10 +14,7 @@ pub use value::*; mod setting; pub use setting::*; -use crate::{ - new_stack::{PluginState, Runtime}, - vtable::RuntimeVTable, -}; +use crate::{vtable::RuntimeVTable, AnyObject, AnyOperation}; /// A container for a callback pointer, used to provide an internal callback function or /// state to a plugin when performing a callback. @@ -24,8 +28,49 @@ impl CallbackPtr { } } +#[derive(Clone)] #[repr(C)] pub struct RuntimeState { pub vtable: RuntimeVTable, - pub operation_state: PluginState, + pub operation_state: OperationState, +} + +impl RuntimeState { + pub unsafe fn from_static() -> Self { + let runtime = giterated_static_runtime::get_runtime_reference(); + + let runtime = runtime.cast::>().as_ref(); + + *runtime.clone() + } +} + +#[async_trait::async_trait(?Send)] +impl ObjectBackend for RuntimeState { + async fn object_operation( + &self, + object: O, + _operation: &str, + payload: D, + _operation_state: &OperationState, + ) -> Result> + where + O: GiteratedObject + Debug + 'static, + D: GiteratedOperation + Debug + 'static, + D::Success: Clone, + D::Failure: Clone, + { + let _object = AnyObject::new(object); + let _operation = AnyOperation::new(payload); + + todo!() + } + + async fn get_object( + &self, + _object_str: &str, + _operation_state: &OperationState, + ) -> Result, OperationError> { + todo!() + } } diff --git a/giterated-plugin/src/callback/operation.rs b/giterated-plugin/src/callback/operation.rs index 62606ed..c4076db 100644 --- a/giterated-plugin/src/callback/operation.rs +++ b/giterated-plugin/src/callback/operation.rs @@ -1,14 +1,17 @@ use giterated_models::{ - error::OperationError, object::GiteratedObject, operation::GiteratedOperation, - value::GiteratedObjectValue, + error::OperationError, + object::GiteratedObject, + operation::{GiteratedOperation, OperationState}, }; use crate::{ - new_stack::{handle::RuntimeHandle, OperationState, PluginState, Runtime, State}, - AnyObject, AnyOperation, + future::{RuntimeFuture, RuntimeFuturesExt}, + new_stack::{handle::RuntimeHandle, PluginState}, + vtable::OperationVTable, + AnyFailure, AnyObject, AnyOperation, AnySuccess, FFIBox, }; -use std::{any::type_name, fmt::Debug, future::Future, sync::Arc}; +use std::{any::type_name, fmt::Debug, future::Future}; use super::{CallbackPtr, RuntimeState}; @@ -21,7 +24,8 @@ pub struct OperationHandlerCallback { &PluginState, object: AnyObject, operation: AnyOperation, - ), + ) + -> RuntimeFuture>>, } impl OperationHandlerCallback { @@ -48,17 +52,17 @@ pub trait IntoPluginOperationHandler RuntimeFuture>>; fn callback_ptr(&self) -> CallbackPtr; } impl IntoPluginOperationHandler for F where - Fut: Future>>, - F: Fn(S, O, D) -> Fut, - S: Clone + Debug, - O: Debug + GiteratedObject, - D: Debug + GiteratedOperation, + Fut: Future>> + Send + Sync, + F: Fn(S, O, D) -> Fut + Send + Sync + 'static, + S: Clone + Debug + Send + Sync + 'static, + O: Debug + GiteratedObject + 'static, + D: Debug + GiteratedOperation + 'static, { unsafe extern "C" fn handle( callback: CallbackPtr, @@ -66,7 +70,7 @@ where state: &PluginState, mut object: AnyObject, mut operation: AnyOperation, - ) { + ) -> RuntimeFuture>> { let _guard = trace_span!( "operation handler", object = type_name::(), @@ -83,9 +87,24 @@ where let callback: *const F = std::mem::transmute(callback.0); let callback = callback.as_ref().unwrap(); - // callback(state.clone(), *object, *operation) - - todo!() + let state = state.clone(); + runtime_state.spawn_future(async move { + let result = callback(state, *object, *operation).await; + + match result { + Ok(success) => unsafe { + Ok(AnySuccess::from_raw( + FFIBox::from_box(Box::new(success)).untyped(), + OperationVTable::new::(), + )) + }, + Err(err) => match err { + OperationError::Operation(_) => todo!(), + OperationError::Internal(_) => todo!(), + OperationError::Unhandled => todo!(), + }, + } + }) } fn callback_ptr(&self) -> CallbackPtr { @@ -102,12 +121,12 @@ where D: Debug + GiteratedOperation, { unsafe extern "C" fn handle( - callback_ptr: CallbackPtr, - runtime_state: &RuntimeState, - state: &PluginState, - object: AnyObject, - operation: AnyOperation, - ) { + _callback_ptr: CallbackPtr, + _runtime_state: &RuntimeState, + _state: &PluginState, + _object: AnyObject, + _operation: AnyOperation, + ) -> RuntimeFuture>> { todo!() } @@ -125,12 +144,12 @@ where D: Debug + GiteratedOperation, { unsafe extern "C" fn handle( - callback_ptr: CallbackPtr, - runtime_state: &RuntimeState, - state: &PluginState, - object: AnyObject, - operation: AnyOperation, - ) { + _callback_ptr: CallbackPtr, + _runtime_state: &RuntimeState, + _state: &PluginState, + _object: AnyObject, + _operation: AnyOperation, + ) -> RuntimeFuture>> { todo!() } @@ -150,10 +169,10 @@ pub trait FromOperationState: Sized { impl FromOperationState for RuntimeHandle { fn from_operation_state( - operation_state: &OperationState, + _operation_state: &OperationState, runtime_state: &RuntimeState, - object: &O, - operation: &D, + _object: &O, + _operation: &D, ) -> Result> { Ok(unsafe { RuntimeHandle::from_vtable(runtime_state.vtable) }) } @@ -172,14 +191,3 @@ where Ok(T::from_operation_state(operation_state, runtime_state, object, operation).ok()) } } - -impl FromOperationState for State { - fn from_operation_state( - operation_state: &OperationState, - runtime_state: &RuntimeState, - object: &O, - operation: &D, - ) -> Result> { - Ok(unsafe { State(runtime_state.operation_state.transmute_ref::().clone()) }) - } -} diff --git a/giterated-plugin/src/callback/setting.rs b/giterated-plugin/src/callback/setting.rs index 21e368d..4fbf34e 100644 --- a/giterated-plugin/src/callback/setting.rs +++ b/giterated-plugin/src/callback/setting.rs @@ -6,18 +6,23 @@ use giterated_models::{ settings::{AnySetting, Setting}, }; -use crate::{new_stack::PluginState, AnyObject, NewAnySetting}; +use crate::{ + future::{RuntimeFuture, RuntimeFuturesExt}, + new_stack::PluginState, + AnyObject, NewAnySetting, +}; -use super::CallbackPtr; +use super::{CallbackPtr, RuntimeState}; #[derive(Clone, Copy)] pub struct SettingGetterCallback { pub callback_ptr: CallbackPtr, pub func: unsafe extern "C" fn( CallbackPtr, + runtime_state: &RuntimeState, &PluginState, object: AnyObject, - ) -> Result, + ) -> RuntimeFuture>, } impl SettingGetterCallback { @@ -32,9 +37,10 @@ impl SettingGetterCallback { pub trait IntoPluginSettingGetter { unsafe extern "C" fn get_setting( callback_ptr: CallbackPtr, + runtime_state: &RuntimeState, state: &PluginState, object: AnyObject, - ) -> Result; + ) -> RuntimeFuture>; fn callback_ptr(&self) -> CallbackPtr { unsafe { CallbackPtr::from_raw(self as *const _ as *const ()) } @@ -43,17 +49,18 @@ pub trait IntoPluginSettingGetter { impl IntoPluginSettingGetter for F where - Fut: Future>>, - S: Clone, - O: GiteratedObject, - OS: Setting, - F: Fn(S, O) -> Fut, + Fut: Future>> + Send + Sync + 'static, + S: Clone + Send + Sync + 'static, + O: GiteratedObject + Send + Sync + 'static, + OS: Setting + Send + Sync + 'static, + F: Fn(S, O) -> Fut + Send + Sync + 'static, { unsafe extern "C" fn get_setting( callback: CallbackPtr, + runtime_state: &RuntimeState, state: &PluginState, mut object: AnyObject, - ) -> Result { + ) -> RuntimeFuture> { let _guard = trace_span!( "get_setting handler", object = O::object_name(), @@ -68,14 +75,19 @@ where let callback: *const F = std::mem::transmute(callback.0); let callback = callback.as_ref().unwrap(); - // let result = callback(state.clone(), *object); - - // match result { - // Ok(setting) => Ok(NewAnySetting::new(setting)), - // Err(_) => todo!(), - // } - - todo!() + let state = state.clone(); + runtime_state.spawn_future(async move { + let result = callback(state, *object).await; + + match result { + Ok(success) => unsafe { Ok(NewAnySetting::new(success)) }, + Err(err) => match err { + OperationError::Operation(_) => todo!(), + OperationError::Internal(_) => todo!(), + OperationError::Unhandled => todo!(), + }, + } + }) } } @@ -85,7 +97,7 @@ pub trait IntoPluginSettingSetter { state: &PluginState, object: AnyObject, setting: AnySetting, - ) -> Result<(), ()>; + ) -> RuntimeFuture>; fn callback_ptr(&self) -> CallbackPtr { unsafe { CallbackPtr::from_raw(self as *const _ as *const ()) } @@ -104,21 +116,21 @@ where callback: CallbackPtr, state: &PluginState, mut object: AnyObject, - setting: AnySetting, - ) -> Result<(), ()> { + _setting: AnySetting, + ) -> RuntimeFuture> { let _guard = trace_span!( "get_setting handler", object = O::object_name(), setting = OS::name() ) .entered(); - let state = unsafe { state.transmute_ref::() }; + let _state = unsafe { state.transmute_ref::() }; - let object = unsafe { object.transmute_owned::() }; + let _object = unsafe { object.transmute_owned::() }; // Cast the callback ptr to ourselves let callback: *const F = std::mem::transmute(callback.0); - let callback = callback.as_ref().unwrap(); + let _callback = callback.as_ref().unwrap(); // let result = callback(state.clone(), *object); @@ -150,10 +162,10 @@ pub trait IntoSettingChangeCallback { impl IntoSettingChangeCallback for F { unsafe extern "C" fn setting_changed( - state: &PluginState, - object: AnyObject, - setting_name: &str, - new_setting: NewAnySetting, + _state: &PluginState, + _object: AnyObject, + _setting_name: &str, + _new_setting: NewAnySetting, ) { todo!() } diff --git a/giterated-plugin/src/callback/value.rs b/giterated-plugin/src/callback/value.rs index 654ed3d..a932e8c 100644 --- a/giterated-plugin/src/callback/value.rs +++ b/giterated-plugin/src/callback/value.rs @@ -1,24 +1,26 @@ use std::future::Future; use giterated_models::{ - error::OperationError, object::GiteratedObject, settings::Setting, value::GiteratedObjectValue, + error::OperationError, object::GiteratedObject, value::GiteratedObjectValue, }; use crate::{ + future::{RuntimeFuture, RuntimeFuturesExt}, new_stack::PluginState, vtable::{AnyObject, NewAnyValue}, }; -use super::CallbackPtr; +use super::{CallbackPtr, RuntimeState}; #[derive(Copy, Clone)] pub struct ValueGetterCallback { pub callback_ptr: CallbackPtr, pub func: unsafe extern "C" fn( CallbackPtr, + runtime_state: &RuntimeState, &PluginState, object: AnyObject, - ) -> Result, + ) -> RuntimeFuture>, } impl ValueGetterCallback { @@ -33,26 +35,28 @@ impl ValueGetterCallback { pub trait IntoPluginValueGetter { unsafe extern "C" fn get_value( callback: CallbackPtr, + runtime_state: &RuntimeState, state: &PluginState, object: AnyObject, - ) -> Result; + ) -> RuntimeFuture>; fn callback_ptr(&self) -> CallbackPtr; } impl IntoPluginValueGetter for F where - Fut: Future>>, - S: Clone, - O: GiteratedObject, - V: GiteratedObjectValue, - F: Fn(S, O) -> Fut, + Fut: Future>> + Send + Sync, + S: Clone + Send + Sync + 'static, + O: GiteratedObject + 'static, + V: GiteratedObjectValue + Send + Sync + 'static, + F: Fn(S, O) -> Fut + Send + Sync + 'static, { unsafe extern "C" fn get_value( callback: CallbackPtr, + runtime_state: &RuntimeState, state: &PluginState, mut object: AnyObject, - ) -> Result { + ) -> RuntimeFuture> { let _guard = trace_span!( "get_value handler", object = O::object_name(), @@ -67,14 +71,19 @@ where let callback: *const F = std::mem::transmute(callback.0); let callback = callback.as_ref().unwrap(); - let result = callback(state.clone(), *object); - - // match result { - // Ok(value) => Ok(NewAnyValue::new(value)), - // Err(_) => todo!(), - // } - - todo!() + let state = state.clone(); + runtime_state.spawn_future(async move { + let result = callback(state, *object).await; + + match result { + Ok(success) => unsafe { Ok(NewAnyValue::new(success)) }, + Err(err) => match err { + OperationError::Operation(_) => todo!(), + OperationError::Internal(_) => todo!(), + OperationError::Unhandled => todo!(), + }, + } + }) } fn callback_ptr(&self) -> CallbackPtr { @@ -88,7 +97,7 @@ pub struct ValueChangeCallback { object: AnyObject, value_name: &str, new_value: NewAnyValue, - ), + ) -> RuntimeFuture<()>, } pub trait IntoValueChangeCallback { @@ -97,16 +106,16 @@ pub trait IntoValueChangeCallback { object: AnyObject, value_name: &str, new_value: NewAnyValue, - ); + ) -> RuntimeFuture<()>; } impl IntoValueChangeCallback for F { unsafe extern "C" fn value_changed( - state: &PluginState, - object: AnyObject, - value_name: &str, - new_value: NewAnyValue, - ) { + _state: &PluginState, + _object: AnyObject, + _value_name: &str, + _new_value: NewAnyValue, + ) -> RuntimeFuture<()> { todo!() } } diff --git a/giterated-plugin/src/future.rs b/giterated-plugin/src/future.rs new file mode 100644 index 0000000..19bdbd7 --- /dev/null +++ b/giterated-plugin/src/future.rs @@ -0,0 +1,203 @@ +use futures_util::future::BoxFuture; +use futures_util::FutureExt; +use std::{ + cell::UnsafeCell, + future::Future, + marker::PhantomData, + task::{Context, RawWaker, RawWakerVTable, Waker}, +}; + +use crate::{callback::RuntimeState, new_stack::PluginState, FFIBox}; + +/// Future type for futures within the Runtime. +/// +/// Allows for plugins to spawn futures on the runtime. +#[derive(Clone)] +#[repr(C)] +pub struct RuntimeFuture { + /// The plugin's poll function, provided with the poll state for the future. + poll_fn: unsafe extern "C" fn(*const RuntimeFuture<()>, PluginState) -> RuntimeFuturePoll, + /// The function to wake the future, should only be called when the future is ready to be polled. + wake_fn: Option, PluginState)>, + + /// The inner value that the owning plugin can use to poll the future + poll_state: PluginState, + /// The waker that the plugin uses for notification of the future's completion + waker_state: Option, + + /// Whether its safe for the plugin to poll this future, panic if we think + /// we're supposed to poll and this is not set to `true`. + can_poll: bool, + + _output_marker: PhantomData, +} + +unsafe impl Send for RuntimeFuture where Output: Send {} +unsafe impl Sync for RuntimeFuture where Output: Sync {} + +#[repr(C)] +pub struct RuntimeWakerCallback { + callback: PluginState, + waker_func: unsafe extern "C" fn(PluginState), +} + +#[repr(C)] +pub enum RuntimeFuturePoll { + Ready(FFIBox<()>), + Pending, +} + +pub struct WakerState { + waker: Waker, +} + +impl RuntimeFuture { + pub(crate) unsafe fn poll(&mut self) -> RuntimeFuturePoll { + todo!() + } +} + +unsafe extern "C" fn wake(_waker: PluginState) {} + +pub struct LocalRuntimeFuture { + inner: BoxFuture<'static, Output>, + runtime_future: UnsafeCell>, +} + +unsafe impl Send for LocalRuntimeFuture where Output: Send {} +unsafe impl Sync for LocalRuntimeFuture where Output: Sync {} + +impl LocalRuntimeFuture { + pub fn finalize(self) {} + + pub fn into_runtime(&self) -> RuntimeFuture { + todo!() + } +} + +pub trait RuntimeFuturesExt { + fn spawn_future + Send + Sync + 'static>( + &self, + future: F, + ) -> RuntimeFuture; +} + +impl RuntimeFuturesExt for RuntimeState { + fn spawn_future + Send + Sync + 'static>( + &self, + future: F, + ) -> RuntimeFuture { + let type_eraser = async move { + let result = future.await; + + FFIBox::from_box(Box::new(result)).untyped() + }; + + let runtime_future = RuntimeFuture { + poll_fn: poll_local, + wake_fn: None, + poll_state: PluginState::from(type_eraser.boxed()), + waker_state: None, + can_poll: true, + _output_marker: PhantomData, + }; + + runtime_future + } +} + +unsafe extern "C" fn poll_local( + _future: *const RuntimeFuture<()>, + mut future_state: PluginState, +) -> RuntimeFuturePoll { + let mut future: Box>> = future_state.transmute_owned(); + let runtime_future = future.as_ref(); + + let raw_waker = RawWaker::new( + Box::into_raw(Box::new(runtime_future)) as *const (), + &RUNTIME_FUTURE_WAKER_VTABLE, + ); + + let waker = unsafe { Waker::from_raw(raw_waker) }; + + // SAFETY: Pretty sure this has to be static lol + let poll_result = future.poll_unpin(&mut Context::from_waker(&waker)); + + #[allow(unused_assignments)] + { + // This is meant to communicate with the compiler the lifecycle of the object + future_state = PluginState::from_raw(future); + } + + match poll_result { + std::task::Poll::Ready(result) => RuntimeFuturePoll::Ready(result), + std::task::Poll::Pending => RuntimeFuturePoll::Pending, + } +} + +pub static RUNTIME_FUTURE_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( + runtime_waker_vtable::waker_clone, + runtime_waker_vtable::waker_wake, + runtime_waker_vtable::waker_wake_by_ref, + runtime_waker_vtable::waker_drop, +); + +mod runtime_waker_vtable { + use std::task::RawWaker; + + pub unsafe fn waker_clone(_data: *const ()) -> RawWaker { + todo!() + } + + pub unsafe fn waker_wake(_data: *const ()) { + todo!() + } + + pub unsafe fn waker_wake_by_ref(_data: *const ()) { + todo!() + } + + pub unsafe fn waker_drop(_data: *const ()) { + // no-op + } +} + +/// Allows for a remote future to be polled on the target. +/// +/// The target can be the host or a plugin, but the future should only be polled by one +/// source. +impl Future for RuntimeFuture { + type Output = Output; + + fn poll( + mut self: std::pin::Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> std::task::Poll { + let waker_state = WakerState { + waker: cx.waker().clone(), + }; + + let waker_state = PluginState::from(waker_state); + + self.waker_state = Some(waker_state); + self.wake_fn = Some(wake_local); + + match unsafe { + (self.poll_fn)( + &*self as *const RuntimeFuture<_> as *const RuntimeFuture<()>, + self.poll_state, + ) + } { + RuntimeFuturePoll::Ready(result) => { + let result: Output = unsafe { *result.retype::().into_box() }; + + std::task::Poll::Ready(result) + } + RuntimeFuturePoll::Pending => std::task::Poll::Pending, + } + } +} + +unsafe extern "C" fn wake_local(_future: *const RuntimeFuture<()>, _waker_state: PluginState) { + todo!() +} diff --git a/giterated-plugin/src/handle.rs b/giterated-plugin/src/handle.rs index f262422..b0bedae 100644 --- a/giterated-plugin/src/handle.rs +++ b/giterated-plugin/src/handle.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, marker::PhantomData, path::Path, sync::Arc}; +use std::{collections::HashMap, marker::PhantomData, sync::Arc}; use anyhow::Error; use dlopen2::wrapper::Container; @@ -6,10 +6,12 @@ use semver::Version; use tracing::{debug, trace}; use crate::{ - callback::{OperationHandlerCallback, SettingGetterCallback, ValueGetterCallback}, + callback::{ + OperationHandlerCallback, RuntimeState, SettingGetterCallback, ValueGetterCallback, + }, new_stack::{ ObjectOperationPair, ObjectSettingPair, ObjectValuePair, PluginMeta, PluginState, - RuntimeHandlers, TypeMetadata, + TypeMetadata, }, vtable::{InitializationVTable, ObjectVtable, OperationVTable, SettingVtable, ValueVTable}, GiteratedPluginApi, @@ -31,7 +33,8 @@ impl PluginHandle { let mut handle = unsafe { Container::load(path) }?; // Initialize the raw handle - let init_state = Self::initialize_raw_handle(&mut handle)?; + let init_state = + Self::initialize_raw_handle(&mut handle, &unsafe { RuntimeState::from_static() })?; let metadata = Self::get_meta(&mut handle)?; @@ -94,10 +97,11 @@ impl PluginHandle { fn initialize_raw_handle( handle: &mut Container, + runtime_state: &RuntimeState, ) -> Result { debug!("Initializing plugin handle..."); - let state = unsafe { handle.initialize() }; + let state = unsafe { handle.initialize(runtime_state) }; debug!("Plugin handle initialized!"); diff --git a/giterated-plugin/src/lib.rs b/giterated-plugin/src/lib.rs index fdc606a..754b986 100644 --- a/giterated-plugin/src/lib.rs +++ b/giterated-plugin/src/lib.rs @@ -1,4 +1,7 @@ +#![allow(improper_ctypes_definitions)] + pub mod callback; +pub mod future; pub mod handle; pub mod new_stack; pub mod vtable; @@ -6,14 +9,9 @@ pub mod vtable; #[macro_use] extern crate tracing; -use std::{any::Any, fmt::Debug, mem::transmute, ptr::null_mut, sync::Arc}; - -use callback::{OperationHandlerCallback, SettingGetterCallback, ValueGetterCallback}; +use callback::RuntimeState; use dlopen2::wrapper::WrapperApi; -use giterated_models::{ - object::GiteratedObject, operation::GiteratedOperation, settings::Setting, - value::GiteratedObjectValue, -}; + use handle::PluginInitializationState; use new_stack::{FFIPluginMeta, PluginState}; @@ -25,7 +23,7 @@ pub struct GiteratedPluginApi { plugin_meta: unsafe extern "C" fn() -> FFIPluginMeta, load_host_vtable: unsafe extern "C" fn(vtable: &HostVTable), load_initialization_vtable: unsafe extern "C" fn(vtable: &InitializationVTable), - initialize: unsafe extern "C" fn() -> PluginState, + initialize: unsafe extern "C" fn(runtime_state: *const RuntimeState) -> PluginState, initialize_registration: unsafe extern "C" fn( init_state: *mut PluginInitializationState, ) -> *mut PluginInitializationState, @@ -42,11 +40,29 @@ impl FFIBox { pub fn untyped(self) -> FFIBox<()> { FFIBox(self.0 as *mut ()) } + + pub unsafe fn retype(self) -> FFIBox { + FFIBox(self.0 as *mut N) + } + + pub unsafe fn into_box(self) -> Box { + Box::from_raw(self.0) + } + + pub unsafe fn transmute_ref(&self) -> &N { + unsafe { (self.0 as *const N).as_ref() }.unwrap() + } +} + +impl ToString for FFIBox { + fn to_string(&self) -> String { + todo!() + } } impl AsRef for FFIBox { fn as_ref(&self) -> &T { - todo!() + unsafe { self.0.as_ref() }.unwrap() } } diff --git a/giterated-plugin/src/new_stack/handle.rs b/giterated-plugin/src/new_stack/handle.rs index 65f3bbd..77e4cca 100644 --- a/giterated-plugin/src/new_stack/handle.rs +++ b/giterated-plugin/src/new_stack/handle.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use giterated_models::{ error::OperationError, object::{GiteratedObject, Object, ObjectRequestError}, @@ -20,9 +18,9 @@ pub struct RuntimeHandle { impl RuntimeHandle { pub async fn handle_serialized( &self, - object: &str, - operation_name: &str, - payload: &[u8], + _object: &str, + _operation_name: &str, + _payload: &[u8], ) -> Result, OperationError>> { todo!() } @@ -35,13 +33,13 @@ impl RuntimeHandle { } #[async_trait::async_trait(?Send)] -impl ObjectBackend for RuntimeHandle { +impl ObjectBackend for RuntimeHandle { async fn object_operation( &self, - object: O, - operation: &str, - payload: D, - operation_state: &OperationState, + _object: O, + _operation: &str, + _payload: D, + _operation_state: &OperationState, ) -> Result> where O: GiteratedObject + Debug + 'static, @@ -54,9 +52,9 @@ impl ObjectBackend for RuntimeHandle { async fn get_object( &self, - object_str: &str, - operation_state: &OperationState, - ) -> Result, OperationError> { + _object_str: &str, + _operation_state: &OperationState, + ) -> Result, OperationError> { todo!() } } diff --git a/giterated-plugin/src/new_stack/mod.rs b/giterated-plugin/src/new_stack/mod.rs index 5ab4969..efce8d1 100644 --- a/giterated-plugin/src/new_stack/mod.rs +++ b/giterated-plugin/src/new_stack/mod.rs @@ -2,26 +2,28 @@ pub mod handle; pub mod operation_walker; pub mod runtime_handler; -use std::{ - any::type_name, collections::HashMap, fmt::Debug, marker::PhantomData, mem::transmute, - ptr::null_mut, sync::Arc, -}; +use std::{collections::HashMap, fmt::Debug, mem::transmute, ptr::null_mut, sync::Arc}; use giterated_models::{ - error::OperationError, instance::Instance, object::GiteratedObject, - operation::GiteratedOperation, + error::OperationError, + object::GiteratedObject, + operation::{GiteratedOperation, OperationState}, }; use semver::Version; -use serde::Serialize; -use tracing::{debug, debug_span, field::DebugValue, span, trace, trace_span, warn, Level}; + +use tracing::{debug, debug_span, trace, trace_span, warn}; use crate::{ callback::{ - OperationHandlerCallback, SettingChangeCallback, SettingGetterCallback, + OperationHandlerCallback, RuntimeState, SettingChangeCallback, SettingGetterCallback, ValueChangeCallback, ValueGetterCallback, }, - handle::{PluginHandle, PluginInitializationState}, - vtable::{ObjectVtable, OperationVTable, SettingVtable, ValueVTable}, + future::RuntimeFuture, + handle::PluginHandle, + vtable::{ + IntoRuntimeVtable, ObjectVtable, OperationVTable, RuntimeVTable, SettingVtable, ValueVTable, + }, + AnyFailure, AnySuccess, }; use self::operation_walker::OperationHandlerRules; @@ -158,6 +160,9 @@ pub struct PluginState { pub inner: *mut (), } +unsafe impl Send for PluginState {} +unsafe impl Sync for PluginState {} + impl PluginState { pub unsafe fn transmute_owned(&mut self) -> Box { Box::from_raw(self.inner as *mut T) @@ -171,6 +176,18 @@ impl PluginState { } impl PluginState { + pub fn from(source: S) -> Self { + Self { + inner: Box::into_raw(Box::new(source)) as *mut _, + } + } + + pub unsafe fn from_raw(raw: Box) -> Self { + Self { + inner: Box::into_raw(raw) as *mut _, + } + } + pub fn null() -> Self { Self { inner: null_mut() } } @@ -181,15 +198,38 @@ pub struct Runtime { handlers: RuntimeHandlers, } +impl IntoRuntimeVtable for Runtime { + unsafe extern "C" fn handle( + _this: PluginState, + _object_kind: crate::FFIBox, + _operation_name: crate::FFIBox, + _object: crate::FFIBox, + _operation_payload: crate::FFIBox<[u8]>, + _operation_state: crate::FFIBox<[u8]>, + ) -> RuntimeFuture>> { + todo!() + } +} + impl Runtime { - pub fn new() -> Self { - Self { + pub fn new() -> Box { + Box::new(Self { plugins: vec![], handlers: RuntimeHandlers::default(), + }) + } + + pub fn state(self: &Box, operation_state: &OperationState) -> RuntimeState { + RuntimeState { + vtable: RuntimeVTable { + runtime: PluginState::from(self), + handle_fn: ::handle, + }, + operation_state: operation_state.clone(), } } - pub fn insert_plugin(&mut self, mut plugin: PluginHandle) { + pub fn insert_plugin(&mut self, plugin: PluginHandle) { let _guard = debug_span!("inserting plugin", meta = debug(&plugin.meta)).entered(); for (pair, callback) in &plugin.initialization.operation_handlers { @@ -241,24 +281,29 @@ impl Runtime { } } - pub fn handle( - &self, - object_kind: &str, - operation_name: &str, - object: &str, - operation_payload: &[u8], - ) -> Result<(), OperationError<()>> { - // let rules = self.handlers.handle_operation(object_kind, operation_name); + pub fn init(self: Box) { + unsafe { giterated_static_runtime::initialize_runtime(Box::into_raw(self).cast::<()>()) } + } - // rules.handle(object, operation_payload) + // pub async fn handle( + // &self, + // object_kind: &str, + // operation_name: &str, + // object: &str, + // operation_payload: &[u8], + // operation_state: &OperationState, + // ) -> Result> { + // let rules = self.handlers.handle_operation(object_kind, operation_name); - todo!() - } + // let state = self.state(operation_state); + + // rules.handle(&state, object, operation_payload).await + // } pub fn handle_typed>( &self, - object: O, - operation: D, + _object: O, + _operation: D, ) -> Result> { todo!() } @@ -480,37 +525,3 @@ impl RuntimePlugin { } } } - -pub enum HandlerError { - Failure(()), - Internal(()), - Unhandled, -} - -pub trait StateId { - fn state_id(&self) -> &'static str; -} - -pub unsafe trait FfiState: StateId { - fn into_ffi_state_bytes(self) -> Vec; - - fn from_ffi_state_bytes(bytes: Vec) -> Self; -} - -unsafe impl FfiState for T -where - T: Serialize + StateId, -{ - fn into_ffi_state_bytes(self) -> Vec { - todo!() - } - - fn from_ffi_state_bytes(bytes: Vec) -> Self { - todo!() - } -} - -#[derive(Clone, Debug)] -pub struct OperationState { - entries: HashMap<&'static str, Vec>, -} diff --git a/giterated-plugin/src/new_stack/operation_walker.rs b/giterated-plugin/src/new_stack/operation_walker.rs index bb9f6f6..af99230 100644 --- a/giterated-plugin/src/new_stack/operation_walker.rs +++ b/giterated-plugin/src/new_stack/operation_walker.rs @@ -1,10 +1,14 @@ -use crate::callback::RuntimeState; -use giterated_models::{operation::GiteratedOperation, settings::GetSetting, value::GetValue}; +use crate::{callback::RuntimeState, AnyFailure, AnySuccess, FFIBox}; +use giterated_models::{ + error::OperationError, operation::GiteratedOperation, settings::GetSetting, value::GetValue, +}; + +use serde_json::Value; use tracing::{debug_span, trace, trace_span}; -use crate::new_stack::{ObjectOperationPair, PluginState}; +use crate::new_stack::ObjectOperationPair; -use super::{HandlerError, ObjectSettingPair, ObjectValuePair, RuntimeHandlers}; +use super::{ObjectSettingPair, ObjectValuePair, RuntimeHandlers}; /// A wrapper for operation handling that enforces handling rules. /// @@ -40,15 +44,15 @@ impl<'o> OperationHandlerRules<'o> { } } - pub fn handle( + pub async fn handle( &self, runtime_state: &RuntimeState, object: &str, operation_payload: &[u8], - ) -> Result<(), HandlerError> { + ) -> Result> { // object_kind: `any` // operation_kind: `typed` - if let Some(handler) = self + if let Some(_handler) = self .handlers .operation_handlers .get(&ObjectOperationPair::new("any", self.operation_name)) @@ -58,7 +62,7 @@ impl<'o> OperationHandlerRules<'o> { // object_kind: `typed` // operation_kind: `any` - if let Some(handler) = self + if let Some(_handler) = self .handlers .operation_handlers .get(&ObjectOperationPair::new(self.object_kind, "any")) @@ -66,7 +70,7 @@ impl<'o> OperationHandlerRules<'o> { // object_kind: `any` // operation_kind: `any` - if let Some(handler) = self + if let Some(_handler) = self .handlers .operation_handlers .get(&ObjectOperationPair::new("any", "any")) @@ -95,12 +99,12 @@ impl<'o> OperationHandlerRules<'o> { let object_vtable = domain .object_vtable(self.object_kind) - .ok_or_else(|| HandlerError::Unhandled)?; + .ok_or_else(|| OperationError::Unhandled)?; trace!("Resolved object vtable for {}", self.object_kind); - let value_vtable = domain + let _value_vtable = domain .value_vtable(self.object_kind, &operation.value_name) - .ok_or_else(|| HandlerError::Unhandled)?; + .ok_or_else(|| OperationError::Unhandled)?; trace!( "Resolved value vtable for {}::{}", self.object_kind, @@ -108,16 +112,24 @@ impl<'o> OperationHandlerRules<'o> { ); let object = unsafe { (object_vtable.from_str)(object) } - .map_err(|_| HandlerError::Internal(()))?; + .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; let _guard = debug_span!("get_value handler"); - let result = - unsafe { (callback.func)(callback.callback_ptr, &domain.plugin.state, object) }; - - // Todo deser - - return Ok(()); + 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!(), + } } else { trace!("Failed to resolve handler."); } @@ -146,25 +158,46 @@ impl<'o> OperationHandlerRules<'o> { let object_vtable = domain .object_vtable(self.object_kind) - .ok_or_else(|| HandlerError::Unhandled)?; + .ok_or_else(|| OperationError::Unhandled)?; trace!("Resolved object vtable for {}", self.object_kind); - let setting_vtable = domain + let _setting_vtable = domain .setting_vtable(self.object_kind, &operation.setting_name) - .ok_or_else(|| HandlerError::Unhandled)?; + .ok_or_else(|| OperationError::Unhandled)?; trace!("Resolved setting vtable for {}", operation.setting_name); let object = unsafe { (object_vtable.from_str)(object) } - .map_err(|_| HandlerError::Internal(()))?; + .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; let _guard = debug_span!("get_value handler"); - let result = - unsafe { (callback.func)(callback.callback_ptr, &domain.plugin.state, object) }; - - // Todo deser - - return Ok(()); + 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(); + + return Ok(unsafe { + AnySuccess::from_raw( + FFIBox::from_box(Box::new(return_value)).untyped(), + vtable, + ) + }); + } + Err(_err) => todo!(), + } } else { trace!("Failed to resolve handler."); } @@ -173,12 +206,12 @@ impl<'o> OperationHandlerRules<'o> { // ⚠️ Special Case ⚠️ // object_kind: `any` // operation_kind: `SetSetting` - if self.operation_name == "set_setting" {} + self.operation_name == "set_setting"; // ⚠️ Special Case ⚠️ // object_kind: `any` // operation_kind: `ObjectRequest` - if self.operation_name == "object_request" {} + self.operation_name == "object_request"; // object_kind: `typed` // operation_kind: `typed` @@ -194,12 +227,12 @@ impl<'o> OperationHandlerRules<'o> { let object_vtable = domain .object_vtable(self.object_kind) - .ok_or_else(|| HandlerError::Unhandled)?; + .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(|| HandlerError::Unhandled)?; + .ok_or_else(|| OperationError::Unhandled)?; trace!( "Resolved operation vtable for {}::{}", self.object_kind, @@ -207,9 +240,9 @@ impl<'o> OperationHandlerRules<'o> { ); let object = unsafe { (object_vtable.from_str)(object) } - .map_err(|_| HandlerError::Internal(()))?; + .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; let operation = unsafe { (operation_vtable.deserialize)(operation_payload) } - .map_err(|_| HandlerError::Internal(()))?; + .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; trace!("Parsed operation data"); let _guard = debug_span!("calling handler").entered(); @@ -223,10 +256,9 @@ impl<'o> OperationHandlerRules<'o> { ) }; - // todo - return Ok(()); + return result.await; } - Err(HandlerError::Unhandled) + Err(OperationError::Unhandled) } } diff --git a/giterated-plugin/src/new_stack/runtime_handler.rs b/giterated-plugin/src/new_stack/runtime_handler.rs index 56ae989..dc6e4bf 100644 --- a/giterated-plugin/src/new_stack/runtime_handler.rs +++ b/giterated-plugin/src/new_stack/runtime_handler.rs @@ -1,16 +1,8 @@ -use std::fmt::Debug; -use std::sync::Arc; - -use giterated_models::{ - error::OperationError, - object::{GiteratedObject, Object, ObjectRequestError}, - object_backend::ObjectBackend, - operation::GiteratedOperation, -}; +use giterated_models::error::OperationError; use crate::vtable::{AnyFailure, AnySuccess, OperationVTable}; -use super::{handle::RuntimeHandle, PluginState}; +use super::PluginState; #[repr(C)] struct RuntimeHandleInner { diff --git a/giterated-plugin/src/vtable/object.rs b/giterated-plugin/src/vtable/object.rs index dc00436..a04d897 100644 --- a/giterated-plugin/src/vtable/object.rs +++ b/giterated-plugin/src/vtable/object.rs @@ -1,4 +1,4 @@ -use std::mem::transmute; +use std::{mem::transmute, str::FromStr}; use giterated_models::object::GiteratedObject; @@ -9,10 +9,10 @@ use crate::FFIBox; pub struct ObjectVtable { object_kind: *const u8, object_kind_len: usize, - pub to_str: unsafe extern "C" fn(AnyObject) -> FFIBox, + pub to_str: unsafe extern "C" fn(&AnyObject) -> FFIBox, pub from_str: unsafe extern "C" fn(&str) -> Result>, pub home_uri: unsafe extern "C" fn(&AnyObject) -> FFIBox, - pub is_same: unsafe extern "C" fn(AnyObject) -> bool, + pub is_same: unsafe extern "C" fn(&AnyObject) -> bool, } impl ObjectVtable { @@ -39,14 +39,14 @@ impl ObjectVtable { pub trait IntoObjectVTable { fn object_kind() -> &'static str; - unsafe extern "C" fn to_str(this: AnyObject) -> FFIBox; + unsafe extern "C" fn to_str(this: &AnyObject) -> FFIBox; unsafe extern "C" fn from_str(src: &str) -> Result>; unsafe extern "C" fn home_uri(this: &AnyObject) -> FFIBox; - unsafe extern "C" fn is_same(other: AnyObject) -> bool; + unsafe extern "C" fn is_same(other: &AnyObject) -> bool; } impl IntoObjectVTable for T { - unsafe extern "C" fn to_str(mut this: AnyObject) -> FFIBox { + unsafe extern "C" fn to_str(this: &AnyObject) -> FFIBox { let this: &Box = this.transmute_ref(); let result = this.to_string(); @@ -62,16 +62,16 @@ impl IntoObjectVTable for T { Ok(any_object) } - unsafe extern "C" fn home_uri(this: &AnyObject) -> FFIBox { + unsafe extern "C" fn home_uri(_this: &AnyObject) -> FFIBox { todo!() } - unsafe extern "C" fn is_same(other: AnyObject) -> bool { + unsafe extern "C" fn is_same(_other: &AnyObject) -> bool { todo!() } fn object_kind() -> &'static str { - todo!() + ::object_name() } } @@ -94,6 +94,29 @@ impl AnyObject { pub fn vtable(&self) -> ObjectVtable { self.vtable } + + pub fn object_kind(&self) -> &str { + unsafe { + std::str::from_utf8_unchecked(std::slice::from_raw_parts( + self.vtable.object_kind, + self.vtable.object_kind_len, + )) + } + } + + pub fn home_uri(&self) -> String { + unsafe { (self.vtable.home_uri)(self).to_string() } + } + + pub fn is_same(&self, other: &AnyObject) -> bool { + unsafe { (self.vtable.is_same)(other) } + } +} + +impl ToString for AnyObject { + fn to_string(&self) -> String { + unsafe { (self.vtable.to_str)(self).to_string() } + } } impl AnyObject { diff --git a/giterated-plugin/src/vtable/operation.rs b/giterated-plugin/src/vtable/operation.rs index 5ecfa36..910f9a2 100644 --- a/giterated-plugin/src/vtable/operation.rs +++ b/giterated-plugin/src/vtable/operation.rs @@ -4,8 +4,6 @@ use giterated_models::{object::GiteratedObject, operation::GiteratedOperation}; use crate::FFIBox; -use super::AnyObject; - #[derive(Clone, Copy)] #[repr(C)] pub struct OperationVTable { @@ -13,7 +11,7 @@ pub struct OperationVTable { operation_kind_len: usize, pub serialize: unsafe extern "C" fn(&AnyOperation) -> Result, ()>, pub deserialize: unsafe extern "C" fn(&[u8]) -> Result, - pub is_same: unsafe extern "C" fn(AnyObject) -> bool, + pub is_same: unsafe extern "C" fn(&AnyOperation) -> bool, pub serialize_success: unsafe extern "C" fn(()) -> Result, ()>, pub serialize_failure: unsafe extern "C" fn(()) -> Result, ()>, pub deserialize_success: unsafe extern "C" fn(&[u8]) -> Result, @@ -46,6 +44,7 @@ impl OperationVTable { } } +#[repr(C)] pub struct AnyOperation { /// A pointer to the plugin-local object type. We are not capable of /// knowing what this type is, we use the provided vtable. @@ -54,6 +53,10 @@ pub struct AnyOperation { } impl AnyOperation { + pub fn new>(_operation: D) -> Self { + todo!() + } + pub unsafe fn transmute_owned(&mut self) -> Box { Box::from_raw(self.inner.0 as *mut T) } @@ -67,6 +70,27 @@ impl AnyOperation { pub fn vtable(&self) -> OperationVTable { self.vtable } + + pub fn operation_kind(&self) -> &str { + unsafe { + std::str::from_utf8_unchecked(std::slice::from_raw_parts( + self.vtable.operation_kind, + self.vtable.operation_kind_len, + )) + } + } + + pub fn serialize(&self) -> Result, anyhow::Error> { + todo!() + } + + pub fn deserialize(_source: &[u8], _vtable: OperationVTable) -> Result { + todo!() + } + + pub fn is_same(&self, _other: &AnyOperation) -> bool { + todo!() + } } #[repr(C)] @@ -75,17 +99,56 @@ pub struct AnySuccess { vtable: OperationVTable, } +impl AnySuccess { + pub unsafe fn inner(&self) -> &T { + self.inner.transmute_ref() + } + + pub unsafe fn from_raw(inner: FFIBox<()>, vtable: OperationVTable) -> Self { + Self { inner, vtable } + } + + pub fn serialize(&self) -> Result, anyhow::Error> { + todo!() + } + + pub fn deserialize_from_operation( + _source: &[u8], + _vtable: OperationVTable, + ) -> Result { + todo!() + } +} + +unsafe impl Send for AnySuccess {} +unsafe impl Sync for AnySuccess {} + +impl std::fmt::Debug for AnySuccess { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("AnySuccess").finish() + } +} + #[repr(C)] pub struct AnyFailure { inner: FFIBox<()>, vtable: OperationVTable, } +unsafe impl Send for AnyFailure {} +unsafe impl Sync for AnyFailure {} + +impl std::fmt::Debug for AnyFailure { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("AnyFailure").finish() + } +} + pub trait IntoOperationVTable { fn operation_kind() -> &'static str; unsafe extern "C" fn serialize(this: &AnyOperation) -> Result, ()>; unsafe extern "C" fn deserialize(src: &[u8]) -> Result; - unsafe extern "C" fn is_same(this: AnyObject) -> bool; + unsafe extern "C" fn is_same(this: &AnyOperation) -> bool; unsafe extern "C" fn serialize_success(success: ()) -> Result, ()>; unsafe extern "C" fn serialize_failure(failure: ()) -> Result, ()>; unsafe extern "C" fn deserialize_success(src: &[u8]) -> Result; @@ -97,7 +160,7 @@ where D: GiteratedOperation, O: GiteratedObject, { - unsafe extern "C" fn serialize(this: &AnyOperation) -> Result, ()> { + unsafe extern "C" fn serialize(_this: &AnyOperation) -> Result, ()> { todo!() } @@ -110,27 +173,27 @@ where }) } - unsafe extern "C" fn is_same(this: AnyObject) -> bool { + unsafe extern "C" fn is_same(_this: &AnyOperation) -> bool { todo!() } - unsafe extern "C" fn serialize_success(success: ()) -> Result, ()> { + unsafe extern "C" fn serialize_success(_success: ()) -> Result, ()> { todo!() } - unsafe extern "C" fn serialize_failure(failure: ()) -> Result, ()> { + unsafe extern "C" fn serialize_failure(_failure: ()) -> Result, ()> { todo!() } - unsafe extern "C" fn deserialize_success(src: &[u8]) -> Result { + unsafe extern "C" fn deserialize_success(_src: &[u8]) -> Result { todo!() } - unsafe extern "C" fn deserialize_failure(src: &[u8]) -> Result { + unsafe extern "C" fn deserialize_failure(_src: &[u8]) -> Result { todo!() } fn operation_kind() -> &'static str { - todo!() + >::operation_name() } } diff --git a/giterated-plugin/src/vtable/runtime.rs b/giterated-plugin/src/vtable/runtime.rs index 3f37686..5315a88 100644 --- a/giterated-plugin/src/vtable/runtime.rs +++ b/giterated-plugin/src/vtable/runtime.rs @@ -1,2 +1,29 @@ +use giterated_models::error::OperationError; + +use crate::{future::RuntimeFuture, new_stack::PluginState, AnyFailure, AnySuccess, FFIBox}; + #[derive(Clone, Copy)] -pub struct RuntimeVTable {} +pub struct RuntimeVTable { + pub(crate) runtime: PluginState, + pub(crate) handle_fn: unsafe extern "C" fn( + PluginState, + FFIBox, + FFIBox, + FFIBox, + FFIBox<[u8]>, + FFIBox<[u8]>, + ) -> RuntimeFuture< + Result>, + >, +} + +pub trait IntoRuntimeVtable { + unsafe extern "C" fn handle( + this: PluginState, + object_kind: FFIBox, + operation_name: FFIBox, + object: FFIBox, + operation_payload: FFIBox<[u8]>, + operation_state: FFIBox<[u8]>, + ) -> RuntimeFuture>>; +} diff --git a/giterated-plugin/src/vtable/setting.rs b/giterated-plugin/src/vtable/setting.rs index 4fd768f..38e20ad 100644 --- a/giterated-plugin/src/vtable/setting.rs +++ b/giterated-plugin/src/vtable/setting.rs @@ -1,15 +1,20 @@ use std::mem::transmute; -use giterated_models::settings::Setting; +use giterated_models::{ + instance::Instance, + settings::{GetSetting, Setting}, +}; -use crate::FFIBox; +use crate::{AnySuccess, FFIBox}; + +use super::OperationVTable; #[repr(C)] pub struct NewAnySetting { /// A pointer to the plugin-local object type. We are not capable of /// knowing what this type is, we use the provided vtable. inner: FFIBox<()>, - vtable: SettingVtable, + pub vtable: SettingVtable, } impl NewAnySetting { @@ -31,9 +36,17 @@ impl NewAnySetting { } } +impl From for AnySuccess { + fn from(val: NewAnySetting) -> Self { + unsafe { AnySuccess::from_raw(val.inner, (val.vtable.get_setting_vtable)()) } + } +} + #[derive(Clone, Copy)] #[repr(C)] pub struct SettingVtable { + pub get_setting_vtable: unsafe extern "C" fn() -> OperationVTable, + pub deserialize: unsafe extern "C" fn(&[u8]) -> Result<(), ()>, pub serialize: unsafe extern "C" fn(NewAnySetting) -> Result, ()>, } @@ -41,6 +54,7 @@ pub struct SettingVtable { impl SettingVtable { pub fn new() -> Self { Self { + get_setting_vtable: T::get_setting_vtable, deserialize: T::deserialize, serialize: T::serialize, } @@ -48,6 +62,7 @@ impl SettingVtable { } pub trait IntoSettingVTable { + unsafe extern "C" fn get_setting_vtable() -> OperationVTable; unsafe extern "C" fn deserialize(src: &[u8]) -> Result<(), ()>; unsafe extern "C" fn serialize(this: NewAnySetting) -> Result, ()>; } @@ -56,11 +71,21 @@ impl IntoSettingVTable for S where S: Setting, { - unsafe extern "C" fn deserialize(src: &[u8]) -> Result<(), ()> { + unsafe extern "C" fn deserialize(_src: &[u8]) -> Result<(), ()> { todo!() } unsafe extern "C" fn serialize(this: NewAnySetting) -> Result, ()> { - todo!() + let setting = this.transmute_owned::(); + + let serialized = serde_json::to_vec(&setting).unwrap(); + + let serialized = serialized.into_boxed_slice(); + + Ok(FFIBox::from_box(serialized)) + } + + unsafe extern "C" fn get_setting_vtable() -> OperationVTable { + OperationVTable::new::() } } diff --git a/giterated-plugin/src/vtable/value.rs b/giterated-plugin/src/vtable/value.rs index ba9eb93..27cd514 100644 --- a/giterated-plugin/src/vtable/value.rs +++ b/giterated-plugin/src/vtable/value.rs @@ -1,6 +1,11 @@ -use giterated_models::{object::GiteratedObject, value::GiteratedObjectValue}; +use giterated_models::{ + object::GiteratedObject, + value::{GetValue, GiteratedObjectValue}, +}; -use crate::FFIBox; +use crate::{AnySuccess, FFIBox}; + +use super::OperationVTable; #[repr(C)] pub struct NewAnyValue { @@ -10,8 +15,11 @@ pub struct NewAnyValue { vtable: ValueVTable, } +unsafe impl Send for NewAnyValue {} +unsafe impl Sync for NewAnyValue {} + impl NewAnyValue { - pub fn new>(value: V) -> Self { + pub fn new + Send + Sync>(value: V) -> Self { NewAnyValue { inner: FFIBox::from_box(Box::new(value)).untyped(), vtable: ValueVTable::new::(), @@ -19,9 +27,17 @@ impl NewAnyValue { } } +impl From for AnySuccess { + fn from(val: NewAnyValue) -> Self { + unsafe { AnySuccess::from_raw(val.inner, (val.vtable.get_value_vtable)()) } + } +} + #[derive(Clone, Copy)] #[repr(C)] pub struct ValueVTable { + pub get_value_vtable: unsafe extern "C" fn() -> OperationVTable, + pub deserialize: unsafe extern "C" fn(&[u8]) -> Result, pub serialize: unsafe extern "C" fn(NewAnyValue) -> Result, ()>, } @@ -29,6 +45,7 @@ pub struct ValueVTable { impl ValueVTable { pub fn new>() -> Self { Self { + get_value_vtable: T::get_value_vtable, deserialize: T::deserialize, serialize: T::serialize, } @@ -36,6 +53,7 @@ impl ValueVTable { } pub trait IntoValueVTable { + unsafe extern "C" fn get_value_vtable() -> OperationVTable; unsafe extern "C" fn deserialize(src: &[u8]) -> Result; unsafe extern "C" fn serialize(this: NewAnyValue) -> Result, ()>; } @@ -45,6 +63,10 @@ where O: GiteratedObject, V: GiteratedObjectValue, { + unsafe extern "C" fn get_value_vtable() -> OperationVTable { + OperationVTable::new::() + } + unsafe extern "C" fn deserialize(src: &[u8]) -> Result { let _guard = trace_span!( "deserialize value", @@ -61,7 +83,7 @@ where }) } - unsafe extern "C" fn serialize(this: NewAnyValue) -> Result, ()> { + unsafe extern "C" fn serialize(_this: NewAnyValue) -> Result, ()> { todo!() } } diff --git a/plugins/example-plugin/Cargo.toml b/plugins/example-plugin/Cargo.toml index 7021024..58728c7 100644 --- a/plugins/example-plugin/Cargo.toml +++ b/plugins/example-plugin/Cargo.toml @@ -13,9 +13,11 @@ crate-type = ["dylib"] [dependencies] giterated-plugin = { path = "../../giterated-plugin" } giterated-plugin-sys = { path = "../../giterated-plugin/giterated-plugin-sys" } +giterated-static-runtime = { path = "../../giterated-plugin/giterated-static-runtime" } dlopen2 = "0.6" tracing-subscriber = "0.3" giterated-models = { path = "../../giterated-models" } tracing = "0.1" serde_json = "1.0" anyhow = "1" +tokio = { version = "1.32", features = [ "full" ] } diff --git a/plugins/example-plugin/src/lib.rs b/plugins/example-plugin/src/lib.rs index 4b580e3..53e7156 100644 --- a/plugins/example-plugin/src/lib.rs +++ b/plugins/example-plugin/src/lib.rs @@ -1,4 +1,4 @@ -use std::sync::OnceLock; +use std::{mem::forget, sync::OnceLock}; use giterated_models::{ error::OperationError, @@ -36,7 +36,7 @@ pub extern "C" fn load_host_vtable(_vtable: &HostVTable) { #[no_mangle] pub extern "C" fn load_initialization_vtable(init_vtable: &InitializationVTable) { - INIT_VTABLE.set(init_vtable.clone()).unwrap(); + INIT_VTABLE.set(*init_vtable).unwrap(); println!("Loaded initialization vtable"); } @@ -48,6 +48,16 @@ pub extern "C" fn initialize() -> PluginState { .with_max_level(Level::TRACE) .init(); + println!("Building runtime"); + let runtime = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); + + let _guard = runtime.enter(); + + forget(_guard); + PluginState { inner: Box::into_raw(Box::new(())), } @@ -64,32 +74,37 @@ pub extern "C" fn initialize_registration( builder.object::().object::(); builder.operation(handler); builder.value(value_getter); - // builder.setting_getter(setting_getter); + builder.setting_getter(setting_getter); state } async fn handler( - state: (), - _object: Instance, - _operation: ObjectRequest, + _state: (), + object: Instance, + operation: ObjectRequest, ) -> Result> { info!("handling operation!"); - todo!() + info!("Try get object {} from instance {}", operation.0, object); + + Ok(ObjectResponse(operation.0)) } async fn value_getter( - state: (), - object: User, + _state: (), + _object: User, ) -> Result> { info!("OwO, value gotten!"); Ok(DisplayName(String::from("heya!"))) } -// fn setting_getter(state: (), object: User) -> Result { -// info!("OwO, setting gotten!"); +async fn setting_getter( + _state: (), + _object: User, +) -> Result> { + info!("OwO, setting gotten!"); -// Ok(DisplayName(String::from("heya! (but from a setting)"))) -// } + Ok(DisplayName(String::from("heya! (but from a setting)"))) +} diff --git a/plugins/example-plugin/src/main.rs b/plugins/example-plugin/src/main.rs index e5a42b2..4cf6f4a 100644 --- a/plugins/example-plugin/src/main.rs +++ b/plugins/example-plugin/src/main.rs @@ -1,62 +1,52 @@ +use giterated_models::object_backend::ObjectBackend; use giterated_models::{ instance::Instance, - object::{GiteratedObject, ObjectRequest}, - operation::GiteratedOperation, - settings::{GetSetting, Setting}, + object::ObjectRequest, + operation::OperationState, user::{DisplayName, User}, - value::GetValue, }; -use giterated_plugin::{handle::PluginHandle, new_stack::Runtime, GiteratedPluginApi}; +use giterated_plugin::{callback::RuntimeState, handle::PluginHandle, new_stack::Runtime}; use tracing::{info, Level}; -fn main() { +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { tracing_subscriber::fmt() .pretty() .with_thread_names(true) .with_max_level(Level::TRACE) .init(); - let mut handle = PluginHandle::from_dylib("example_plugin_dylib.dll").unwrap(); + let handle = PluginHandle::from_dylib("example_plugin_dylib.dll").unwrap(); let mut runtime = Runtime::new(); runtime.insert_plugin(handle); - let object_request = ObjectRequest(String::from("foobar")); - - match runtime.handle( - Instance::object_name(), - ObjectRequest::operation_name(), - "meow", - &serde_json::to_vec(&object_request).unwrap(), - ) { - Ok(success) => info!("handler call success!"), - Err(_) => info!("handler call error"), - } - - match runtime.handle( - User::object_name(), - >::operation_name(), - "amber:giterated.dev", - &serde_json::to_vec(&GetValue { - value_name: String::from("display_name"), - }) - .unwrap(), - ) { - Ok(success) => info!("get_value handler call success!"), - Err(_) => info!("get_value handler call error"), - } - - match runtime.handle( - User::object_name(), - >::operation_name(), - "amber:giterated.dev", - &serde_json::to_vec(&GetSetting { - setting_name: DisplayName::name().to_string(), - }) - .unwrap(), - ) { - Ok(success) => info!("get_setting handler call success!"), - Err(_) => info!("get_setting handler call error"), - } + runtime.init(); + + let runtime = unsafe { RuntimeState::from_static() }; + + let _object_request = ObjectRequest(String::from("foobar")); + + let _state = OperationState::default(); + + let _instance = runtime + .get_object::("giterated.dev", &OperationState::default()) + .await?; + + let mut user = runtime + .get_object::("ambee:giterated.dev", &OperationState::default()) + .await?; + + let display_name = user.get::(&OperationState::default()).await?; + + info!("Display name for user as a value: {}", display_name); + + let display_name = user + .get_setting::(&OperationState::default()) + .await?; + + info!("Display name for user as a setting: {}", display_name); + + Ok(()) } diff --git a/plugins/giterated-backend/src/handlers.rs b/plugins/giterated-backend/src/handlers.rs index 8447c51..28c49de 100644 --- a/plugins/giterated-backend/src/handlers.rs +++ b/plugins/giterated-backend/src/handlers.rs @@ -1,28 +1,27 @@ -use std::sync::Arc; - use giterated_models::{ error::{OperationError, RepositoryError, UserError}, + operation::OperationState, repository::{Repository, RepositoryInfoRequest, RepositorySummary, RepositoryView}, user::{User, UserRepositoriesRequest}, }; -use giterated_plugin::new_stack::{handle::RuntimeHandle, OperationState, Runtime, State}; +use giterated_plugin::new_stack::{handle::RuntimeHandle, State}; use crate::DatabaseBackend; pub async fn user_get_repositories( - state: DatabaseBackend, - object: User, - request: UserRepositoriesRequest, + _state: DatabaseBackend, + _object: User, + _request: UserRepositoriesRequest, ) -> Result, OperationError> { todo!() } pub async fn repository_info( - state: DatabaseBackend, - object: Repository, - request: RepositoryInfoRequest, - runtime: RuntimeHandle, - State(operation_state): State, + _state: DatabaseBackend, + _object: Repository, + _request: RepositoryInfoRequest, + _runtime: RuntimeHandle, + State(_operation_state): State, ) -> Result> { todo!() } diff --git a/plugins/giterated-backend/src/lib.rs b/plugins/giterated-backend/src/lib.rs index 4f4e49b..a4fd034 100644 --- a/plugins/giterated-backend/src/lib.rs +++ b/plugins/giterated-backend/src/lib.rs @@ -1,11 +1,9 @@ pub mod handlers; pub mod value; -use giterated_models::{instance::Instance, repository::Repository, user::User}; -use giterated_plugin_sys::{PluginStackBuilder, ValueSettingExt}; -use handlers::{repository_info, user_get_repositories}; +use giterated_models::instance::Instance; + use sqlx::PgPool; -use value::{user_get_bio, user_get_display_name, user_set_bio, user_set_display_name}; /// A backend implementation which attempts to resolve data from the instance's database. #[derive(Debug, Clone)] diff --git a/plugins/giterated-backend/src/value.rs b/plugins/giterated-backend/src/value.rs index ea9a291..9500d5a 100644 --- a/plugins/giterated-backend/src/value.rs +++ b/plugins/giterated-backend/src/value.rs @@ -6,31 +6,31 @@ use giterated_models::{ use crate::DatabaseBackend; pub async fn user_get_display_name( - state: DatabaseBackend, - user: User, + _state: DatabaseBackend, + _user: User, ) -> Result> { todo!() } pub async fn user_set_display_name( - state: DatabaseBackend, - user: User, - display_name: DisplayName, + _state: DatabaseBackend, + _user: User, + _display_name: DisplayName, ) -> Result<(), OperationError> { todo!() } pub async fn user_get_bio( - state: DatabaseBackend, - user: User, + _state: DatabaseBackend, + _user: User, ) -> Result> { todo!() } pub async fn user_set_bio( - state: DatabaseBackend, - user: User, - bio: Bio, + _state: DatabaseBackend, + _user: User, + _bio: Bio, ) -> Result<(), OperationError> { todo!() } diff --git a/plugins/giterated-issues/src/lib.rs b/plugins/giterated-issues/src/lib.rs index 8423fc3..b8a1fef 100644 --- a/plugins/giterated-issues/src/lib.rs +++ b/plugins/giterated-issues/src/lib.rs @@ -4,7 +4,7 @@ use anyhow::Error; use giterated_models::{object::GiteratedObject, repository::Repository}; use giterated_plugin::{ handle::PluginInitializationState, - new_stack::{FFIPluginMeta, OperationState, PluginState}, + new_stack::{FFIPluginMeta, PluginState}, vtable::{HostVTable, InitializationVTable}, }; use giterated_plugin_sys::PluginStackBuilder; @@ -62,7 +62,7 @@ impl FromStr for Issue { type Err = IssueParseError; fn from_str(s: &str) -> Result { - let (index, repository) = s.split_once(':').ok_or_else(|| IssueParseError)?; + let (index, repository) = s.split_once(':').ok_or(IssueParseError)?; let id: u32 = index.parse().map_err(|_| IssueParseError)?; let repository = Repository::from_str(repository).map_err(|_| IssueParseError)?; @@ -98,7 +98,7 @@ pub extern "C" fn load_host_vtable(_vtable: &HostVTable) { #[no_mangle] pub extern "C" fn load_initialization_vtable(init_vtable: &InitializationVTable) { - INIT_VTABLE.set(init_vtable.clone()).unwrap(); + INIT_VTABLE.set(*init_vtable).unwrap(); println!("Loaded initialization vtable"); } diff --git a/plugins/giterated-issues/src/main.rs b/plugins/giterated-issues/src/main.rs index 2049821..e6a0b91 100644 --- a/plugins/giterated-issues/src/main.rs +++ b/plugins/giterated-issues/src/main.rs @@ -1,13 +1,7 @@ use std::str::FromStr; use giterated_issues::operations::CreateIssueRequest; -use giterated_models::{ - instance::Instance, - object::{GiteratedObject, ObjectRequest}, - operation::GiteratedOperation, - repository::Repository, - user::User, -}; +use giterated_models::{repository::Repository, user::User}; use giterated_plugin::{handle::PluginHandle, new_stack::Runtime}; use tracing::Level; @@ -19,7 +13,7 @@ pub async fn main() { .with_max_level(Level::TRACE) .init(); - let mut handle = PluginHandle::from_dylib("giterated_issues.dll").unwrap(); + let handle = PluginHandle::from_dylib("giterated_issues.dll").unwrap(); let mut runtime = Runtime::new(); diff --git a/plugins/giterated-protocol/src/handlers.rs b/plugins/giterated-protocol/src/handlers.rs index 24ce9b9..07f02d5 100644 --- a/plugins/giterated-protocol/src/handlers.rs +++ b/plugins/giterated-protocol/src/handlers.rs @@ -9,8 +9,7 @@ use giterated_models::{ operation::GiteratedOperation, }; use giterated_plugin::{ - new_stack::{handle::RuntimeHandle, OperationState}, - AnyFailure, AnyObject, AnyOperation, AnySuccess, + new_stack::handle::RuntimeHandle, AnyFailure, AnyObject, AnyOperation, AnySuccess, }; use serde::{Deserialize, Serialize}; use tokio::net::TcpStream; @@ -103,9 +102,9 @@ pub async fn try_handle_with_remote( // TODO: // Ideally we support pass-through on object types that aren't used locally. // For now, we aren't worrying about that. - let object_meta = object.vtable().clone(); + let object_meta = object.vtable(); - let operation_meta = operation.vtable().clone(); + let operation_meta = operation.vtable(); // trace!( // "Serializing with {}::{}", @@ -132,7 +131,7 @@ pub async fn try_handle_with_remote( // operation.kind().operation_name // ); - let object = NetworkedObject(unsafe { (object_meta.to_str)(object).as_ref().to_string() }); + let object = NetworkedObject(unsafe { (object_meta.to_str)(&object).as_ref().to_string() }); let payload = unsafe { (operation_meta.serialize)(&operation) }.unwrap(); let payload = Vec::from(payload.as_ref()); diff --git a/plugins/giterated-protocol/src/lib.rs b/plugins/giterated-protocol/src/lib.rs index 4eacc08..4dc0412 100644 --- a/plugins/giterated-protocol/src/lib.rs +++ b/plugins/giterated-protocol/src/lib.rs @@ -73,6 +73,12 @@ pub struct NetworkOperationState { authentication: Vec>, } +impl Default for NetworkOperationState { + fn default() -> Self { + Self::new() + } +} + impl NetworkOperationState { pub fn new() -> Self { Self { @@ -286,8 +292,7 @@ impl> Authenticated { source: self .source .drain(..) - .map(|provider| provider.as_ref().authenticate_all(&payload)) - .flatten() + .flat_map(|provider| provider.as_ref().authenticate_all(&payload)) .collect::>(), payload, }