use core::ffi::c_char;
use core::ptr;
use std::ffi::CStr;
use std::sync::Arc;
use mbus_core::transport::UnitIdOrSlaveAddr;
use mbus_server_async::AsyncTcpServer as InnerAsyncTcpServer;
use tokio::sync::Notify;
use super::vtable::{DotNetServerAdapter, MbusDnServerVtable};
use crate::dotnet::runtime;
use crate::dotnet::status::{self, MbusDnStatus};
pub struct MbusDnTcpServer {
bind_addr: String,
unit_id: u8,
vtable: Arc<MbusDnServerVtable>,
stop_signal: Arc<Notify>,
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mbus_dn_tcp_server_new(
host: *const c_char,
port: u16,
unit_id: u8,
vtable: *const MbusDnServerVtable,
) -> *mut MbusDnTcpServer {
if host.is_null() || vtable.is_null() {
return ptr::null_mut();
}
let host_str = match unsafe { CStr::from_ptr(host) }.to_str() {
Ok(s) => s,
Err(_) => return ptr::null_mut(),
};
if UnitIdOrSlaveAddr::new(unit_id).is_err() {
return ptr::null_mut();
}
let vt: MbusDnServerVtable = unsafe { core::ptr::read(vtable) };
Box::into_raw(Box::new(MbusDnTcpServer {
bind_addr: format!("{host_str}:{port}"),
unit_id,
vtable: Arc::new(vt),
stop_signal: Arc::new(Notify::new()),
}))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mbus_dn_tcp_server_free(handle: *mut MbusDnTcpServer) {
if !handle.is_null() {
drop(unsafe { Box::from_raw(handle) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mbus_dn_tcp_server_start(handle: *mut MbusDnTcpServer) -> MbusDnStatus {
let srv = match unsafe { handle.as_ref() } {
Some(s) => s,
None => return MbusDnStatus::MbusErrNullPointer,
};
let unit = match UnitIdOrSlaveAddr::new(srv.unit_id) {
Ok(u) => u,
Err(e) => return status::from_mbus(e),
};
let addr = srv.bind_addr.clone();
let adapter = DotNetServerAdapter::new_with_arc(srv.vtable.clone());
let stop_signal = srv.stop_signal.clone();
std::thread::spawn(move || {
let rt = runtime::get();
let _ = rt.block_on(InnerAsyncTcpServer::serve_with_shutdown(
addr.as_str(),
adapter,
unit,
stop_signal.notified(),
));
});
MbusDnStatus::MbusOk
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mbus_dn_tcp_server_stop(handle: *mut MbusDnTcpServer) {
if let Some(s) = unsafe { handle.as_ref() } {
s.stop_signal.notify_one();
}
}