use std::{fmt::Display, str::FromStr, sync::OnceLock}; use anyhow::Error; use giterated_models::{object::GiteratedObject, repository::Repository}; use giterated_plugin::{ handle::PluginInitializationState, new_stack::{FFIPluginMeta, PluginState}, HostVTable, InitializationVTable, }; use giterated_plugin_sys::PluginStackBuilder; use handlers::{ create_issue_request, edit_issue_request, issue_get_setting_contents, issue_get_setting_name, issue_post_comment_request, issue_set_setting_contents, issue_set_setting_name, issue_value_author, issue_value_comment_count, issue_value_creation_date, query_issues_request, }; use serde::{Deserialize, Serialize}; use setting::{Contents, NotificationsOverride}; use sqlx::PgPool; use value::{Author, CommentCount, CreationDate, Name}; pub mod db; pub mod handlers; pub mod operations; pub mod setting; pub mod value; /// An issue, defined by the repository which owns it and its index. /// /// # Textual Format /// An issue's textual format is defined as: /// /// `@{index: u32}:{repository: Repository}` #[derive(Hash, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct Issue { pub repository: Repository, pub id: u32, } impl Display for Issue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(&format!("{}:{}", self.id, self.repository)) } } impl GiteratedObject for Issue { fn object_name() -> &'static str { "issue" } fn home_uri(&self) -> String { self.repository.home_uri() } fn from_object_str(object_str: &str) -> Result { Ok(Issue::from_str(object_str)?) } } impl FromStr for Issue { type Err = IssueParseError; fn from_str(s: &str) -> Result { let (index, repository) = s.split_once(':').ok_or_else(|| IssueParseError)?; let id: u32 = index.parse().map_err(|_| IssueParseError)?; let repository = Repository::from_str(repository).map_err(|_| IssueParseError)?; Ok(Self { repository, id }) } } #[derive(Debug, thiserror::Error)] #[error("error parsing issue")] pub struct IssueParseError; static INIT_VTABLE: OnceLock = OnceLock::new(); #[no_mangle] pub extern "C" fn plugin_meta() -> FFIPluginMeta { const PLUGIN_NAME: &str = "Giterated [Issues]"; const PLUGIN_VERSION: &str = "0.1.0"; FFIPluginMeta { name: PLUGIN_NAME.as_ptr(), name_len: PLUGIN_NAME.len(), version: PLUGIN_VERSION.as_ptr(), version_len: PLUGIN_VERSION.len(), } } #[no_mangle] pub extern "C" fn load_host_vtable(_vtable: &HostVTable) { println!("Loading vtable"); } #[no_mangle] pub extern "C" fn load_initialization_vtable(init_vtable: &InitializationVTable) { INIT_VTABLE.set(init_vtable.clone()).unwrap(); println!("Loaded initialization vtable"); } #[no_mangle] pub extern "C" fn initialize() -> PluginState { // tracing_subscriber::fmt() // .pretty() // .with_thread_names(true) // .with_max_level(Level::TRACE) // .init(); PluginState { inner: Box::into_raw(Box::new(())), } } #[no_mangle] pub extern "C" fn initialize_registration( state: *mut PluginInitializationState, ) -> *mut PluginInitializationState { // let _guard: tracing::span::EnteredSpan = trace_span!("initialize_registration").entered(); let init_vtable = INIT_VTABLE.get().unwrap(); let plugin_state = { todo!() }; let mut builder = PluginStackBuilder::new(plugin_state, state, init_vtable); builder.object::(); builder .object_setting(issue_get_setting_name, issue_set_setting_name) .object_setting(issue_get_setting_contents, issue_set_setting_contents); builder.object_user_setting::(); builder .value(issue_value_creation_date) .value(issue_value_comment_count) .value(issue_get_setting_name) .value(issue_value_author); builder .operation_handler(create_issue_request) .operation_handler(query_issues_request) .operation_handler(edit_issue_request) .operation_handler(issue_post_comment_request); state } #[derive(Clone, Debug)] pub struct IssuesPluginState { pub pool: PgPool, }