use std::{fmt::Display, str::FromStr}; use anyhow::Error; use giterated_models::{object::GiteratedObject, repository::Repository}; use giterated_plugin::{local::PluginStackBuilder, plugin, StateUUID}; 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::NotificationsOverride; use sqlx::{postgres::PgConnectOptions, PgPool}; use tokio::{fs::File, io::AsyncReadExt, runtime::Runtime}; use toml::Table; use tracing::{debug, info}; pub mod db; pub mod handlers; pub mod operations; pub mod setting; pub mod value; plugin!( name: "plugin name" ); /// 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(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; #[derive(Clone, Debug)] pub struct IssuesPluginState { pub pool: PgPool, } impl StateUUID for IssuesPluginState { fn uuid() -> u128 { todo!() } } #[plugin::init] pub fn init(builder: &mut PluginStackBuilder) -> Result<(), Error> { let runtime = Runtime::new().unwrap(); let db_pool = runtime.block_on(async { let config: Table = { let mut file = File::open("Giterated.toml").await.unwrap(); let mut text = String::new(); file.read_to_string(&mut text).await.unwrap(); text.parse().unwrap() }; let db_conn_options = PgConnectOptions::new() .host(config["postgres"]["host"].as_str().unwrap()) .port(config["postgres"]["port"].as_integer().unwrap() as u16) .database(config["postgres"]["database"].as_str().unwrap()) .username(config["postgres"]["user"].as_str().unwrap()) .password(config["postgres"]["password"].as_str().unwrap()); let db_pool = PgPool::connect_with(db_conn_options).await.unwrap(); debug!("Running database migrations..."); // sqlx::migrate!().run(&db_pool).await.unwrap(); info!("Connected"); db_pool }); // ASYNC_RUNTIME.set(runtime).unwrap(); let plugin_state = IssuesPluginState { pool: db_pool }; // let mut builder: PluginStackBuilder<'_, IssuesPluginState> = // 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(create_issue_request) .operation(query_issues_request) .operation(edit_issue_request) .operation(issue_post_comment_request); Ok(()) }