Skip to content

Instantly share code, notes, and snippets.

@susilolab
Last active October 8, 2022 01:16
Show Gist options
  • Select an option

  • Save susilolab/22641ef382e29d1203a1fcb06f35ec38 to your computer and use it in GitHub Desktop.

Select an option

Save susilolab/22641ef382e29d1203a1fcb06f35ec38 to your computer and use it in GitHub Desktop.
Windows service tcp server
use std::ffi::OsString;
use std::env;
use std::sync::{Arc, Mutex, mpsc};
use std::time::Duration;
use tokio::{
net::TcpListener,
io::{
AsyncReadExt, AsyncWriteExt
},
};
use windows_service::service_control_handler::ServiceStatusHandle;
use windows_service::{
service_dispatcher,
define_windows_service,
service::{
ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus,
ServiceType,
},
service_control_handler::{self, ServiceControlHandlerResult},
Result,
};
const SERVICE_NAME: &str = "lisha_svc";
const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS;
pub fn run() -> Result<()> {
service_dispatcher::start(SERVICE_NAME, ffi_service_main)
}
define_windows_service!(ffi_service_main, lisha_service_main);
pub fn lisha_service_main(arguments: Vec<OsString>) {
if let Err(_e) = run_service() {
}
}
pub fn run_service() -> Result<()> {
let (shutdown_tx, shutdown_rx) = mpsc::channel();
let shared_status_handle: Arc<Mutex<Option<ServiceStatusHandle>>> = Arc::new(Mutex::new(None));
let cloned_status_handle = Arc::clone(&shared_status_handle);
let event_handler = move |control_event| -> ServiceControlHandlerResult {
match control_event {
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
ServiceControl::Stop => {
let status_handle = cloned_status_handle.lock().unwrap().unwrap();
shutdown_tx.send(()).unwrap();
ServiceControlHandlerResult::NoError
}
_ => ServiceControlHandlerResult::NotImplemented,
}
};
let status_handle = service_control_handler::register(SERVICE_NAME, event_handler)?;
status_handle.set_service_status(ServiceStatus {
service_type: SERVICE_TYPE,
current_state: ServiceState::Running,
controls_accepted: ServiceControlAccept::STOP,
exit_code: ServiceExitCode::Win32(0),
checkpoint: 0,
wait_hint: tokio::time::Duration::default(),
process_id: None,
})?;
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
env::set_var("RUST_LOG", "debug");
tracing_subscriber::fmt::init();
let listener = TcpListener::bind("127.0.0.1:4000").await.unwrap();
tracing::debug!("listening pada port 4000");
loop {
let (mut socket,_) = listener.accept().await.unwrap();
match shutdown_rx.recv_timeout(Duration::from_secs(1)) {
Ok(_) | Err(mpsc::RecvTimeoutError::Disconnected) => break,
Err(mpsc::RecvTimeoutError::Timeout) => (),
}
tokio::spawn(async move {
let mut buf = [0; 1024];
loop {
let n = match socket.read(&mut buf).await {
Ok(n) if n == 0 => return,
Ok(n) => n,
Err(e) => {
eprintln!("Gagal membaca dari socket; err = {:?}", e);
return;
}
};
println!("data: {:?}", &buf[0..n]);
tracing::debug!("data: {:?}", &buf[0..n]);
if let Err(e) = socket.write_all(&buf[0..n]).await {
eprintln!("Gagal menulis ke socket; err = {:?}", e);
return;
}
}
});
}
});
status_handle.set_service_status(ServiceStatus {
service_type: SERVICE_TYPE,
current_state: ServiceState::Stopped,
controls_accepted: ServiceControlAccept::empty(),
exit_code: ServiceExitCode::Win32(0),
checkpoint: 0,
wait_hint: tokio::time::Duration::default(),
process_id: None,
})?;
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment