diff options
22 files changed, 687 insertions, 414 deletions
@@ -14,3 +14,6 @@ target/ | |||
14 | config.* | 14 | config.* |
15 | 15 | ||
16 | .idea | 16 | .idea |
17 | |||
18 | logs/ | ||
19 | *.log | ||
diff --git a/.sqlx/query-1dc5f44967ffdee882f4cef32262fd643b452aacca373ee527c978e816115de6.json b/.sqlx/query-1dc5f44967ffdee882f4cef32262fd643b452aacca373ee527c978e816115de6.json index 33d524d..dd85eaa 100644 --- a/.sqlx/query-1dc5f44967ffdee882f4cef32262fd643b452aacca373ee527c978e816115de6.json +++ b/.sqlx/query-1dc5f44967ffdee882f4cef32262fd643b452aacca373ee527c978e816115de6.json | |||
@@ -11,7 +11,7 @@ | |||
11 | { | 11 | { |
12 | "ordinal": 1, | 12 | "ordinal": 1, |
13 | "name": "mac", | 13 | "name": "mac", |
14 | "type_info": "Varchar" | 14 | "type_info": "Macaddr" |
15 | }, | 15 | }, |
16 | { | 16 | { |
17 | "ordinal": 2, | 17 | "ordinal": 2, |
@@ -21,7 +21,7 @@ | |||
21 | { | 21 | { |
22 | "ordinal": 3, | 22 | "ordinal": 3, |
23 | "name": "ip", | 23 | "name": "ip", |
24 | "type_info": "Varchar" | 24 | "type_info": "Inet" |
25 | }, | 25 | }, |
26 | { | 26 | { |
27 | "ordinal": 4, | 27 | "ordinal": 4, |
@@ -31,9 +31,9 @@ | |||
31 | ], | 31 | ], |
32 | "parameters": { | 32 | "parameters": { |
33 | "Left": [ | 33 | "Left": [ |
34 | "Macaddr", | ||
34 | "Varchar", | 35 | "Varchar", |
35 | "Varchar", | 36 | "Inet", |
36 | "Varchar", | ||
37 | "Text" | 37 | "Text" |
38 | ] | 38 | ] |
39 | }, | 39 | }, |
diff --git a/.sqlx/query-62c84231c7e9c85dc91d71f6b4f7ee6dae2130c2109fb6f1e47e0990ec395744.json b/.sqlx/query-62c84231c7e9c85dc91d71f6b4f7ee6dae2130c2109fb6f1e47e0990ec395744.json index 5ec47e3..905bb51 100644 --- a/.sqlx/query-62c84231c7e9c85dc91d71f6b4f7ee6dae2130c2109fb6f1e47e0990ec395744.json +++ b/.sqlx/query-62c84231c7e9c85dc91d71f6b4f7ee6dae2130c2109fb6f1e47e0990ec395744.json | |||
@@ -11,7 +11,7 @@ | |||
11 | { | 11 | { |
12 | "ordinal": 1, | 12 | "ordinal": 1, |
13 | "name": "mac", | 13 | "name": "mac", |
14 | "type_info": "Varchar" | 14 | "type_info": "Macaddr" |
15 | }, | 15 | }, |
16 | { | 16 | { |
17 | "ordinal": 2, | 17 | "ordinal": 2, |
@@ -21,7 +21,7 @@ | |||
21 | { | 21 | { |
22 | "ordinal": 3, | 22 | "ordinal": 3, |
23 | "name": "ip", | 23 | "name": "ip", |
24 | "type_info": "Varchar" | 24 | "type_info": "Inet" |
25 | }, | 25 | }, |
26 | { | 26 | { |
27 | "ordinal": 4, | 27 | "ordinal": 4, |
diff --git a/.sqlx/query-a1114f47abaa2ace231ef61cbd787a2f2a30efc581ea075b7e86ae75458c9014.json b/.sqlx/query-a1114f47abaa2ace231ef61cbd787a2f2a30efc581ea075b7e86ae75458c9014.json new file mode 100644 index 0000000..53608ed --- /dev/null +++ b/.sqlx/query-a1114f47abaa2ace231ef61cbd787a2f2a30efc581ea075b7e86ae75458c9014.json | |||
@@ -0,0 +1,46 @@ | |||
1 | { | ||
2 | "db_name": "PostgreSQL", | ||
3 | "query": "\n SELECT id, mac, broadcast_addr, ip, times\n FROM devices\n WHERE id = $1;\n ", | ||
4 | "describe": { | ||
5 | "columns": [ | ||
6 | { | ||
7 | "ordinal": 0, | ||
8 | "name": "id", | ||
9 | "type_info": "Varchar" | ||
10 | }, | ||
11 | { | ||
12 | "ordinal": 1, | ||
13 | "name": "mac", | ||
14 | "type_info": "Macaddr" | ||
15 | }, | ||
16 | { | ||
17 | "ordinal": 2, | ||
18 | "name": "broadcast_addr", | ||
19 | "type_info": "Varchar" | ||
20 | }, | ||
21 | { | ||
22 | "ordinal": 3, | ||
23 | "name": "ip", | ||
24 | "type_info": "Inet" | ||
25 | }, | ||
26 | { | ||
27 | "ordinal": 4, | ||
28 | "name": "times", | ||
29 | "type_info": "Int8Array" | ||
30 | } | ||
31 | ], | ||
32 | "parameters": { | ||
33 | "Left": [ | ||
34 | "Text" | ||
35 | ] | ||
36 | }, | ||
37 | "nullable": [ | ||
38 | false, | ||
39 | false, | ||
40 | false, | ||
41 | false, | ||
42 | true | ||
43 | ] | ||
44 | }, | ||
45 | "hash": "a1114f47abaa2ace231ef61cbd787a2f2a30efc581ea075b7e86ae75458c9014" | ||
46 | } | ||
diff --git a/.sqlx/query-adead45e1a6b02d5eabd68b8cf06394a302d288e91f5eedde65db6630021f737.json b/.sqlx/query-adead45e1a6b02d5eabd68b8cf06394a302d288e91f5eedde65db6630021f737.json index bc4bdd3..d25b12e 100644 --- a/.sqlx/query-adead45e1a6b02d5eabd68b8cf06394a302d288e91f5eedde65db6630021f737.json +++ b/.sqlx/query-adead45e1a6b02d5eabd68b8cf06394a302d288e91f5eedde65db6630021f737.json | |||
@@ -6,9 +6,9 @@ | |||
6 | "parameters": { | 6 | "parameters": { |
7 | "Left": [ | 7 | "Left": [ |
8 | "Varchar", | 8 | "Varchar", |
9 | "Macaddr", | ||
9 | "Varchar", | 10 | "Varchar", |
10 | "Varchar", | 11 | "Inet" |
11 | "Varchar" | ||
12 | ] | 12 | ] |
13 | }, | 13 | }, |
14 | "nullable": [] | 14 | "nullable": [] |
diff --git a/.sqlx/query-e452c5ed8bdaec2011d78386cffd2b4739d88b3061931562e07c3e8dd24e6359.json b/.sqlx/query-e452c5ed8bdaec2011d78386cffd2b4739d88b3061931562e07c3e8dd24e6359.json new file mode 100644 index 0000000..75ec121 --- /dev/null +++ b/.sqlx/query-e452c5ed8bdaec2011d78386cffd2b4739d88b3061931562e07c3e8dd24e6359.json | |||
@@ -0,0 +1,49 @@ | |||
1 | { | ||
2 | "db_name": "PostgreSQL", | ||
3 | "query": "\n UPDATE devices\n SET mac = $1, broadcast_addr = $2, ip = $3 WHERE id = $4\n RETURNING id, mac, broadcast_addr, ip, times;\n ", | ||
4 | "describe": { | ||
5 | "columns": [ | ||
6 | { | ||
7 | "ordinal": 0, | ||
8 | "name": "id", | ||
9 | "type_info": "Varchar" | ||
10 | }, | ||
11 | { | ||
12 | "ordinal": 1, | ||
13 | "name": "mac", | ||
14 | "type_info": "Macaddr" | ||
15 | }, | ||
16 | { | ||
17 | "ordinal": 2, | ||
18 | "name": "broadcast_addr", | ||
19 | "type_info": "Varchar" | ||
20 | }, | ||
21 | { | ||
22 | "ordinal": 3, | ||
23 | "name": "ip", | ||
24 | "type_info": "Inet" | ||
25 | }, | ||
26 | { | ||
27 | "ordinal": 4, | ||
28 | "name": "times", | ||
29 | "type_info": "Int8Array" | ||
30 | } | ||
31 | ], | ||
32 | "parameters": { | ||
33 | "Left": [ | ||
34 | "Macaddr", | ||
35 | "Varchar", | ||
36 | "Inet", | ||
37 | "Text" | ||
38 | ] | ||
39 | }, | ||
40 | "nullable": [ | ||
41 | false, | ||
42 | false, | ||
43 | false, | ||
44 | false, | ||
45 | true | ||
46 | ] | ||
47 | }, | ||
48 | "hash": "e452c5ed8bdaec2011d78386cffd2b4739d88b3061931562e07c3e8dd24e6359" | ||
49 | } | ||
diff --git a/.sqlx/query-edc4ecf39512caec1076be1b2849b2530be7bcdcbe14362077b3fd47cd711c89.json b/.sqlx/query-edc4ecf39512caec1076be1b2849b2530be7bcdcbe14362077b3fd47cd711c89.json new file mode 100644 index 0000000..2b17c9b --- /dev/null +++ b/.sqlx/query-edc4ecf39512caec1076be1b2849b2530be7bcdcbe14362077b3fd47cd711c89.json | |||
@@ -0,0 +1,17 @@ | |||
1 | { | ||
2 | "db_name": "PostgreSQL", | ||
3 | "query": "\n INSERT INTO devices (id, mac, broadcast_addr, ip)\n VALUES ($1, $2, $3, $4);\n ", | ||
4 | "describe": { | ||
5 | "columns": [], | ||
6 | "parameters": { | ||
7 | "Left": [ | ||
8 | "Varchar", | ||
9 | "Macaddr", | ||
10 | "Varchar", | ||
11 | "Inet" | ||
12 | ] | ||
13 | }, | ||
14 | "nullable": [] | ||
15 | }, | ||
16 | "hash": "edc4ecf39512caec1076be1b2849b2530be7bcdcbe14362077b3fd47cd711c89" | ||
17 | } | ||
@@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" | |||
19 | 19 | ||
20 | [[package]] | 20 | [[package]] |
21 | name = "ahash" | 21 | name = "ahash" |
22 | version = "0.8.8" | 22 | version = "0.8.9" |
23 | source = "registry+https://github.com/rust-lang/crates.io-index" | 23 | source = "registry+https://github.com/rust-lang/crates.io-index" |
24 | checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" | 24 | checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" |
25 | dependencies = [ | 25 | dependencies = [ |
26 | "cfg-if", | 26 | "cfg-if", |
27 | "getrandom", | 27 | "getrandom", |
@@ -53,7 +53,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" | |||
53 | dependencies = [ | 53 | dependencies = [ |
54 | "proc-macro2", | 54 | "proc-macro2", |
55 | "quote", | 55 | "quote", |
56 | "syn 2.0.48", | 56 | "syn 2.0.50", |
57 | ] | 57 | ] |
58 | 58 | ||
59 | [[package]] | 59 | [[package]] |
@@ -71,7 +71,7 @@ version = "0.1.2" | |||
71 | source = "registry+https://github.com/rust-lang/crates.io-index" | 71 | source = "registry+https://github.com/rust-lang/crates.io-index" |
72 | checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" | 72 | checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" |
73 | dependencies = [ | 73 | dependencies = [ |
74 | "nix", | 74 | "nix 0.27.1", |
75 | "rand", | 75 | "rand", |
76 | ] | 76 | ] |
77 | 77 | ||
@@ -148,7 +148,7 @@ dependencies = [ | |||
148 | "heck", | 148 | "heck", |
149 | "proc-macro2", | 149 | "proc-macro2", |
150 | "quote", | 150 | "quote", |
151 | "syn 2.0.48", | 151 | "syn 2.0.50", |
152 | ] | 152 | ] |
153 | 153 | ||
154 | [[package]] | 154 | [[package]] |
@@ -216,12 +216,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" | |||
216 | 216 | ||
217 | [[package]] | 217 | [[package]] |
218 | name = "cc" | 218 | name = "cc" |
219 | version = "1.0.83" | 219 | version = "1.0.88" |
220 | source = "registry+https://github.com/rust-lang/crates.io-index" | 220 | source = "registry+https://github.com/rust-lang/crates.io-index" |
221 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" | 221 | checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" |
222 | dependencies = [ | ||
223 | "libc", | ||
224 | ] | ||
225 | 222 | ||
226 | [[package]] | 223 | [[package]] |
227 | name = "cfg-if" | 224 | name = "cfg-if" |
@@ -336,6 +333,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
336 | checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" | 333 | checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" |
337 | 334 | ||
338 | [[package]] | 335 | [[package]] |
336 | name = "crossbeam-channel" | ||
337 | version = "0.5.11" | ||
338 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
339 | checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" | ||
340 | dependencies = [ | ||
341 | "crossbeam-utils", | ||
342 | ] | ||
343 | |||
344 | [[package]] | ||
339 | name = "crossbeam-queue" | 345 | name = "crossbeam-queue" |
340 | version = "0.3.11" | 346 | version = "0.3.11" |
341 | source = "registry+https://github.com/rust-lang/crates.io-index" | 347 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -682,9 +688,9 @@ dependencies = [ | |||
682 | 688 | ||
683 | [[package]] | 689 | [[package]] |
684 | name = "hermit-abi" | 690 | name = "hermit-abi" |
685 | version = "0.3.5" | 691 | version = "0.3.8" |
686 | source = "registry+https://github.com/rust-lang/crates.io-index" | 692 | source = "registry+https://github.com/rust-lang/crates.io-index" |
687 | checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" | 693 | checksum = "379dada1584ad501b383485dd706b8afb7a70fcbc7f4da7d780638a5a6124a60" |
688 | 694 | ||
689 | [[package]] | 695 | [[package]] |
690 | name = "hex" | 696 | name = "hex" |
@@ -767,9 +773,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" | |||
767 | 773 | ||
768 | [[package]] | 774 | [[package]] |
769 | name = "hyper" | 775 | name = "hyper" |
770 | version = "1.1.0" | 776 | version = "1.2.0" |
771 | source = "registry+https://github.com/rust-lang/crates.io-index" | 777 | source = "registry+https://github.com/rust-lang/crates.io-index" |
772 | checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75" | 778 | checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" |
773 | dependencies = [ | 779 | dependencies = [ |
774 | "bytes", | 780 | "bytes", |
775 | "futures-channel", | 781 | "futures-channel", |
@@ -781,6 +787,7 @@ dependencies = [ | |||
781 | "httpdate", | 787 | "httpdate", |
782 | "itoa", | 788 | "itoa", |
783 | "pin-project-lite", | 789 | "pin-project-lite", |
790 | "smallvec", | ||
784 | "tokio", | 791 | "tokio", |
785 | ] | 792 | ] |
786 | 793 | ||
@@ -827,6 +834,15 @@ dependencies = [ | |||
827 | ] | 834 | ] |
828 | 835 | ||
829 | [[package]] | 836 | [[package]] |
837 | name = "ipnetwork" | ||
838 | version = "0.20.0" | ||
839 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
840 | checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" | ||
841 | dependencies = [ | ||
842 | "serde", | ||
843 | ] | ||
844 | |||
845 | [[package]] | ||
830 | name = "itertools" | 846 | name = "itertools" |
831 | version = "0.12.1" | 847 | version = "0.12.1" |
832 | source = "registry+https://github.com/rust-lang/crates.io-index" | 848 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -913,6 +929,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
913 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" | 929 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" |
914 | 930 | ||
915 | [[package]] | 931 | [[package]] |
932 | name = "mac_address" | ||
933 | version = "1.1.5" | ||
934 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
935 | checksum = "4863ee94f19ed315bf3bc00299338d857d4b5bc856af375cc97d237382ad3856" | ||
936 | dependencies = [ | ||
937 | "nix 0.23.2", | ||
938 | "serde", | ||
939 | "winapi", | ||
940 | ] | ||
941 | |||
942 | [[package]] | ||
916 | name = "matchers" | 943 | name = "matchers" |
917 | version = "0.1.0" | 944 | version = "0.1.0" |
918 | source = "registry+https://github.com/rust-lang/crates.io-index" | 945 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -944,6 +971,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
944 | checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" | 971 | checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" |
945 | 972 | ||
946 | [[package]] | 973 | [[package]] |
974 | name = "memoffset" | ||
975 | version = "0.6.5" | ||
976 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
977 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" | ||
978 | dependencies = [ | ||
979 | "autocfg", | ||
980 | ] | ||
981 | |||
982 | [[package]] | ||
947 | name = "mime" | 983 | name = "mime" |
948 | version = "0.3.17" | 984 | version = "0.3.17" |
949 | source = "registry+https://github.com/rust-lang/crates.io-index" | 985 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -977,6 +1013,19 @@ dependencies = [ | |||
977 | 1013 | ||
978 | [[package]] | 1014 | [[package]] |
979 | name = "nix" | 1015 | name = "nix" |
1016 | version = "0.23.2" | ||
1017 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1018 | checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" | ||
1019 | dependencies = [ | ||
1020 | "bitflags 1.3.2", | ||
1021 | "cc", | ||
1022 | "cfg-if", | ||
1023 | "libc", | ||
1024 | "memoffset", | ||
1025 | ] | ||
1026 | |||
1027 | [[package]] | ||
1028 | name = "nix" | ||
980 | version = "0.27.1" | 1029 | version = "0.27.1" |
981 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" |
982 | checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" | 1031 | checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" |
@@ -1077,9 +1126,9 @@ dependencies = [ | |||
1077 | 1126 | ||
1078 | [[package]] | 1127 | [[package]] |
1079 | name = "num_threads" | 1128 | name = "num_threads" |
1080 | version = "0.1.6" | 1129 | version = "0.1.7" |
1081 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1082 | checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" | 1131 | checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" |
1083 | dependencies = [ | 1132 | dependencies = [ |
1084 | "libc", | 1133 | "libc", |
1085 | ] | 1134 | ] |
@@ -1202,7 +1251,7 @@ dependencies = [ | |||
1202 | "pest_meta", | 1251 | "pest_meta", |
1203 | "proc-macro2", | 1252 | "proc-macro2", |
1204 | "quote", | 1253 | "quote", |
1205 | "syn 2.0.48", | 1254 | "syn 2.0.50", |
1206 | ] | 1255 | ] |
1207 | 1256 | ||
1208 | [[package]] | 1257 | [[package]] |
@@ -1233,7 +1282,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" | |||
1233 | dependencies = [ | 1282 | dependencies = [ |
1234 | "proc-macro2", | 1283 | "proc-macro2", |
1235 | "quote", | 1284 | "quote", |
1236 | "syn 2.0.48", | 1285 | "syn 2.0.50", |
1237 | ] | 1286 | ] |
1238 | 1287 | ||
1239 | [[package]] | 1288 | [[package]] |
@@ -1271,9 +1320,9 @@ dependencies = [ | |||
1271 | 1320 | ||
1272 | [[package]] | 1321 | [[package]] |
1273 | name = "pkg-config" | 1322 | name = "pkg-config" |
1274 | version = "0.3.29" | 1323 | version = "0.3.30" |
1275 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1276 | checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" | 1325 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" |
1277 | 1326 | ||
1278 | [[package]] | 1327 | [[package]] |
1279 | name = "pnet_base" | 1328 | name = "pnet_base" |
@@ -1499,9 +1548,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" | |||
1499 | 1548 | ||
1500 | [[package]] | 1549 | [[package]] |
1501 | name = "ryu" | 1550 | name = "ryu" |
1502 | version = "1.0.16" | 1551 | version = "1.0.17" |
1503 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1552 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1504 | checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" | 1553 | checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" |
1505 | 1554 | ||
1506 | [[package]] | 1555 | [[package]] |
1507 | name = "scopeguard" | 1556 | name = "scopeguard" |
@@ -1511,29 +1560,29 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" | |||
1511 | 1560 | ||
1512 | [[package]] | 1561 | [[package]] |
1513 | name = "serde" | 1562 | name = "serde" |
1514 | version = "1.0.196" | 1563 | version = "1.0.197" |
1515 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1564 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1516 | checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" | 1565 | checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" |
1517 | dependencies = [ | 1566 | dependencies = [ |
1518 | "serde_derive", | 1567 | "serde_derive", |
1519 | ] | 1568 | ] |
1520 | 1569 | ||
1521 | [[package]] | 1570 | [[package]] |
1522 | name = "serde_derive" | 1571 | name = "serde_derive" |
1523 | version = "1.0.196" | 1572 | version = "1.0.197" |
1524 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1573 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1525 | checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" | 1574 | checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" |
1526 | dependencies = [ | 1575 | dependencies = [ |
1527 | "proc-macro2", | 1576 | "proc-macro2", |
1528 | "quote", | 1577 | "quote", |
1529 | "syn 2.0.48", | 1578 | "syn 2.0.50", |
1530 | ] | 1579 | ] |
1531 | 1580 | ||
1532 | [[package]] | 1581 | [[package]] |
1533 | name = "serde_json" | 1582 | name = "serde_json" |
1534 | version = "1.0.113" | 1583 | version = "1.0.114" |
1535 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1584 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1536 | checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" | 1585 | checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" |
1537 | dependencies = [ | 1586 | dependencies = [ |
1538 | "itoa", | 1587 | "itoa", |
1539 | "ryu", | 1588 | "ryu", |
@@ -1629,12 +1678,12 @@ checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" | |||
1629 | 1678 | ||
1630 | [[package]] | 1679 | [[package]] |
1631 | name = "socket2" | 1680 | name = "socket2" |
1632 | version = "0.5.5" | 1681 | version = "0.5.6" |
1633 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1682 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1634 | checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" | 1683 | checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" |
1635 | dependencies = [ | 1684 | dependencies = [ |
1636 | "libc", | 1685 | "libc", |
1637 | "windows-sys 0.48.0", | 1686 | "windows-sys 0.52.0", |
1638 | ] | 1687 | ] |
1639 | 1688 | ||
1640 | [[package]] | 1689 | [[package]] |
@@ -1709,7 +1758,9 @@ dependencies = [ | |||
1709 | "hashlink", | 1758 | "hashlink", |
1710 | "hex", | 1759 | "hex", |
1711 | "indexmap", | 1760 | "indexmap", |
1761 | "ipnetwork", | ||
1712 | "log", | 1762 | "log", |
1763 | "mac_address", | ||
1713 | "memchr", | 1764 | "memchr", |
1714 | "once_cell", | 1765 | "once_cell", |
1715 | "paste", | 1766 | "paste", |
@@ -1829,8 +1880,10 @@ dependencies = [ | |||
1829 | "hkdf", | 1880 | "hkdf", |
1830 | "hmac", | 1881 | "hmac", |
1831 | "home", | 1882 | "home", |
1883 | "ipnetwork", | ||
1832 | "itoa", | 1884 | "itoa", |
1833 | "log", | 1885 | "log", |
1886 | "mac_address", | ||
1834 | "md-5", | 1887 | "md-5", |
1835 | "memchr", | 1888 | "memchr", |
1836 | "once_cell", | 1889 | "once_cell", |
@@ -1916,9 +1969,9 @@ dependencies = [ | |||
1916 | 1969 | ||
1917 | [[package]] | 1970 | [[package]] |
1918 | name = "syn" | 1971 | name = "syn" |
1919 | version = "2.0.48" | 1972 | version = "2.0.50" |
1920 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1973 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1921 | checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" | 1974 | checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" |
1922 | dependencies = [ | 1975 | dependencies = [ |
1923 | "proc-macro2", | 1976 | "proc-macro2", |
1924 | "quote", | 1977 | "quote", |
@@ -1960,14 +2013,14 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" | |||
1960 | dependencies = [ | 2013 | dependencies = [ |
1961 | "proc-macro2", | 2014 | "proc-macro2", |
1962 | "quote", | 2015 | "quote", |
1963 | "syn 2.0.48", | 2016 | "syn 2.0.50", |
1964 | ] | 2017 | ] |
1965 | 2018 | ||
1966 | [[package]] | 2019 | [[package]] |
1967 | name = "thread_local" | 2020 | name = "thread_local" |
1968 | version = "1.1.7" | 2021 | version = "1.1.8" |
1969 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2022 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1970 | checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" | 2023 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" |
1971 | dependencies = [ | 2024 | dependencies = [ |
1972 | "cfg-if", | 2025 | "cfg-if", |
1973 | "once_cell", | 2026 | "once_cell", |
@@ -2055,7 +2108,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" | |||
2055 | dependencies = [ | 2108 | dependencies = [ |
2056 | "proc-macro2", | 2109 | "proc-macro2", |
2057 | "quote", | 2110 | "quote", |
2058 | "syn 2.0.48", | 2111 | "syn 2.0.50", |
2059 | ] | 2112 | ] |
2060 | 2113 | ||
2061 | [[package]] | 2114 | [[package]] |
@@ -2118,9 +2171,9 @@ dependencies = [ | |||
2118 | 2171 | ||
2119 | [[package]] | 2172 | [[package]] |
2120 | name = "toml_edit" | 2173 | name = "toml_edit" |
2121 | version = "0.22.4" | 2174 | version = "0.22.6" |
2122 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2175 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2123 | checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951" | 2176 | checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" |
2124 | dependencies = [ | 2177 | dependencies = [ |
2125 | "indexmap", | 2178 | "indexmap", |
2126 | "serde", | 2179 | "serde", |
@@ -2170,6 +2223,18 @@ dependencies = [ | |||
2170 | ] | 2223 | ] |
2171 | 2224 | ||
2172 | [[package]] | 2225 | [[package]] |
2226 | name = "tracing-appender" | ||
2227 | version = "0.2.3" | ||
2228 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
2229 | checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" | ||
2230 | dependencies = [ | ||
2231 | "crossbeam-channel", | ||
2232 | "thiserror", | ||
2233 | "time", | ||
2234 | "tracing-subscriber", | ||
2235 | ] | ||
2236 | |||
2237 | [[package]] | ||
2173 | name = "tracing-attributes" | 2238 | name = "tracing-attributes" |
2174 | version = "0.1.27" | 2239 | version = "0.1.27" |
2175 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2240 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -2177,7 +2242,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" | |||
2177 | dependencies = [ | 2242 | dependencies = [ |
2178 | "proc-macro2", | 2243 | "proc-macro2", |
2179 | "quote", | 2244 | "quote", |
2180 | "syn 2.0.48", | 2245 | "syn 2.0.50", |
2181 | ] | 2246 | ] |
2182 | 2247 | ||
2183 | [[package]] | 2248 | [[package]] |
@@ -2275,9 +2340,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" | |||
2275 | 2340 | ||
2276 | [[package]] | 2341 | [[package]] |
2277 | name = "unicode-normalization" | 2342 | name = "unicode-normalization" |
2278 | version = "0.1.22" | 2343 | version = "0.1.23" |
2279 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2344 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2280 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" | 2345 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" |
2281 | dependencies = [ | 2346 | dependencies = [ |
2282 | "tinyvec", | 2347 | "tinyvec", |
2283 | ] | 2348 | ] |
@@ -2353,20 +2418,24 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" | |||
2353 | 2418 | ||
2354 | [[package]] | 2419 | [[package]] |
2355 | name = "webol" | 2420 | name = "webol" |
2356 | version = "0.3.1" | 2421 | version = "0.3.2" |
2357 | dependencies = [ | 2422 | dependencies = [ |
2358 | "axum", | 2423 | "axum", |
2359 | "axum-macros", | 2424 | "axum-macros", |
2360 | "color-eyre", | 2425 | "color-eyre", |
2361 | "config", | 2426 | "config", |
2362 | "dashmap", | 2427 | "dashmap", |
2428 | "ipnetwork", | ||
2429 | "mac_address", | ||
2363 | "serde", | 2430 | "serde", |
2364 | "serde_json", | 2431 | "serde_json", |
2365 | "sqlx", | 2432 | "sqlx", |
2366 | "surge-ping", | 2433 | "surge-ping", |
2434 | "thiserror", | ||
2367 | "time", | 2435 | "time", |
2368 | "tokio", | 2436 | "tokio", |
2369 | "tracing", | 2437 | "tracing", |
2438 | "tracing-appender", | ||
2370 | "tracing-subscriber", | 2439 | "tracing-subscriber", |
2371 | "uuid", | 2440 | "uuid", |
2372 | ] | 2441 | ] |
@@ -2414,7 +2483,7 @@ version = "0.52.0" | |||
2414 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2483 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2415 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" | 2484 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" |
2416 | dependencies = [ | 2485 | dependencies = [ |
2417 | "windows-targets 0.52.0", | 2486 | "windows-targets 0.52.3", |
2418 | ] | 2487 | ] |
2419 | 2488 | ||
2420 | [[package]] | 2489 | [[package]] |
@@ -2434,17 +2503,17 @@ dependencies = [ | |||
2434 | 2503 | ||
2435 | [[package]] | 2504 | [[package]] |
2436 | name = "windows-targets" | 2505 | name = "windows-targets" |
2437 | version = "0.52.0" | 2506 | version = "0.52.3" |
2438 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2507 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2439 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" | 2508 | checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" |
2440 | dependencies = [ | 2509 | dependencies = [ |
2441 | "windows_aarch64_gnullvm 0.52.0", | 2510 | "windows_aarch64_gnullvm 0.52.3", |
2442 | "windows_aarch64_msvc 0.52.0", | 2511 | "windows_aarch64_msvc 0.52.3", |
2443 | "windows_i686_gnu 0.52.0", | 2512 | "windows_i686_gnu 0.52.3", |
2444 | "windows_i686_msvc 0.52.0", | 2513 | "windows_i686_msvc 0.52.3", |
2445 | "windows_x86_64_gnu 0.52.0", | 2514 | "windows_x86_64_gnu 0.52.3", |
2446 | "windows_x86_64_gnullvm 0.52.0", | 2515 | "windows_x86_64_gnullvm 0.52.3", |
2447 | "windows_x86_64_msvc 0.52.0", | 2516 | "windows_x86_64_msvc 0.52.3", |
2448 | ] | 2517 | ] |
2449 | 2518 | ||
2450 | [[package]] | 2519 | [[package]] |
@@ -2455,9 +2524,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" | |||
2455 | 2524 | ||
2456 | [[package]] | 2525 | [[package]] |
2457 | name = "windows_aarch64_gnullvm" | 2526 | name = "windows_aarch64_gnullvm" |
2458 | version = "0.52.0" | 2527 | version = "0.52.3" |
2459 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2528 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2460 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" | 2529 | checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" |
2461 | 2530 | ||
2462 | [[package]] | 2531 | [[package]] |
2463 | name = "windows_aarch64_msvc" | 2532 | name = "windows_aarch64_msvc" |
@@ -2467,9 +2536,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" | |||
2467 | 2536 | ||
2468 | [[package]] | 2537 | [[package]] |
2469 | name = "windows_aarch64_msvc" | 2538 | name = "windows_aarch64_msvc" |
2470 | version = "0.52.0" | 2539 | version = "0.52.3" |
2471 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2540 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2472 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" | 2541 | checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" |
2473 | 2542 | ||
2474 | [[package]] | 2543 | [[package]] |
2475 | name = "windows_i686_gnu" | 2544 | name = "windows_i686_gnu" |
@@ -2479,9 +2548,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" | |||
2479 | 2548 | ||
2480 | [[package]] | 2549 | [[package]] |
2481 | name = "windows_i686_gnu" | 2550 | name = "windows_i686_gnu" |
2482 | version = "0.52.0" | 2551 | version = "0.52.3" |
2483 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2552 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2484 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" | 2553 | checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" |
2485 | 2554 | ||
2486 | [[package]] | 2555 | [[package]] |
2487 | name = "windows_i686_msvc" | 2556 | name = "windows_i686_msvc" |
@@ -2491,9 +2560,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" | |||
2491 | 2560 | ||
2492 | [[package]] | 2561 | [[package]] |
2493 | name = "windows_i686_msvc" | 2562 | name = "windows_i686_msvc" |
2494 | version = "0.52.0" | 2563 | version = "0.52.3" |
2495 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2564 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2496 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" | 2565 | checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" |
2497 | 2566 | ||
2498 | [[package]] | 2567 | [[package]] |
2499 | name = "windows_x86_64_gnu" | 2568 | name = "windows_x86_64_gnu" |
@@ -2503,9 +2572,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" | |||
2503 | 2572 | ||
2504 | [[package]] | 2573 | [[package]] |
2505 | name = "windows_x86_64_gnu" | 2574 | name = "windows_x86_64_gnu" |
2506 | version = "0.52.0" | 2575 | version = "0.52.3" |
2507 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2576 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2508 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" | 2577 | checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" |
2509 | 2578 | ||
2510 | [[package]] | 2579 | [[package]] |
2511 | name = "windows_x86_64_gnullvm" | 2580 | name = "windows_x86_64_gnullvm" |
@@ -2515,9 +2584,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" | |||
2515 | 2584 | ||
2516 | [[package]] | 2585 | [[package]] |
2517 | name = "windows_x86_64_gnullvm" | 2586 | name = "windows_x86_64_gnullvm" |
2518 | version = "0.52.0" | 2587 | version = "0.52.3" |
2519 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2588 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2520 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" | 2589 | checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" |
2521 | 2590 | ||
2522 | [[package]] | 2591 | [[package]] |
2523 | name = "windows_x86_64_msvc" | 2592 | name = "windows_x86_64_msvc" |
@@ -2527,15 +2596,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" | |||
2527 | 2596 | ||
2528 | [[package]] | 2597 | [[package]] |
2529 | name = "windows_x86_64_msvc" | 2598 | name = "windows_x86_64_msvc" |
2530 | version = "0.52.0" | 2599 | version = "0.52.3" |
2531 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2600 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2532 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" | 2601 | checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" |
2533 | 2602 | ||
2534 | [[package]] | 2603 | [[package]] |
2535 | name = "winnow" | 2604 | name = "winnow" |
2536 | version = "0.5.39" | 2605 | version = "0.6.2" |
2537 | source = "registry+https://github.com/rust-lang/crates.io-index" | 2606 | source = "registry+https://github.com/rust-lang/crates.io-index" |
2538 | checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29" | 2607 | checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178" |
2539 | dependencies = [ | 2608 | dependencies = [ |
2540 | "memchr", | 2609 | "memchr", |
2541 | ] | 2610 | ] |
@@ -2566,7 +2635,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" | |||
2566 | dependencies = [ | 2635 | dependencies = [ |
2567 | "proc-macro2", | 2636 | "proc-macro2", |
2568 | "quote", | 2637 | "quote", |
2569 | "syn 2.0.48", | 2638 | "syn 2.0.50", |
2570 | ] | 2639 | ] |
2571 | 2640 | ||
2572 | [[package]] | 2641 | [[package]] |
@@ -1,6 +1,6 @@ | |||
1 | [package] | 1 | [package] |
2 | name = "webol" | 2 | name = "webol" |
3 | version = "0.3.1" | 3 | version = "0.3.2" |
4 | edition = "2021" | 4 | edition = "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 |
@@ -14,9 +14,13 @@ time = { version = "0.3", features = ["macros"] } | |||
14 | serde = { version = "1.0", features = ["derive"] } | 14 | serde = { version = "1.0", features = ["derive"] } |
15 | serde_json = "1.0" | 15 | serde_json = "1.0" |
16 | config = "0.14" | 16 | config = "0.14" |
17 | sqlx = { version = "0.7", features = ["postgres", "runtime-tokio"]} | 17 | sqlx = { version = "0.7", features = ["postgres", "runtime-tokio", "ipnetwork", "mac_address"]} |
18 | surge-ping = "0.8" | 18 | surge-ping = "0.8" |
19 | axum-macros = "0.4" | 19 | axum-macros = "0.4" |
20 | uuid = { version = "1.6", features = ["v4", "fast-rng"] } | 20 | uuid = { version = "1.6", features = ["v4", "fast-rng"] } |
21 | dashmap = "5.5" | 21 | dashmap = "5.5" |
22 | color-eyre = "0.6" | 22 | color-eyre = "0.6" |
23 | thiserror = "1.0" | ||
24 | ipnetwork = "0.20.0" | ||
25 | mac_address = { version = "1.1.5", features = ["serde"] } | ||
26 | tracing-appender = "0.2.3" | ||
diff --git a/migrations/20231009123228_devices.sql b/migrations/20231009123228_devices.sql index d36946c..6983ada 100644 --- a/migrations/20231009123228_devices.sql +++ b/migrations/20231009123228_devices.sql | |||
@@ -2,8 +2,8 @@ | |||
2 | CREATE TABLE IF NOT EXISTS "devices" | 2 | CREATE TABLE IF NOT EXISTS "devices" |
3 | ( | 3 | ( |
4 | "id" VARCHAR(255) PRIMARY KEY NOT NULL, | 4 | "id" VARCHAR(255) PRIMARY KEY NOT NULL, |
5 | "mac" VARCHAR(17) NOT NULL, | 5 | "mac" MACADDR NOT NULL, |
6 | "broadcast_addr" VARCHAR(39) NOT NULL, | 6 | "broadcast_addr" VARCHAR(39) NOT NULL, |
7 | "ip" VARCHAR(39) NOT NULL, | 7 | "ip" INET NOT NULL, |
8 | "times" BIGINT[] | 8 | "times" BIGINT[] |
9 | ) | 9 | ) |
diff --git a/src/auth.rs b/src/auth.rs deleted file mode 100644 index feca652..0000000 --- a/src/auth.rs +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | use axum::http::{StatusCode, HeaderValue}; | ||
2 | use axum::http::header::ToStrError; | ||
3 | use tracing::{debug, error, trace}; | ||
4 | use crate::auth::Error::{MissingSecret, WrongSecret}; | ||
5 | use crate::config::Config; | ||
6 | |||
7 | pub fn auth(config: &Config, secret: Option<&HeaderValue>) -> Result<bool, Error> { | ||
8 | debug!("auth request with secret {:?}", secret); | ||
9 | if let Some(value) = secret { | ||
10 | trace!("value exists"); | ||
11 | let key = &config.apikey; | ||
12 | if value.to_str().map_err(Error::HeaderToStr)? == key.as_str() { | ||
13 | debug!("successful auth"); | ||
14 | Ok(true) | ||
15 | } else { | ||
16 | debug!("unsuccessful auth (wrong secret)"); | ||
17 | Err(WrongSecret) | ||
18 | } | ||
19 | } else { | ||
20 | debug!("unsuccessful auth (no secret)"); | ||
21 | Err(MissingSecret) | ||
22 | } | ||
23 | } | ||
24 | |||
25 | #[derive(Debug)] | ||
26 | pub enum Error { | ||
27 | WrongSecret, | ||
28 | MissingSecret, | ||
29 | HeaderToStr(ToStrError) | ||
30 | } | ||
31 | |||
32 | impl Error { | ||
33 | pub fn get(self) -> (StatusCode, &'static str) { | ||
34 | match self { | ||
35 | Self::WrongSecret => (StatusCode::UNAUTHORIZED, "Wrong credentials"), | ||
36 | Self::MissingSecret => (StatusCode::BAD_REQUEST, "Missing credentials"), | ||
37 | Self::HeaderToStr(err) => { | ||
38 | error!("server error: {}", err.to_string()); | ||
39 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") | ||
40 | }, | ||
41 | } | ||
42 | } | ||
43 | } | ||
@@ -1,13 +1,13 @@ | |||
1 | use serde::Serialize; | 1 | use serde::Serialize; |
2 | use sqlx::{PgPool, postgres::PgPoolOptions}; | 2 | use sqlx::{PgPool, postgres::PgPoolOptions, types::{ipnetwork::IpNetwork, mac_address::MacAddress}}; |
3 | use tracing::{debug, info}; | 3 | use tracing::{debug, info}; |
4 | 4 | ||
5 | #[derive(Serialize, Debug)] | 5 | #[derive(Serialize, Debug)] |
6 | pub struct Device { | 6 | pub struct Device { |
7 | pub id: String, | 7 | pub id: String, |
8 | pub mac: String, | 8 | pub mac: MacAddress, |
9 | pub broadcast_addr: String, | 9 | pub broadcast_addr: String, |
10 | pub ip: String, | 10 | pub ip: IpNetwork, |
11 | pub times: Option<Vec<i64>> | 11 | pub times: Option<Vec<i64>> |
12 | } | 12 | } |
13 | 13 | ||
diff --git a/src/error.rs b/src/error.rs index 56d6c52..513b51b 100644 --- a/src/error.rs +++ b/src/error.rs | |||
@@ -1,44 +1,80 @@ | |||
1 | use std::io; | 1 | use ::ipnetwork::IpNetworkError; |
2 | use axum::http::header::ToStrError; | ||
2 | use axum::http::StatusCode; | 3 | use axum::http::StatusCode; |
3 | use axum::Json; | ||
4 | use axum::response::{IntoResponse, Response}; | 4 | use axum::response::{IntoResponse, Response}; |
5 | use axum::Json; | ||
6 | use mac_address::MacParseError; | ||
5 | use serde_json::json; | 7 | use serde_json::json; |
8 | use std::io; | ||
6 | use tracing::error; | 9 | use tracing::error; |
7 | use crate::auth::Error as AuthError; | ||
8 | 10 | ||
9 | #[derive(Debug)] | 11 | #[derive(Debug, thiserror::Error)] |
10 | pub enum Error { | 12 | pub enum Error { |
11 | Generic, | 13 | #[error("db: {source}")] |
12 | Auth(AuthError), | 14 | Db { |
13 | DB(sqlx::Error), | 15 | #[from] |
14 | IpParse(<std::net::IpAddr as std::str::FromStr>::Err), | 16 | source: sqlx::Error, |
15 | BufferParse(std::num::ParseIntError), | 17 | }, |
16 | Broadcast(io::Error), | 18 | |
19 | #[error("buffer parse: {source}")] | ||
20 | ParseInt { | ||
21 | #[from] | ||
22 | source: std::num::ParseIntError, | ||
23 | }, | ||
24 | |||
25 | #[error("header parse: {source}")] | ||
26 | ParseHeader { | ||
27 | #[from] | ||
28 | source: ToStrError, | ||
29 | }, | ||
30 | |||
31 | #[error("string parse: {source}")] | ||
32 | IpParse { | ||
33 | #[from] | ||
34 | source: IpNetworkError, | ||
35 | }, | ||
36 | |||
37 | #[error("mac parse: {source}")] | ||
38 | MacParse { | ||
39 | #[from] | ||
40 | source: MacParseError, | ||
41 | }, | ||
42 | |||
43 | #[error("io: {source}")] | ||
44 | Io { | ||
45 | #[from] | ||
46 | source: io::Error, | ||
47 | }, | ||
17 | } | 48 | } |
18 | 49 | ||
19 | impl IntoResponse for Error { | 50 | impl IntoResponse for Error { |
20 | fn into_response(self) -> Response { | 51 | fn into_response(self) -> Response { |
52 | error!("{}", self.to_string()); | ||
21 | let (status, error_message) = match self { | 53 | let (status, error_message) = match self { |
22 | Self::Auth(err) => { | 54 | Self::Db { source } => { |
23 | err.get() | 55 | error!("{source}"); |
24 | }, | 56 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") |
25 | Self::Generic => (StatusCode::INTERNAL_SERVER_ERROR, ""), | 57 | } |
26 | Self::IpParse(err) => { | 58 | Self::Io { source } => { |
27 | error!("server error: {}", err.to_string()); | 59 | error!("{source}"); |
60 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") | ||
61 | } | ||
62 | Self::ParseHeader { source } => { | ||
63 | error!("{source}"); | ||
28 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") | 64 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") |
29 | }, | 65 | } |
30 | Self::DB(err) => { | 66 | Self::ParseInt { source } => { |
31 | error!("server error: {}", err.to_string()); | 67 | error!("{source}"); |
32 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") | 68 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") |
33 | }, | 69 | } |
34 | Self::Broadcast(err) => { | 70 | Self::MacParse { source } => { |
35 | error!("server error: {}", err.to_string()); | 71 | error!("{source}"); |
36 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") | 72 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") |
37 | }, | 73 | } |
38 | Self::BufferParse(err) => { | 74 | Self::IpParse { source } => { |
39 | error!("server error: {}", err.to_string()); | 75 | error!("{source}"); |
40 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") | 76 | (StatusCode::INTERNAL_SERVER_ERROR, "Server Error") |
41 | }, | 77 | } |
42 | }; | 78 | }; |
43 | let body = Json(json!({ | 79 | let body = Json(json!({ |
44 | "error": error_message, | 80 | "error": error_message, |
diff --git a/src/extractors.rs b/src/extractors.rs new file mode 100644 index 0000000..4d441e9 --- /dev/null +++ b/src/extractors.rs | |||
@@ -0,0 +1,24 @@ | |||
1 | use axum::{ | ||
2 | extract::{Request, State}, | ||
3 | http::{HeaderMap, StatusCode}, | ||
4 | middleware::Next, | ||
5 | response::Response, | ||
6 | }; | ||
7 | |||
8 | use crate::AppState; | ||
9 | |||
10 | pub async fn auth( | ||
11 | State(state): State<AppState>, | ||
12 | headers: HeaderMap, | ||
13 | request: Request, | ||
14 | next: Next, | ||
15 | ) -> Result<Response, StatusCode> { | ||
16 | let secret = headers.get("authorization"); | ||
17 | match secret { | ||
18 | Some(token) if token == state.config.apikey.as_str() => { | ||
19 | let response = next.run(request).await; | ||
20 | Ok(response) | ||
21 | } | ||
22 | _ => Err(StatusCode::UNAUTHORIZED), | ||
23 | } | ||
24 | } | ||
diff --git a/src/main.rs b/src/main.rs index 4ef129b..d17984f 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -1,42 +1,44 @@ | |||
1 | use std::env; | ||
2 | use std::sync::Arc; | ||
3 | use axum::{Router, routing::post}; | ||
4 | use axum::routing::{get, put}; | ||
5 | use dashmap::DashMap; | ||
6 | use sqlx::PgPool; | ||
7 | use time::util::local_offset; | ||
8 | use tokio::sync::broadcast::{channel, Sender}; | ||
9 | use tracing::{info, level_filters::LevelFilter}; | ||
10 | use tracing_subscriber::{EnvFilter, fmt::{self, time::LocalTime}, prelude::*}; | ||
11 | use crate::config::Config; | 1 | use crate::config::Config; |
12 | use crate::db::init_db_pool; | 2 | use crate::db::init_db_pool; |
13 | use crate::routes::device; | 3 | use crate::routes::device; |
14 | use crate::routes::start::start; | 4 | use crate::routes::start::start; |
15 | use crate::routes::status::status; | 5 | use crate::routes::status::status; |
16 | use crate::services::ping::{BroadcastCommands, StatusMap}; | 6 | use crate::services::ping::StatusMap; |
7 | use axum::middleware::from_fn_with_state; | ||
8 | use axum::routing::{get, put}; | ||
9 | use axum::{routing::post, Router}; | ||
10 | use dashmap::DashMap; | ||
11 | use services::ping::BroadcastCommand; | ||
12 | use sqlx::PgPool; | ||
13 | use std::env; | ||
14 | use std::sync::Arc; | ||
15 | use tokio::sync::broadcast::{channel, Sender}; | ||
16 | use tracing::{info, level_filters::LevelFilter}; | ||
17 | use tracing_subscriber::fmt::time::UtcTime; | ||
18 | use tracing_subscriber::{fmt, prelude::*, EnvFilter}; | ||
17 | 19 | ||
18 | mod auth; | ||
19 | mod config; | 20 | mod config; |
20 | mod routes; | ||
21 | mod wol; | ||
22 | mod db; | 21 | mod db; |
23 | mod error; | 22 | mod error; |
23 | mod extractors; | ||
24 | mod routes; | ||
24 | mod services; | 25 | mod services; |
26 | mod wol; | ||
25 | 27 | ||
26 | #[tokio::main] | 28 | #[tokio::main] |
27 | async fn main() -> color_eyre::eyre::Result<()> { | 29 | async fn main() -> color_eyre::eyre::Result<()> { |
28 | |||
29 | color_eyre::install()?; | 30 | color_eyre::install()?; |
30 | 31 | ||
31 | unsafe { local_offset::set_soundness(local_offset::Soundness::Unsound); } | ||
32 | let time_format = | 32 | let time_format = |
33 | time::macros::format_description!("[year]-[month]-[day] [hour]:[minute]:[second]"); | 33 | time::macros::format_description!("[year]-[month]-[day] [hour]:[minute]:[second]"); |
34 | let loc = LocalTime::new(time_format); | 34 | let loc = UtcTime::new(time_format); |
35 | |||
36 | let file_appender = tracing_appender::rolling::daily("logs", "webol.log"); | ||
37 | let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender); | ||
35 | 38 | ||
36 | tracing_subscriber::registry() | 39 | tracing_subscriber::registry() |
37 | .with(fmt::layer() | 40 | .with(fmt::layer().with_writer(non_blocking).with_ansi(false)) |
38 | .with_timer(loc) | 41 | .with(fmt::layer().with_timer(loc)) |
39 | ) | ||
40 | .with( | 42 | .with( |
41 | EnvFilter::builder() | 43 | EnvFilter::builder() |
42 | .with_default_directive(LevelFilter::INFO.into()) | 44 | .with_default_directive(LevelFilter::INFO.into()) |
@@ -56,8 +58,13 @@ async fn main() -> color_eyre::eyre::Result<()> { | |||
56 | let (tx, _) = channel(32); | 58 | let (tx, _) = channel(32); |
57 | 59 | ||
58 | let ping_map: StatusMap = DashMap::new(); | 60 | let ping_map: StatusMap = DashMap::new(); |
59 | 61 | ||
60 | let shared_state = Arc::new(AppState { db, config: config.clone(), ping_send: tx, ping_map }); | 62 | let shared_state = AppState { |
63 | db, | ||
64 | config: config.clone(), | ||
65 | ping_send: tx, | ||
66 | ping_map, | ||
67 | }; | ||
61 | 68 | ||
62 | let app = Router::new() | 69 | let app = Router::new() |
63 | .route("/start", post(start)) | 70 | .route("/start", post(start)) |
@@ -65,20 +72,21 @@ async fn main() -> color_eyre::eyre::Result<()> { | |||
65 | .route("/device", put(device::put)) | 72 | .route("/device", put(device::put)) |
66 | .route("/device", post(device::post)) | 73 | .route("/device", post(device::post)) |
67 | .route("/status", get(status)) | 74 | .route("/status", get(status)) |
68 | .with_state(shared_state); | 75 | .route_layer(from_fn_with_state(shared_state.clone(), extractors::auth)) |
76 | .with_state(Arc::new(shared_state)); | ||
69 | 77 | ||
70 | let addr = config.serveraddr; | 78 | let addr = config.serveraddr; |
71 | info!("start server on {}", addr); | 79 | info!("start server on {}", addr); |
72 | let listener = tokio::net::TcpListener::bind(addr) | 80 | let listener = tokio::net::TcpListener::bind(addr).await?; |
73 | .await?; | ||
74 | axum::serve(listener, app).await?; | 81 | axum::serve(listener, app).await?; |
75 | 82 | ||
76 | Ok(()) | 83 | Ok(()) |
77 | } | 84 | } |
78 | 85 | ||
86 | #[derive(Clone)] | ||
79 | pub struct AppState { | 87 | pub struct AppState { |
80 | db: PgPool, | 88 | db: PgPool, |
81 | config: Config, | 89 | config: Config, |
82 | ping_send: Sender<BroadcastCommands>, | 90 | ping_send: Sender<BroadcastCommand>, |
83 | ping_map: StatusMap, | 91 | ping_map: StatusMap, |
84 | } | 92 | } |
diff --git a/src/routes/mod.rs b/src/routes.rs index d5ab0d6..d5ab0d6 100644 --- a/src/routes/mod.rs +++ b/src/routes.rs | |||
diff --git a/src/routes/device.rs b/src/routes/device.rs index c85df1b..d39d98e 100644 --- a/src/routes/device.rs +++ b/src/routes/device.rs | |||
@@ -1,34 +1,34 @@ | |||
1 | use std::sync::Arc; | 1 | use crate::db::Device; |
2 | use crate::error::Error; | ||
2 | use axum::extract::State; | 3 | use axum::extract::State; |
3 | use axum::Json; | 4 | use axum::Json; |
4 | use axum::http::HeaderMap; | 5 | use mac_address::MacAddress; |
5 | use serde::{Deserialize, Serialize}; | 6 | use serde::{Deserialize, Serialize}; |
6 | use serde_json::{json, Value}; | 7 | use serde_json::{json, Value}; |
8 | use sqlx::types::ipnetwork::IpNetwork; | ||
9 | use std::{sync::Arc, str::FromStr}; | ||
7 | use tracing::{debug, info}; | 10 | use tracing::{debug, info}; |
8 | use crate::auth::auth; | ||
9 | use crate::db::Device; | ||
10 | use crate::error::Error; | ||
11 | 11 | ||
12 | pub async fn get(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<GetDevicePayload>) -> Result<Json<Value>, Error> { | 12 | pub async fn get( |
13 | info!("add device {}", payload.id); | 13 | State(state): State<Arc<crate::AppState>>, |
14 | let secret = headers.get("authorization"); | 14 | Json(payload): Json<GetDevicePayload>, |
15 | if auth(&state.config, secret).map_err(Error::Auth)? { | 15 | ) -> Result<Json<Value>, Error> { |
16 | let device = sqlx::query_as!( | 16 | info!("get device {}", payload.id); |
17 | Device, | 17 | let device = sqlx::query_as!( |
18 | r#" | 18 | Device, |
19 | SELECT id, mac, broadcast_addr, ip, times | 19 | r#" |
20 | FROM devices | 20 | SELECT id, mac, broadcast_addr, ip, times |
21 | WHERE id = $1; | 21 | FROM devices |
22 | "#, | 22 | WHERE id = $1; |
23 | payload.id | 23 | "#, |
24 | ).fetch_one(&state.db).await.map_err(Error::DB)?; | 24 | payload.id |
25 | ) | ||
26 | .fetch_one(&state.db) | ||
27 | .await?; | ||
25 | 28 | ||
26 | debug!("got device {:?}", device); | 29 | debug!("got device {:?}", device); |
27 | 30 | ||
28 | Ok(Json(json!(device))) | 31 | Ok(Json(json!(device))) |
29 | } else { | ||
30 | Err(Error::Generic) | ||
31 | } | ||
32 | } | 32 | } |
33 | 33 | ||
34 | #[derive(Deserialize)] | 34 | #[derive(Deserialize)] |
@@ -36,25 +36,31 @@ pub struct GetDevicePayload { | |||
36 | id: String, | 36 | id: String, |
37 | } | 37 | } |
38 | 38 | ||
39 | pub async fn put(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<PutDevicePayload>) -> Result<Json<Value>, Error> { | 39 | pub async fn put( |
40 | info!("add device {} ({}, {}, {})", payload.id, payload.mac, payload.broadcast_addr, payload.ip); | 40 | State(state): State<Arc<crate::AppState>>, |
41 | let secret = headers.get("authorization"); | 41 | Json(payload): Json<PutDevicePayload>, |
42 | if auth(&state.config, secret).map_err(Error::Auth)? { | 42 | ) -> Result<Json<Value>, Error> { |
43 | sqlx::query!( | 43 | info!( |
44 | r#" | 44 | "add device {} ({}, {}, {})", |
45 | INSERT INTO devices (id, mac, broadcast_addr, ip) | 45 | payload.id, payload.mac, payload.broadcast_addr, payload.ip |
46 | VALUES ($1, $2, $3, $4); | 46 | ); |
47 | "#, | 47 | |
48 | payload.id, | 48 | let ip = IpNetwork::from_str(&payload.ip)?; |
49 | payload.mac, | 49 | let mac = MacAddress::from_str(&payload.mac)?; |
50 | payload.broadcast_addr, | 50 | sqlx::query!( |
51 | payload.ip | 51 | r#" |
52 | ).execute(&state.db).await.map_err(Error::DB)?; | 52 | INSERT INTO devices (id, mac, broadcast_addr, ip) |
53 | VALUES ($1, $2, $3, $4); | ||
54 | "#, | ||
55 | payload.id, | ||
56 | mac, | ||
57 | payload.broadcast_addr, | ||
58 | ip | ||
59 | ) | ||
60 | .execute(&state.db) | ||
61 | .await?; | ||
53 | 62 | ||
54 | Ok(Json(json!(PutDeviceResponse { success: true }))) | 63 | Ok(Json(json!(PutDeviceResponse { success: true }))) |
55 | } else { | ||
56 | Err(Error::Generic) | ||
57 | } | ||
58 | } | 64 | } |
59 | 65 | ||
60 | #[derive(Deserialize)] | 66 | #[derive(Deserialize)] |
@@ -62,35 +68,40 @@ pub struct PutDevicePayload { | |||
62 | id: String, | 68 | id: String, |
63 | mac: String, | 69 | mac: String, |
64 | broadcast_addr: String, | 70 | broadcast_addr: String, |
65 | ip: String | 71 | ip: String, |
66 | } | 72 | } |
67 | 73 | ||
68 | #[derive(Serialize)] | 74 | #[derive(Serialize)] |
69 | pub struct PutDeviceResponse { | 75 | pub struct PutDeviceResponse { |
70 | success: bool | 76 | success: bool, |
71 | } | 77 | } |
72 | 78 | ||
73 | pub async fn post(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<PostDevicePayload>) -> Result<Json<Value>, Error> { | 79 | pub async fn post( |
74 | info!("edit device {} ({}, {}, {})", payload.id, payload.mac, payload.broadcast_addr, payload.ip); | 80 | State(state): State<Arc<crate::AppState>>, |
75 | let secret = headers.get("authorization"); | 81 | Json(payload): Json<PostDevicePayload>, |
76 | if auth(&state.config, secret).map_err(Error::Auth)? { | 82 | ) -> Result<Json<Value>, Error> { |
77 | let device = sqlx::query_as!( | 83 | info!( |
78 | Device, | 84 | "edit device {} ({}, {}, {})", |
79 | r#" | 85 | payload.id, payload.mac, payload.broadcast_addr, payload.ip |
80 | UPDATE devices | 86 | ); |
81 | SET mac = $1, broadcast_addr = $2, ip = $3 WHERE id = $4 | 87 | let ip = IpNetwork::from_str(&payload.ip)?; |
82 | RETURNING id, mac, broadcast_addr, ip, times; | 88 | let mac = MacAddress::from_str(&payload.mac)?; |
83 | "#, | 89 | let device = sqlx::query_as!( |
84 | payload.mac, | 90 | Device, |
85 | payload.broadcast_addr, | 91 | r#" |
86 | payload.ip, | 92 | UPDATE devices |
87 | payload.id | 93 | SET mac = $1, broadcast_addr = $2, ip = $3 WHERE id = $4 |
88 | ).fetch_one(&state.db).await.map_err(Error::DB)?; | 94 | RETURNING id, mac, broadcast_addr, ip, times; |
95 | "#, | ||
96 | mac, | ||
97 | payload.broadcast_addr, | ||
98 | ip, | ||
99 | payload.id | ||
100 | ) | ||
101 | .fetch_one(&state.db) | ||
102 | .await?; | ||
89 | 103 | ||
90 | Ok(Json(json!(device))) | 104 | Ok(Json(json!(device))) |
91 | } else { | ||
92 | Err(Error::Generic) | ||
93 | } | ||
94 | } | 105 | } |
95 | 106 | ||
96 | #[derive(Deserialize)] | 107 | #[derive(Deserialize)] |
diff --git a/src/routes/start.rs b/src/routes/start.rs index ce95bf3..d4c0802 100644 --- a/src/routes/start.rs +++ b/src/routes/start.rs | |||
@@ -1,10 +1,8 @@ | |||
1 | use crate::auth::auth; | ||
2 | use crate::db::Device; | 1 | use crate::db::Device; |
3 | use crate::error::Error; | 2 | use crate::error::Error; |
4 | use crate::services::ping::Value as PingValue; | 3 | use crate::services::ping::Value as PingValue; |
5 | use crate::wol::{create_buffer, send_packet}; | 4 | use crate::wol::{create_buffer, send_packet}; |
6 | use axum::extract::State; | 5 | use axum::extract::State; |
7 | use axum::http::HeaderMap; | ||
8 | use axum::Json; | 6 | use axum::Json; |
9 | use serde::{Deserialize, Serialize}; | 7 | use serde::{Deserialize, Serialize}; |
10 | use serde_json::{json, Value}; | 8 | use serde_json::{json, Value}; |
@@ -12,86 +10,82 @@ use std::sync::Arc; | |||
12 | use tracing::{debug, info}; | 10 | use tracing::{debug, info}; |
13 | use uuid::Uuid; | 11 | use uuid::Uuid; |
14 | 12 | ||
15 | #[axum_macros::debug_handler] | ||
16 | pub async fn start( | 13 | pub async fn start( |
17 | State(state): State<Arc<crate::AppState>>, | 14 | State(state): State<Arc<crate::AppState>>, |
18 | headers: HeaderMap, | ||
19 | Json(payload): Json<Payload>, | 15 | Json(payload): Json<Payload>, |
20 | ) -> Result<Json<Value>, Error> { | 16 | ) -> Result<Json<Value>, Error> { |
21 | info!("POST request"); | 17 | info!("POST request"); |
22 | let secret = headers.get("authorization"); | 18 | let device = sqlx::query_as!( |
23 | let authorized = auth(&state.config, secret).map_err(Error::Auth)?; | 19 | Device, |
24 | if authorized { | 20 | r#" |
25 | let device = sqlx::query_as!( | 21 | SELECT id, mac, broadcast_addr, ip, times |
26 | Device, | 22 | FROM devices |
27 | r#" | 23 | WHERE id = $1; |
28 | SELECT id, mac, broadcast_addr, ip, times | 24 | "#, |
29 | FROM devices | 25 | payload.id |
30 | WHERE id = $1; | 26 | ) |
31 | "#, | 27 | .fetch_one(&state.db) |
32 | payload.id | 28 | .await?; |
33 | ) | ||
34 | .fetch_one(&state.db) | ||
35 | .await | ||
36 | .map_err(Error::DB)?; | ||
37 | |||
38 | info!("starting {}", device.id); | ||
39 | |||
40 | let bind_addr = "0.0.0.0:0"; | ||
41 | 29 | ||
42 | let _ = send_packet( | 30 | info!("starting {}", device.id); |
43 | &bind_addr.parse().map_err(Error::IpParse)?, | ||
44 | &device.broadcast_addr.parse().map_err(Error::IpParse)?, | ||
45 | &create_buffer(&device.mac)?, | ||
46 | )?; | ||
47 | let dev_id = device.id.clone(); | ||
48 | let uuid = if payload.ping.is_some_and(|ping| ping) { | ||
49 | let mut uuid: Option<String> = None; | ||
50 | for (key, value) in state.ping_map.clone() { | ||
51 | if value.ip == device.ip { | ||
52 | debug!("service already exists"); | ||
53 | uuid = Some(key); | ||
54 | break; | ||
55 | } | ||
56 | } | ||
57 | let uuid_gen = match uuid { | ||
58 | Some(u) => u, | ||
59 | None => Uuid::new_v4().to_string(), | ||
60 | }; | ||
61 | let uuid_genc = uuid_gen.clone(); | ||
62 | 31 | ||
63 | tokio::spawn(async move { | 32 | let bind_addr = "0.0.0.0:0"; |
64 | debug!("init ping service"); | ||
65 | state.ping_map.insert( | ||
66 | uuid_gen.clone(), | ||
67 | PingValue { | ||
68 | ip: device.ip.clone(), | ||
69 | online: false, | ||
70 | }, | ||
71 | ); | ||
72 | 33 | ||
73 | crate::services::ping::spawn( | 34 | let _ = send_packet( |
74 | state.ping_send.clone(), | 35 | bind_addr, |
75 | &state.config, | 36 | &device.broadcast_addr, |
76 | device, | 37 | &create_buffer(&device.mac.to_string())?, |
77 | uuid_gen.clone(), | 38 | )?; |
78 | &state.ping_map, | 39 | let dev_id = device.id.clone(); |
79 | &state.db, | 40 | let uuid = if payload.ping.is_some_and(|ping| ping) { |
80 | ) | 41 | Some(setup_ping(state, device)) |
81 | .await; | ||
82 | }); | ||
83 | Some(uuid_genc) | ||
84 | } else { | ||
85 | None | ||
86 | }; | ||
87 | Ok(Json(json!(Response { | ||
88 | id: dev_id, | ||
89 | boot: true, | ||
90 | uuid | ||
91 | }))) | ||
92 | } else { | 42 | } else { |
93 | Err(Error::Generic) | 43 | None |
44 | }; | ||
45 | Ok(Json(json!(Response { | ||
46 | id: dev_id, | ||
47 | boot: true, | ||
48 | uuid | ||
49 | }))) | ||
50 | } | ||
51 | |||
52 | fn setup_ping(state: Arc<crate::AppState>, device: Device) -> String { | ||
53 | let mut uuid: Option<String> = None; | ||
54 | for (key, value) in state.ping_map.clone() { | ||
55 | if value.ip == device.ip { | ||
56 | debug!("service already exists"); | ||
57 | uuid = Some(key); | ||
58 | break; | ||
59 | } | ||
94 | } | 60 | } |
61 | let uuid_gen = match uuid { | ||
62 | Some(u) => u, | ||
63 | None => Uuid::new_v4().to_string(), | ||
64 | }; | ||
65 | let uuid_ret = uuid_gen.clone(); | ||
66 | |||
67 | debug!("init ping service"); | ||
68 | state.ping_map.insert( | ||
69 | uuid_gen.clone(), | ||
70 | PingValue { | ||
71 | ip: device.ip, | ||
72 | online: false, | ||
73 | }, | ||
74 | ); | ||
75 | |||
76 | tokio::spawn(async move { | ||
77 | crate::services::ping::spawn( | ||
78 | state.ping_send.clone(), | ||
79 | &state.config, | ||
80 | device, | ||
81 | uuid_gen, | ||
82 | &state.ping_map, | ||
83 | &state.db, | ||
84 | ) | ||
85 | .await; | ||
86 | }); | ||
87 | |||
88 | uuid_ret | ||
95 | } | 89 | } |
96 | 90 | ||
97 | #[derive(Deserialize)] | 91 | #[derive(Deserialize)] |
diff --git a/src/routes/status.rs b/src/routes/status.rs index 31ef996..0e25f7d 100644 --- a/src/routes/status.rs +++ b/src/routes/status.rs | |||
@@ -1,10 +1,79 @@ | |||
1 | use std::sync::Arc; | 1 | use crate::services::ping::BroadcastCommand; |
2 | use crate::AppState; | ||
3 | use axum::extract::ws::{Message, WebSocket}; | ||
2 | use axum::extract::{State, WebSocketUpgrade}; | 4 | use axum::extract::{State, WebSocketUpgrade}; |
3 | use axum::response::Response; | 5 | use axum::response::Response; |
4 | use crate::AppState; | 6 | use sqlx::PgPool; |
5 | use crate::services::ping::status_websocket; | 7 | use std::sync::Arc; |
8 | use tracing::{debug, trace}; | ||
6 | 9 | ||
7 | #[axum_macros::debug_handler] | ||
8 | pub async fn status(State(state): State<Arc<AppState>>, ws: WebSocketUpgrade) -> Response { | 10 | pub async fn status(State(state): State<Arc<AppState>>, ws: WebSocketUpgrade) -> Response { |
9 | ws.on_upgrade(move |socket| status_websocket(socket, state)) | 11 | ws.on_upgrade(move |socket| websocket(socket, state)) |
12 | } | ||
13 | |||
14 | pub async fn websocket(mut socket: WebSocket, state: Arc<AppState>) { | ||
15 | trace!("wait for ws message (uuid)"); | ||
16 | let msg = socket.recv().await; | ||
17 | let uuid = msg.unwrap().unwrap().into_text().unwrap(); | ||
18 | |||
19 | trace!("Search for uuid: {}", uuid); | ||
20 | |||
21 | let eta = get_eta(&state.db).await; | ||
22 | let _ = socket | ||
23 | .send(Message::Text(format!("eta_{eta}_{uuid}"))) | ||
24 | .await; | ||
25 | |||
26 | let device_exists = state.ping_map.contains_key(&uuid); | ||
27 | if device_exists { | ||
28 | let _ = socket | ||
29 | .send(receive_ping_broadcast(state.clone(), uuid).await) | ||
30 | .await; | ||
31 | } else { | ||
32 | debug!("didn't find any device"); | ||
33 | let _ = socket.send(Message::Text(format!("notfound_{uuid}"))).await; | ||
34 | }; | ||
35 | |||
36 | let _ = socket.close().await; | ||
37 | } | ||
38 | |||
39 | async fn receive_ping_broadcast(state: Arc<AppState>, uuid: String) -> Message { | ||
40 | let pm = state.ping_map.clone().into_read_only(); | ||
41 | let device = pm.get(&uuid).expect("fatal error"); | ||
42 | debug!("got device: {} (online: {})", device.ip, device.online); | ||
43 | if device.online { | ||
44 | debug!("already started"); | ||
45 | Message::Text(BroadcastCommand::success(uuid).to_string()) | ||
46 | } else { | ||
47 | loop { | ||
48 | trace!("wait for tx message"); | ||
49 | let message = state | ||
50 | .ping_send | ||
51 | .subscribe() | ||
52 | .recv() | ||
53 | .await | ||
54 | .expect("fatal error"); | ||
55 | trace!("got message {:?}", message); | ||
56 | |||
57 | if message.uuid != uuid { | ||
58 | continue; | ||
59 | } | ||
60 | trace!("message == uuid success"); | ||
61 | return Message::Text(message.to_string()); | ||
62 | } | ||
63 | } | ||
64 | } | ||
65 | |||
66 | async fn get_eta(db: &PgPool) -> i64 { | ||
67 | let query = sqlx::query!(r#"SELECT times FROM devices;"#) | ||
68 | .fetch_one(db) | ||
69 | .await | ||
70 | .unwrap(); | ||
71 | |||
72 | let times = if let Some(times) = query.times { | ||
73 | times | ||
74 | } else { | ||
75 | vec![0] | ||
76 | }; | ||
77 | |||
78 | times.iter().sum::<i64>() / i64::try_from(times.len()).unwrap() | ||
10 | } | 79 | } |
diff --git a/src/services/mod.rs b/src/services.rs index a766209..a766209 100644 --- a/src/services/mod.rs +++ b/src/services.rs | |||
diff --git a/src/services/ping.rs b/src/services/ping.rs index 9b164c8..9191f86 100644 --- a/src/services/ping.rs +++ b/src/services/ping.rs | |||
@@ -1,59 +1,58 @@ | |||
1 | use std::str::FromStr; | 1 | use crate::config::Config; |
2 | use std::net::IpAddr; | 2 | use crate::db::Device; |
3 | use std::sync::Arc; | ||
4 | |||
5 | use axum::extract::ws::WebSocket; | ||
6 | use axum::extract::ws::Message; | ||
7 | use dashmap::DashMap; | 3 | use dashmap::DashMap; |
4 | use ipnetwork::IpNetwork; | ||
8 | use sqlx::PgPool; | 5 | use sqlx::PgPool; |
6 | use std::fmt::Display; | ||
9 | use time::{Duration, Instant}; | 7 | use time::{Duration, Instant}; |
10 | use tokio::sync::broadcast::Sender; | 8 | use tokio::sync::broadcast::Sender; |
11 | use tracing::{debug, error, trace}; | 9 | use tracing::{debug, error, trace}; |
12 | use crate::AppState; | ||
13 | use crate::config::Config; | ||
14 | use crate::db::Device; | ||
15 | 10 | ||
16 | pub type StatusMap = DashMap<String, Value>; | 11 | pub type StatusMap = DashMap<String, Value>; |
17 | 12 | ||
18 | #[derive(Debug, Clone)] | 13 | #[derive(Debug, Clone)] |
19 | pub struct Value { | 14 | pub struct Value { |
20 | pub ip: String, | 15 | pub ip: IpNetwork, |
21 | pub online: bool | 16 | pub online: bool, |
22 | } | 17 | } |
23 | 18 | ||
24 | pub async fn spawn(tx: Sender<BroadcastCommands>, config: &Config, device: Device, uuid: String, ping_map: &StatusMap, db: &PgPool) { | 19 | pub async fn spawn( |
20 | tx: Sender<BroadcastCommand>, | ||
21 | config: &Config, | ||
22 | device: Device, | ||
23 | uuid: String, | ||
24 | ping_map: &StatusMap, | ||
25 | db: &PgPool, | ||
26 | ) { | ||
25 | let timer = Instant::now(); | 27 | let timer = Instant::now(); |
26 | let payload = [0; 8]; | 28 | let payload = [0; 8]; |
27 | 29 | ||
28 | let ping_ip = IpAddr::from_str(&device.ip).expect("bad ip"); | 30 | let mut msg: Option<BroadcastCommand> = None; |
29 | |||
30 | let mut msg: Option<BroadcastCommands> = None; | ||
31 | while msg.is_none() { | 31 | while msg.is_none() { |
32 | let ping = surge_ping::ping( | 32 | let ping = surge_ping::ping(device.ip.ip(), &payload).await; |
33 | ping_ip, | ||
34 | &payload | ||
35 | ).await; | ||
36 | 33 | ||
37 | if let Err(ping) = ping { | 34 | if let Err(ping) = ping { |
38 | let ping_timeout = matches!(ping, surge_ping::SurgeError::Timeout { .. }); | 35 | let ping_timeout = matches!(ping, surge_ping::SurgeError::Timeout { .. }); |
39 | if !ping_timeout { | 36 | if !ping_timeout { |
40 | error!("{}", ping.to_string()); | 37 | error!("{}", ping.to_string()); |
41 | msg = Some(BroadcastCommands::Error(uuid.clone())); | 38 | msg = Some(BroadcastCommand::error(uuid.clone())); |
42 | } | 39 | } |
43 | if timer.elapsed() >= Duration::minutes(config.pingtimeout) { | 40 | if timer.elapsed() >= Duration::minutes(config.pingtimeout) { |
44 | msg = Some(BroadcastCommands::Timeout(uuid.clone())); | 41 | msg = Some(BroadcastCommand::timeout(uuid.clone())); |
45 | } | 42 | } |
46 | } else { | 43 | } else { |
47 | let (_, duration) = ping.map_err(|err| error!("{}", err.to_string())).expect("fatal error"); | 44 | let (_, duration) = ping |
45 | .map_err(|err| error!("{}", err.to_string())) | ||
46 | .expect("fatal error"); | ||
48 | debug!("ping took {:?}", duration); | 47 | debug!("ping took {:?}", duration); |
49 | msg = Some(BroadcastCommands::Success(uuid.clone())); | 48 | msg = Some(BroadcastCommand::success(uuid.clone())); |
50 | }; | 49 | }; |
51 | } | 50 | } |
52 | 51 | ||
53 | let msg = msg.expect("fatal error"); | 52 | let msg = msg.expect("fatal error"); |
54 | 53 | ||
55 | let _ = tx.send(msg.clone()); | 54 | let _ = tx.send(msg.clone()); |
56 | if let BroadcastCommands::Success(..) = msg { | 55 | if let BroadcastCommands::Success = msg.command { |
57 | sqlx::query!( | 56 | sqlx::query!( |
58 | r#" | 57 | r#" |
59 | UPDATE devices | 58 | UPDATE devices |
@@ -62,8 +61,17 @@ pub async fn spawn(tx: Sender<BroadcastCommands>, config: &Config, device: Devic | |||
62 | "#, | 61 | "#, |
63 | timer.elapsed().whole_seconds(), | 62 | timer.elapsed().whole_seconds(), |
64 | device.id | 63 | device.id |
65 | ).execute(db).await.unwrap(); | 64 | ) |
66 | ping_map.insert(uuid.clone(), Value { ip: device.ip.clone(), online: true }); | 65 | .execute(db) |
66 | .await | ||
67 | .unwrap(); | ||
68 | ping_map.insert( | ||
69 | uuid.clone(), | ||
70 | Value { | ||
71 | ip: device.ip, | ||
72 | online: true, | ||
73 | }, | ||
74 | ); | ||
67 | tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; | 75 | tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; |
68 | } | 76 | } |
69 | trace!("remove {} from ping_map", uuid); | 77 | trace!("remove {} from ping_map", uuid); |
@@ -72,74 +80,48 @@ pub async fn spawn(tx: Sender<BroadcastCommands>, config: &Config, device: Devic | |||
72 | 80 | ||
73 | #[derive(Clone, Debug, PartialEq)] | 81 | #[derive(Clone, Debug, PartialEq)] |
74 | pub enum BroadcastCommands { | 82 | pub enum BroadcastCommands { |
75 | Success(String), | 83 | Success, |
76 | Timeout(String), | 84 | Timeout, |
77 | Error(String), | 85 | Error, |
78 | } | 86 | } |
79 | 87 | ||
80 | pub async fn status_websocket(mut socket: WebSocket, state: Arc<AppState>) { | 88 | #[derive(Clone, Debug, PartialEq)] |
81 | trace!("wait for ws message (uuid)"); | 89 | pub struct BroadcastCommand { |
82 | let msg = socket.recv().await; | 90 | pub uuid: String, |
83 | let uuid = msg.unwrap().unwrap().into_text().unwrap(); | 91 | pub command: BroadcastCommands, |
84 | 92 | } | |
85 | trace!("Search for uuid: {}", uuid); | ||
86 | |||
87 | let eta = get_eta(&state.db).await; | ||
88 | let _ = socket.send(Message::Text(format!("eta_{eta}_{uuid}"))).await; | ||
89 | 93 | ||
90 | let device_exists = state.ping_map.contains_key(&uuid); | 94 | impl Display for BroadcastCommand { |
91 | if device_exists { | 95 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
92 | let _ = socket.send(process_device(state.clone(), uuid).await).await; | 96 | let prefix = match self.command { |
93 | } else { | 97 | BroadcastCommands::Success => "start", |
94 | debug!("didn't find any device"); | 98 | BroadcastCommands::Timeout => "timeout", |
95 | let _ = socket.send(Message::Text(format!("notfound_{uuid}"))).await; | 99 | BroadcastCommands::Error => "error", |
96 | }; | 100 | }; |
97 | 101 | ||
98 | let _ = socket.close().await; | 102 | f.write_str(format!("{prefix}_{}", self.uuid).as_str()) |
103 | } | ||
99 | } | 104 | } |
100 | 105 | ||
101 | async fn get_eta(db: &PgPool) -> i64 { | 106 | impl BroadcastCommand { |
102 | let query = sqlx::query!( | 107 | pub fn success(uuid: String) -> Self { |
103 | r#"SELECT times FROM devices;"# | 108 | Self { |
104 | ).fetch_one(db).await.unwrap(); | 109 | uuid, |
105 | 110 | command: BroadcastCommands::Success, | |
106 | let times = match query.times { | 111 | } |
107 | None => { vec![0] }, | 112 | } |
108 | Some(t) => t, | ||
109 | }; | ||
110 | times.iter().sum::<i64>() / i64::try_from(times.len()).unwrap() | ||
111 | 113 | ||
112 | } | 114 | pub fn timeout(uuid: String) -> Self { |
115 | Self { | ||
116 | uuid, | ||
117 | command: BroadcastCommands::Timeout, | ||
118 | } | ||
119 | } | ||
113 | 120 | ||
114 | async fn process_device(state: Arc<AppState>, uuid: String) -> Message { | 121 | pub fn error(uuid: String) -> Self { |
115 | let pm = state.ping_map.clone().into_read_only(); | 122 | Self { |
116 | let device = pm.get(&uuid).expect("fatal error"); | 123 | uuid, |
117 | debug!("got device: {} (online: {})", device.ip, device.online); | 124 | command: BroadcastCommands::Error, |
118 | if device.online { | ||
119 | debug!("already started"); | ||
120 | Message::Text(format!("start_{uuid}")) | ||
121 | } else { | ||
122 | loop { | ||
123 | trace!("wait for tx message"); | ||
124 | let message = state.ping_send.subscribe().recv().await.expect("fatal error"); | ||
125 | trace!("got message {:?}", message); | ||
126 | return match message { | ||
127 | BroadcastCommands::Success(msg_uuid) => { | ||
128 | if msg_uuid != uuid { continue; } | ||
129 | trace!("message == uuid success"); | ||
130 | Message::Text(format!("start_{uuid}")) | ||
131 | }, | ||
132 | BroadcastCommands::Timeout(msg_uuid) => { | ||
133 | if msg_uuid != uuid { continue; } | ||
134 | trace!("message == uuid timeout"); | ||
135 | Message::Text(format!("timeout_{uuid}")) | ||
136 | }, | ||
137 | BroadcastCommands::Error(msg_uuid) => { | ||
138 | if msg_uuid != uuid { continue; } | ||
139 | trace!("message == uuid error"); | ||
140 | Message::Text(format!("error_{uuid}")) | ||
141 | } | ||
142 | } | ||
143 | } | 125 | } |
144 | } | 126 | } |
145 | } | 127 | } |
@@ -1,4 +1,4 @@ | |||
1 | use std::net::{SocketAddr, UdpSocket}; | 1 | use std::net::{ToSocketAddrs, UdpSocket}; |
2 | 2 | ||
3 | use crate::error::Error; | 3 | use crate::error::Error; |
4 | 4 | ||
@@ -11,8 +11,8 @@ pub fn create_buffer(mac_addr: &str) -> Result<Vec<u8>, Error> { | |||
11 | let mut mac = Vec::new(); | 11 | let mut mac = Vec::new(); |
12 | let sp = mac_addr.split(':'); | 12 | let sp = mac_addr.split(':'); |
13 | for f in sp { | 13 | for f in sp { |
14 | mac.push(u8::from_str_radix(f, 16).map_err(Error::BufferParse)?); | 14 | mac.push(u8::from_str_radix(f, 16)?); |
15 | }; | 15 | } |
16 | let mut buf = vec![255; 6]; | 16 | let mut buf = vec![255; 6]; |
17 | for _ in 0..16 { | 17 | for _ in 0..16 { |
18 | for i in &mac { | 18 | for i in &mac { |
@@ -23,8 +23,12 @@ pub fn create_buffer(mac_addr: &str) -> Result<Vec<u8>, Error> { | |||
23 | } | 23 | } |
24 | 24 | ||
25 | /// Sends a buffer on UDP broadcast | 25 | /// Sends a buffer on UDP broadcast |
26 | pub fn send_packet(bind_addr: &SocketAddr, broadcast_addr: &SocketAddr, buffer: &[u8]) -> Result<usize, Error> { | 26 | pub fn send_packet<A: ToSocketAddrs>( |
27 | let socket = UdpSocket::bind(bind_addr).map_err(Error::Broadcast)?; | 27 | bind_addr: A, |
28 | socket.set_broadcast(true).map_err(Error::Broadcast)?; | 28 | broadcast_addr: A, |
29 | socket.send_to(buffer, broadcast_addr).map_err(Error::Broadcast) | 29 | buffer: &[u8], |
30 | ) -> Result<usize, Error> { | ||
31 | let socket = UdpSocket::bind(bind_addr)?; | ||
32 | socket.set_broadcast(true)?; | ||
33 | Ok(socket.send_to(buffer, broadcast_addr)?) | ||
30 | } | 34 | } |