1
1
use crate :: types:: * ;
2
+ use std:: convert:: TryFrom ;
3
+ use std:: sync:: { Arc , RwLock , Weak } ;
2
4
use std:: time;
3
5
4
6
pub mod errors;
7
+ pub mod native_app;
8
+ pub mod rest;
5
9
pub mod types;
6
10
7
11
#[ derive( Debug ) ]
8
12
pub struct HomeAssistantAPI {
9
13
instance_url : String ,
10
- token : Option < Token > ,
11
- client : reqwest:: Client ,
12
- webhook_id : Option < String > ,
13
- cloudhook_url : Option < String > ,
14
- remote_ui_url : Option < String > ,
14
+ token : Token ,
15
15
client_id : String ,
16
+ self_reference : Weak < RwLock < Self > > ,
16
17
}
17
18
18
19
#[ derive( Debug , Clone ) ]
19
20
pub enum Token {
20
21
Oauth ( OAuthToken ) ,
21
22
LongLived ( LongLivedToken ) ,
23
+ None ,
24
+ }
25
+
26
+ impl Token {
27
+ pub fn as_string ( & self ) -> Result < String , errors:: Error > {
28
+ match self {
29
+ Token :: Oauth ( token) => Ok ( token. token . clone ( ) ) ,
30
+ Token :: LongLived ( token) => Ok ( token. token . clone ( ) ) ,
31
+ Token :: None => Err ( errors:: Error :: NoAuth ( ) ) ,
32
+ }
33
+ }
34
+
35
+ pub fn need_refresh ( & self ) -> bool {
36
+ match self {
37
+ Token :: Oauth ( token) => {
38
+ match time:: SystemTime :: now ( ) . duration_since ( token. token_expiration ) {
39
+ Ok ( sec_left) => sec_left > time:: Duration :: from_secs ( 10 ) ,
40
+ Err ( _) => false ,
41
+ }
42
+ }
43
+ Token :: LongLived ( _) => false ,
44
+ Token :: None => false ,
45
+ }
46
+ }
22
47
}
23
48
24
49
#[ derive( Debug , Clone ) ]
@@ -34,20 +59,18 @@ pub struct LongLivedToken {
34
59
}
35
60
36
61
impl HomeAssistantAPI {
37
- pub fn new (
38
- instance_url : String ,
39
- client_id : String ,
40
- maybe_long_lived_token : Option < String > ,
41
- ) -> Self {
42
- Self {
62
+ pub fn new ( instance_url : String , client_id : String ) -> Arc < RwLock < Self > > {
63
+ let token = Token :: None ;
64
+ let ret = Arc :: new ( RwLock :: new ( Self {
43
65
instance_url,
44
- token : maybe_long_lived_token. map ( |token| Token :: LongLived ( LongLivedToken { token } ) ) ,
45
- client : reqwest:: Client :: new ( ) ,
46
- webhook_id : None ,
47
- cloudhook_url : None ,
48
- remote_ui_url : None ,
66
+ token,
49
67
client_id,
50
- }
68
+ self_reference : Weak :: new ( ) ,
69
+ } ) ) ;
70
+
71
+ ret. write ( ) . unwrap ( ) . self_reference = Arc :: downgrade ( & ret) ;
72
+
73
+ ret
51
74
}
52
75
53
76
pub fn set_oauth_token (
@@ -62,63 +85,18 @@ impl HomeAssistantAPI {
62
85
+ time:: Duration :: from_secs ( expires_in as u64 ) ,
63
86
refresh_token,
64
87
} ;
65
- let oauth_token = Token :: Oauth ( oauth) ;
66
- self . token = Some ( oauth_token) ;
88
+ self . token = Token :: Oauth ( oauth) ;
67
89
}
68
90
69
91
pub fn set_long_lived_token ( & mut self , token : String ) {
70
- let long_lived = Token :: LongLived ( LongLivedToken { token } ) ;
71
- self . token = Some ( long_lived)
72
- }
73
-
74
- pub fn set_webhook_info (
75
- & mut self ,
76
- webhook_id : String ,
77
- cloudhook_url : Option < String > ,
78
- remote_ui_url : Option < String > ,
79
- ) {
80
- self . webhook_id = Some ( webhook_id) ;
81
- self . cloudhook_url = cloudhook_url;
82
- self . remote_ui_url = remote_ui_url;
83
- }
84
-
85
- pub fn need_refresh ( & self ) -> bool {
86
- let token_result = self . token . as_ref ( ) . ok_or_else ( || {
87
- errors:: Error :: Config ( "Refreshing token - expected a token to exist" . to_string ( ) )
88
- } ) ;
89
-
90
- match token_result {
91
- Ok ( token) => match token {
92
- Token :: Oauth ( token) => {
93
- match time:: SystemTime :: now ( ) . duration_since ( token. token_expiration ) {
94
- Ok ( sec_left) => sec_left > time:: Duration :: from_secs ( 10 ) ,
95
- Err ( _) => false ,
96
- }
97
- }
98
- Token :: LongLived ( _) => false ,
99
- } ,
100
- Err ( _) => false ,
101
- }
92
+ self . token = Token :: LongLived ( LongLivedToken { token } ) ;
102
93
}
103
94
104
- pub async fn refresh_token ( & mut self ) -> Result < ( ) , errors:: Error > {
105
- let token = self . token . clone ( ) ; // This is dump but I have to do it apparently
106
- let refresh_token: String ;
107
- match token {
108
- Some ( token) => {
109
- refresh_token = match token {
110
- Token :: Oauth ( oauth) => oauth. refresh_token ,
111
- Token :: LongLived ( _) => {
112
- return Err ( errors:: Error :: Refresh ( ) ) ;
113
- }
114
- } ;
115
- }
116
- None => return Err ( errors:: Error :: NoAuth ( ) ) ,
117
- }
95
+ pub async fn refresh_oauth_token ( & mut self ) -> Result < ( ) , errors:: Error > {
96
+ let refresh_token = String :: from ( "test" ) ;
118
97
119
- let response = self
120
- . client
121
- . post ( format ! ( "http://{}/auth/token" , self . instance_url) . as_str ( ) )
98
+ let response = reqwest:: Client :: new ( )
99
+ . post ( format ! ( "{}/auth/token" , self . instance_url) . as_str ( ) )
122
100
. query ( & [
123
101
( "grant_type" , "refresh_token" ) ,
124
102
( "client_id" , & self . client_id ) ,
@@ -146,9 +124,8 @@ impl HomeAssistantAPI {
146
124
code,
147
125
client_id,
148
126
} ;
149
- let resp = self
150
- . client
151
- . post ( format ! ( "http://{}/auth/token" , self . instance_url) . as_str ( ) )
127
+ let resp = reqwest:: Client :: new ( )
128
+ . post ( format ! ( "{}/auth/token" , self . instance_url) . as_str ( ) )
152
129
. form ( & request)
153
130
. send ( )
154
131
. await ?;
@@ -173,109 +150,27 @@ impl HomeAssistantAPI {
173
150
}
174
151
}
175
152
176
- pub async fn api_states ( & self ) -> Result < Vec < HaEntityState > , errors:: Error > {
177
- let endpoint = format ! ( "http://{}/api/states" , self . instance_url) ;
178
- let token = self . get_token ( ) ?;
179
- let resp = self
180
- . client
181
- . get ( endpoint. as_str ( ) )
182
- . header ( "Authorization" , format ! ( "Bearer {}" , token) )
183
- . send ( )
184
- . await ?;
185
-
186
- let api_states = resp. json :: < Vec < HaEntityState > > ( ) . await ?;
187
- Ok ( api_states)
188
- }
189
-
190
- pub async fn register_machine (
191
- & mut self ,
192
- request : & RegisterDeviceRequest ,
193
- ) -> Result < RegisterDeviceResponse , errors:: Error > {
194
- if self . need_refresh ( ) {
195
- self . refresh_token ( ) . await ?;
196
- }
197
- let endpoint = format ! ( "http://{}/api/mobile_app/registrations" , self . instance_url) ;
198
- let token = self . get_token ( ) ?;
199
- let resp = self
200
- . client
201
- . post ( endpoint. as_str ( ) )
202
- . header ( "Authorization" , format ! ( "Bearer {}" , token) )
203
- . json ( & request)
204
- . send ( )
205
- . await ?;
206
-
207
- let r: RegisterDeviceResponse = resp. json ( ) . await ?;
208
- self . set_webhook_info (
209
- r. webhook_id . clone ( ) ,
210
- r. cloud_hook_url . clone ( ) ,
211
- r. remote_ui_url . clone ( ) ,
212
- ) ;
213
- Ok ( r)
214
- }
215
-
216
- pub async fn register_sensor (
217
- & mut self ,
218
- request : & SensorRegistrationRequest ,
219
- ) -> Result < RegisterSensorResponse , errors:: Error > {
220
- if self . need_refresh ( ) {
221
- self . refresh_token ( ) . await ?;
153
+ pub async fn get_rest_client ( & self ) -> rest:: Rest {
154
+ match rest:: Rest :: try_from ( self . self_reference . clone ( ) ) {
155
+ Ok ( rest) => rest,
156
+ Err ( _) => unreachable ! ( ) ,
222
157
}
223
- let webhook_id = self
224
- . webhook_id
225
- . as_ref ( )
226
- . ok_or_else ( || errors:: Error :: Config ( "expected webhook_id to exist" . to_string ( ) ) ) ?;
227
- let token = self . get_token ( ) ?;
228
- let endpoint = format ! ( "http://{}/api/webhook/{}" , self . instance_url, webhook_id) ;
229
-
230
- let response = self
231
- . client
232
- . post ( endpoint. as_str ( ) )
233
- . header ( "Authorization" , format ! ( "Bearer {}" , token) )
234
- . json ( & request)
235
- . send ( )
236
- . await ?;
237
-
238
- let resp_json: RegisterSensorResponse = response. json ( ) . await ?;
239
- Ok ( resp_json)
240
158
}
241
159
242
- pub async fn update_sensor (
243
- & mut self ,
244
- sensor_data : SensorUpdateData ,
245
- ) -> Result < ( ) , errors:: Error > {
246
- if self . need_refresh ( ) {
247
- self . refresh_token ( ) . await ?;
160
+ pub async fn get_native_client_from_config (
161
+ & self ,
162
+ config : native_app:: NativeAppConfig ,
163
+ ) -> native_app:: NativeApp {
164
+ match native_app:: NativeApp :: from_config ( config, self . self_reference . clone ( ) ) {
165
+ Ok ( native_app) => native_app,
166
+ Err ( _) => unreachable ! ( ) ,
248
167
}
249
- let webhook_id = self
250
- . webhook_id
251
- . as_ref ( )
252
- . ok_or_else ( || errors:: Error :: Config ( "missing webhook id" . to_string ( ) ) ) ?;
253
-
254
- let endpoint = format ! ( "{}/api/webhook/{}" , self . instance_url, webhook_id) ;
255
- let token = self . get_token ( ) ?;
256
-
257
- let request = types:: SensorUpdateRequest {
258
- data : sensor_data,
259
- r#type : String :: from ( "update_sensor_states" ) ,
260
- } ;
261
-
262
- self . client
263
- . post ( endpoint. as_str ( ) )
264
- . header ( "Authorization" , format ! ( "Bearer {}" , token) )
265
- . json ( & request)
266
- . send ( )
267
- . await ?;
268
-
269
- Ok ( ( ) )
270
168
}
271
169
272
- fn get_token ( & self ) -> Result < String , errors:: Error > {
273
- let token = self . token . as_ref ( ) . ok_or_else ( || {
274
- errors:: Error :: Config ( "Get Token - expected a token to exist" . to_string ( ) )
275
- } ) ?;
276
- match token {
277
- Token :: Oauth ( token) => Ok ( token. token . clone ( ) ) ,
278
- Token :: LongLived ( token) => Ok ( token. token . clone ( ) ) ,
170
+ pub async fn get_native_client ( & self ) -> native_app:: NativeApp {
171
+ match native_app:: NativeApp :: new ( self . self_reference . clone ( ) ) {
172
+ Ok ( native_app) => native_app,
173
+ Err ( _) => unreachable ! ( ) ,
279
174
}
280
175
}
281
176
}
0 commit comments