use libcoap_rs::message::{CoapMessageCommon, CoapRequest, CoapResponse};
use libcoap_rs::protocol::{CoapMessageCode, CoapMessageType, CoapRequestCode, CoapResponseCode};
use libcoap_rs::session::CoapSessionCommon;
use libcoap_rs::types::{CoapUri, CoapUriHost};
use libcoap_rs::{CoapContext, CoapRequestHandler, CoapResource};
use std::net::{SocketAddr, UdpSocket};
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Condvar, Mutex};
use std::thread::JoinHandle;
use std::time::Duration;
pub(crate) fn get_unused_server_addr() -> SocketAddr {
UdpSocket::bind("localhost:0")
.expect("Failed to bind server socket")
.local_addr()
.expect("Failed to get server socket address")
}
pub(crate) fn spawn_test_server<F: FnOnce(&mut CoapContext) + Send + 'static>(
context_configurator: F,
) -> JoinHandle<()> {
let ready_condition = Arc::new((Mutex::new(false), Condvar::new()));
let ready_condition2 = Arc::clone(&ready_condition);
let server_handle = std::thread::spawn(move || {
let (ready_var, ready_cond) = &*ready_condition2;
run_test_server(|context| {
context_configurator(context);
let mut ready_var = ready_var.lock().expect("ready condition mutex is poisoned");
*ready_var = true;
ready_cond.notify_all();
});
});
let (ready_var, ready_cond) = &*ready_condition;
drop(
ready_cond
.wait_while(ready_var.lock().expect("ready condition mutex is poisoned"), |ready| {
!*ready
})
.expect("ready condition mutex is poisoned"),
);
server_handle
}
pub(crate) fn run_test_server<F: FnOnce(&mut CoapContext)>(context_configurator: F) {
let mut context = CoapContext::new().unwrap();
context_configurator(&mut context);
let request_completed = Rc::new(AtomicBool::new(false));
let resource = CoapResource::new("test1", request_completed.clone(), false);
resource.set_method_handler(
CoapRequestCode::Get,
Some(CoapRequestHandler::new(
|completed: &mut Rc<AtomicBool>, sess, _req, mut rsp: CoapResponse| {
let data = Vec::<u8>::from("Hello World!".as_bytes());
rsp.set_data(Some(data));
rsp.set_code(CoapMessageCode::Response(CoapResponseCode::Content));
sess.send(rsp).unwrap();
completed.store(true, Ordering::Relaxed);
},
)),
);
context.add_resource(resource);
loop {
assert!(
context.do_io(Some(Duration::from_secs(10))).unwrap() < Duration::from_secs(10),
"timeout while waiting for test client request"
);
if request_completed.load(Ordering::Relaxed) {
break;
}
}
context.shutdown(Some(Duration::from_secs(0))).unwrap();
}
pub(crate) fn gen_test_request(server_address: SocketAddr) -> CoapRequest {
let uri = CoapUri::new(
None,
Some(CoapUriHost::IpLiteral(server_address.ip())),
Some(server_address.port()),
Some(vec!["test1".to_string()]),
None,
);
let mut request = CoapRequest::new(CoapMessageType::Con, CoapRequestCode::Get).unwrap();
request.set_uri(Some(uri)).unwrap();
request
}