Skip to content

Commit

Permalink
Update workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
brianp committed Apr 25, 2023
1 parent a874662 commit d80a7b9
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 11 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/integration_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
--all-features
--release
--package tari_integration_tests
-- -t "${{ env.CI_PROFILE }} and (not @wallet-ffi) and (not @broken)"
-- -t "${{ env.CI_PROFILE }} and (not @wallet-ffi) and (not @chat-ffi) and (not @broken)"
-c 5
--retry 2
Expand Down Expand Up @@ -167,6 +167,6 @@ jobs:
--all-features
--release
--package tari_integration_tests
-- -t "@wallet-ffi and ${{ env.CI_PROFILE }} and (not @broken)"
-- -t "@wallet-ffi and @chat-ffi and ${{ env.CI_PROFILE }} and (not @broken)"
-c 1
--retry 2
47 changes: 46 additions & 1 deletion base_layer/chat_ffi/chat.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,52 @@ void send_message(struct ClientFFI *client,
const char *message_c_char);

/**
* Sends a message over a client
* Add a contact
*
* ## Arguments
* `client` - The Client pointer
* `address` - A TariAddress ptr
*
* ## Returns
* `()` - Does not return a value, equivalent to void in C
*
* # Safety
* The ```address``` should be destroyed after use
*/
void add_contact(struct ClientFFI *client, struct TariAddress *receiver);

/**
* Check the online status of a contact
*
* ## Arguments
* `client` - The Client pointer
* `address` - A TariAddress ptr
*
* ## Returns
* `()` - Does not return a value, equivalent to void in C
*
* # Safety
* The ```address``` should be destroyed after use
*/
int check_online_status(struct ClientFFI *client, struct TariAddress *receiver);

/**
* Get a ptr to all messages from or to address
*
* ## Arguments
* `client` - The Client pointer
* `address` - A TariAddress ptr
*
* ## Returns
* `()` - Does not return a value, equivalent to void in C
*
* # Safety
* The ```address``` should be destroyed after use
*/
Message **get_all_messages(struct ClientFFI *client, struct TariAddress *address);

/**
* Creates a TariAddress and returns a ptr
*
* ## Arguments
* `receiver_c_char` - A string containing a tari address hex value
Expand Down
83 changes: 81 additions & 2 deletions base_layer/chat_ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@

use std::{ffi::CStr, fs::File, io::Read, path::PathBuf, str::FromStr};

use libc::c_char;
use libc::{c_char, c_int};
use tari_chat_client::{ChatClient, Client};
use tari_common::configuration::Network;
use tari_common_types::tari_address::TariAddress;
use tari_comms::{peer_manager::Peer, NodeIdentity};
use tari_contacts::contacts_service::types::Message;
use tari_p2p::P2pConfig;
use tokio::runtime::Runtime;

Expand Down Expand Up @@ -148,7 +149,85 @@ pub unsafe extern "C" fn send_message(
.block_on((*client).client.send_message((*receiver).clone(), message));
}

/// Sends a message over a client
/// Add a contact
///
/// ## Arguments
/// `client` - The Client pointer
/// `address` - A TariAddress ptr
///
/// ## Returns
/// `()` - Does not return a value, equivalent to void in C
///
/// # Safety
/// The ```address``` should be destroyed after use
#[no_mangle]
pub unsafe extern "C" fn add_contact(client: *mut ClientFFI, receiver: *mut TariAddress) {
(*client).runtime.block_on((*client).client.add_contact(&(*receiver)));
}

/// Check the online status of a contact
///
/// ## Arguments
/// `client` - The Client pointer
/// `address` - A TariAddress ptr
///
/// ## Returns
/// `()` - Does not return a value, equivalent to void in C
///
/// # Safety
/// The ```address``` should be destroyed after use
#[no_mangle]
pub unsafe extern "C" fn check_online_status(client: *mut ClientFFI, receiver: *mut TariAddress) -> c_int {
let status = (client)
.runtime
.block_on((client).client.check_online_status(&*receiver));

status.as_u8().into()
}

/// Get a ptr to all messages from or to address
///
/// ## Arguments
/// `client` - The Client pointer
/// `address` - A TariAddress ptr
///
/// ## Returns
/// `()` - Does not return a value, equivalent to void in C
///
/// # Safety
/// The ```address``` should be destroyed after use
/// The returned pointer to ```*mut *mut Message``` should be destroyed after use
#[no_mangle]
pub unsafe extern "C" fn get_all_messages(client: *mut ClientFFI, address: *mut TariAddress) -> *mut *mut Message {
let all_messages: Vec<Message> = (*client).runtime.block_on((*client).client.get_all_messages(&*address));

let mut messages: Vec<*mut Message> = Vec::with_capacity(all_messages.len() + 1);
for message in all_messages {
messages.push(Box::into_raw(Box::new(message)));
}
messages.push(std::ptr::null_mut());

messages.as_mut_ptr()
}

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

/// Creates a TariAddress and returns a ptr
///
/// ## Arguments
/// `receiver_c_char` - A string containing a tari address hex value
Expand Down
22 changes: 22 additions & 0 deletions base_layer/contacts/src/contacts_service/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,35 @@ impl Display for ContactMessageType {
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum ContactOnlineStatus {
Online,
Offline,
NeverSeen,
Banned(String),
}

impl ContactOnlineStatus {
pub fn as_u8(self) -> u8 {
match self {
Self::Online => 1,
Self::Offline => 2,
Self::NeverSeen => 3,
Self::Banned(_) => 4,
}
}

pub fn from_byte(value: u8) -> Option<Self> {
match value {
1 => Some(Self::Online),
2 => Some(Self::Offline),
3 => Some(Self::NeverSeen),
4 => Some(Self::Banned("No reason listed".to_string())),
_ => None,
}
}
}

impl Display for ContactOnlineStatus {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
match self {
Expand Down
40 changes: 35 additions & 5 deletions integration_tests/src/chat_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use async_trait::async_trait;

type ClientFFI = c_void;

use libc::c_char;
use libc::{c_char, c_int};
use rand::rngs::OsRng;
use tari_chat_client::{database, ChatClient};
use tari_common::configuration::{MultiaddrList, Network};
Expand Down Expand Up @@ -60,6 +60,9 @@ extern "C" {
network_str: *const c_char,
) -> *mut ClientFFI;
pub fn send_message(client: *mut ClientFFI, receiver: *mut TariAddress, message: *const c_char);
pub fn add_contact(client: *mut ClientFFI, address: *mut TariAddress);
pub fn check_online_status(client: *mut ClientFFI, address: *mut TariAddress) -> c_int;
pub fn get_all_messages(client: *mut ClientFFI, sender: *mut TariAddress) -> *mut *mut Message;
}

#[derive(Debug)]
Expand All @@ -75,11 +78,22 @@ pub struct ChatFFI {
#[async_trait]
impl ChatClient for ChatFFI {
async fn add_contact(&self, address: &TariAddress) {
todo!()
let client = self.ptr.lock().unwrap();

let address_ptr = Box::into_raw(Box::new(address.to_owned()));

unsafe { add_contact(client.0, address_ptr) }
}

async fn check_online_status(&self, address: &TariAddress) -> ContactOnlineStatus {
todo!()
let client = self.ptr.lock().unwrap();

let address_ptr = Box::into_raw(Box::new(address.to_owned()));

let result;
unsafe { result = check_online_status(client.0, address_ptr) }

ContactOnlineStatus::from_byte(result as u8).expect("A valid u8 from FFI status")
}

async fn send_message(&self, receiver: TariAddress, message: String) {
Expand All @@ -95,8 +109,24 @@ impl ChatClient for ChatFFI {
}
}

async fn get_all_messages(&self, sender: &TariAddress) -> Vec<Message> {
todo!()
async fn get_all_messages(&self, address: &TariAddress) -> Vec<Message> {
let client = self.ptr.lock().unwrap();

let address_ptr = Box::into_raw(Box::new(address.clone()));

let mut messages_vec = Vec::new();
unsafe {
let messages = get_all_messages(client.0, address_ptr);

let mut i = 0;
while !(*messages.offset(i)).is_null() {
let message = (**messages.offset(i)).clone();
messages_vec.push(message);
i += 1;
}
}

messages_vec
}

fn identity(&self) -> &NodeIdentity {
Expand Down
13 changes: 12 additions & 1 deletion integration_tests/tests/features/ChatFFI.feature
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
# Copyright 2023 The Tari Project
# SPDX-License-Identifier: BSD-3-Clause

@chat-ffi
Feature: Chat FFI messaging

Scenario: A message is propagated between an FFI node and client via 3rd party
Scenario: A message is propagated between an FFI node and native client via 3rd party
Given I have a seed node SEED_A
When I have a chat FFI client CHAT_A connected to seed node SEED_A
When I have a chat client CHAT_B connected to seed node SEED_A
When I use CHAT_A to send a message 'Hey there' to CHAT_B
Then CHAT_B will have 1 message with CHAT_A

Scenario: A message is sent directly between two FFI clients
Given I have a seed node SEED_A
When I have a chat FFI client CHAT_A connected to seed node SEED_A
When I have a chat FFI client CHAT_B connected to seed node SEED_A
When CHAT_A adds CHAT_B as a contact
When I stop node SEED_A
When CHAT_A waits for contact CHAT_B to be online
When I use CHAT_A to send a message 'Hey there' to CHAT_B
Then CHAT_B will have 1 message with CHAT_A

0 comments on commit d80a7b9

Please sign in to comment.