Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -14,6 +14,7 @@ crate_type = ["dylib", "rlib"]

[dependencies]
libc = "0.2.113"
log = "0.4.14"

[build-dependencies]
cbindgen = "0.20.0"
cbindgen = "0.20.0"
9 changes: 9 additions & 0 deletions src/plugin/auth_method.rs
Original file line number Diff line number Diff line change
@@ -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
}
7 changes: 7 additions & 0 deletions src/plugin/auth_result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[repr(C)]
pub enum AuthResult {
Success,
FailRejected,
FailConnectionError,
Connecting
}
10 changes: 10 additions & 0 deletions src/plugin/conversation.rs
Original file line number Diff line number Diff line change
@@ -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
}
7 changes: 7 additions & 0 deletions src/plugin/conversation_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[repr(C)]
pub enum ConversationType {
DirectMessage,
GroupDirectMessage,
PublicChannel,
PrivateChannel
}
9 changes: 9 additions & 0 deletions src/plugin/core_interface.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
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, _test_msg: String) {}
}
11 changes: 11 additions & 0 deletions src/plugin/field.rs
Original file line number Diff line number Diff line change
@@ -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
}
6 changes: 6 additions & 0 deletions src/plugin/field_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[repr(C)]
pub enum FieldType {
Integer,
String,
Url
}
39 changes: 36 additions & 3 deletions src/plugin/init_plugin.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
use super::{PluginInfo, APIVersion, Message, SendStatus};
use super::{PluginInfo, APIVersion, Message, SendStatus, AuthMethod,
AuthResult, Conversation};
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 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),
}

impl InitializedPlugin {
pub fn new(plugin: &PluginInfo) -> Result<InitializedPlugin, String> {
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() {
Expand All @@ -27,25 +36,49 @@ 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 {
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
})
}
}
8 changes: 7 additions & 1 deletion src/plugin/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,10 @@ use libc::c_char;
#[repr(C)]
pub struct Message {
pub body: *const c_char
}
}
/*
impl InitializedPlugin {
pub fn set_body(body: String) {

}
}*/
21 changes: 20 additions & 1 deletion src/plugin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
pub 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);
}
30 changes: 29 additions & 1 deletion src/plugin/plugin_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<extern fn() -> Account>,
//pub init_account: Option<extern fn()>,
pub destroy_account: Option<extern fn(acc: Account)>,
/**
* 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<extern fn(acc: Account, * const AuthMethod, * const c_char) -> 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<extern fn(acc: Account, conv: Conversation,
timestamp: u64, limit: u32)>,
/// 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<extern fn(msg: * const Message) -> SendStatus>,
pub post_message: Option<extern fn(acc: Account, msg: * const Message) -> SendStatus>,
pub print: Option<extern fn(acc: Account)>,
}

Expand All @@ -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(),
}
}
}
63 changes: 63 additions & 0 deletions src/plugin/polychat_api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

use super::CoreInterface;

use libc::{c_void, c_char};
use std::{
ffi::CString,
fmt::Debug,
fmt::Result,
fmt::Formatter
};

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<dyn CoreInterface>,
// TODO: Eventually add fields identifying info about core
//get_teams: Option<extern fn(&PolyChatApiV1, acc: Account) -> *mut Team>,
pub test: Option<extern fn(&PolyChatApiV1, test_msg: *const c_char)>,
}

impl PolyChatApiV1 {
pub fn new(core: *mut &Box<dyn CoreInterface>) -> PolyChatApiV1 {
PolyChatApiV1 {
core: 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<Box<dyn CoreInterface>> = 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<Box<dyn CoreInterface>> = unsafe { Box::from_raw(self.core as *mut _) };
// Convert to rust string
unsafe {
let rust_c_str = CString::from_raw(test_msg as *mut c_char).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());
}
};
}
}
}

impl Debug for PolyChatApiV1 {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_tuple("")
.finish()
}
}
7 changes: 7 additions & 0 deletions src/plugin/team.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use libc::c_char;

#[repr(C)]
pub struct Team {
pub id: *const c_char,
pub name: *const c_char,
}