use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use prost::Message as _;
use super::DeRecProtocolHandle;
use crate::ffi::common::{empty_buffer, vec_into_buffer, DeRecBuffer};
use crate::ffi::error::{
ffi_error, from_lib_error, success, DeRecError, DEREC_CODE_FFI_BAD_PROTO,
DEREC_CODE_FFI_INVALID_ENUM, DEREC_CODE_FFI_NULL_PTR,
};
use crate::types::ChannelId;
#[repr(C)]
pub struct DeRecProtocolFingerprintResult {
pub error: DeRecError,
pub fingerprint: *mut c_char,
}
impl From<DeRecError> for DeRecProtocolFingerprintResult {
fn from(error: DeRecError) -> Self {
Self {
error,
fingerprint: std::ptr::null_mut(),
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn derec_protocol_get_fingerprint(
handle: *mut DeRecProtocolHandle,
channel_id: u64,
) -> DeRecProtocolFingerprintResult {
if handle.is_null() {
return ffi_error(DEREC_CODE_FFI_NULL_PTR, "handle is null").into();
}
let h = unsafe { &*handle };
let inner = h.lock_inner();
let result = h
.runtime
.block_on(inner.get_fingerprint(ChannelId(channel_id)));
match result {
Ok(s) => match CString::new(s) {
Ok(c) => DeRecProtocolFingerprintResult {
error: success(),
fingerprint: c.into_raw(),
},
Err(_) => ffi_error(DEREC_CODE_FFI_BAD_PROTO, "fingerprint contains NUL byte").into(),
},
Err(e) => from_lib_error(e).into(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn derec_protocol_verify_fingerprint(
handle: *mut DeRecProtocolHandle,
channel_id: u64,
fingerprint_ptr: *const c_char,
out_matched: *mut u32,
) -> DeRecError {
if handle.is_null() || fingerprint_ptr.is_null() || out_matched.is_null() {
return ffi_error(DEREC_CODE_FFI_NULL_PTR, "null pointer in verify_fingerprint");
}
unsafe {
*out_matched = 0;
}
let fingerprint = match unsafe { CStr::from_ptr(fingerprint_ptr) }.to_str() {
Ok(s) => s.to_owned(),
Err(_) => {
return ffi_error(DEREC_CODE_FFI_BAD_PROTO, "fingerprint is not valid UTF-8");
}
};
let h = unsafe { &*handle };
let mut inner = h.lock_inner();
match h
.runtime
.block_on(inner.verify_fingerprint(ChannelId(channel_id), &fingerprint))
{
Ok(matched) => {
unsafe {
*out_matched = if matched { 1 } else { 0 };
}
success()
}
Err(e) => from_lib_error(e),
}
}
#[repr(C)]
pub struct DeRecProtocolCreateContactResult {
pub error: DeRecError,
pub contact_wire_bytes: DeRecBuffer,
}
impl From<DeRecError> for DeRecProtocolCreateContactResult {
fn from(error: DeRecError) -> Self {
Self {
error,
contact_wire_bytes: empty_buffer(),
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn derec_protocol_create_contact(
handle: *mut DeRecProtocolHandle,
has_channel_id: u32,
channel_id: u64,
contact_mode: i32,
has_nonce: u32,
nonce: u64,
) -> DeRecProtocolCreateContactResult {
if handle.is_null() {
return ffi_error(DEREC_CODE_FFI_NULL_PTR, "handle is null").into();
}
let mode = match derec_proto::ContactMode::try_from(contact_mode) {
Ok(m) => m,
Err(_) => {
return ffi_error(
DEREC_CODE_FFI_INVALID_ENUM,
format!("invalid ContactMode: {contact_mode}"),
)
.into();
}
};
let id_arg: Option<ChannelId> = if has_channel_id != 0 {
Some(ChannelId(channel_id))
} else {
None
};
let nonce_arg: Option<u64> = if has_nonce != 0 { Some(nonce) } else { None };
let h = unsafe { &*handle };
let mut inner = h.lock_inner();
match h
.runtime
.block_on(inner.create_contact(id_arg, mode, nonce_arg))
{
Ok(contact) => DeRecProtocolCreateContactResult {
error: success(),
contact_wire_bytes: vec_into_buffer(contact.encode_to_vec()),
},
Err(e) => from_lib_error(e).into(),
}
}