sysreq/clients/
resolve.rs1use super::SystemHttpClient;
2use crate::Error;
3use std::{
4 cell::UnsafeCell,
5 sync::atomic::{self, AtomicU8},
6 time::Duration,
7};
8
9const PENDING: u8 = 0;
10const BUSY: u8 = 1;
11const READY: u8 = 2;
12
13struct GlobalResolvedSystemHttpClient {
14 state: AtomicU8,
15 value: UnsafeCell<Option<SystemHttpClient>>,
16}
17impl GlobalResolvedSystemHttpClient {
18 fn get() -> Option<SystemHttpClient> {
19 static HTTP_CLIENT: GlobalResolvedSystemHttpClient = GlobalResolvedSystemHttpClient {
20 state: AtomicU8::new(PENDING),
21 value: UnsafeCell::new(None),
22 };
23
24 let mut spin_wait = Duration::from_millis(50);
25 loop {
26 match HTTP_CLIENT.state.fetch_max(BUSY, atomic::Ordering::SeqCst) {
27 BUSY => (),
28 PENDING => break,
29 READY => return unsafe { *HTTP_CLIENT.value.get() },
30 _ => unreachable!(),
31 }
32 std::thread::sleep(spin_wait);
33 spin_wait = Duration::max(spin_wait * 2, Duration::from_secs(2));
34 }
35
36 let resolved = SystemHttpClient::resolve();
37
38 unsafe { *HTTP_CLIENT.value.get() = resolved };
39
40 HTTP_CLIENT.state.store(READY, atomic::Ordering::Release);
41
42 resolved
43 }
44}
45unsafe impl Sync for GlobalResolvedSystemHttpClient {}
46
47pub(crate) fn resolve() -> Result<SystemHttpClient, Error> {
48 match GlobalResolvedSystemHttpClient::get() {
49 Some(client) => Ok(client),
50 None => Err(Error::SystemHTTPClientNotFound),
51 }
52}
53
54#[must_use]
55pub fn installed() -> bool {
57 GlobalResolvedSystemHttpClient::get().is_some()
58}
59
60#[must_use]
61pub fn http_client() -> Option<SystemHttpClient> {
63 GlobalResolvedSystemHttpClient::get()
64}