summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock281
-rw-r--r--Cargo.toml27
-rw-r--r--docker-compose.yml10
-rw-r--r--src/config.rs39
-rw-r--r--src/error.rs56
-rw-r--r--src/main.rs111
-rw-r--r--src/requests.rs (renamed from src/requests/mod.rs)0
-rw-r--r--src/requests/device.rs86
-rw-r--r--src/requests/start.rs189
9 files changed, 494 insertions, 305 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5620d60..25f23fe 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -18,21 +18,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
18checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 18checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
19 19
20[[package]] 20[[package]]
21name = "ahash"
22version = "0.7.7"
23source = "registry+https://github.com/rust-lang/crates.io-index"
24checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd"
25dependencies = [
26 "getrandom",
27 "once_cell",
28 "version_check",
29]
30
31[[package]]
32name = "anstream" 21name = "anstream"
33version = "0.6.4" 22version = "0.6.12"
34source = "registry+https://github.com/rust-lang/crates.io-index" 23source = "registry+https://github.com/rust-lang/crates.io-index"
35checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" 24checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540"
36dependencies = [ 25dependencies = [
37 "anstyle", 26 "anstyle",
38 "anstyle-parse", 27 "anstyle-parse",
@@ -77,6 +66,12 @@ dependencies = [
77] 66]
78 67
79[[package]] 68[[package]]
69name = "anyhow"
70version = "1.0.80"
71source = "registry+https://github.com/rust-lang/crates.io-index"
72checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
73
74[[package]]
80name = "async-trait" 75name = "async-trait"
81version = "0.1.74" 76version = "0.1.74"
82source = "registry+https://github.com/rust-lang/crates.io-index" 77source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -110,12 +105,6 @@ dependencies = [
110 105
111[[package]] 106[[package]]
112name = "base64" 107name = "base64"
113version = "0.13.1"
114source = "registry+https://github.com/rust-lang/crates.io-index"
115checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
116
117[[package]]
118name = "base64"
119version = "0.21.5" 108version = "0.21.5"
120source = "registry+https://github.com/rust-lang/crates.io-index" 109source = "registry+https://github.com/rust-lang/crates.io-index"
121checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" 110checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
@@ -131,6 +120,9 @@ name = "bitflags"
131version = "2.4.1" 120version = "2.4.1"
132source = "registry+https://github.com/rust-lang/crates.io-index" 121source = "registry+https://github.com/rust-lang/crates.io-index"
133checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" 122checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
123dependencies = [
124 "serde",
125]
134 126
135[[package]] 127[[package]]
136name = "block-buffer" 128name = "block-buffer"
@@ -176,9 +168,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
176 168
177[[package]] 169[[package]]
178name = "clap" 170name = "clap"
179version = "4.4.8" 171version = "4.5.1"
180source = "registry+https://github.com/rust-lang/crates.io-index" 172source = "registry+https://github.com/rust-lang/crates.io-index"
181checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" 173checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da"
182dependencies = [ 174dependencies = [
183 "clap_builder", 175 "clap_builder",
184 "clap_derive", 176 "clap_derive",
@@ -186,9 +178,9 @@ dependencies = [
186 178
187[[package]] 179[[package]]
188name = "clap_builder" 180name = "clap_builder"
189version = "4.4.8" 181version = "4.5.1"
190source = "registry+https://github.com/rust-lang/crates.io-index" 182source = "registry+https://github.com/rust-lang/crates.io-index"
191checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" 183checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb"
192dependencies = [ 184dependencies = [
193 "anstream", 185 "anstream",
194 "anstyle", 186 "anstyle",
@@ -198,18 +190,18 @@ dependencies = [
198 190
199[[package]] 191[[package]]
200name = "clap_complete" 192name = "clap_complete"
201version = "4.4.4" 193version = "4.5.1"
202source = "registry+https://github.com/rust-lang/crates.io-index" 194source = "registry+https://github.com/rust-lang/crates.io-index"
203checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae" 195checksum = "885e4d7d5af40bfb99ae6f9433e292feac98d452dcb3ec3d25dfe7552b77da8c"
204dependencies = [ 196dependencies = [
205 "clap", 197 "clap",
206] 198]
207 199
208[[package]] 200[[package]]
209name = "clap_derive" 201name = "clap_derive"
210version = "4.4.7" 202version = "4.5.0"
211source = "registry+https://github.com/rust-lang/crates.io-index" 203source = "registry+https://github.com/rust-lang/crates.io-index"
212checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" 204checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
213dependencies = [ 205dependencies = [
214 "heck", 206 "heck",
215 "proc-macro2", 207 "proc-macro2",
@@ -219,9 +211,9 @@ dependencies = [
219 211
220[[package]] 212[[package]]
221name = "clap_lex" 213name = "clap_lex"
222version = "0.6.0" 214version = "0.7.0"
223source = "registry+https://github.com/rust-lang/crates.io-index" 215source = "registry+https://github.com/rust-lang/crates.io-index"
224checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" 216checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
225 217
226[[package]] 218[[package]]
227name = "colorchoice" 219name = "colorchoice"
@@ -231,11 +223,12 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
231 223
232[[package]] 224[[package]]
233name = "config" 225name = "config"
234version = "0.13.3" 226version = "0.14.0"
235source = "registry+https://github.com/rust-lang/crates.io-index" 227source = "registry+https://github.com/rust-lang/crates.io-index"
236checksum = "d379af7f68bfc21714c6c7dea883544201741d2ce8274bb12fa54f89507f52a7" 228checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be"
237dependencies = [ 229dependencies = [
238 "async-trait", 230 "async-trait",
231 "convert_case",
239 "json5", 232 "json5",
240 "lazy_static", 233 "lazy_static",
241 "nom", 234 "nom",
@@ -262,6 +255,35 @@ dependencies = [
262] 255]
263 256
264[[package]] 257[[package]]
258name = "const-random"
259version = "0.1.17"
260source = "registry+https://github.com/rust-lang/crates.io-index"
261checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a"
262dependencies = [
263 "const-random-macro",
264]
265
266[[package]]
267name = "const-random-macro"
268version = "0.1.16"
269source = "registry+https://github.com/rust-lang/crates.io-index"
270checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
271dependencies = [
272 "getrandom",
273 "once_cell",
274 "tiny-keccak",
275]
276
277[[package]]
278name = "convert_case"
279version = "0.6.0"
280source = "registry+https://github.com/rust-lang/crates.io-index"
281checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
282dependencies = [
283 "unicode-segmentation",
284]
285
286[[package]]
265name = "core-foundation" 287name = "core-foundation"
266version = "0.9.3" 288version = "0.9.3"
267source = "registry+https://github.com/rust-lang/crates.io-index" 289source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -287,6 +309,12 @@ dependencies = [
287] 309]
288 310
289[[package]] 311[[package]]
312name = "crunchy"
313version = "0.2.2"
314source = "registry+https://github.com/rust-lang/crates.io-index"
315checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
316
317[[package]]
290name = "crypto-common" 318name = "crypto-common"
291version = "0.1.6" 319version = "0.1.6"
292source = "registry+https://github.com/rust-lang/crates.io-index" 320source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -335,9 +363,12 @@ dependencies = [
335 363
336[[package]] 364[[package]]
337name = "dlv-list" 365name = "dlv-list"
338version = "0.3.0" 366version = "0.5.2"
339source = "registry+https://github.com/rust-lang/crates.io-index" 367source = "registry+https://github.com/rust-lang/crates.io-index"
340checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" 368checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
369dependencies = [
370 "const-random",
371]
341 372
342[[package]] 373[[package]]
343name = "encode_unicode" 374name = "encode_unicode"
@@ -355,6 +386,12 @@ dependencies = [
355] 386]
356 387
357[[package]] 388[[package]]
389name = "equivalent"
390version = "1.0.1"
391source = "registry+https://github.com/rust-lang/crates.io-index"
392checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
393
394[[package]]
358name = "errno" 395name = "errno"
359version = "0.3.6" 396version = "0.3.6"
360source = "registry+https://github.com/rust-lang/crates.io-index" 397source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -499,8 +536,8 @@ dependencies = [
499 "futures-core", 536 "futures-core",
500 "futures-sink", 537 "futures-sink",
501 "futures-util", 538 "futures-util",
502 "http", 539 "http 0.2.10",
503 "indexmap", 540 "indexmap 1.9.3",
504 "slab", 541 "slab",
505 "tokio", 542 "tokio",
506 "tokio-util", 543 "tokio-util",
@@ -512,9 +549,18 @@ name = "hashbrown"
512version = "0.12.3" 549version = "0.12.3"
513source = "registry+https://github.com/rust-lang/crates.io-index" 550source = "registry+https://github.com/rust-lang/crates.io-index"
514checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 551checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
515dependencies = [ 552
516 "ahash", 553[[package]]
517] 554name = "hashbrown"
555version = "0.13.2"
556source = "registry+https://github.com/rust-lang/crates.io-index"
557checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
558
559[[package]]
560name = "hashbrown"
561version = "0.14.3"
562source = "registry+https://github.com/rust-lang/crates.io-index"
563checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
518 564
519[[package]] 565[[package]]
520name = "heck" 566name = "heck"
@@ -540,13 +586,24 @@ dependencies = [
540] 586]
541 587
542[[package]] 588[[package]]
589name = "http"
590version = "1.0.0"
591source = "registry+https://github.com/rust-lang/crates.io-index"
592checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
593dependencies = [
594 "bytes",
595 "fnv",
596 "itoa",
597]
598
599[[package]]
543name = "http-body" 600name = "http-body"
544version = "0.4.5" 601version = "0.4.5"
545source = "registry+https://github.com/rust-lang/crates.io-index" 602source = "registry+https://github.com/rust-lang/crates.io-index"
546checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 603checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
547dependencies = [ 604dependencies = [
548 "bytes", 605 "bytes",
549 "http", 606 "http 0.2.10",
550 "pin-project-lite", 607 "pin-project-lite",
551] 608]
552 609
@@ -573,7 +630,7 @@ dependencies = [
573 "futures-core", 630 "futures-core",
574 "futures-util", 631 "futures-util",
575 "h2", 632 "h2",
576 "http", 633 "http 0.2.10",
577 "http-body", 634 "http-body",
578 "httparse", 635 "httparse",
579 "httpdate", 636 "httpdate",
@@ -616,7 +673,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
616checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 673checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
617dependencies = [ 674dependencies = [
618 "autocfg", 675 "autocfg",
619 "hashbrown", 676 "hashbrown 0.12.3",
677]
678
679[[package]]
680name = "indexmap"
681version = "2.2.3"
682source = "registry+https://github.com/rust-lang/crates.io-index"
683checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
684dependencies = [
685 "equivalent",
686 "hashbrown 0.14.3",
620] 687]
621 688
622[[package]] 689[[package]]
@@ -807,9 +874,9 @@ dependencies = [
807 874
808[[package]] 875[[package]]
809name = "once_cell" 876name = "once_cell"
810version = "1.18.0" 877version = "1.19.0"
811source = "registry+https://github.com/rust-lang/crates.io-index" 878source = "registry+https://github.com/rust-lang/crates.io-index"
812checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 879checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
813 880
814[[package]] 881[[package]]
815name = "openssl" 882name = "openssl"
@@ -863,12 +930,12 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
863 930
864[[package]] 931[[package]]
865name = "ordered-multimap" 932name = "ordered-multimap"
866version = "0.4.3" 933version = "0.6.0"
867source = "registry+https://github.com/rust-lang/crates.io-index" 934source = "registry+https://github.com/rust-lang/crates.io-index"
868checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" 935checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e"
869dependencies = [ 936dependencies = [
870 "dlv-list", 937 "dlv-list",
871 "hashbrown", 938 "hashbrown 0.13.2",
872] 939]
873 940
874[[package]] 941[[package]]
@@ -960,18 +1027,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
960 1027
961[[package]] 1028[[package]]
962name = "proc-macro2" 1029name = "proc-macro2"
963version = "1.0.69" 1030version = "1.0.78"
964source = "registry+https://github.com/rust-lang/crates.io-index" 1031source = "registry+https://github.com/rust-lang/crates.io-index"
965checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" 1032checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
966dependencies = [ 1033dependencies = [
967 "unicode-ident", 1034 "unicode-ident",
968] 1035]
969 1036
970[[package]] 1037[[package]]
971name = "quote" 1038name = "quote"
972version = "1.0.33" 1039version = "1.0.35"
973source = "registry+https://github.com/rust-lang/crates.io-index" 1040source = "registry+https://github.com/rust-lang/crates.io-index"
974checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 1041checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
975dependencies = [ 1042dependencies = [
976 "proc-macro2", 1043 "proc-macro2",
977] 1044]
@@ -1032,13 +1099,13 @@ version = "0.11.22"
1032source = "registry+https://github.com/rust-lang/crates.io-index" 1099source = "registry+https://github.com/rust-lang/crates.io-index"
1033checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" 1100checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
1034dependencies = [ 1101dependencies = [
1035 "base64 0.21.5", 1102 "base64",
1036 "bytes", 1103 "bytes",
1037 "encoding_rs", 1104 "encoding_rs",
1038 "futures-core", 1105 "futures-core",
1039 "futures-util", 1106 "futures-util",
1040 "h2", 1107 "h2",
1041 "http", 1108 "http 0.2.10",
1042 "http-body", 1109 "http-body",
1043 "hyper", 1110 "hyper",
1044 "hyper-tls", 1111 "hyper-tls",
@@ -1066,20 +1133,21 @@ dependencies = [
1066 1133
1067[[package]] 1134[[package]]
1068name = "ron" 1135name = "ron"
1069version = "0.7.1" 1136version = "0.8.1"
1070source = "registry+https://github.com/rust-lang/crates.io-index" 1137source = "registry+https://github.com/rust-lang/crates.io-index"
1071checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" 1138checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
1072dependencies = [ 1139dependencies = [
1073 "base64 0.13.1", 1140 "base64",
1074 "bitflags 1.3.2", 1141 "bitflags 2.4.1",
1075 "serde", 1142 "serde",
1143 "serde_derive",
1076] 1144]
1077 1145
1078[[package]] 1146[[package]]
1079name = "rust-ini" 1147name = "rust-ini"
1080version = "0.18.0" 1148version = "0.19.0"
1081source = "registry+https://github.com/rust-lang/crates.io-index" 1149source = "registry+https://github.com/rust-lang/crates.io-index"
1082checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" 1150checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091"
1083dependencies = [ 1151dependencies = [
1084 "cfg-if", 1152 "cfg-if",
1085 "ordered-multimap", 1153 "ordered-multimap",
@@ -1174,6 +1242,15 @@ dependencies = [
1174] 1242]
1175 1243
1176[[package]] 1244[[package]]
1245name = "serde_spanned"
1246version = "0.6.5"
1247source = "registry+https://github.com/rust-lang/crates.io-index"
1248checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
1249dependencies = [
1250 "serde",
1251]
1252
1253[[package]]
1177name = "serde_urlencoded" 1254name = "serde_urlencoded"
1178version = "0.7.1" 1255version = "0.7.1"
1179source = "registry+https://github.com/rust-lang/crates.io-index" 1256source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1238,15 +1315,15 @@ dependencies = [
1238 1315
1239[[package]] 1316[[package]]
1240name = "strsim" 1317name = "strsim"
1241version = "0.10.0" 1318version = "0.11.0"
1242source = "registry+https://github.com/rust-lang/crates.io-index" 1319source = "registry+https://github.com/rust-lang/crates.io-index"
1243checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1320checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
1244 1321
1245[[package]] 1322[[package]]
1246name = "syn" 1323name = "syn"
1247version = "2.0.39" 1324version = "2.0.50"
1248source = "registry+https://github.com/rust-lang/crates.io-index" 1325source = "registry+https://github.com/rust-lang/crates.io-index"
1249checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" 1326checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
1250dependencies = [ 1327dependencies = [
1251 "proc-macro2", 1328 "proc-macro2",
1252 "quote", 1329 "quote",
@@ -1289,18 +1366,18 @@ dependencies = [
1289 1366
1290[[package]] 1367[[package]]
1291name = "thiserror" 1368name = "thiserror"
1292version = "1.0.50" 1369version = "1.0.57"
1293source = "registry+https://github.com/rust-lang/crates.io-index" 1370source = "registry+https://github.com/rust-lang/crates.io-index"
1294checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" 1371checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
1295dependencies = [ 1372dependencies = [
1296 "thiserror-impl", 1373 "thiserror-impl",
1297] 1374]
1298 1375
1299[[package]] 1376[[package]]
1300name = "thiserror-impl" 1377name = "thiserror-impl"
1301version = "1.0.50" 1378version = "1.0.57"
1302source = "registry+https://github.com/rust-lang/crates.io-index" 1379source = "registry+https://github.com/rust-lang/crates.io-index"
1303checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" 1380checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
1304dependencies = [ 1381dependencies = [
1305 "proc-macro2", 1382 "proc-macro2",
1306 "quote", 1383 "quote",
@@ -1308,6 +1385,15 @@ dependencies = [
1308] 1385]
1309 1386
1310[[package]] 1387[[package]]
1388name = "tiny-keccak"
1389version = "2.0.2"
1390source = "registry+https://github.com/rust-lang/crates.io-index"
1391checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
1392dependencies = [
1393 "crunchy",
1394]
1395
1396[[package]]
1311name = "tinyvec" 1397name = "tinyvec"
1312version = "1.6.0" 1398version = "1.6.0"
1313source = "registry+https://github.com/rust-lang/crates.io-index" 1399source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1324,9 +1410,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
1324 1410
1325[[package]] 1411[[package]]
1326name = "tokio" 1412name = "tokio"
1327version = "1.34.0" 1413version = "1.36.0"
1328source = "registry+https://github.com/rust-lang/crates.io-index" 1414source = "registry+https://github.com/rust-lang/crates.io-index"
1329checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" 1415checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
1330dependencies = [ 1416dependencies = [
1331 "backtrace", 1417 "backtrace",
1332 "bytes", 1418 "bytes",
@@ -1362,9 +1448,9 @@ dependencies = [
1362 1448
1363[[package]] 1449[[package]]
1364name = "tokio-tungstenite" 1450name = "tokio-tungstenite"
1365version = "0.20.1" 1451version = "0.21.0"
1366source = "registry+https://github.com/rust-lang/crates.io-index" 1452source = "registry+https://github.com/rust-lang/crates.io-index"
1367checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" 1453checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38"
1368dependencies = [ 1454dependencies = [
1369 "futures-util", 1455 "futures-util",
1370 "log", 1456 "log",
@@ -1388,11 +1474,36 @@ dependencies = [
1388 1474
1389[[package]] 1475[[package]]
1390name = "toml" 1476name = "toml"
1391version = "0.5.11" 1477version = "0.8.10"
1478source = "registry+https://github.com/rust-lang/crates.io-index"
1479checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290"
1480dependencies = [
1481 "serde",
1482 "serde_spanned",
1483 "toml_datetime",
1484 "toml_edit",
1485]
1486
1487[[package]]
1488name = "toml_datetime"
1489version = "0.6.5"
1490source = "registry+https://github.com/rust-lang/crates.io-index"
1491checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
1492dependencies = [
1493 "serde",
1494]
1495
1496[[package]]
1497name = "toml_edit"
1498version = "0.22.6"
1392source = "registry+https://github.com/rust-lang/crates.io-index" 1499source = "registry+https://github.com/rust-lang/crates.io-index"
1393checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" 1500checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6"
1394dependencies = [ 1501dependencies = [
1502 "indexmap 2.2.3",
1395 "serde", 1503 "serde",
1504 "serde_spanned",
1505 "toml_datetime",
1506 "winnow",
1396] 1507]
1397 1508
1398[[package]] 1509[[package]]
@@ -1428,14 +1539,14 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
1428 1539
1429[[package]] 1540[[package]]
1430name = "tungstenite" 1541name = "tungstenite"
1431version = "0.20.1" 1542version = "0.21.0"
1432source = "registry+https://github.com/rust-lang/crates.io-index" 1543source = "registry+https://github.com/rust-lang/crates.io-index"
1433checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" 1544checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"
1434dependencies = [ 1545dependencies = [
1435 "byteorder", 1546 "byteorder",
1436 "bytes", 1547 "bytes",
1437 "data-encoding", 1548 "data-encoding",
1438 "http", 1549 "http 1.0.0",
1439 "httparse", 1550 "httparse",
1440 "log", 1551 "log",
1441 "rand", 1552 "rand",
@@ -1479,6 +1590,12 @@ dependencies = [
1479] 1590]
1480 1591
1481[[package]] 1592[[package]]
1593name = "unicode-segmentation"
1594version = "1.11.0"
1595source = "registry+https://github.com/rust-lang/crates.io-index"
1596checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
1597
1598[[package]]
1482name = "unicode-width" 1599name = "unicode-width"
1483version = "0.1.11" 1600version = "0.1.11"
1484source = "registry+https://github.com/rust-lang/crates.io-index" 1601source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1612,18 +1729,19 @@ dependencies = [
1612 1729
1613[[package]] 1730[[package]]
1614name = "webol-cli" 1731name = "webol-cli"
1615version = "0.1.0" 1732version = "0.2.0"
1616dependencies = [ 1733dependencies = [
1734 "anyhow",
1617 "clap", 1735 "clap",
1618 "clap_complete", 1736 "clap_complete",
1619 "config", 1737 "config",
1620 "dirs", 1738 "dirs",
1621 "futures-util", 1739 "futures-util",
1622 "indicatif", 1740 "indicatif",
1623 "once_cell",
1624 "reqwest", 1741 "reqwest",
1625 "serde", 1742 "serde",
1626 "serde_json", 1743 "serde_json",
1744 "thiserror",
1627 "tokio", 1745 "tokio",
1628 "tokio-tungstenite", 1746 "tokio-tungstenite",
1629] 1747]
@@ -1783,6 +1901,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1783checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1901checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
1784 1902
1785[[package]] 1903[[package]]
1904name = "winnow"
1905version = "0.6.2"
1906source = "registry+https://github.com/rust-lang/crates.io-index"
1907checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178"
1908dependencies = [
1909 "memchr",
1910]
1911
1912[[package]]
1786name = "winreg" 1913name = "winreg"
1787version = "0.50.0" 1914version = "0.50.0"
1788source = "registry+https://github.com/rust-lang/crates.io-index" 1915source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index ca76349..36b08c5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "webol-cli" 2name = "webol-cli"
3version = "0.1.0" 3version = "0.2.0"
4edition = "2021" 4edition = "2021"
5 5
6# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 6# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -10,15 +10,16 @@ name = "webol"
10path = "src/main.rs" 10path = "src/main.rs"
11 11
12[dependencies] 12[dependencies]
13clap = { version = "4.4.6", features = ["derive"] } 13anyhow = "1.0"
14clap_complete = "4.4.4" 14clap = { version = "4.5", features = ["derive"] }
15config = "0.13.3" 15clap_complete = "4.5"
16dirs = "5.0.1" 16config = "0.14"
17futures-util = "0.3.29" 17dirs = "5.0"
18indicatif = "0.17.7" 18futures-util = "0.3"
19once_cell = "1.18.0" 19indicatif = "0.17"
20reqwest = { version = "0.11.22", features = ["blocking"] } 20reqwest = { version = "0.11", features = ["blocking"] }
21serde = "1.0.189" 21serde = "1.0"
22serde_json = "1.0.107" 22serde_json = "1.0"
23tokio = { version = "1.33.0", features = ["macros", "rt-multi-thread", "io-std"] } 23thiserror = "1.0"
24tokio-tungstenite = "0.20.1" 24tokio = { version = "1.36", features = ["macros", "rt-multi-thread", "io-std"] }
25tokio-tungstenite = "0.21"
diff --git a/docker-compose.yml b/docker-compose.yml
index 3a0ade5..ea10db2 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,20 +1,20 @@
1services: 1services:
2 webol: 2 webol:
3 image: ghcr.io/fxqnlr/webol:dev-6 3 image: ghcr.io/fxqnlr/webol:dev-9
4 container_name: webol 4 container_name: webol-cli-server
5 restart: no 5 restart: no
6 depends_on: 6 depends_on:
7 - db 7 - db
8 environment: 8 environment:
9 - RUST_LOG=info,webol=trace 9 - RUST_LOG=info,webol=trace
10 - WEBOL_DATABASE_URL=postgres://postgres:postgres@localhost:5432/webol 10 - WEBOL_DATABASE_URL=postgres://postgres:postgres@localhost:5432/webol
11 - WEBOL_APIKEY=aaa 11 - WEBOL_APIKEY=dev
12 - WEBOL_SERVERADDR=127.0.0.1:7229 12 - WEBOL_SERVERADDR=0.0.0.0:7229
13 network_mode: host 13 network_mode: host
14 14
15 db: 15 db:
16 image: postgres 16 image: postgres
17 container_name: webol-db 17 container_name: webol-cli-db
18 restart: no 18 restart: no
19 environment: 19 environment:
20 POSTGRES_PASSWORD: postgres 20 POSTGRES_PASSWORD: postgres
diff --git a/src/config.rs b/src/config.rs
index 9a9e44b..769269c 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,19 +1,30 @@
1use config::Config; 1use serde::Deserialize;
2use once_cell::sync::Lazy;
3 2
4pub static SETTINGS: Lazy<Config> = Lazy::new(setup); 3#[derive(Deserialize)]
4pub struct Config {
5 pub apikey: String,
6 pub server: String,
7}
8
9impl Config {
10 pub fn load() -> Result<Config, config::ConfigError> {
11 let config_dir = dirs::config_dir();
12
13 let builder = config::Config::builder();
5 14
6fn setup() -> Config { 15 let builder = if let Some(conf) = config_dir {
7 #[cfg(not(debug_assertions))] 16 let dir = conf.to_string_lossy();
8 let builder = Config::builder().add_source(config::File::with_name( 17 builder.add_source(config::File::with_name(format!("{dir}/webol-cli").as_str()).required(false))
9 format!("{}/webol-cli.toml", dirs::config_dir().unwrap().to_string_lossy()).as_str(), 18 } else {
10 )); 19 println!("!No config dir found");
20 builder
21 };
11 22
12 #[cfg(debug_assertions)] 23 let build = builder
13 let builder = Config::builder().add_source(config::File::with_name("webol-cli.toml")); 24 .add_source(config::File::with_name("webol-cli").required(false))
25 .add_source(config::Environment::with_prefix("WEBOL_CLI").separator("_"))
26 .build()?;
14 27
15 builder 28 build.try_deserialize()
16 .add_source(config::Environment::with_prefix("WEBOL_CLI_").separator("_")) 29 }
17 .build()
18 .unwrap()
19} 30}
diff --git a/src/error.rs b/src/error.rs
index f15c60a..1e6eac1 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,21 +1,43 @@
1use std::{fmt::Debug, num::ParseIntError}; 1use std::{fmt::Debug, num::ParseIntError};
2 2
3pub enum CliError { 3use reqwest::header::InvalidHeaderValue;
4 Reqwest(reqwest::Error),
5 Config(config::ConfigError),
6 Serde(serde_json::Error),
7 Parse(ParseIntError),
8 WsResponse,
9}
10 4
11impl Debug for CliError { 5#[derive(Debug, thiserror::Error)]
12 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 6pub enum Error {
13 match self { 7 #[error("request: {source}")]
14 Self::Reqwest(err) => { err.fmt(f) }, 8 Reqwest {
15 Self::Config(err) => { err.fmt(f) }, 9 #[from]
16 Self::Serde(err) => { err.fmt(f) }, 10 source: reqwest::Error,
17 Self::Parse(err) => { err.fmt(f) }, 11 },
18 Self::WsResponse => { f.write_str("Error in Response") }, 12 #[error("config: {source}")]
19 } 13 Config {
20 } 14 #[from]
15 source: config::ConfigError,
16 },
17 #[error("serde: {source}")]
18 Serde {
19 #[from]
20 source: serde_json::Error,
21 },
22 #[error("parse int: {source}")]
23 Parse {
24 #[from]
25 source: ParseIntError,
26 },
27 #[error("parse header: {source}")]
28 InvalidHeaderValue {
29 #[from]
30 source: InvalidHeaderValue,
31 },
32 #[error("tungstenite: {source}")]
33 Tungstenite {
34 #[from]
35 source: tokio_tungstenite::tungstenite::Error,
36 },
37 #[error("faulty websocket response")]
38 WsResponse,
39 #[error("authorization failed")]
40 Authorization,
41 #[error("Http error status: {0}")]
42 HttpStatus(u16),
21} 43}
diff --git a/src/main.rs b/src/main.rs
index afe6fac..5a0931d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,21 +1,24 @@
1use std::{fmt::Display, time::Duration}; 1use std::{fmt::Display, time::Duration};
2 2
3use clap::{Parser, Command, CommandFactory, Subcommand}; 3use crate::config::Config;
4use clap_complete::{generate, Shell, Generator}; 4use clap::{Command, CommandFactory, Parser, Subcommand};
5use config::SETTINGS; 5use clap_complete::{generate, Generator, Shell};
6use error::CliError; 6use error::Error;
7use indicatif::{ProgressBar, ProgressStyle, MultiProgress}; 7use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
8use requests::{start::start, device}; 8use requests::{device, start::start};
9use reqwest::header::{HeaderMap, HeaderValue}; 9use reqwest::{
10 header::{HeaderMap, HeaderValue},
11 Response,
12};
10use serde::Deserialize; 13use serde::Deserialize;
11 14
12mod config; 15mod config;
13mod error; 16mod error;
14mod requests; 17mod requests;
15 18
16static OVERVIEW_STYLE: &str = "{spinner:.green} ({elapsed}{wide_msg}"; 19static OVERVIEW_STYLE: &str = "{spinner:.green} ({elapsed_precise}{wide_msg}";
17static OVERVIEW_ERROR: &str = "✗ ({elapsed}) {wide_msg}"; 20static OVERVIEW_ERROR: &str = "✗ ({elapsed_precise}) {wide_msg}";
18static OVERVIEW_DONE: &str = "✓ ({elapsed}) {wide_msg}"; 21static OVERVIEW_DONE: &str = "✓ ({elapsed_precise}) {wide_msg}";
19static DEFAULT_STYLE: &str = " {spinner:.green} {wide_msg}"; 22static DEFAULT_STYLE: &str = " {spinner:.green} {wide_msg}";
20static DONE_STYLE: &str = " ✓ {wide_msg}"; 23static DONE_STYLE: &str = " ✓ {wide_msg}";
21static ERROR_STYLE: &str = " ✗ {wide_msg}"; 24static ERROR_STYLE: &str = " ✗ {wide_msg}";
@@ -35,7 +38,7 @@ enum Commands {
35 /// id of the device 38 /// id of the device
36 id: String, 39 id: String,
37 #[arg(short, long)] 40 #[arg(short, long)]
38 ping: Option<bool> 41 ping: Option<bool>,
39 }, 42 },
40 Device { 43 Device {
41 #[command(subcommand)] 44 #[command(subcommand)]
@@ -52,7 +55,7 @@ enum DeviceCmd {
52 id: String, 55 id: String,
53 mac: String, 56 mac: String,
54 broadcast_addr: String, 57 broadcast_addr: String,
55 ip: String 58 ip: String,
56 }, 59 },
57 Get { 60 Get {
58 id: String, 61 id: String,
@@ -61,35 +64,45 @@ enum DeviceCmd {
61 id: String, 64 id: String,
62 mac: String, 65 mac: String,
63 broadcast_addr: String, 66 broadcast_addr: String,
64 ip: String 67 ip: String,
65 }, 68 },
66} 69}
67 70
68#[tokio::main] 71#[tokio::main]
69async fn main() -> Result<(), CliError> { 72async fn main() -> Result<(), anyhow::Error> {
73 let config = Config::load()?;
74
70 let cli = Args::parse(); 75 let cli = Args::parse();
71 76
72 match cli.commands { 77 match cli.commands {
73 Commands::Start { id, ping } => { 78 Commands::Start { id, ping } => {
74 start(id, ping.unwrap_or(true)).await?; 79 start(&config, id, ping.unwrap_or(true)).await?;
75 }, 80 }
76 Commands::Device { devicecmd } => { 81 Commands::Device { devicecmd } => match devicecmd {
77 match devicecmd { 82 DeviceCmd::Add {
78 DeviceCmd::Add { id, mac, broadcast_addr, ip } => { 83 id,
79 device::put(id, mac, broadcast_addr, ip).await?; 84 mac,
80 }, 85 broadcast_addr,
81 DeviceCmd::Get { id } => { 86 ip,
82 device::get(id).await?; 87 } => {
83 }, 88 device::put(&config, id, mac, broadcast_addr, ip).await?;
84 DeviceCmd::Edit { id, mac, broadcast_addr, ip } => { 89 }
85 device::post(id, mac, broadcast_addr, ip).await?; 90 DeviceCmd::Get { id } => {
86 }, 91 device::get(&config, id).await?;
92 }
93 DeviceCmd::Edit {
94 id,
95 mac,
96 broadcast_addr,
97 ip,
98 } => {
99 device::post(&config, id, mac, broadcast_addr, ip).await?;
87 } 100 }
88 }, 101 },
89 Commands::CliGen { id } => { 102 Commands::CliGen { id } => {
90 eprintln!("Generating completion file for {id:?}..."); 103 eprintln!("Generating completion file for {id:?}...");
91 let mut cmd = Args::command(); 104 let mut cmd = Args::command();
92 print_completions(id, &mut cmd) 105 print_completions(id, &mut cmd);
93 } 106 }
94 } 107 }
95 108
@@ -100,29 +113,28 @@ fn print_completions<G: Generator>(gen: G, cmd: &mut Command) {
100 generate(gen, cmd, cmd.get_name().to_string(), &mut std::io::stdout()); 113 generate(gen, cmd, cmd.get_name().to_string(), &mut std::io::stdout());
101} 114}
102 115
103fn default_headers() -> Result<HeaderMap, CliError> { 116fn default_headers(config: &Config) -> Result<HeaderMap, Error> {
104 let mut map = HeaderMap::new(); 117 let mut map = HeaderMap::new();
105 map.append("Accept-Content", HeaderValue::from_str("application/json").unwrap()); 118 map.append("Accept-Content", HeaderValue::from_str("application/json")?);
106 map.append("Content-Type", HeaderValue::from_str("application/json").unwrap()); 119 map.append("Content-Type", HeaderValue::from_str("application/json")?);
107 map.append( 120 map.append("Authorization", HeaderValue::from_str(&config.apikey)?);
108 "Authorization",
109 HeaderValue::from_str(
110 SETTINGS.get_string("key")
111 .map_err(CliError::Config)?
112 .as_str()
113 ).unwrap()
114 );
115 121
116 Ok(map) 122 Ok(map)
117} 123}
118 124
119fn format_url(path: &str, protocol: Protocols) -> Result<String, CliError> { 125fn format_url(config: &Config, path: &str, protocol: &Protocols) -> String {
120 Ok(format!( 126 format!("{}://{}/{}", protocol, config.server, path)
121 "{}://{}/{}", 127}
122 protocol, 128
123 SETTINGS.get_string("server").map_err(CliError::Config)?, 129async fn check_success(res: Response) -> Result<String, Error> {
124 path 130 let status = res.status();
125 )) 131 if status.is_success() {
132 Ok(res.text().await?)
133 } else if status.as_u16() == 401 {
134 Err(Error::Authorization)
135 } else {
136 Err(Error::HttpStatus(status.as_u16()))
137 }
126} 138}
127 139
128fn add_pb(mp: &MultiProgress, template: &str, message: String) -> ProgressBar { 140fn add_pb(mp: &MultiProgress, template: &str, message: String) -> ProgressBar {
@@ -134,10 +146,9 @@ fn add_pb(mp: &MultiProgress, template: &str, message: String) -> ProgressBar {
134 pb 146 pb
135} 147}
136 148
137fn finish_pb(pb: ProgressBar, message: String, template: &str) { 149fn finish_pb(pb: &ProgressBar, message: String, template: &str) {
138 pb.set_style(ProgressStyle::with_template(template).unwrap()); 150 pb.set_style(ProgressStyle::with_template(template).unwrap());
139 pb.finish_with_message(message); 151 pb.finish_with_message(message);
140
141} 152}
142 153
143enum Protocols { 154enum Protocols {
@@ -149,12 +160,12 @@ impl Display for Protocols {
149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 match self { 161 match self {
151 Self::Http => f.write_str("http"), 162 Self::Http => f.write_str("http"),
152 Self::Websocket => f.write_str("ws") 163 Self::Websocket => f.write_str("ws"),
153 } 164 }
154 } 165 }
155} 166}
156 167
157#[derive(Debug, Deserialize)] 168#[derive(Debug, Deserialize)]
158struct ErrorResponse { 169struct ErrorResponse {
159 error: String 170 error: String,
160} 171}
diff --git a/src/requests/mod.rs b/src/requests.rs
index 6855db1..6855db1 100644
--- a/src/requests/mod.rs
+++ b/src/requests.rs
diff --git a/src/requests/device.rs b/src/requests/device.rs
index cbc838e..7583406 100644
--- a/src/requests/device.rs
+++ b/src/requests/device.rs
@@ -1,66 +1,58 @@
1use crate::{error::CliError, default_headers, format_url, Protocols}; 1use crate::{check_success, config::Config, default_headers, error::Error, format_url, Protocols};
2 2
3pub async fn put(id: String, mac: String, broadcast_addr: String, ip: String) -> Result<(), CliError> { 3pub async fn put(
4 let url = format_url("device", Protocols::Http)?; 4 config: &Config,
5 println!("{}", url); 5 id: String,
6 mac: String,
7 broadcast_addr: String,
8 ip: String,
9) -> Result<(), Error> {
10 let url = format_url(config, "device", &Protocols::Http);
11 println!("{url}");
6 let res = reqwest::Client::new() 12 let res = reqwest::Client::new()
7 .put(url) 13 .put(url)
8 .headers(default_headers()?) 14 .headers(default_headers(config)?)
9 .body( 15 .body(format!(
10 format!( 16 r#"{{"id": "{id}", "mac": "{mac}", "broadcast_addr": "{broadcast_addr}", "ip": "{ip}"}}"#,
11 r#"{{"id": "{}", "mac": "{}", "broadcast_addr": "{}", "ip": "{}"}}"#, 17 ))
12 id,
13 mac,
14 broadcast_addr,
15 ip
16 )
17 )
18 .send() 18 .send()
19 .await 19 .await?;
20 .map_err(CliError::Reqwest)?
21 .text()
22 .await;
23 20
24 println!("{:?}", res); 21 let body = check_success(res).await?;
22 println!("{body}");
25 Ok(()) 23 Ok(())
26} 24}
27 25
28pub async fn get(id: String) -> Result<(), CliError> { 26pub async fn get(config: &Config, id: String) -> Result<(), Error> {
29 let res = reqwest::Client::new() 27 let res = reqwest::Client::new()
30 .get(format_url("device", Protocols::Http)?) 28 .get(format_url(config, "device", &Protocols::Http))
31 .headers(default_headers()?) 29 .headers(default_headers(config)?)
32 .body( 30 .body(format!(r#"{{"id": "{id}"}}"#))
33 format!(r#"{{"id": "{}"}}"#, id)
34 )
35 .send() 31 .send()
36 .await 32 .await?;
37 .map_err(CliError::Reqwest)?
38 .text()
39 .await;
40 33
41 println!("{:?}", res); 34 let body = check_success(res).await?;
35 println!("{body}");
42 Ok(()) 36 Ok(())
43} 37}
44 38
45pub async fn post(id: String, mac: String, broadcast_addr: String, ip: String) -> Result<(), CliError> { 39pub async fn post(
40 config: &Config,
41 id: String,
42 mac: String,
43 broadcast_addr: String,
44 ip: String,
45) -> Result<(), Error> {
46 let res = reqwest::Client::new() 46 let res = reqwest::Client::new()
47 .post(format_url("device", Protocols::Http)?) 47 .post(format_url(config, "device", &Protocols::Http))
48 .headers(default_headers()?) 48 .headers(default_headers(config)?)
49 .body( 49 .body(format!(
50 format!( 50 r#"{{"id": "{id}", "mac": "{mac}", "broadcast_addr": "{broadcast_addr}", "ip": "{ip}"}}"#,
51 r#"{{"id": "{}", "mac": "{}", "broadcast_addr": "{}", "ip": "{}"}}"#, 51 ))
52 id,
53 mac,
54 broadcast_addr,
55 ip
56 )
57 )
58 .send() 52 .send()
59 .await 53 .await?;
60 .map_err(CliError::Reqwest)?
61 .text()
62 .await;
63 54
64 println!("{:?}", res); 55 let body = check_success(res).await?;
56 println!("{body}");
65 Ok(()) 57 Ok(())
66} 58}
diff --git a/src/requests/start.rs b/src/requests/start.rs
index ca4ca44..3afbe3a 100644
--- a/src/requests/start.rs
+++ b/src/requests/start.rs
@@ -1,124 +1,149 @@
1use futures_util::{StreamExt, SinkExt}; 1use futures_util::{SinkExt, StreamExt};
2use indicatif::{MultiProgress, ProgressBar}; 2use indicatif::{MultiProgress, ProgressBar};
3use reqwest::StatusCode; 3use reqwest::StatusCode;
4use serde::Deserialize; 4use serde::Deserialize;
5use tokio_tungstenite::{connect_async, tungstenite::Message}; 5use tokio_tungstenite::{
6 6 connect_async,
7use crate::{error::CliError, default_headers, ErrorResponse, format_url, Protocols, OVERVIEW_STYLE, DEFAULT_STYLE, DONE_STYLE, finish_pb, ERROR_STYLE, OVERVIEW_ERROR, OVERVIEW_DONE, add_pb}; 7 tungstenite::{http::Request, Message},
8 8};
9pub async fn start(id: String, ping: bool) -> Result<(), CliError> { 9
10 10use crate::{
11 add_pb, config::Config, default_headers, error::Error, finish_pb, format_url, ErrorResponse,
12 Protocols, DEFAULT_STYLE, DONE_STYLE, ERROR_STYLE, OVERVIEW_DONE, OVERVIEW_ERROR,
13 OVERVIEW_STYLE,
14};
15
16pub async fn start(config: &Config, id: String, ping: bool) -> Result<(), Error> {
11 let send_start = MultiProgress::new(); 17 let send_start = MultiProgress::new();
12 let overview = add_pb(&send_start, OVERVIEW_STYLE, format!(") start {}", id)); 18 let overview = add_pb(&send_start, OVERVIEW_STYLE, format!(") start {id}"));
13 19
14 // TODO: calculate average start-time on server 20 let url = format_url(config, "start", &Protocols::Http);
15 let url = format_url("start", Protocols::Http)?; 21 let connect = add_pb(&send_start, DEFAULT_STYLE, format!("connect to {url}"));
16 let connect = add_pb(&send_start, DEFAULT_STYLE, format!("connect to {}", url));
17 let res = reqwest::Client::new() 22 let res = reqwest::Client::new()
18 .post(url) 23 .post(url)
19 .headers(default_headers()?) 24 .headers(default_headers(config)?)
20 .body( 25 .body(format!(r#"{{"id": "{id}", "ping": {ping}}}"#))
21 format!(r#"{{"id": "{}", "ping": {}}}"#, id, ping)
22 )
23 .send() 26 .send()
24 .await 27 .await?;
25 .map_err(CliError::Reqwest)?; 28 finish_pb(&connect, "connected, got response".to_string(), DONE_STYLE);
26 finish_pb(connect, "connected, got response".to_string(), DONE_STYLE);
27 29
28 let res_pb = add_pb(&send_start, DEFAULT_STYLE, "analyzing response".to_string()); 30 let res_pb = add_pb(&send_start, DEFAULT_STYLE, "analyzing response".to_string());
29 match res.status() {
30 StatusCode::OK => {
31 let body = serde_json::from_str::<StartResponse>(
32 &res.text().await.map_err(CliError::Reqwest)?
33 )
34 .map_err(CliError::Serde)?;
35
36 if body.boot {
37 finish_pb(res_pb, "sent start packet".to_string(), DONE_STYLE);
38 }
39 31
40 if ping { 32 if res.status() == StatusCode::OK {
41 let status = status_socket(body.uuid, &send_start, &overview, id).await?; 33 let body = serde_json::from_str::<StartResponse>(&res.text().await?)?;
42 if status {
43 finish_pb(overview, format!("successfully started {}", body.id), OVERVIEW_DONE);
44 } else {
45 finish_pb(overview, format!("error while starting {}", body.id), OVERVIEW_ERROR);
46 }
47 }
48 },
49 _ => {
50 let body = serde_json::from_str::<ErrorResponse>(
51 &res.text().await.map_err(CliError::Reqwest)?
52 )
53 .map_err(CliError::Serde)?;
54 34
55 res_pb.finish_with_message(format!("✗ got error: {}", body.error)); 35 if body.boot {
36 finish_pb(&res_pb, "sent start packet".to_string(), DONE_STYLE);
56 } 37 }
38
39 if ping {
40 let status = status_socket(config, body.uuid, &send_start, &overview, id).await?;
41 if status {
42 finish_pb(
43 &overview,
44 format!("successfully started {}", body.id),
45 OVERVIEW_DONE,
46 );
47 } else {
48 finish_pb(
49 &overview,
50 format!("error while starting {}", body.id),
51 OVERVIEW_ERROR,
52 );
53 }
54 }
55 } else {
56 let body = serde_json::from_str::<ErrorResponse>(&res.text().await?)?;
57
58 res_pb.finish_with_message(format!("✗ got error: {}", body.error));
57 } 59 }
58 60
59 Ok(()) 61 Ok(())
60} 62}
61 63
62async fn status_socket(uuid: String, pb: &MultiProgress, overview: &ProgressBar, id: String) -> Result<bool, CliError> { 64async fn status_socket(
63 // TODO: Remove unwraps 65 config: &Config,
66 uuid: String,
67 pb: &MultiProgress,
68 overview: &ProgressBar,
69 id: String,
70) -> Result<bool, Error> {
64 let ws_pb = add_pb(pb, DEFAULT_STYLE, "connect to websocket".to_string()); 71 let ws_pb = add_pb(pb, DEFAULT_STYLE, "connect to websocket".to_string());
65 let (mut ws_stream, _response) = connect_async(format_url("status", Protocols::Websocket)?) 72
66 .await 73 let request = Request::builder()
67 .expect("Failed to connect"); 74 .uri(format_url(config, "status", &Protocols::Websocket))
68 finish_pb(ws_pb, "connected to websocket".to_string(), DONE_STYLE); 75 .header("Authorization", &config.apikey)
69 76 .header("sec-websocket-key", "")
77 .header("host", &config.server)
78 .header("upgrade", "websocket")
79 .header("connection", "upgrade")
80 .header("sec-websocket-version", 13)
81 .body(())
82 .unwrap();
83
84 let (mut ws_stream, _response) = connect_async(request).await?;
85 finish_pb(&ws_pb, "connected to websocket".to_string(), DONE_STYLE);
86
70 ws_stream.send(Message::Text(uuid.clone())).await.unwrap(); 87 ws_stream.send(Message::Text(uuid.clone())).await.unwrap();
71 88
72 // Get ETA 89 // Get ETA
73 let eta_msg = ws_stream.next().await.unwrap().unwrap(); 90 let eta_msg = ws_stream.next().await.unwrap().unwrap();
74 let eta = get_eta(eta_msg.into_text().unwrap(), uuid.clone())? + overview.elapsed().as_secs(); 91 let eta = get_eta(&eta_msg.into_text().unwrap(), &uuid)?;
75 overview.set_message(format!("/{}) start {}", eta, id)); 92 overview.set_message(format!("/{eta}) start {id}"));
76 93
77 let msg_pb = add_pb(pb, DEFAULT_STYLE, "await message".to_string()); 94 let msg_pb = add_pb(pb, DEFAULT_STYLE, "await message".to_string());
78 let msg = ws_stream.next().await.unwrap(); 95 let msg = ws_stream.next().await.unwrap();
79 finish_pb(msg_pb, "received message".to_string(), DONE_STYLE); 96 finish_pb(&msg_pb, "received message".to_string(), DONE_STYLE);
80 97
81 ws_stream.close(None).await.unwrap(); 98 ws_stream.close(None).await.unwrap();
82 99
83 let v_pb = add_pb(pb, DEFAULT_STYLE, "verify response".to_string()); 100 let v_pb = add_pb(pb, DEFAULT_STYLE, "verify response".to_string());
84 let res = verify_response(msg.unwrap().to_string(), uuid)?; 101 let res = verify_response(&msg.unwrap().to_string(), &uuid)?;
85 match res { 102 match res {
86 Verified::WrongUuid => { 103 Verified::WrongUuid => {
87 finish_pb(v_pb, "returned wrong uuid".to_string(), ERROR_STYLE); 104 finish_pb(&v_pb, "returned wrong uuid".to_string(), ERROR_STYLE);
88 Ok(false) 105 Ok(false)
89 },
90 Verified::ResponseType(res_type) => {
91 match res_type {
92 ResponseType::Start => {
93 finish_pb(v_pb, "device started".to_string(), DONE_STYLE);
94 Ok(true)
95 },
96 ResponseType::Timeout => {
97 finish_pb(v_pb, "ping timed out".to_string(), ERROR_STYLE);
98 Ok(false)
99 },
100 ResponseType::NotFound => {
101 finish_pb(v_pb, "unknown uuid".to_string(), ERROR_STYLE);
102 Ok(false)
103 },
104 }
105 } 106 }
107 Verified::ResponseType(res_type) => match res_type {
108 ResponseType::Start => {
109 finish_pb(&v_pb, "device started".to_string(), DONE_STYLE);
110 Ok(true)
111 }
112 ResponseType::Timeout => {
113 finish_pb(&v_pb, "ping timed out".to_string(), ERROR_STYLE);
114 Ok(false)
115 }
116 ResponseType::NotFound => {
117 finish_pb(&v_pb, "unknown uuid".to_string(), ERROR_STYLE);
118 Ok(false)
119 }
120 },
106 } 121 }
107} 122}
108 123
109fn get_eta(msg: String, uuid: String) -> Result<u64, CliError> { 124fn get_eta(msg: &str, uuid: &str) -> Result<String, Error> {
110 let spl: Vec<&str> = msg.split('_').collect(); 125 let spl: Vec<&str> = msg.split('_').collect();
111 if (spl[0] != "eta") || (spl[2] != uuid) { return Err(CliError::WsResponse); }; 126 if (spl[0] != "eta") || (spl[2] != uuid) {
112 Ok(u64::from_str_radix(spl[1], 10).map_err(CliError::Parse)?) 127 return Err(Error::WsResponse);
128 };
129 let input: u64 = spl[1].parse()?;
130
131 let sec = input % 60;
132 let min = (input / 60) % 60;
133 let hou = (input / (60 * 60)) % 60;
134
135 Ok(format!("{hou:0>2}:{min:0>2}:{sec:0>2}"))
113} 136}
114 137
115fn verify_response(res: String, org_uuid: String) -> Result<Verified, CliError> { 138fn verify_response(res: &str, org_uuid: &str) -> Result<Verified, Error> {
116 let spl: Vec<&str> = res.split('_').collect(); 139 let spl: Vec<&str> = res.split('_').collect();
117 let res_type = spl[0]; 140 let res_type = spl[0];
118 let uuid = spl[1]; 141 let uuid = spl[1];
119 142
120 if uuid != org_uuid { return Ok(Verified::WrongUuid) }; 143 if uuid != org_uuid {
121 144 return Ok(Verified::WrongUuid);
145 };
146
122 Ok(Verified::ResponseType(ResponseType::from(res_type)?)) 147 Ok(Verified::ResponseType(ResponseType::from(res_type)?))
123} 148}
124 149
@@ -131,7 +156,7 @@ struct StartResponse {
131 156
132enum Verified { 157enum Verified {
133 ResponseType(ResponseType), 158 ResponseType(ResponseType),
134 WrongUuid 159 WrongUuid,
135} 160}
136 161
137enum ResponseType { 162enum ResponseType {
@@ -141,12 +166,12 @@ enum ResponseType {
141} 166}
142 167
143impl ResponseType { 168impl ResponseType {
144 fn from(value: &str) -> Result<Self, CliError> { 169 fn from(value: &str) -> Result<Self, Error> {
145 match value { 170 match value {
146 "start" => Ok(ResponseType::Start), 171 "start" => Ok(ResponseType::Start),
147 "timeout" => Ok(ResponseType::Timeout), 172 "timeout" => Ok(ResponseType::Timeout),
148 "notfound" => Ok(ResponseType::NotFound), 173 "notfound" => Ok(ResponseType::NotFound),
149 _ => Err(CliError::WsResponse), 174 _ => Err(Error::WsResponse),
150 } 175 }
151 } 176 }
152} 177}