You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

169 lines
5.1 KiB

2 days ago
mod server;
mod bridge;
mod events;
mod logging;
mod db;
use std::ffi::{c_char, c_int, CStr, CString};
// --- Server ---
#[unsafe(no_mangle)]
pub extern "C" fn rgl_start(port: c_int) -> c_int {
match server::start(port as u16) {
Ok(()) => 0,
Err(_) => -1,
}
}
#[unsafe(no_mangle)]
pub extern "C" fn rgl_stop() {
server::stop();
}
// --- Logging ---
#[unsafe(no_mangle)]
pub extern "C" fn rgl_log_init(path: *const c_char) {
let path = unsafe { CStr::from_ptr(path) }.to_str().unwrap_or("");
logging::init(path);
}
#[unsafe(no_mangle)]
pub extern "C" fn rgl_log(level: *const c_char, tag: *const c_char, msg: *const c_char) {
let level = unsafe { CStr::from_ptr(level) }.to_str().unwrap_or("INFO");
let tag = unsafe { CStr::from_ptr(tag) }.to_str().unwrap_or("");
let msg_bytes = unsafe { CStr::from_ptr(msg) }.to_bytes();
let msg = events::win1251_to_utf8(msg_bytes);
logging::log(level, tag, &msg);
}
// --- Database ---
#[unsafe(no_mangle)]
pub extern "C" fn rgl_db_init(path: *const c_char) {
let path = unsafe { CStr::from_ptr(path) }.to_str().unwrap_or("");
db::init(path);
}
#[unsafe(no_mangle)]
pub extern "C" fn rgl_db_get(key: *const c_char) -> *mut c_char {
let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap_or("");
match db::get(key) {
Some(v) => CString::new(v).unwrap_or_default().into_raw(),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn rgl_db_set(key: *const c_char, value: *const c_char) -> c_int {
let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap_or("");
let value = unsafe { CStr::from_ptr(value) }.to_str().unwrap_or("");
if db::set(key, value) { 0 } else { -1 }
}
#[unsafe(no_mangle)]
pub extern "C" fn rgl_db_delete(key: *const c_char) -> c_int {
let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap_or("");
if db::delete(key) { 0 } else { -1 }
}
/// List all key-value pairs with prefix as JSON. Caller must free.
#[unsafe(no_mangle)]
pub extern "C" fn rgl_db_list(prefix: *const c_char) -> *mut c_char {
let prefix = unsafe { CStr::from_ptr(prefix) }.to_str().unwrap_or("");
let json = db::list_keys_json(prefix);
CString::new(json).unwrap_or_default().into_raw()
}
/// Delete all keys with prefix. Returns count deleted.
#[unsafe(no_mangle)]
pub extern "C" fn rgl_db_delete_prefix(prefix: *const c_char) -> c_int {
let prefix = unsafe { CStr::from_ptr(prefix) }.to_str().unwrap_or("");
db::delete_prefix(prefix) as c_int
}
/// Submit async batch. Returns request id instantly.
#[unsafe(no_mangle)]
pub extern "C" fn rgl_db_submit(ops: *const c_char) -> u32 {
let ops = unsafe { CStr::from_ptr(ops) }.to_str().unwrap_or("[]");
db::submit_batch(ops)
}
/// Poll batch result. Returns JSON string if ready (caller must free), null if pending.
#[unsafe(no_mangle)]
pub extern "C" fn rgl_db_poll(id: u32) -> *mut c_char {
match db::poll_result(id) {
Some(r) => CString::new(r).unwrap_or_default().into_raw(),
None => std::ptr::null_mut(),
}
}
// --- Modules ---
#[unsafe(no_mangle)]
pub extern "C" fn rgl_register_module(name: *const c_char, static_dir: *const c_char) {
let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap_or("");
let dir = unsafe { CStr::from_ptr(static_dir) }.to_str().unwrap_or("");
server::register_module(name, dir);
}
/// Register a chat command (for tracking/web visibility).
#[unsafe(no_mangle)]
pub extern "C" fn rgl_register_command(name: *const c_char, owner: *const c_char) {
let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap_or("");
let owner = unsafe { CStr::from_ptr(owner) }.to_str().unwrap_or("");
server::register_command(name, owner);
}
/// Get registered commands as JSON. Caller must free.
#[unsafe(no_mangle)]
pub extern "C" fn rgl_get_commands() -> *mut c_char {
let json = server::get_commands_json();
CString::new(json).unwrap_or_default().into_raw()
}
// --- Events ---
#[unsafe(no_mangle)]
pub extern "C" fn rgl_push_event(
event_name: *const c_char,
json_args: *const c_char,
) -> *mut c_char {
let name = unsafe { CStr::from_ptr(event_name) }.to_str().unwrap_or("");
let args_bytes = unsafe { CStr::from_ptr(json_args) }.to_bytes();
let args = events::win1251_to_utf8(args_bytes);
match bridge::push_event(name, &args) {
Some(response) => CString::new(response).unwrap_or_default().into_raw(),
None => std::ptr::null_mut(),
}
}
// --- Bridge ---
#[unsafe(no_mangle)]
pub extern "C" fn rgl_poll() -> *mut c_char {
match bridge::poll_requests() {
Some(json) => CString::new(json).unwrap_or_default().into_raw(),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn rgl_respond(request_id: c_int, result_json: *const c_char) {
let result = unsafe { CStr::from_ptr(result_json) }.to_str().unwrap_or("");
bridge::respond(request_id as u32, result);
}
#[unsafe(no_mangle)]
pub extern "C" fn rgl_free(s: *mut c_char) {
if !s.is_null() {
unsafe { drop(CString::from_raw(s)) };
}
}
#[unsafe(no_mangle)]
pub extern "C" fn rgl_hello() -> c_int {
42
}