Skip to content

Commit

Permalink
feat: chatffi simpler callbacks and managed identity and db (#5681)
Browse files Browse the repository at this point in the history
Description
---
Offer a managed identity file, and db creation. 
Simplify callback return values to c-readable structs.

Motivation and Context
---
- Wallet can't provide it's identity file, and we probably shouldn't
share it anyway. So lets write and use our own in the chatffi.
- Callbacks couldn't be read as rust structs
- db init can be managed on our end

How Has This Been Tested?
---
CI

Breaking Changes
---

- [x] None
- [ ] Requires data directory on base node to be deleted
- [ ] Requires hard fork
- [ ] Other - Please specify
  • Loading branch information
brianp committed Sep 7, 2023
1 parent 4b83267 commit 79ab584
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 48 deletions.
49 changes: 43 additions & 6 deletions base_layer/chat_ffi/chat.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,24 @@ struct ChatMessages;

struct ClientFFI;

struct ContactsLivenessData;
struct TariAddress;

struct Message;
struct ChatFFIContactsLivenessData {
const char *address;
uint64_t last_seen;
uint8_t online_status;
};

struct TariAddress;
typedef void (*CallbackContactStatusChange)(struct ChatFFIContactsLivenessData*);

typedef void (*CallbackContactStatusChange)(struct ContactsLivenessData*);
struct ChatFFIMessage {
const char *body;
const char *from_address;
uint64_t stored_at;
const char *message_id;
};

typedef void (*CallbackMessageReceived)(struct Message*);
typedef void (*CallbackMessageReceived)(struct ChatFFIMessage*);

#ifdef __cplusplus
extern "C" {
Expand All @@ -44,7 +53,6 @@ extern "C" {
* The ```destroy_client``` method must be called when finished with a ClientFFI to prevent a memory leak
*/
struct ClientFFI *create_chat_client(struct ApplicationConfig *config,
const char *identity_file_path,
int *error_out,
CallbackContactStatusChange callback_contact_status_change,
CallbackMessageReceived callback_message_received);
Expand Down Expand Up @@ -80,6 +88,7 @@ void destroy_client_ffi(struct ClientFFI *client);
struct ApplicationConfig *create_chat_config(const char *network_str,
const char *public_address,
const char *datastore_path,
const char *identity_file_path,
const char *log_path,
int *error_out);

Expand Down Expand Up @@ -215,6 +224,34 @@ struct TariAddress *create_tari_address(const char *receiver_c_char, int *error_
*/
void destroy_tari_address(struct TariAddress *address);

/**
* Frees memory for a ChatFFIMessage
*
* ## Arguments
* `address` - The pointer of a ChatFFIMessage
*
* ## Returns
* `()` - Does not return a value, equivalent to void in C
*
* # Safety
* None
*/
void destroy_chat_ffi_message(struct ChatFFIMessage *address);

/**
* Frees memory for a ChatFFIContactsLivenessData
*
* ## Arguments
* `address` - The pointer of a ChatFFIContactsLivenessData
*
* ## Returns
* `()` - Does not return a value, equivalent to void in C
*
* # Safety
* None
*/
void destroy_chat_ffi_liveness_data(struct ChatFFIContactsLivenessData *address);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
95 changes: 87 additions & 8 deletions base_layer/chat_ffi/src/callback_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::ops::Deref;
use std::{convert::TryFrom, ffi::CString, ops::Deref};

use log::{debug, info, trace};
use libc::c_char;
use log::{debug, error, info, trace};
use tari_contacts::contacts_service::{
handle::{ContactsLivenessData, ContactsLivenessEvent, ContactsServiceHandle},
types::Message,
Expand All @@ -31,8 +32,76 @@ use tari_shutdown::ShutdownSignal;

const LOG_TARGET: &str = "chat_ffi::callback_handler";

pub(crate) type CallbackContactStatusChange = unsafe extern "C" fn(*mut ContactsLivenessData);
pub(crate) type CallbackMessageReceived = unsafe extern "C" fn(*mut Message);
pub(crate) type CallbackContactStatusChange = unsafe extern "C" fn(*mut ChatFFIContactsLivenessData);
pub(crate) type CallbackMessageReceived = unsafe extern "C" fn(*mut ChatFFIMessage);

#[repr(C)]
pub struct ChatFFIContactsLivenessData {
pub address: *const c_char,
pub last_seen: u64,
pub online_status: u8,
}

impl TryFrom<ContactsLivenessData> for ChatFFIContactsLivenessData {
type Error = String;

fn try_from(v: ContactsLivenessData) -> Result<Self, Self::Error> {
let address = match CString::new(v.address().to_bytes()) {
Ok(s) => s,
Err(e) => return Err(e.to_string()),
};

let last_seen = match v.last_ping_pong_received() {
Some(ts) => match u64::try_from(ts.timestamp_micros()) {
Ok(num) => num,
Err(e) => return Err(e.to_string()),
},
None => 0,
};

Ok(Self {
address: address.as_ptr(),
last_seen,
online_status: v.online_status().as_u8(),
})
}
}

#[repr(C)]
pub struct ChatFFIMessage {
pub body: *const c_char,
pub from_address: *const c_char,
pub stored_at: u64,
pub message_id: *const c_char,
}

impl TryFrom<Message> for ChatFFIMessage {
type Error = String;

fn try_from(v: Message) -> Result<Self, Self::Error> {
let body = match CString::new(v.body) {
Ok(s) => s,
Err(e) => return Err(e.to_string()),
};

let address = match CString::new(v.address.to_bytes()) {
Ok(s) => s,
Err(e) => return Err(e.to_string()),
};

let id = match CString::new(v.message_id) {
Ok(s) => s,
Err(e) => return Err(e.to_string()),
};

Ok(Self {
body: body.as_ptr(),
from_address: address.as_ptr(),
stored_at: v.stored_at,
message_id: id.as_ptr(),
})
}
}

#[derive(Clone)]
pub struct CallbackHandler {
Expand Down Expand Up @@ -103,8 +172,14 @@ impl CallbackHandler {
"Calling ContactStatusChanged callback function for contact {}",
data.address(),
);
unsafe {
(self.callback_contact_status_change)(Box::into_raw(Box::new(data)));

match ChatFFIContactsLivenessData::try_from(data) {
Ok(data) => unsafe {
(self.callback_contact_status_change)(Box::into_raw(Box::new(data)));
},
Err(e) => {
error!(target: LOG_TARGET, "Error processing contacts liveness data received callback: {}", e)
},
}
}

Expand All @@ -114,8 +189,12 @@ impl CallbackHandler {
"Calling MessageReceived callback function for sender {}",
message.address,
);
unsafe {
(self.callback_message_received)(Box::into_raw(Box::new(message)));

match ChatFFIMessage::try_from(message) {
Ok(message) => unsafe {
(self.callback_message_received)(Box::into_raw(Box::new(message)));
},
Err(e) => error!(target: LOG_TARGET, "Error processing message received callback: {}", e),
}
}
}
83 changes: 64 additions & 19 deletions base_layer/chat_ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

#![recursion_limit = "1024"]

use std::{convert::TryFrom, ffi::CStr, path::PathBuf, ptr, str::FromStr, sync::Arc};
use std::{convert::TryFrom, ffi::CStr, path::PathBuf, ptr, str::FromStr};

use callback_handler::CallbackContactStatusChange;
use libc::{c_char, c_int};
Expand All @@ -38,23 +38,24 @@ use log4rs::{
config::{Appender, Config, Logger, Root},
encode::pattern::PatternEncoder,
};
use minotari_app_utilities::identity_management::load_from_json;
use minotari_app_utilities::identity_management::setup_node_identity;
use tari_chat_client::{
config::{ApplicationConfig, ChatClientConfig},
networking::PeerFeatures,
ChatClient,
Client,
};
use tari_common::configuration::{MultiaddrList, Network};
use tari_common_types::tari_address::TariAddress;
use tari_comms::{multiaddr::Multiaddr, NodeIdentity};
use tari_comms::multiaddr::Multiaddr;
use tari_contacts::contacts_service::{
handle::{DEFAULT_MESSAGE_LIMIT, DEFAULT_MESSAGE_PAGE},
types::Message,
};
use tokio::runtime::Runtime;

use crate::{
callback_handler::{CallbackHandler, CallbackMessageReceived},
callback_handler::{CallbackHandler, CallbackMessageReceived, ChatFFIContactsLivenessData, ChatFFIMessage},
error::{InterfaceError, LibChatError},
};

Expand Down Expand Up @@ -92,7 +93,6 @@ pub struct ClientFFI {
#[no_mangle]
pub unsafe extern "C" fn create_chat_client(
config: *mut ApplicationConfig,
identity_file_path: *const c_char,
error_out: *mut c_int,
callback_contact_status_change: CallbackContactStatusChange,
callback_message_received: CallbackMessageReceived,
Expand Down Expand Up @@ -124,20 +124,15 @@ pub unsafe extern "C" fn create_chat_client(
ptr::swap(error_out, &mut error as *mut c_int);
};

let identity: Arc<NodeIdentity> = match CStr::from_ptr(identity_file_path).to_str() {
Ok(str) => {
let identity_path = PathBuf::from(str);

match load_from_json(identity_path) {
Ok(Some(identity)) => Arc::new(identity),
_ => {
bad_identity("No identity loaded".to_string());
return ptr::null_mut();
},
}
},
Err(e) => {
bad_identity(e.to_string());
let identity = match setup_node_identity(
(*config).chat_client.identity_file.clone(),
(*config).chat_client.p2p.public_addresses.clone().into_vec(),
true,
PeerFeatures::COMMUNICATION_NODE,
) {
Ok(node_id) => node_id,
_ => {
bad_identity("No identity loaded".to_string());
return ptr::null_mut();
},
};
Expand Down Expand Up @@ -199,11 +194,13 @@ pub unsafe extern "C" fn destroy_client_ffi(client: *mut ClientFFI) {
///
/// # Safety
/// The ```destroy_config``` method must be called when finished with a Config to prevent a memory leak
#[allow(clippy::too_many_lines)]
#[no_mangle]
pub unsafe extern "C" fn create_chat_config(
network_str: *const c_char,
public_address: *const c_char,
datastore_path: *const c_char,
identity_file_path: *const c_char,
log_path: *const c_char,
error_out: *mut c_int,
) -> *mut ApplicationConfig {
Expand Down Expand Up @@ -298,11 +295,25 @@ pub unsafe extern "C" fn create_chat_config(
}
let log_path = PathBuf::from(log_path_string);

let mut bad_identity = |e| {
error = LibChatError::from(InterfaceError::InvalidArgument(e)).code;
ptr::swap(error_out, &mut error as *mut c_int);
};

let identity_path = match CStr::from_ptr(identity_file_path).to_str() {
Ok(str) => PathBuf::from(str),
Err(e) => {
bad_identity(e.to_string());
return ptr::null_mut();
},
};

let mut chat_client_config = ChatClientConfig::default();
chat_client_config.network = network;
chat_client_config.p2p.transport.tcp.listener_address = address.clone();
chat_client_config.p2p.public_addresses = MultiaddrList::from(vec![address]);
chat_client_config.log_path = Some(log_path);
chat_client_config.identity_file = identity_path;
chat_client_config.set_base_path(datastore_path);

let config = ApplicationConfig {
Expand Down Expand Up @@ -691,3 +702,37 @@ pub unsafe extern "C" fn destroy_tari_address(address: *mut TariAddress) {
drop(Box::from_raw(address))
}
}

/// Frees memory for a ChatFFIMessage
///
/// ## Arguments
/// `address` - The pointer of a ChatFFIMessage
///
/// ## Returns
/// `()` - Does not return a value, equivalent to void in C
///
/// # Safety
/// None
#[no_mangle]
pub unsafe extern "C" fn destroy_chat_ffi_message(address: *mut ChatFFIMessage) {
if !address.is_null() {
drop(Box::from_raw(address))
}
}

/// Frees memory for a ChatFFIContactsLivenessData
///
/// ## Arguments
/// `address` - The pointer of a ChatFFIContactsLivenessData
///
/// ## Returns
/// `()` - Does not return a value, equivalent to void in C
///
/// # Safety
/// None
#[no_mangle]
pub unsafe extern "C" fn destroy_chat_ffi_liveness_data(address: *mut ChatFFIContactsLivenessData) {
if !address.is_null() {
drop(Box::from_raw(address))
}
}
6 changes: 5 additions & 1 deletion base_layer/contacts/examples/chat_client/src/networking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,17 @@ use tari_p2p::{
use tari_service_framework::StackBuilder;
use tari_shutdown::ShutdownSignal;

use crate::{config::ApplicationConfig, database::connect_to_db};
use crate::{
config::ApplicationConfig,
database::{connect_to_db, create_chat_storage},
};

pub async fn start(
node_identity: Arc<NodeIdentity>,
config: ApplicationConfig,
shutdown_signal: ShutdownSignal,
) -> anyhow::Result<(ContactsServiceHandle, CommsNode)> {
create_chat_storage(&config.chat_client.db_file);
let backend = connect_to_db(config.chat_client.db_file)?;

let (publisher, subscription_factory) = pubsub_connector(100);
Expand Down
Loading

0 comments on commit 79ab584

Please sign in to comment.