1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use super::super::sync::client::{WSEvent as RWSEvent, Reason};
use std::ffi::{c_void, CString};
use crate::result::WebSocketError;
use std::ptr;

#[repr(C)]
#[allow(non_camel_case_types)]
enum WSEvent {
    ON_CONNECT,
    ON_TEXT,
    ON_CLOSE
}

#[repr(C)]
#[allow(non_camel_case_types)]
pub struct WSEvent_t {
    event: WSEvent,
    value: *const c_void
}

#[repr(C)]
#[allow(non_camel_case_types)]
enum WSReason {
    SERVER_CLOSED,
    CLIENT_CLOSED
}

#[repr(C)]
#[allow(non_camel_case_types)]
struct WSReason_t {
    reason: WSReason,
    status: u16
}

#[repr(C)]
#[derive(Debug, Clone)]
pub enum WSStatus { 
    OK,
    UnreachableHost,
    HandShake,
    InvalidFrame,
    ConnectionClose,
    DecodingFromUTF8,
    IOError,
}

pub fn rust_error_to_c_error(error: WebSocketError) -> WSStatus {
    match error {
        WebSocketError::UnreachableHost => WSStatus::UnreachableHost,
        WebSocketError::HandShake => WSStatus::HandShake,
        WebSocketError::InvalidFrame => WSStatus::InvalidFrame,
        WebSocketError::ConnectionClose => WSStatus::ConnectionClose,
        WebSocketError::DecodingFromUTF8 => WSStatus::DecodingFromUTF8,
        WebSocketError::IOError => WSStatus::IOError
    }
}

#[no_mangle]
pub extern "C" fn from_rust_event(event: &RWSEvent) -> WSEvent_t {
    match event {
        RWSEvent::ON_CONNECT(msg) => {
            let mut value = ptr::null_mut();
            if let Some(m) = msg {
                println!("[RUST] M: {}", m);
                let m = m.replace('\0', "");
                let m = m.trim();
                let c_str = CString::new(m).map_err(|err| {
                    eprintln!("Error converting to CString: {err}");
                }).unwrap();
                value = c_str.into_raw();
            }
            WSEvent_t { event: WSEvent::ON_CONNECT, value: value as *const c_void }
        }
        , 
        RWSEvent::ON_TEXT(msg) => {
            let c_str = CString::new(msg.clone()).unwrap();
            WSEvent_t { event: WSEvent::ON_TEXT, value: c_str.into_raw() as *const c_void }
        },
        RWSEvent::ON_CLOSE(reason) => {
            let (reason, status) = match reason {
                Reason::SERVER_CLOSE(status) => (WSReason::SERVER_CLOSED, status.clone()),   
                Reason::CLIENT_CLOSE(status) => (WSReason::CLIENT_CLOSED, status.clone())
            };
            let reason = WSReason_t { reason, status };
            let reason = Box::into_raw(Box::new(reason));
            WSEvent_t { event: WSEvent::ON_CLOSE, value: reason as *const c_void } 
        }
    }
}