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
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
|
||
|
|
}
|