From 6e233a9dae634a4c5e673e500255f050cdc69cde Mon Sep 17 00:00:00 2001 From: jaredoconnell Date: Sat, 26 Feb 2022 17:39:18 -0500 Subject: [PATCH 1/8] Progress towards minimum viable api Not in working state --- Cargo.toml | 1 + src/plugin/auth_method.rs | 9 ++++++ src/plugin/auth_result.rs | 7 +++++ src/plugin/conversation.rs | 10 +++++++ src/plugin/conversation_type.rs | 7 +++++ src/plugin/core_interface.rs | 14 +++++++++ src/plugin/field.rs | 11 +++++++ src/plugin/field_type.rs | 6 ++++ src/plugin/init_plugin.rs | 24 +++++++++++++-- src/plugin/message.rs | 8 ++++- src/plugin/mod.rs | 21 ++++++++++++- src/plugin/plugin_info.rs | 30 ++++++++++++++++++- src/plugin/polychat_api.rs | 53 +++++++++++++++++++++++++++++++++ src/plugin/team.rs | 7 +++++ 14 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 src/plugin/auth_method.rs create mode 100644 src/plugin/auth_result.rs create mode 100644 src/plugin/conversation.rs create mode 100644 src/plugin/conversation_type.rs create mode 100644 src/plugin/core_interface.rs create mode 100644 src/plugin/field.rs create mode 100644 src/plugin/field_type.rs create mode 100644 src/plugin/polychat_api.rs create mode 100644 src/plugin/team.rs diff --git a/Cargo.toml b/Cargo.toml index a63c89a..5098be9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ crate_type = ["dylib", "rlib"] [dependencies] libc = "0.2.113" +log = "0.4.14" [build-dependencies] cbindgen = "0.20.0" \ No newline at end of file diff --git a/src/plugin/auth_method.rs b/src/plugin/auth_method.rs new file mode 100644 index 0000000..32730c2 --- /dev/null +++ b/src/plugin/auth_method.rs @@ -0,0 +1,9 @@ +use libc::c_char; +use super::Field; + +#[repr(C)] +pub struct AuthMethod { + pub name: *const c_char, + pub num_fields: u32, + pub fields: *const Field +} \ No newline at end of file diff --git a/src/plugin/auth_result.rs b/src/plugin/auth_result.rs new file mode 100644 index 0000000..8fc8797 --- /dev/null +++ b/src/plugin/auth_result.rs @@ -0,0 +1,7 @@ +#[repr(C)] +pub enum AuthResult { + Success, + FailRejected, + FailConnectionError, + Connecting +} diff --git a/src/plugin/conversation.rs b/src/plugin/conversation.rs new file mode 100644 index 0000000..b88ffa8 --- /dev/null +++ b/src/plugin/conversation.rs @@ -0,0 +1,10 @@ +use libc::c_char; +use super::ConversationType; + +#[repr(C)] +pub struct Conversation { + pub id: *const c_char, + pub name: *const c_char, + pub team_id: *const c_char, + pub conversation_type: ConversationType +} \ No newline at end of file diff --git a/src/plugin/conversation_type.rs b/src/plugin/conversation_type.rs new file mode 100644 index 0000000..3d09579 --- /dev/null +++ b/src/plugin/conversation_type.rs @@ -0,0 +1,7 @@ +#[repr(C)] +pub enum ConversationType { + DirectMessage, + GroupDirectMessage, + PublicChannel, + PrivateChannel +} diff --git a/src/plugin/core_interface.rs b/src/plugin/core_interface.rs new file mode 100644 index 0000000..030f209 --- /dev/null +++ b/src/plugin/core_interface.rs @@ -0,0 +1,14 @@ +use super::{Team}; +use crate::types::Account; + +use std::ptr; + +pub trait CoreInterface { + // Note: All functions must have self reference to allow + // this trait to be made into an object. + /*fn get_teams(&self, _acc: Account) -> *mut Team { + return ptr::null_mut(); + }*/ + + fn test(&self, testMsg: String) {} +} \ No newline at end of file diff --git a/src/plugin/field.rs b/src/plugin/field.rs new file mode 100644 index 0000000..84f166f --- /dev/null +++ b/src/plugin/field.rs @@ -0,0 +1,11 @@ +use libc::c_char; +use super::FieldType; + +#[repr(C)] +pub struct Field { + pub name: *const c_char, + pub field_type: FieldType, + pub value: *const c_char, + pub required: bool, + pub sensitive: bool +} \ No newline at end of file diff --git a/src/plugin/field_type.rs b/src/plugin/field_type.rs new file mode 100644 index 0000000..4615c8e --- /dev/null +++ b/src/plugin/field_type.rs @@ -0,0 +1,6 @@ +#[repr(C)] +pub enum FieldType { + Integer, + String, + Url +} diff --git a/src/plugin/init_plugin.rs b/src/plugin/init_plugin.rs index a73b99b..995b7af 100644 --- a/src/plugin/init_plugin.rs +++ b/src/plugin/init_plugin.rs @@ -1,4 +1,5 @@ -use super::{PluginInfo, APIVersion, Message, SendStatus}; +use super::{PluginInfo, APIVersion, Message, SendStatus, AuthMethod, + AuthResult, Conversation}; use crate::types::Account; use libc::c_char; @@ -8,10 +9,15 @@ use std::ffi::CString; pub struct InitializedPlugin { pub supported_api: APIVersion, pub name: String, + pub protocol_name: String, + pub auth_methods: *const AuthMethod, pub create_account: extern fn() -> Account, pub destroy_account: extern fn(acc: Account), - pub post_message: extern fn(msg: * const Message) -> SendStatus, + pub post_message: extern fn(acc: Account, msg: * const Message) -> SendStatus, + pub login: extern fn(acc: Account, * const AuthMethod, * const c_char) -> AuthResult, + pub request_messages: extern fn(acc: Account, conv: Conversation, + timestamp: u64, limit: u32), pub print: extern fn(acc: Account), } @@ -30,6 +36,7 @@ impl InitializedPlugin { } let name: String; + let protocol_name: String; unsafe { let name_res = CString::from_raw(plugin.name as *mut c_char).into_string(); if name_res.is_err() { @@ -37,15 +44,26 @@ impl InitializedPlugin { } name = name_res.unwrap(); + + let protocol_name_res = CString::from_raw(plugin.protocol_name as *mut c_char).into_string(); + if protocol_name_res.is_err() { + return Err("Could not decode plugin protocol name".to_string()); + } + + protocol_name = protocol_name_res.unwrap(); } Ok(InitializedPlugin { supported_api: plugin.supported_api, create_account: plugin.create_account.unwrap(), destroy_account: plugin.destroy_account.unwrap(), + login: plugin.login.unwrap(), + request_messages: plugin.request_messages.unwrap(), post_message: plugin.post_message.unwrap(), print: plugin.print.unwrap(), - name, + name: name, + protocol_name: protocol_name, + auth_methods: plugin.auth_methods }) } } diff --git a/src/plugin/message.rs b/src/plugin/message.rs index 8b812f1..872aacc 100644 --- a/src/plugin/message.rs +++ b/src/plugin/message.rs @@ -3,4 +3,10 @@ use libc::c_char; #[repr(C)] pub struct Message { pub body: *const c_char -} \ No newline at end of file +} +/* +impl InitializedPlugin { + pub fn set_body(body: String) { + + } +}*/ \ No newline at end of file diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index 8a7bec7..75de603 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -2,16 +2,35 @@ mod api_version; mod init_plugin; mod plugin_info; mod send_status; +mod field_type; +mod conversation_type; +mod auth_result; +mod auth_method; mod message; +mod team; +mod conversation; +mod field; +mod polychat_api; +mod core_interface; pub use plugin_info::PluginInfo; pub use init_plugin::InitializedPlugin; pub use api_version::APIVersion; pub use send_status::SendStatus; +pub use field_type::FieldType; +pub use conversation_type::ConversationType; +pub use auth_result::AuthResult; +pub use team::Team; +pub use conversation::Conversation; +pub use field::Field; +pub use auth_method::AuthMethod; +pub use polychat_api::PolyChatApiV1; +pub use core_interface::CoreInterface; + pub use message::Message; pub const INITIALIZE_FN_NAME: &str = "initialize"; extern "C" { - pub fn initialize(thing: *mut PluginInfo); + pub fn initialize(plugin_info: *mut PluginInfo, core_api: *const PolyChatApiV1); } diff --git a/src/plugin/plugin_info.rs b/src/plugin/plugin_info.rs index cae1d31..e7a5b7b 100644 --- a/src/plugin/plugin_info.rs +++ b/src/plugin/plugin_info.rs @@ -2,6 +2,9 @@ use crate::types::*; use super::api_version::APIVersion; use super::send_status::SendStatus; use super::message::Message; +use super::auth_method::AuthMethod; +use super::auth_result::AuthResult; +use super::conversation::Conversation; use std::option::Option; use std::ptr; @@ -12,14 +15,35 @@ use libc::c_char; pub struct PluginInfo { pub supported_api: APIVersion, pub name: *const c_char, + pub protocol_name: *const c_char, + pub auth_methods: *const AuthMethod, + pub create_account: Option Account>, + //pub init_account: Option, pub destroy_account: Option, + /** + * Tries to login with the given authmethod, with the given array of strings. + * + * Async, so the final auth result may not be immediately available. + * TODO: The way to update auth status. + */ + pub login: Option AuthResult>, + /** + * Sends a request to retrieve messages for the conversation that the account + * has access to. + * The third parameter is the timestamp for which all messages should be older than + * The fourth parameter is the maximum quantity of messages to retrieve. + * + * Messages should be added using the function TODO. + */ + pub request_messages: Option, /// Instructs the plugin to post a message in the associated channel. /// The lifetime of msg is only guaranteed during the function call. /// To keep the message for longer (likely required), make a copy. /// TODO: Add way to update future message status as it is done async. - pub post_message: Option SendStatus>, + pub post_message: Option SendStatus>, pub print: Option, } @@ -33,9 +57,13 @@ impl PluginInfo { }, create_account: None, destroy_account: None, + login: None, + request_messages: None, post_message: None, print: None, name: ptr::null(), + protocol_name: ptr::null(), + auth_methods: ptr::null(), } } } diff --git a/src/plugin/polychat_api.rs b/src/plugin/polychat_api.rs new file mode 100644 index 0000000..a06453a --- /dev/null +++ b/src/plugin/polychat_api.rs @@ -0,0 +1,53 @@ + +use super::{Team, CoreInterface}; +use crate::types::Account; + +use libc::c_void; +use libc::c_char; +use std::ffi:CString; + +use log::{error}; + + +/** + * This is the interface that is passed into C that allows the core's functions to be called. + * It takes in a boxed CoreInterface, allowing the plugin to call items from the trait. + */ +#[repr(C)] +pub struct PolyChatApiV1 { + core: *mut c_void, // Hidden *mut Box, + // TODO: Eventually add fields identifying info about core + //get_teams: Option *mut Team>, + test: Option, +} + +impl PolyChatApiV1 { + pub fn new(core: Box>) -> PolyChatApiV1 { + PolyChatApiV1 { + core: Box::into_raw(core) as *mut c_void, + //get_teams: Some(PolyChatApiV1::get_teams_impl) + test: Some(PolyChatApiV1::test_impl) + } + } + + /*extern fn get_teams_impl(&self, acc: Account) -> *mut Team { + let interface: Box> = unsafe { Box::from_raw(self.core as *mut _) }; + return interface.get_teams(acc); + }*/ + extern fn test_impl(&self, test_msg: *const c_char) { + let interface: Box> = unsafe { Box::from_raw(self.core as *mut _) }; + // Convert to rust string + unsafe { + let rust_c_str = CString::from_raw(test_msg).into_string(); + match (rust_c_str) { + Ok(string) => { + interface.test(string); + }, + Err(error) => { + // Complain to logs. This should never happen. Incompatible ABI? + error!("Error converting from c string to rust string in test_impl {}", error.to_string()); + } + }; + } + } +} \ No newline at end of file diff --git a/src/plugin/team.rs b/src/plugin/team.rs new file mode 100644 index 0000000..0a2c8b9 --- /dev/null +++ b/src/plugin/team.rs @@ -0,0 +1,7 @@ +use libc::c_char; + +#[repr(C)] +pub struct Team { + pub id: *const c_char, + pub name: *const c_char, +} \ No newline at end of file From 63463db7fbdf11edea180582dde3e4c1cc7ee568 Mon Sep 17 00:00:00 2001 From: Keith Valin Date: Sat, 26 Feb 2022 17:43:44 -0500 Subject: [PATCH 2/8] Fixed compile issues --- src/plugin/polychat_api.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plugin/polychat_api.rs b/src/plugin/polychat_api.rs index a06453a..4fb873d 100644 --- a/src/plugin/polychat_api.rs +++ b/src/plugin/polychat_api.rs @@ -2,11 +2,10 @@ use super::{Team, CoreInterface}; use crate::types::Account; -use libc::c_void; -use libc::c_char; -use std::ffi:CString; +use libc::{c_void, c_char}; +use std::ffi::CString; -use log::{error}; +use log::error; /** @@ -38,8 +37,8 @@ impl PolyChatApiV1 { let interface: Box> = unsafe { Box::from_raw(self.core as *mut _) }; // Convert to rust string unsafe { - let rust_c_str = CString::from_raw(test_msg).into_string(); - match (rust_c_str) { + let rust_c_str = CString::from_raw(test_msg as *mut c_char).into_string(); + match rust_c_str { Ok(string) => { interface.test(string); }, From 25a2d09e36c893454f8dd4f27bd4c38981611c5f Mon Sep 17 00:00:00 2001 From: Keith Valin Date: Sat, 26 Feb 2022 19:20:56 -0500 Subject: [PATCH 3/8] Fixed weird debug derive issue --- src/plugin/polychat_api.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/plugin/polychat_api.rs b/src/plugin/polychat_api.rs index 4fb873d..63e469b 100644 --- a/src/plugin/polychat_api.rs +++ b/src/plugin/polychat_api.rs @@ -3,7 +3,12 @@ use super::{Team, CoreInterface}; use crate::types::Account; use libc::{c_void, c_char}; -use std::ffi::CString; +use std::{ + ffi::CString, + fmt::Debug, + fmt::Result, + fmt::Formatter +}; use log::error; @@ -21,9 +26,9 @@ pub struct PolyChatApiV1 { } impl PolyChatApiV1 { - pub fn new(core: Box>) -> PolyChatApiV1 { + pub fn new(core: *mut &Box) -> PolyChatApiV1 { PolyChatApiV1 { - core: Box::into_raw(core) as *mut c_void, + core: core as *mut c_void, //get_teams: Some(PolyChatApiV1::get_teams_impl) test: Some(PolyChatApiV1::test_impl) } @@ -49,4 +54,11 @@ impl PolyChatApiV1 { }; } } +} + +impl Debug for PolyChatApiV1 { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + f.debug_tuple("") + .finish() + } } \ No newline at end of file From 23ed167be0fd192ca291d49b54dd3213f11e1420 Mon Sep 17 00:00:00 2001 From: Keith Valin Date: Sat, 26 Feb 2022 19:44:43 -0500 Subject: [PATCH 4/8] Made test function public --- src/plugin/polychat_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugin/polychat_api.rs b/src/plugin/polychat_api.rs index 63e469b..4e92f32 100644 --- a/src/plugin/polychat_api.rs +++ b/src/plugin/polychat_api.rs @@ -22,7 +22,7 @@ pub struct PolyChatApiV1 { core: *mut c_void, // Hidden *mut Box, // TODO: Eventually add fields identifying info about core //get_teams: Option *mut Team>, - test: Option, + pub test: Option, } impl PolyChatApiV1 { From 806a9e3be04946e97216d66c5fdc58e2455ac3e7 Mon Sep 17 00:00:00 2001 From: Keith Valin Date: Tue, 20 Dec 2022 00:17:24 -0500 Subject: [PATCH 5/8] Updated CoreInterface to be public --- src/plugin/core_interface.rs | 2 +- src/plugin/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugin/core_interface.rs b/src/plugin/core_interface.rs index 030f209..8fa7192 100644 --- a/src/plugin/core_interface.rs +++ b/src/plugin/core_interface.rs @@ -10,5 +10,5 @@ pub trait CoreInterface { return ptr::null_mut(); }*/ - fn test(&self, testMsg: String) {} + fn test(&self, test_msg: String) {} } \ No newline at end of file diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index 75de603..d4f3bbb 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -11,7 +11,7 @@ mod team; mod conversation; mod field; mod polychat_api; -mod core_interface; +pub mod core_interface; pub use plugin_info::PluginInfo; pub use init_plugin::InitializedPlugin; From 0c447af4d06cccfa22d2a0554796118d2e74591d Mon Sep 17 00:00:00 2001 From: Keith Valin Date: Tue, 20 Dec 2022 13:00:50 -0500 Subject: [PATCH 6/8] Added some debug statements, added additonal checks to make sure plugin is well-formed --- Cargo.toml | 2 +- src/plugin/init_plugin.rs | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5098be9..3dfa47b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,4 +17,4 @@ libc = "0.2.113" log = "0.4.14" [build-dependencies] -cbindgen = "0.20.0" \ No newline at end of file +cbindgen = "0.20.0" diff --git a/src/plugin/init_plugin.rs b/src/plugin/init_plugin.rs index 995b7af..aa4cb72 100644 --- a/src/plugin/init_plugin.rs +++ b/src/plugin/init_plugin.rs @@ -4,13 +4,14 @@ use crate::types::Account; use libc::c_char; use std::ffi::CString; +use log::debug; #[derive(Debug)] pub struct InitializedPlugin { pub supported_api: APIVersion, pub name: String, pub protocol_name: String, - pub auth_methods: *const AuthMethod, +// pub auth_methods: *const AuthMethod, pub create_account: extern fn() -> Account, pub destroy_account: extern fn(acc: Account), @@ -23,6 +24,8 @@ pub struct InitializedPlugin { impl InitializedPlugin { pub fn new(plugin: &PluginInfo) -> Result { + debug!("Verifying functions exists"); + //TODO programatically check is_none/null for the fields if plugin.create_account.is_none() { return Err("create_account is not defined".to_string()); } else if plugin.destroy_account.is_none() { @@ -33,24 +36,36 @@ impl InitializedPlugin { return Err("print is not defined".to_string()); } else if plugin.name.is_null() { return Err("name is not defined".to_string()); + } else if plugin.protocol_name.is_null() { + return Err("protocol_name is not defined".to_string()); + } else if plugin.request_messages.is_none() { + return Err("request_messages is undefined".to_string()); + } else if plugin.login.is_none() { + return Err("login is undefined".to_string()); } + debug!("Functions do exists"); + let name: String; let protocol_name: String; unsafe { + debug!("Reading plugin name"); let name_res = CString::from_raw(plugin.name as *mut c_char).into_string(); if name_res.is_err() { return Err("Could not decode plugin name".to_string()); } name = name_res.unwrap(); - + debug!("Got plugin name as {}", name); + + debug!("Trying to read protocol name"); let protocol_name_res = CString::from_raw(plugin.protocol_name as *mut c_char).into_string(); if protocol_name_res.is_err() { return Err("Could not decode plugin protocol name".to_string()); } protocol_name = protocol_name_res.unwrap(); + debug!("Got protocol name as {}", protocol_name); } Ok(InitializedPlugin { @@ -63,7 +78,7 @@ impl InitializedPlugin { print: plugin.print.unwrap(), name: name, protocol_name: protocol_name, - auth_methods: plugin.auth_methods +// auth_methods: plugin.auth_methods }) } } From be72e1d838906350e1e4ca5e595620ca21464665 Mon Sep 17 00:00:00 2001 From: Keith Valin Date: Fri, 23 Dec 2022 19:13:16 -0500 Subject: [PATCH 7/8] Remove compiler errors --- src/plugin/core_interface.rs | 7 +------ src/plugin/polychat_api.rs | 3 +-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/plugin/core_interface.rs b/src/plugin/core_interface.rs index 8fa7192..8aa97f5 100644 --- a/src/plugin/core_interface.rs +++ b/src/plugin/core_interface.rs @@ -1,8 +1,3 @@ -use super::{Team}; -use crate::types::Account; - -use std::ptr; - pub trait CoreInterface { // Note: All functions must have self reference to allow // this trait to be made into an object. @@ -10,5 +5,5 @@ pub trait CoreInterface { return ptr::null_mut(); }*/ - fn test(&self, test_msg: String) {} + fn test(&self, _test_msg: String) {} } \ No newline at end of file diff --git a/src/plugin/polychat_api.rs b/src/plugin/polychat_api.rs index 4e92f32..01d2ef5 100644 --- a/src/plugin/polychat_api.rs +++ b/src/plugin/polychat_api.rs @@ -1,6 +1,5 @@ -use super::{Team, CoreInterface}; -use crate::types::Account; +use super::CoreInterface; use libc::{c_void, c_char}; use std::{ From 0e07c1fde94c65c53e8e6b84fa92347ae0d11448 Mon Sep 17 00:00:00 2001 From: jaredoconnell Date: Sat, 11 Feb 2023 21:50:20 -0500 Subject: [PATCH 8/8] Bump version to 0.4.0 There are a lot of changes, deserving a minor instead of patch change --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3dfa47b..d973934 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polychat-plugin" -version = "0.3.1" +version = "0.4.0" edition = "2018" description = "A library containing types required to make a polychat plugin"