1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::{any::Any, sync::Arc};

use fxhash::FxHashMap;

use crate::{
    client_config::ParsedConfig, client_polling, client_registration,
    client_types::types::DeviceCapabilityStatus,
};

//todo: make these optional parameters user can change
const RSA_KEY_SIZE: usize = 2048;
const POLLING_INTERVAL: u64 = 500;

pub type ThreadSafeMutable<T> = Arc<tokio::sync::Mutex<T>>;

pub struct ClientHandler<S: State> {
    callbacks: FxHashMap<String, Box<Callback<S>>>,
    state: S,
}

impl<S> ClientHandler<S>
where
    S: State + 'static,
{
    pub fn new() -> Self {
        Self {
            callbacks: FxHashMap::default(),
            state: S::default(),
        }
    }
    ///Replaces current callback function with supplied one
    pub fn add_callback(mut self, capabillity: &str, callback: Box<Callback<S>>) -> Self {
        self.callbacks.insert(String::from(capabillity), callback);
        return self;
    }
    pub fn add_state(mut self, state: S) -> Self {
        self.state = state;
        return self;
    }

    ///consumes self
    pub async fn run(mut self, config: ParsedConfig, server_ip: String) -> anyhow::Result<()> {
        let private_key;
        let capabilities = config.capabilities;

        let capabilities: ThreadSafeMutable<Vec<DeviceCapabilityStatus>> =
            Arc::new(tokio::sync::Mutex::new(capabilities));
        {
            let mut rng = rand::thread_rng();
            private_key = rsa::RsaPrivateKey::new(&mut rng, RSA_KEY_SIZE).unwrap();
        }

        let client_connection_details = client_registration::repeated_register_self(
            &private_key.to_public_key(),
            capabilities.clone(),
            config.device_name,
            server_ip.clone(),
        )
        .await;

        {
            let certificate = client_connection_details.security_certificate.clone();
            let uuid = client_connection_details.uuid.clone();
            let has_update = ThreadSafeMutable::new(tokio::sync::Mutex::new(false));

            let mut interval =
                tokio::time::interval(std::time::Duration::from_millis(POLLING_INTERVAL));

            let mut polling_service = client_polling::PollingService {
                client: client_polling::polling::request_update_service_client::RequestUpdateServiceClient::connect(server_ip).await.unwrap(),
                capabilities: capabilities.clone(),
                updated: has_update.clone(),
            };

            loop {
                interval.tick().await;
                let updates = polling_service
                    .get_updates(certificate.clone(), uuid.clone())
                    .await;
                let updates = match updates {
                    Some(v) => v,
                    None => {
                        // println!("No updates available");
                        continue;
                    }
                };
                for update in updates.into_iter() {
                    let callback = self.callbacks.get(&update.capability);
                    //todo: remove
                    let temp_req = Request::new();
                    match callback {
                        Some(v) => v(&mut self.state, temp_req),
                        None => println!("Received signal to {}", update.capability),
                    }
                }
            }
        }
    }
}

pub trait State: Default {}

pub type Callback<S> = fn(&mut S, Request);

pub struct Request {
    contents: Arc<String>,
}
impl Request {
    pub fn new() -> Self {
        Self {
            contents: Arc::default(),
        }
    }
}