use crate::ffi::errors::{ErrorHandle, Status};
use crate::ffi::{Buffer, Slice};
use crate::models::Role;
use crate::protocol::base::Transport;
use crate::websocket::{CloseCode, Frame, Opcode, WebSocketConnection};
pub struct WebSocket {
pub connection: WebSocketConnection<Box<dyn Transport>>,
pub handle: tokio::runtime::Handle,
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_websocket_free(socket: *mut WebSocket) {
if !socket.is_null() {
drop(unsafe { Box::from_raw(socket) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_websocket_role(socket: *const WebSocket) -> u32 {
match unsafe { socket.as_ref() } {
Some(socket) => Role::build(socket.connection.role()),
None => Role::build(Role::UserAgent),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_websocket_closing(socket: *const WebSocket) -> bool {
unsafe { socket.as_ref() }.is_some_and(|socket| socket.connection.closing())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_websocket_id(socket: *const WebSocket) -> Buffer {
match unsafe { socket.as_ref() } {
Some(socket) => Buffer::new(socket.connection.id().0.to_vec()),
None => Buffer::EMPTY,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_websocket_send(socket: *mut WebSocket, fin: bool, opcode: u8, payload: *const u8, payload_len: usize, error: *mut *mut ErrorHandle) -> Status {
let Some(socket) = (unsafe { socket.as_mut() }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
let Some(opcode) = Opcode::from_code(opcode) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
let payload = unsafe { Slice::borrow(payload, payload_len) }.unwrap_or_default().to_vec();
let frame = Frame { fin, opcode, mask: None, payload: payload.into() };
match socket.handle.clone().block_on(socket.connection.send(frame)) {
Ok(()) => Status::Ok,
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_websocket_receive(socket: *mut WebSocket, fin: *mut bool, opcode: *mut u8, out: *mut Buffer, error: *mut *mut ErrorHandle) -> Status {
let Some(socket) = (unsafe { socket.as_mut() }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
if out.is_null() {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
}
match socket.handle.clone().block_on(socket.connection.receive()) {
Ok(frame) => {
if !fin.is_null() {
unsafe { *fin = frame.fin };
}
if !opcode.is_null() {
unsafe { *opcode = frame.opcode.code() };
}
unsafe { *out = Buffer::new(frame.payload.to_vec()) };
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_websocket_send_message(socket: *mut WebSocket, opcode: u8, payload: *const u8, payload_len: usize, error: *mut *mut ErrorHandle) -> Status {
unsafe { soyokaze_websocket_send(socket, true, opcode, payload, payload_len, error) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_websocket_receive_message(socket: *mut WebSocket, opcode: *mut u8, out: *mut Buffer, error: *mut *mut ErrorHandle) -> Status {
let Some(socket) = (unsafe { socket.as_mut() }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
if out.is_null() {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
}
match socket.handle.clone().block_on(socket.connection.receive_message()) {
Ok((received, payload)) => {
if !opcode.is_null() {
unsafe { *opcode = received.code() };
}
unsafe { *out = Buffer::new(payload.to_vec()) };
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_websocket_close(socket: *mut WebSocket, code: u16, reason: *const u8, reason_len: usize) -> bool {
let Some(socket) = (unsafe { socket.as_mut() }) else {
return false;
};
let Some(code) = CloseCode::from_code(code) else {
return false;
};
let reason = unsafe { Slice::borrow_text(reason, reason_len) }.unwrap_or_default();
socket.handle.clone().block_on(socket.connection.close(code, reason));
true
}