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
use super::super::super::sync::client::{Config, WSEvent as RWSEvent, WSClient};
use std::ffi::{c_void, c_char, CStr};
use std::alloc::{alloc, Layout};
use std::mem;
use std::ptr;
use std::str;
use super::super::common;

#[no_mangle]
extern "C" fn wssclient_new<'a>() -> *mut WSClient<'a, *mut c_void> {
    // Box doesn't return a Result type, that the reason to use layout, to check if the system
    // gave me memory to store the client.
    let size = mem::size_of::<WSClient<*mut c_void>>();
    let aling = std::mem::align_of::<WSClient<*mut c_void>>();
    let layout = Layout::from_size_align(size, aling);

    if layout.is_err() {
        return std::ptr::null_mut();
    }

    let ptr = unsafe { alloc(layout.unwrap()) };
    let client = WSClient::<*mut c_void>::new();

    unsafe {
        ptr::copy_nonoverlapping(&client, ptr as *mut WSClient<*mut c_void>, 1);
    }

    ptr as *mut WSClient<*mut c_void>
}

#[no_mangle]
unsafe extern "C" fn wssclient_init<'a> (
    client: *mut WSClient<'a, *mut c_void>,
    host: *const c_char,
    port: u16,
    path: *const c_char,
    callback: *mut c_void,
) {
    let host = str::from_utf8(CStr::from_ptr(host).to_bytes()).unwrap();
    let path = str::from_utf8(CStr::from_ptr(path).to_bytes()).unwrap();

    let callback: fn(&mut WSClient<'a, *mut c_void>, &RWSEvent, Option<*mut c_void>) = mem::transmute(callback);
    let config = Config { callback: Some(callback), data: None, protocols: None };
    
    let client = &mut *client;

    client.init(host, port, path, Some(config));
}

#[no_mangle]
unsafe extern "C" fn wssclient_loop<'a>(client: *mut WSClient<'a, *mut c_void>) -> common::WSStatus {
    let client = &mut *client;

    match client.event_loop() {
        Ok(_) => {}
        Err(e) => {
            return common::rust_error_to_c_error(e);
        } 
    }

    common::WSStatus::OK
}

#[no_mangle]
unsafe extern "C" fn wssclient_send<'a>(client: *mut WSClient<'a, *mut c_void>, message: *const c_char) {
    let msg = str::from_utf8(CStr::from_ptr(message).to_bytes()).unwrap();
    let client = &mut *client;
    client.send(msg);
}

#[no_mangle]
extern "C" fn wssclient_drop<'a>(client: *mut WSClient<'a, *mut c_void>) {
    // Create a box from the raw pointer, at the end of the function the client will be dropped and the memory will be free.
    unsafe {
        let _c = Box::from_raw(client);
    }
}