neon_arch Spencerjibz commited on
Commit
991f3f5
β€’
1 Parent(s): 8d9b660

:zap: perf: several optimizations for improving the performance of the engine (#540)

Browse files

* :recycle: refactor: initialize & store the config & cache structs as a constant (#486)
- initializes & stores the config & cache structs as a static constant.
- Pass the config & cache structs as a static reference to all the
functions handling their respective route.

* :zap: perf: replace hashmaps with vectors for fetching & aggregating results (#486)
- replace hashmaps with vectors for fetching, collecting & aggregating results as it tends to be contigous & cache efficient data structure.
- refactor & redesign algorithms for fetching & aggregating results
centered around vectors in aggregate function.

* :heavy_plus_sign: build: add the future crate (#486)

* :zap: perf: use `futureunordered` for collecting results fetched from the tokio spawn tasks (#486)
- using the `futureunordered` instead of vector for collecting results
reduces the time it takes to fetch the results as the results do not
need to come in specific order so any result that gets fetched first
gets collected in the `futureunordered` type.

Co-authored-by: Spencerjibz <[email protected]>

* :zap: perf: initialize new async connections parallely using tokio spawn tasks (#486)

* :zap: perf: initialize redis pipeline struct once with the default size of 3 (#486)

* :zap: perf: reduce branch predictions by reducing conditional code branches (#486)

* :white_check_mark: test(unit): provide unit test for the `get_safesearch_level` function (#486)

* :zap: perf: reduce clones & use index based loop to improve search results filtering performance (#486)

* 🚨 fix(clippy): make clippy/format checks happy (#486)

* 🚨 fix(build): make the cargo build check happy (#486)

* :zap: perf: reduce the amount of clones, to_owneds & to_strings (#486)

* :zap: perf: use async crates & methods & make functions async (#486)

* :bookmark: chore(release): bump the app version (#486)

---------

Co-authored-by: Spencerjibz <[email protected]>

Cargo.lock CHANGED
@@ -4,17 +4,17 @@ version = 3
4
 
5
  [[package]]
6
  name = "actix-codec"
7
- version = "0.5.1"
8
  source = "registry+https://github.com/rust-lang/crates.io-index"
9
- checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8"
10
  dependencies = [
11
- "bitflags 1.3.2",
12
  "bytes 1.5.0",
13
  "futures-core",
14
  "futures-sink",
15
  "memchr",
16
  "pin-project-lite",
17
- "tokio 1.35.1",
18
  "tokio-util",
19
  "tracing",
20
  ]
@@ -44,7 +44,7 @@ dependencies = [
44
  "actix-service",
45
  "actix-utils",
46
  "actix-web",
47
- "bitflags 2.4.1",
48
  "bytes 1.5.0",
49
  "derive_more",
50
  "futures-core",
@@ -71,24 +71,24 @@ dependencies = [
71
 
72
  [[package]]
73
  name = "actix-http"
74
- version = "3.5.1"
75
  source = "registry+https://github.com/rust-lang/crates.io-index"
76
- checksum = "129d4c88e98860e1758c5de288d1632b07970a16d59bdf7b8d66053d582bb71f"
77
  dependencies = [
78
  "actix-codec",
79
  "actix-rt",
80
  "actix-service",
81
  "actix-utils",
82
- "ahash 0.8.7",
83
- "base64 0.21.5",
84
- "bitflags 2.4.1",
85
  "brotli",
86
  "bytes 1.5.0",
87
  "bytestring",
88
  "derive_more",
89
  "encoding_rs",
90
  "futures-core",
91
- "http 0.2.11",
92
  "httparse",
93
  "httpdate",
94
  "itoa 1.0.10",
@@ -100,7 +100,7 @@ dependencies = [
100
  "rand 0.8.5",
101
  "sha1",
102
  "smallvec 1.13.1",
103
- "tokio 1.35.1",
104
  "tokio-util",
105
  "tracing",
106
  ]
@@ -112,7 +112,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
112
  checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
113
  dependencies = [
114
  "quote 1.0.35",
115
- "syn 2.0.48",
116
  ]
117
 
118
  [[package]]
@@ -122,7 +122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
122
  checksum = "d22475596539443685426b6bdadb926ad0ecaefdfc5fb05e5e3441f15463c511"
123
  dependencies = [
124
  "bytestring",
125
- "http 0.2.11",
126
  "regex",
127
  "serde",
128
  "tracing",
@@ -135,7 +135,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
135
  checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d"
136
  dependencies = [
137
  "futures-core",
138
- "tokio 1.35.1",
139
  ]
140
 
141
  [[package]]
@@ -149,9 +149,9 @@ dependencies = [
149
  "actix-utils",
150
  "futures-core",
151
  "futures-util",
152
- "mio 0.8.10",
153
  "socket2",
154
- "tokio 1.35.1",
155
  "tracing",
156
  ]
157
 
@@ -178,9 +178,9 @@ dependencies = [
178
 
179
  [[package]]
180
  name = "actix-web"
181
- version = "4.4.1"
182
  source = "registry+https://github.com/rust-lang/crates.io-index"
183
- checksum = "e43428f3bf11dee6d166b00ec2df4e3aa8cc1606aaa0b7433c146852e2f4e03b"
184
  dependencies = [
185
  "actix-codec",
186
  "actix-http",
@@ -191,7 +191,7 @@ dependencies = [
191
  "actix-service",
192
  "actix-utils",
193
  "actix-web-codegen",
194
- "ahash 0.8.7",
195
  "bytes 1.5.0",
196
  "bytestring",
197
  "cfg-if 1.0.0",
@@ -212,7 +212,7 @@ dependencies = [
212
  "serde_urlencoded 0.7.1",
213
  "smallvec 1.13.1",
214
  "socket2",
215
- "time 0.3.31",
216
  "url 2.5.0",
217
  ]
218
 
@@ -225,7 +225,7 @@ dependencies = [
225
  "actix-router",
226
  "proc-macro2 1.0.78",
227
  "quote 1.0.35",
228
- "syn 2.0.48",
229
  ]
230
 
231
  [[package]]
@@ -255,20 +255,9 @@ dependencies = [
255
 
256
  [[package]]
257
  name = "ahash"
258
- version = "0.7.7"
259
- source = "registry+https://github.com/rust-lang/crates.io-index"
260
- checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd"
261
- dependencies = [
262
- "getrandom",
263
- "once_cell",
264
- "version_check",
265
- ]
266
-
267
- [[package]]
268
- name = "ahash"
269
- version = "0.8.7"
270
  source = "registry+https://github.com/rust-lang/crates.io-index"
271
- checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
272
  dependencies = [
273
  "cfg-if 1.0.0",
274
  "getrandom",
@@ -318,21 +307,21 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
318
 
319
  [[package]]
320
  name = "anstyle"
321
- version = "1.0.4"
322
  source = "registry+https://github.com/rust-lang/crates.io-index"
323
- checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
324
 
325
  [[package]]
326
  name = "anyhow"
327
- version = "1.0.77"
328
  source = "registry+https://github.com/rust-lang/crates.io-index"
329
- checksum = "c9d19de80eff169429ac1e9f48fffb163916b448a44e8e046186232046d9e1f9"
330
 
331
  [[package]]
332
  name = "arc-swap"
333
- version = "1.6.0"
334
  source = "registry+https://github.com/rust-lang/crates.io-index"
335
- checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
336
 
337
  [[package]]
338
  name = "arrayref"
@@ -348,16 +337,16 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
348
 
349
  [[package]]
350
  name = "async-compression"
351
- version = "0.4.5"
352
  source = "registry+https://github.com/rust-lang/crates.io-index"
353
- checksum = "bc2d0cfb2a7388d34f590e76686704c494ed7aaceed62ee1ba35cbf363abc2a5"
354
  dependencies = [
355
  "brotli",
356
  "flate2",
357
  "futures-core",
358
  "memchr",
359
  "pin-project-lite",
360
- "tokio 1.35.1",
361
  ]
362
 
363
  [[package]]
@@ -368,13 +357,13 @@ checksum = "9338790e78aa95a416786ec8389546c4b6a1dfc3dc36071ed9518a9413a542eb"
368
 
369
  [[package]]
370
  name = "async-trait"
371
- version = "0.1.76"
372
  source = "registry+https://github.com/rust-lang/crates.io-index"
373
- checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514"
374
  dependencies = [
375
  "proc-macro2 1.0.78",
376
  "quote 1.0.35",
377
- "syn 2.0.48",
378
  ]
379
 
380
  [[package]]
@@ -418,9 +407,9 @@ dependencies = [
418
 
419
  [[package]]
420
  name = "base64"
421
- version = "0.21.5"
422
  source = "registry+https://github.com/rust-lang/crates.io-index"
423
- checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
424
 
425
  [[package]]
426
  name = "bit-set"
@@ -445,9 +434,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
445
 
446
  [[package]]
447
  name = "bitflags"
448
- version = "2.4.1"
449
  source = "registry+https://github.com/rust-lang/crates.io-index"
450
- checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
451
 
452
  [[package]]
453
  name = "blake3"
@@ -494,9 +483,9 @@ dependencies = [
494
 
495
  [[package]]
496
  name = "bstr"
497
- version = "1.9.0"
498
  source = "registry+https://github.com/rust-lang/crates.io-index"
499
- checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc"
500
  dependencies = [
501
  "memchr",
502
  "serde",
@@ -504,9 +493,9 @@ dependencies = [
504
 
505
  [[package]]
506
  name = "bumpalo"
507
- version = "3.14.0"
508
  source = "registry+https://github.com/rust-lang/crates.io-index"
509
- checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
510
 
511
  [[package]]
512
  name = "bytecount"
@@ -557,9 +546,9 @@ dependencies = [
557
 
558
  [[package]]
559
  name = "cargo-platform"
560
- version = "0.1.6"
561
  source = "registry+https://github.com/rust-lang/crates.io-index"
562
- checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d"
563
  dependencies = [
564
  "serde",
565
  ]
@@ -572,7 +561,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
572
  dependencies = [
573
  "camino",
574
  "cargo-platform",
575
- "semver 1.0.20",
576
  "serde",
577
  "serde_json",
578
  ]
@@ -585,12 +574,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
585
 
586
  [[package]]
587
  name = "cc"
588
- version = "1.0.83"
589
  source = "registry+https://github.com/rust-lang/crates.io-index"
590
- checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
591
- dependencies = [
592
- "libc",
593
- ]
594
 
595
  [[package]]
596
  name = "cfg-if"
@@ -639,9 +625,9 @@ dependencies = [
639
 
640
  [[package]]
641
  name = "ciborium"
642
- version = "0.2.1"
643
  source = "registry+https://github.com/rust-lang/crates.io-index"
644
- checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
645
  dependencies = [
646
  "ciborium-io",
647
  "ciborium-ll",
@@ -650,15 +636,15 @@ dependencies = [
650
 
651
  [[package]]
652
  name = "ciborium-io"
653
- version = "0.2.1"
654
  source = "registry+https://github.com/rust-lang/crates.io-index"
655
- checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
656
 
657
  [[package]]
658
  name = "ciborium-ll"
659
- version = "0.2.1"
660
  source = "registry+https://github.com/rust-lang/crates.io-index"
661
- checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
662
  dependencies = [
663
  "ciborium-io",
664
  "half",
@@ -677,18 +663,18 @@ dependencies = [
677
 
678
  [[package]]
679
  name = "clap"
680
- version = "4.4.12"
681
  source = "registry+https://github.com/rust-lang/crates.io-index"
682
- checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d"
683
  dependencies = [
684
  "clap_builder",
685
  ]
686
 
687
  [[package]]
688
  name = "clap_builder"
689
- version = "4.4.12"
690
  source = "registry+https://github.com/rust-lang/crates.io-index"
691
- checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
692
  dependencies = [
693
  "anstyle",
694
  "clap_lex",
@@ -696,9 +682,9 @@ dependencies = [
696
 
697
  [[package]]
698
  name = "clap_lex"
699
- version = "0.6.0"
700
  source = "registry+https://github.com/rust-lang/crates.io-index"
701
- checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
702
 
703
  [[package]]
704
  name = "cloudabi"
@@ -719,7 +705,7 @@ dependencies = [
719
  "futures-core",
720
  "memchr",
721
  "pin-project-lite",
722
- "tokio 1.35.1",
723
  "tokio-util",
724
  ]
725
 
@@ -772,7 +758,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
772
  checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
773
  dependencies = [
774
  "percent-encoding 2.3.1",
775
- "time 0.3.31",
776
  "version_check",
777
  ]
778
 
@@ -812,18 +798,18 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
812
 
813
  [[package]]
814
  name = "cpufeatures"
815
- version = "0.2.11"
816
  source = "registry+https://github.com/rust-lang/crates.io-index"
817
- checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
818
  dependencies = [
819
  "libc",
820
  ]
821
 
822
  [[package]]
823
  name = "crc32fast"
824
- version = "1.3.2"
825
  source = "registry+https://github.com/rust-lang/crates.io-index"
826
- checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
827
  dependencies = [
828
  "cfg-if 1.0.0",
829
  ]
@@ -864,12 +850,11 @@ dependencies = [
864
 
865
  [[package]]
866
  name = "crossbeam-channel"
867
- version = "0.5.10"
868
  source = "registry+https://github.com/rust-lang/crates.io-index"
869
- checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2"
870
  dependencies = [
871
- "cfg-if 1.0.0",
872
- "crossbeam-utils 0.8.18",
873
  ]
874
 
875
  [[package]]
@@ -922,12 +907,15 @@ dependencies = [
922
 
923
  [[package]]
924
  name = "crossbeam-utils"
925
- version = "0.8.18"
926
  source = "registry+https://github.com/rust-lang/crates.io-index"
927
- checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
928
- dependencies = [
929
- "cfg-if 1.0.0",
930
- ]
 
 
 
931
 
932
  [[package]]
933
  name = "crypto-common"
@@ -982,7 +970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
982
  checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
983
  dependencies = [
984
  "quote 1.0.35",
985
- "syn 2.0.48",
986
  ]
987
 
988
  [[package]]
@@ -1006,9 +994,9 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
1006
 
1007
  [[package]]
1008
  name = "deranged"
1009
- version = "0.3.10"
1010
  source = "registry+https://github.com/rust-lang/crates.io-index"
1011
- checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc"
1012
  dependencies = [
1013
  "powerfmt",
1014
  ]
@@ -1081,9 +1069,9 @@ checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591"
1081
 
1082
  [[package]]
1083
  name = "either"
1084
- version = "1.9.0"
1085
  source = "registry+https://github.com/rust-lang/crates.io-index"
1086
- checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
1087
 
1088
  [[package]]
1089
  name = "encoding_rs"
@@ -1105,9 +1093,9 @@ dependencies = [
1105
 
1106
  [[package]]
1107
  name = "env_logger"
1108
- version = "0.11.1"
1109
  source = "registry+https://github.com/rust-lang/crates.io-index"
1110
- checksum = "05e7cf40684ae96ade6232ed84582f40ce0a66efcd43a5117aef610534f8e0b8"
1111
  dependencies = [
1112
  "env_filter",
1113
  "log",
@@ -1347,7 +1335,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
1347
  dependencies = [
1348
  "proc-macro2 1.0.78",
1349
  "quote 1.0.35",
1350
- "syn 2.0.48",
1351
  ]
1352
 
1353
  [[package]]
@@ -1364,9 +1352,9 @@ checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
1364
 
1365
  [[package]]
1366
  name = "futures-timer"
1367
- version = "3.0.2"
1368
  source = "registry+https://github.com/rust-lang/crates.io-index"
1369
- checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
1370
 
1371
  [[package]]
1372
  name = "futures-util"
@@ -1416,9 +1404,9 @@ dependencies = [
1416
 
1417
  [[package]]
1418
  name = "getrandom"
1419
- version = "0.2.11"
1420
  source = "registry+https://github.com/rust-lang/crates.io-index"
1421
- checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
1422
  dependencies = [
1423
  "cfg-if 1.0.0",
1424
  "libc",
@@ -1439,9 +1427,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
1439
 
1440
  [[package]]
1441
  name = "governor"
1442
- version = "0.6.0"
1443
  source = "registry+https://github.com/rust-lang/crates.io-index"
1444
- checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4"
1445
  dependencies = [
1446
  "cfg-if 1.0.0",
1447
  "dashmap",
@@ -1450,9 +1438,11 @@ dependencies = [
1450
  "no-std-compat",
1451
  "nonzero_ext",
1452
  "parking_lot 0.12.1",
 
1453
  "quanta",
1454
  "rand 0.8.5",
1455
  "smallvec 1.13.1",
 
1456
  ]
1457
 
1458
  [[package]]
@@ -1475,28 +1465,32 @@ dependencies = [
1475
 
1476
  [[package]]
1477
  name = "h2"
1478
- version = "0.3.22"
1479
  source = "registry+https://github.com/rust-lang/crates.io-index"
1480
- checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
1481
  dependencies = [
1482
  "bytes 1.5.0",
1483
  "fnv",
1484
  "futures-core",
1485
  "futures-sink",
1486
  "futures-util",
1487
- "http 0.2.11",
1488
- "indexmap 2.1.0",
1489
  "slab",
1490
- "tokio 1.35.1",
1491
  "tokio-util",
1492
  "tracing",
1493
  ]
1494
 
1495
  [[package]]
1496
  name = "half"
1497
- version = "1.8.2"
1498
  source = "registry+https://github.com/rust-lang/crates.io-index"
1499
- checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
 
 
 
 
1500
 
1501
  [[package]]
1502
  name = "hashbrown"
@@ -1510,7 +1504,7 @@ version = "0.13.2"
1510
  source = "registry+https://github.com/rust-lang/crates.io-index"
1511
  checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
1512
  dependencies = [
1513
- "ahash 0.8.7",
1514
  "bumpalo",
1515
  ]
1516
 
@@ -1522,9 +1516,9 @@ checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
1522
 
1523
  [[package]]
1524
  name = "hermit-abi"
1525
- version = "0.3.3"
1526
  source = "registry+https://github.com/rust-lang/crates.io-index"
1527
- checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
1528
 
1529
  [[package]]
1530
  name = "home"
@@ -1576,9 +1570,9 @@ dependencies = [
1576
 
1577
  [[package]]
1578
  name = "http"
1579
- version = "0.2.11"
1580
  source = "registry+https://github.com/rust-lang/crates.io-index"
1581
- checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
1582
  dependencies = [
1583
  "bytes 1.5.0",
1584
  "fnv",
@@ -1604,7 +1598,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1604
  checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
1605
  dependencies = [
1606
  "bytes 1.5.0",
1607
- "http 0.2.11",
1608
  "pin-project-lite",
1609
  ]
1610
 
@@ -1666,15 +1660,15 @@ dependencies = [
1666
  "futures-channel",
1667
  "futures-core",
1668
  "futures-util",
1669
- "h2 0.3.22",
1670
- "http 0.2.11",
1671
  "http-body 0.4.6",
1672
  "httparse",
1673
  "httpdate",
1674
  "itoa 1.0.10",
1675
  "pin-project-lite",
1676
  "socket2",
1677
- "tokio 1.35.1",
1678
  "tower-service",
1679
  "tracing",
1680
  "want 0.3.1",
@@ -1687,10 +1681,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1687
  checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
1688
  dependencies = [
1689
  "futures-util",
1690
- "http 0.2.11",
1691
  "hyper 0.14.28",
1692
  "rustls",
1693
- "tokio 1.35.1",
1694
  "tokio-rustls",
1695
  ]
1696
 
@@ -1751,9 +1745,9 @@ dependencies = [
1751
 
1752
  [[package]]
1753
  name = "indexmap"
1754
- version = "2.1.0"
1755
  source = "registry+https://github.com/rust-lang/crates.io-index"
1756
- checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
1757
  dependencies = [
1758
  "equivalent",
1759
  "hashbrown 0.14.3",
@@ -1785,12 +1779,12 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
1785
 
1786
  [[package]]
1787
  name = "is-terminal"
1788
- version = "0.4.10"
1789
  source = "registry+https://github.com/rust-lang/crates.io-index"
1790
- checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
1791
  dependencies = [
1792
  "hermit-abi",
1793
- "rustix",
1794
  "windows-sys 0.52.0",
1795
  ]
1796
 
@@ -1817,9 +1811,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
1817
 
1818
  [[package]]
1819
  name = "js-sys"
1820
- version = "0.3.66"
1821
  source = "registry+https://github.com/rust-lang/crates.io-index"
1822
- checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
1823
  dependencies = [
1824
  "wasm-bindgen",
1825
  ]
@@ -1864,16 +1858,17 @@ dependencies = [
1864
 
1865
  [[package]]
1866
  name = "lightningcss"
1867
- version = "1.0.0-alpha.52"
1868
  source = "registry+https://github.com/rust-lang/crates.io-index"
1869
- checksum = "771a62dedf5ec563bbfea9760f6c6a6bc546e67355eba0cd7d00c0dc34b11d90"
1870
  dependencies = [
1871
- "ahash 0.7.7",
1872
- "bitflags 2.4.1",
1873
  "const-str",
1874
  "cssparser 0.33.0",
1875
  "cssparser-color",
1876
  "data-encoding",
 
1877
  "itertools",
1878
  "lazy_static",
1879
  "parcel_selectors",
@@ -1884,9 +1879,9 @@ dependencies = [
1884
 
1885
  [[package]]
1886
  name = "linux-raw-sys"
1887
- version = "0.4.12"
1888
  source = "registry+https://github.com/rust-lang/crates.io-index"
1889
- checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
1890
 
1891
  [[package]]
1892
  name = "local-channel"
@@ -1941,9 +1936,9 @@ dependencies = [
1941
 
1942
  [[package]]
1943
  name = "luajit-src"
1944
- version = "210.5.3+29b0b28"
1945
  source = "registry+https://github.com/rust-lang/crates.io-index"
1946
- checksum = "0c2bb89013916ce5c949f01a1fbd6d435a58e1d980767a791d755911211d792d"
1947
  dependencies = [
1948
  "cc",
1949
  "which",
@@ -1955,15 +1950,6 @@ version = "0.1.1"
1955
  source = "registry+https://github.com/rust-lang/crates.io-index"
1956
  checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
1957
 
1958
- [[package]]
1959
- name = "mach2"
1960
- version = "0.4.2"
1961
- source = "registry+https://github.com/rust-lang/crates.io-index"
1962
- checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
1963
- dependencies = [
1964
- "libc",
1965
- ]
1966
-
1967
  [[package]]
1968
  name = "markup5ever"
1969
  version = "0.8.1"
@@ -2073,12 +2059,12 @@ dependencies = [
2073
 
2074
  [[package]]
2075
  name = "mini-moka"
2076
- version = "0.10.2"
2077
  source = "registry+https://github.com/rust-lang/crates.io-index"
2078
- checksum = "23e0b72e7c9042467008b10279fc732326bd605459ae03bda88825909dd19b56"
2079
  dependencies = [
2080
  "crossbeam-channel",
2081
- "crossbeam-utils 0.8.18",
2082
  "dashmap",
2083
  "skeptic",
2084
  "smallvec 1.13.1",
@@ -2099,22 +2085,18 @@ dependencies = [
2099
 
2100
  [[package]]
2101
  name = "miniz_oxide"
2102
- version = "0.7.1"
2103
  source = "registry+https://github.com/rust-lang/crates.io-index"
2104
- checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
2105
  dependencies = [
2106
  "adler",
2107
  ]
2108
 
2109
  [[package]]
2110
  name = "mintex"
2111
- version = "0.1.2"
2112
  source = "registry+https://github.com/rust-lang/crates.io-index"
2113
- checksum = "fd7c5ba1c3b5a23418d7bbf98c71c3d4946a0125002129231da8d6b723d559cb"
2114
- dependencies = [
2115
- "once_cell",
2116
- "sys-info",
2117
- ]
2118
 
2119
  [[package]]
2120
  name = "mio"
@@ -2137,9 +2119,9 @@ dependencies = [
2137
 
2138
  [[package]]
2139
  name = "mio"
2140
- version = "0.8.10"
2141
  source = "registry+https://github.com/rust-lang/crates.io-index"
2142
- checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
2143
  dependencies = [
2144
  "libc",
2145
  "log",
@@ -2161,9 +2143,9 @@ dependencies = [
2161
 
2162
  [[package]]
2163
  name = "mlua"
2164
- version = "0.9.2"
2165
  source = "registry+https://github.com/rust-lang/crates.io-index"
2166
- checksum = "7c81f8ac20188feb5461a73eabb22a34dd09d6d58513535eb587e46bff6ba250"
2167
  dependencies = [
2168
  "bstr",
2169
  "mlua-sys",
@@ -2174,9 +2156,9 @@ dependencies = [
2174
 
2175
  [[package]]
2176
  name = "mlua-sys"
2177
- version = "0.4.0"
2178
  source = "registry+https://github.com/rust-lang/crates.io-index"
2179
- checksum = "fc29228347d6bdc9e613dc95c69df2817f755434ee0f7f3b27b57755fe238b7f"
2180
  dependencies = [
2181
  "cc",
2182
  "cfg-if 1.0.0",
@@ -2238,11 +2220,17 @@ version = "0.3.0"
2238
  source = "registry+https://github.com/rust-lang/crates.io-index"
2239
  checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
2240
 
 
 
 
 
 
 
2241
  [[package]]
2242
  name = "num-traits"
2243
- version = "0.2.17"
2244
  source = "registry+https://github.com/rust-lang/crates.io-index"
2245
- checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
2246
  dependencies = [
2247
  "autocfg 1.1.0",
2248
  ]
@@ -2280,17 +2268,17 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
2280
 
2281
  [[package]]
2282
  name = "opaque-debug"
2283
- version = "0.3.0"
2284
  source = "registry+https://github.com/rust-lang/crates.io-index"
2285
- checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
2286
 
2287
  [[package]]
2288
  name = "openssl"
2289
- version = "0.10.62"
2290
  source = "registry+https://github.com/rust-lang/crates.io-index"
2291
- checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671"
2292
  dependencies = [
2293
- "bitflags 2.4.1",
2294
  "cfg-if 1.0.0",
2295
  "foreign-types",
2296
  "libc",
@@ -2307,7 +2295,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
2307
  dependencies = [
2308
  "proc-macro2 1.0.78",
2309
  "quote 1.0.35",
2310
- "syn 2.0.48",
2311
  ]
2312
 
2313
  [[package]]
@@ -2318,9 +2306,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
2318
 
2319
  [[package]]
2320
  name = "openssl-sys"
2321
- version = "0.9.98"
2322
  source = "registry+https://github.com/rust-lang/crates.io-index"
2323
- checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7"
2324
  dependencies = [
2325
  "cc",
2326
  "libc",
@@ -2334,7 +2322,7 @@ version = "0.26.4"
2334
  source = "registry+https://github.com/rust-lang/crates.io-index"
2335
  checksum = "05d74befe2d076330d9a58bf9ca2da424568724ab278adf15fb5718253133887"
2336
  dependencies = [
2337
- "bitflags 2.4.1",
2338
  "cssparser 0.33.0",
2339
  "fxhash",
2340
  "log",
@@ -2518,7 +2506,7 @@ dependencies = [
2518
  "phf_shared 0.11.2",
2519
  "proc-macro2 1.0.78",
2520
  "quote 1.0.35",
2521
- "syn 2.0.48",
2522
  ]
2523
 
2524
  [[package]]
@@ -2550,22 +2538,22 @@ dependencies = [
2550
 
2551
  [[package]]
2552
  name = "pin-project"
2553
- version = "1.1.3"
2554
  source = "registry+https://github.com/rust-lang/crates.io-index"
2555
- checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
2556
  dependencies = [
2557
  "pin-project-internal",
2558
  ]
2559
 
2560
  [[package]]
2561
  name = "pin-project-internal"
2562
- version = "1.1.3"
2563
  source = "registry+https://github.com/rust-lang/crates.io-index"
2564
- checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
2565
  dependencies = [
2566
  "proc-macro2 1.0.78",
2567
  "quote 1.0.35",
2568
- "syn 2.0.48",
2569
  ]
2570
 
2571
  [[package]]
@@ -2582,9 +2570,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
2582
 
2583
  [[package]]
2584
  name = "pkg-config"
2585
- version = "0.3.28"
2586
  source = "registry+https://github.com/rust-lang/crates.io-index"
2587
- checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
2588
 
2589
  [[package]]
2590
  name = "poly1305"
@@ -2597,6 +2585,12 @@ dependencies = [
2597
  "universal-hash",
2598
  ]
2599
 
 
 
 
 
 
 
2600
  [[package]]
2601
  name = "powerfmt"
2602
  version = "0.2.0"
@@ -2669,24 +2663,23 @@ dependencies = [
2669
 
2670
  [[package]]
2671
  name = "pulldown-cmark"
2672
- version = "0.9.3"
2673
  source = "registry+https://github.com/rust-lang/crates.io-index"
2674
- checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998"
2675
  dependencies = [
2676
- "bitflags 1.3.2",
2677
  "memchr",
2678
  "unicase",
2679
  ]
2680
 
2681
  [[package]]
2682
  name = "quanta"
2683
- version = "0.11.1"
2684
  source = "registry+https://github.com/rust-lang/crates.io-index"
2685
- checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab"
2686
  dependencies = [
2687
- "crossbeam-utils 0.8.18",
2688
  "libc",
2689
- "mach2",
2690
  "once_cell",
2691
  "raw-cpuid",
2692
  "wasi 0.11.0+wasi-snapshot-preview1",
@@ -2850,11 +2843,11 @@ dependencies = [
2850
 
2851
  [[package]]
2852
  name = "raw-cpuid"
2853
- version = "10.7.0"
2854
  source = "registry+https://github.com/rust-lang/crates.io-index"
2855
- checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
2856
  dependencies = [
2857
- "bitflags 1.3.2",
2858
  ]
2859
 
2860
  [[package]]
@@ -2882,7 +2875,7 @@ dependencies = [
2882
  "percent-encoding 2.3.1",
2883
  "pin-project-lite",
2884
  "ryu",
2885
- "tokio 1.35.1",
2886
  "tokio-retry",
2887
  "tokio-util",
2888
  "url 2.5.0",
@@ -2905,9 +2898,9 @@ dependencies = [
2905
 
2906
  [[package]]
2907
  name = "regex"
2908
- version = "1.10.2"
2909
  source = "registry+https://github.com/rust-lang/crates.io-index"
2910
- checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
2911
  dependencies = [
2912
  "aho-corasick 1.1.2",
2913
  "memchr",
@@ -2917,9 +2910,9 @@ dependencies = [
2917
 
2918
  [[package]]
2919
  name = "regex-automata"
2920
- version = "0.4.3"
2921
  source = "registry+https://github.com/rust-lang/crates.io-index"
2922
- checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
2923
  dependencies = [
2924
  "aho-corasick 1.1.2",
2925
  "memchr",
@@ -2968,18 +2961,18 @@ dependencies = [
2968
 
2969
  [[package]]
2970
  name = "reqwest"
2971
- version = "0.11.24"
2972
  source = "registry+https://github.com/rust-lang/crates.io-index"
2973
- checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
2974
  dependencies = [
2975
  "async-compression",
2976
- "base64 0.21.5",
2977
  "bytes 1.5.0",
2978
  "encoding_rs",
2979
  "futures-core",
2980
  "futures-util",
2981
- "h2 0.3.22",
2982
- "http 0.2.11",
2983
  "http-body 0.4.6",
2984
  "hyper 0.14.28",
2985
  "hyper-rustls",
@@ -2997,7 +2990,7 @@ dependencies = [
2997
  "serde_urlencoded 0.7.1",
2998
  "sync_wrapper",
2999
  "system-configuration",
3000
- "tokio 1.35.1",
3001
  "tokio-rustls",
3002
  "tokio-util",
3003
  "tower-service",
@@ -3011,16 +3004,17 @@ dependencies = [
3011
 
3012
  [[package]]
3013
  name = "ring"
3014
- version = "0.17.7"
3015
  source = "registry+https://github.com/rust-lang/crates.io-index"
3016
- checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
3017
  dependencies = [
3018
  "cc",
 
3019
  "getrandom",
3020
  "libc",
3021
  "spin",
3022
  "untrusted",
3023
- "windows-sys 0.48.0",
3024
  ]
3025
 
3026
  [[package]]
@@ -3050,7 +3044,7 @@ version = "0.4.0"
3050
  source = "registry+https://github.com/rust-lang/crates.io-index"
3051
  checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
3052
  dependencies = [
3053
- "semver 1.0.20",
3054
  ]
3055
 
3056
  [[package]]
@@ -3059,7 +3053,7 @@ version = "0.38.31"
3059
  source = "registry+https://github.com/rust-lang/crates.io-index"
3060
  checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
3061
  dependencies = [
3062
- "bitflags 2.4.1",
3063
  "errno",
3064
  "libc",
3065
  "linux-raw-sys",
@@ -3084,7 +3078,7 @@ version = "1.0.4"
3084
  source = "registry+https://github.com/rust-lang/crates.io-index"
3085
  checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
3086
  dependencies = [
3087
- "base64 0.21.5",
3088
  ]
3089
 
3090
  [[package]]
@@ -3111,9 +3105,9 @@ dependencies = [
3111
 
3112
  [[package]]
3113
  name = "ryu"
3114
- version = "1.0.16"
3115
  source = "registry+https://github.com/rust-lang/crates.io-index"
3116
- checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
3117
 
3118
  [[package]]
3119
  name = "same-file"
@@ -3145,7 +3139,7 @@ version = "0.18.1"
3145
  source = "registry+https://github.com/rust-lang/crates.io-index"
3146
  checksum = "585480e3719b311b78a573db1c9d9c4c1f8010c2dee4cc59c2efe58ea4dbc3e1"
3147
  dependencies = [
3148
- "ahash 0.8.7",
3149
  "cssparser 0.31.2",
3150
  "ego-tree",
3151
  "html5ever 0.26.0",
@@ -3203,7 +3197,7 @@ version = "0.25.0"
3203
  source = "registry+https://github.com/rust-lang/crates.io-index"
3204
  checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06"
3205
  dependencies = [
3206
- "bitflags 2.4.1",
3207
  "cssparser 0.31.2",
3208
  "derive_more",
3209
  "fxhash",
@@ -3227,9 +3221,9 @@ dependencies = [
3227
 
3228
  [[package]]
3229
  name = "semver"
3230
- version = "1.0.20"
3231
  source = "registry+https://github.com/rust-lang/crates.io-index"
3232
- checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
3233
  dependencies = [
3234
  "serde",
3235
  ]
@@ -3242,29 +3236,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
3242
 
3243
  [[package]]
3244
  name = "serde"
3245
- version = "1.0.196"
3246
  source = "registry+https://github.com/rust-lang/crates.io-index"
3247
- checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
3248
  dependencies = [
3249
  "serde_derive",
3250
  ]
3251
 
3252
  [[package]]
3253
  name = "serde_derive"
3254
- version = "1.0.196"
3255
  source = "registry+https://github.com/rust-lang/crates.io-index"
3256
- checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
3257
  dependencies = [
3258
  "proc-macro2 1.0.78",
3259
  "quote 1.0.35",
3260
- "syn 2.0.48",
3261
  ]
3262
 
3263
  [[package]]
3264
  name = "serde_json"
3265
- version = "1.0.109"
3266
  source = "registry+https://github.com/rust-lang/crates.io-index"
3267
- checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9"
3268
  dependencies = [
3269
  "itoa 1.0.10",
3270
  "ryu",
@@ -3380,12 +3374,12 @@ dependencies = [
3380
 
3381
  [[package]]
3382
  name = "socket2"
3383
- version = "0.5.5"
3384
  source = "registry+https://github.com/rust-lang/crates.io-index"
3385
- checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
3386
  dependencies = [
3387
  "libc",
3388
- "windows-sys 0.48.0",
3389
  ]
3390
 
3391
  [[package]]
@@ -3394,6 +3388,15 @@ version = "0.9.8"
3394
  source = "registry+https://github.com/rust-lang/crates.io-index"
3395
  checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
3396
 
 
 
 
 
 
 
 
 
 
3397
  [[package]]
3398
  name = "stable_deref_trait"
3399
  version = "1.2.0"
@@ -3499,9 +3502,9 @@ dependencies = [
3499
 
3500
  [[package]]
3501
  name = "syn"
3502
- version = "2.0.48"
3503
  source = "registry+https://github.com/rust-lang/crates.io-index"
3504
- checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
3505
  dependencies = [
3506
  "proc-macro2 1.0.78",
3507
  "quote 1.0.35",
@@ -3526,32 +3529,22 @@ dependencies = [
3526
  "unicode-xid 0.2.4",
3527
  ]
3528
 
3529
- [[package]]
3530
- name = "sys-info"
3531
- version = "0.9.1"
3532
- source = "registry+https://github.com/rust-lang/crates.io-index"
3533
- checksum = "0b3a0d0aba8bf96a0e1ddfdc352fc53b3df7f39318c71854910c3c4b024ae52c"
3534
- dependencies = [
3535
- "cc",
3536
- "libc",
3537
- ]
3538
-
3539
  [[package]]
3540
  name = "system-configuration"
3541
- version = "0.5.1"
3542
  source = "registry+https://github.com/rust-lang/crates.io-index"
3543
- checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
3544
  dependencies = [
3545
- "bitflags 1.3.2",
3546
  "core-foundation",
3547
  "system-configuration-sys",
3548
  ]
3549
 
3550
  [[package]]
3551
  name = "system-configuration-sys"
3552
- version = "0.5.0"
3553
  source = "registry+https://github.com/rust-lang/crates.io-index"
3554
- checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
3555
  dependencies = [
3556
  "core-foundation-sys",
3557
  "libc",
@@ -3605,12 +3598,13 @@ dependencies = [
3605
 
3606
  [[package]]
3607
  name = "time"
3608
- version = "0.3.31"
3609
  source = "registry+https://github.com/rust-lang/crates.io-index"
3610
- checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e"
3611
  dependencies = [
3612
  "deranged",
3613
  "itoa 1.0.10",
 
3614
  "powerfmt",
3615
  "serde",
3616
  "time-core",
@@ -3625,10 +3619,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
3625
 
3626
  [[package]]
3627
  name = "time-macros"
3628
- version = "0.2.16"
3629
  source = "registry+https://github.com/rust-lang/crates.io-index"
3630
- checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f"
3631
  dependencies = [
 
3632
  "time-core",
3633
  ]
3634
 
@@ -3678,14 +3673,14 @@ dependencies = [
3678
 
3679
  [[package]]
3680
  name = "tokio"
3681
- version = "1.35.1"
3682
  source = "registry+https://github.com/rust-lang/crates.io-index"
3683
- checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
3684
  dependencies = [
3685
  "backtrace",
3686
  "bytes 1.5.0",
3687
  "libc",
3688
- "mio 0.8.10",
3689
  "num_cpus",
3690
  "parking_lot 0.12.1",
3691
  "pin-project-lite",
@@ -3745,7 +3740,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
3745
  dependencies = [
3746
  "proc-macro2 1.0.78",
3747
  "quote 1.0.35",
3748
- "syn 2.0.48",
3749
  ]
3750
 
3751
  [[package]]
@@ -3775,7 +3770,7 @@ checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f"
3775
  dependencies = [
3776
  "pin-project",
3777
  "rand 0.8.5",
3778
- "tokio 1.35.1",
3779
  ]
3780
 
3781
  [[package]]
@@ -3785,7 +3780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
3785
  checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
3786
  dependencies = [
3787
  "rustls",
3788
- "tokio 1.35.1",
3789
  ]
3790
 
3791
  [[package]]
@@ -3851,7 +3846,7 @@ dependencies = [
3851
  "futures-core",
3852
  "futures-sink",
3853
  "pin-project-lite",
3854
- "tokio 1.35.1",
3855
  "tracing",
3856
  ]
3857
 
@@ -3928,9 +3923,9 @@ dependencies = [
3928
 
3929
  [[package]]
3930
  name = "unicode-bidi"
3931
- version = "0.3.14"
3932
  source = "registry+https://github.com/rust-lang/crates.io-index"
3933
- checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
3934
 
3935
  [[package]]
3936
  name = "unicode-ident"
@@ -3940,9 +3935,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
3940
 
3941
  [[package]]
3942
  name = "unicode-normalization"
3943
- version = "0.1.22"
3944
  source = "registry+https://github.com/rust-lang/crates.io-index"
3945
- checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
3946
  dependencies = [
3947
  "tinyvec",
3948
  ]
@@ -4038,9 +4033,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
4038
 
4039
  [[package]]
4040
  name = "walkdir"
4041
- version = "2.4.0"
4042
  source = "registry+https://github.com/rust-lang/crates.io-index"
4043
- checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
4044
  dependencies = [
4045
  "same-file",
4046
  "winapi-util",
@@ -4080,9 +4075,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
4080
 
4081
  [[package]]
4082
  name = "wasm-bindgen"
4083
- version = "0.2.89"
4084
  source = "registry+https://github.com/rust-lang/crates.io-index"
4085
- checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
4086
  dependencies = [
4087
  "cfg-if 1.0.0",
4088
  "wasm-bindgen-macro",
@@ -4090,24 +4085,24 @@ dependencies = [
4090
 
4091
  [[package]]
4092
  name = "wasm-bindgen-backend"
4093
- version = "0.2.89"
4094
  source = "registry+https://github.com/rust-lang/crates.io-index"
4095
- checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
4096
  dependencies = [
4097
  "bumpalo",
4098
  "log",
4099
  "once_cell",
4100
  "proc-macro2 1.0.78",
4101
  "quote 1.0.35",
4102
- "syn 2.0.48",
4103
  "wasm-bindgen-shared",
4104
  ]
4105
 
4106
  [[package]]
4107
  name = "wasm-bindgen-futures"
4108
- version = "0.4.39"
4109
  source = "registry+https://github.com/rust-lang/crates.io-index"
4110
- checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
4111
  dependencies = [
4112
  "cfg-if 1.0.0",
4113
  "js-sys",
@@ -4117,9 +4112,9 @@ dependencies = [
4117
 
4118
  [[package]]
4119
  name = "wasm-bindgen-macro"
4120
- version = "0.2.89"
4121
  source = "registry+https://github.com/rust-lang/crates.io-index"
4122
- checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
4123
  dependencies = [
4124
  "quote 1.0.35",
4125
  "wasm-bindgen-macro-support",
@@ -4127,28 +4122,28 @@ dependencies = [
4127
 
4128
  [[package]]
4129
  name = "wasm-bindgen-macro-support"
4130
- version = "0.2.89"
4131
  source = "registry+https://github.com/rust-lang/crates.io-index"
4132
- checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
4133
  dependencies = [
4134
  "proc-macro2 1.0.78",
4135
  "quote 1.0.35",
4136
- "syn 2.0.48",
4137
  "wasm-bindgen-backend",
4138
  "wasm-bindgen-shared",
4139
  ]
4140
 
4141
  [[package]]
4142
  name = "wasm-bindgen-shared"
4143
- version = "0.2.89"
4144
  source = "registry+https://github.com/rust-lang/crates.io-index"
4145
- checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
4146
 
4147
  [[package]]
4148
  name = "web-sys"
4149
- version = "0.3.66"
4150
  source = "registry+https://github.com/rust-lang/crates.io-index"
4151
- checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
4152
  dependencies = [
4153
  "js-sys",
4154
  "wasm-bindgen",
@@ -4156,23 +4151,23 @@ dependencies = [
4156
 
4157
  [[package]]
4158
  name = "webpki-roots"
4159
- version = "0.25.3"
4160
  source = "registry+https://github.com/rust-lang/crates.io-index"
4161
- checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10"
4162
 
4163
  [[package]]
4164
  name = "websurfx"
4165
- version = "1.9.20"
4166
  dependencies = [
4167
  "actix-cors",
4168
  "actix-files",
4169
  "actix-governor",
4170
  "actix-web",
 
4171
  "async-once-cell",
4172
  "async-trait",
4173
- "base64 0.21.5",
4174
  "blake3",
4175
- "brotli",
4176
  "cfg-if 1.0.0",
4177
  "chacha20",
4178
  "chacha20poly1305",
@@ -4191,27 +4186,27 @@ dependencies = [
4191
  "mlua",
4192
  "redis",
4193
  "regex",
4194
- "reqwest 0.11.24",
4195
  "rusty-hook",
4196
  "scraper",
4197
  "serde",
4198
  "serde_json",
4199
  "smallvec 1.13.1",
4200
  "tempfile",
4201
- "tokio 1.35.1",
4202
  ]
4203
 
4204
  [[package]]
4205
  name = "which"
4206
- version = "5.0.0"
4207
  source = "registry+https://github.com/rust-lang/crates.io-index"
4208
- checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14"
4209
  dependencies = [
4210
  "either",
4211
  "home",
4212
  "once_cell",
4213
  "rustix",
4214
- "windows-sys 0.48.0",
4215
  ]
4216
 
4217
  [[package]]
@@ -4272,7 +4267,7 @@ version = "0.52.0"
4272
  source = "registry+https://github.com/rust-lang/crates.io-index"
4273
  checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
4274
  dependencies = [
4275
- "windows-targets 0.52.0",
4276
  ]
4277
 
4278
  [[package]]
@@ -4292,17 +4287,17 @@ dependencies = [
4292
 
4293
  [[package]]
4294
  name = "windows-targets"
4295
- version = "0.52.0"
4296
  source = "registry+https://github.com/rust-lang/crates.io-index"
4297
- checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
4298
  dependencies = [
4299
- "windows_aarch64_gnullvm 0.52.0",
4300
- "windows_aarch64_msvc 0.52.0",
4301
- "windows_i686_gnu 0.52.0",
4302
- "windows_i686_msvc 0.52.0",
4303
- "windows_x86_64_gnu 0.52.0",
4304
- "windows_x86_64_gnullvm 0.52.0",
4305
- "windows_x86_64_msvc 0.52.0",
4306
  ]
4307
 
4308
  [[package]]
@@ -4313,9 +4308,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
4313
 
4314
  [[package]]
4315
  name = "windows_aarch64_gnullvm"
4316
- version = "0.52.0"
4317
  source = "registry+https://github.com/rust-lang/crates.io-index"
4318
- checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
4319
 
4320
  [[package]]
4321
  name = "windows_aarch64_msvc"
@@ -4325,9 +4320,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
4325
 
4326
  [[package]]
4327
  name = "windows_aarch64_msvc"
4328
- version = "0.52.0"
4329
  source = "registry+https://github.com/rust-lang/crates.io-index"
4330
- checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
4331
 
4332
  [[package]]
4333
  name = "windows_i686_gnu"
@@ -4337,9 +4332,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
4337
 
4338
  [[package]]
4339
  name = "windows_i686_gnu"
4340
- version = "0.52.0"
4341
  source = "registry+https://github.com/rust-lang/crates.io-index"
4342
- checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
4343
 
4344
  [[package]]
4345
  name = "windows_i686_msvc"
@@ -4349,9 +4344,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
4349
 
4350
  [[package]]
4351
  name = "windows_i686_msvc"
4352
- version = "0.52.0"
4353
  source = "registry+https://github.com/rust-lang/crates.io-index"
4354
- checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
4355
 
4356
  [[package]]
4357
  name = "windows_x86_64_gnu"
@@ -4361,9 +4356,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
4361
 
4362
  [[package]]
4363
  name = "windows_x86_64_gnu"
4364
- version = "0.52.0"
4365
  source = "registry+https://github.com/rust-lang/crates.io-index"
4366
- checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
4367
 
4368
  [[package]]
4369
  name = "windows_x86_64_gnullvm"
@@ -4373,9 +4368,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
4373
 
4374
  [[package]]
4375
  name = "windows_x86_64_gnullvm"
4376
- version = "0.52.0"
4377
  source = "registry+https://github.com/rust-lang/crates.io-index"
4378
- checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
4379
 
4380
  [[package]]
4381
  name = "windows_x86_64_msvc"
@@ -4385,9 +4380,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
4385
 
4386
  [[package]]
4387
  name = "windows_x86_64_msvc"
4388
- version = "0.52.0"
4389
  source = "registry+https://github.com/rust-lang/crates.io-index"
4390
- checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
4391
 
4392
  [[package]]
4393
  name = "winreg"
@@ -4435,7 +4430,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
4435
  dependencies = [
4436
  "proc-macro2 1.0.78",
4437
  "quote 1.0.35",
4438
- "syn 2.0.48",
4439
  ]
4440
 
4441
  [[package]]
 
4
 
5
  [[package]]
6
  name = "actix-codec"
7
+ version = "0.5.2"
8
  source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a"
10
  dependencies = [
11
+ "bitflags 2.4.2",
12
  "bytes 1.5.0",
13
  "futures-core",
14
  "futures-sink",
15
  "memchr",
16
  "pin-project-lite",
17
+ "tokio 1.36.0",
18
  "tokio-util",
19
  "tracing",
20
  ]
 
44
  "actix-service",
45
  "actix-utils",
46
  "actix-web",
47
+ "bitflags 2.4.2",
48
  "bytes 1.5.0",
49
  "derive_more",
50
  "futures-core",
 
71
 
72
  [[package]]
73
  name = "actix-http"
74
+ version = "3.6.0"
75
  source = "registry+https://github.com/rust-lang/crates.io-index"
76
+ checksum = "d223b13fd481fc0d1f83bb12659ae774d9e3601814c68a0bc539731698cca743"
77
  dependencies = [
78
  "actix-codec",
79
  "actix-rt",
80
  "actix-service",
81
  "actix-utils",
82
+ "ahash",
83
+ "base64 0.21.7",
84
+ "bitflags 2.4.2",
85
  "brotli",
86
  "bytes 1.5.0",
87
  "bytestring",
88
  "derive_more",
89
  "encoding_rs",
90
  "futures-core",
91
+ "http 0.2.12",
92
  "httparse",
93
  "httpdate",
94
  "itoa 1.0.10",
 
100
  "rand 0.8.5",
101
  "sha1",
102
  "smallvec 1.13.1",
103
+ "tokio 1.36.0",
104
  "tokio-util",
105
  "tracing",
106
  ]
 
112
  checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
113
  dependencies = [
114
  "quote 1.0.35",
115
+ "syn 2.0.52",
116
  ]
117
 
118
  [[package]]
 
122
  checksum = "d22475596539443685426b6bdadb926ad0ecaefdfc5fb05e5e3441f15463c511"
123
  dependencies = [
124
  "bytestring",
125
+ "http 0.2.12",
126
  "regex",
127
  "serde",
128
  "tracing",
 
135
  checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d"
136
  dependencies = [
137
  "futures-core",
138
+ "tokio 1.36.0",
139
  ]
140
 
141
  [[package]]
 
149
  "actix-utils",
150
  "futures-core",
151
  "futures-util",
152
+ "mio 0.8.11",
153
  "socket2",
154
+ "tokio 1.36.0",
155
  "tracing",
156
  ]
157
 
 
178
 
179
  [[package]]
180
  name = "actix-web"
181
+ version = "4.5.1"
182
  source = "registry+https://github.com/rust-lang/crates.io-index"
183
+ checksum = "43a6556ddebb638c2358714d853257ed226ece6023ef9364f23f0c70737ea984"
184
  dependencies = [
185
  "actix-codec",
186
  "actix-http",
 
191
  "actix-service",
192
  "actix-utils",
193
  "actix-web-codegen",
194
+ "ahash",
195
  "bytes 1.5.0",
196
  "bytestring",
197
  "cfg-if 1.0.0",
 
212
  "serde_urlencoded 0.7.1",
213
  "smallvec 1.13.1",
214
  "socket2",
215
+ "time 0.3.34",
216
  "url 2.5.0",
217
  ]
218
 
 
225
  "actix-router",
226
  "proc-macro2 1.0.78",
227
  "quote 1.0.35",
228
+ "syn 2.0.52",
229
  ]
230
 
231
  [[package]]
 
255
 
256
  [[package]]
257
  name = "ahash"
258
+ version = "0.8.11"
 
 
 
 
 
 
 
 
 
 
 
259
  source = "registry+https://github.com/rust-lang/crates.io-index"
260
+ checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
261
  dependencies = [
262
  "cfg-if 1.0.0",
263
  "getrandom",
 
307
 
308
  [[package]]
309
  name = "anstyle"
310
+ version = "1.0.6"
311
  source = "registry+https://github.com/rust-lang/crates.io-index"
312
+ checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
313
 
314
  [[package]]
315
  name = "anyhow"
316
+ version = "1.0.80"
317
  source = "registry+https://github.com/rust-lang/crates.io-index"
318
+ checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
319
 
320
  [[package]]
321
  name = "arc-swap"
322
+ version = "1.7.0"
323
  source = "registry+https://github.com/rust-lang/crates.io-index"
324
+ checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f"
325
 
326
  [[package]]
327
  name = "arrayref"
 
337
 
338
  [[package]]
339
  name = "async-compression"
340
+ version = "0.4.6"
341
  source = "registry+https://github.com/rust-lang/crates.io-index"
342
+ checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c"
343
  dependencies = [
344
  "brotli",
345
  "flate2",
346
  "futures-core",
347
  "memchr",
348
  "pin-project-lite",
349
+ "tokio 1.36.0",
350
  ]
351
 
352
  [[package]]
 
357
 
358
  [[package]]
359
  name = "async-trait"
360
+ version = "0.1.77"
361
  source = "registry+https://github.com/rust-lang/crates.io-index"
362
+ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
363
  dependencies = [
364
  "proc-macro2 1.0.78",
365
  "quote 1.0.35",
366
+ "syn 2.0.52",
367
  ]
368
 
369
  [[package]]
 
407
 
408
  [[package]]
409
  name = "base64"
410
+ version = "0.21.7"
411
  source = "registry+https://github.com/rust-lang/crates.io-index"
412
+ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
413
 
414
  [[package]]
415
  name = "bit-set"
 
434
 
435
  [[package]]
436
  name = "bitflags"
437
+ version = "2.4.2"
438
  source = "registry+https://github.com/rust-lang/crates.io-index"
439
+ checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
440
 
441
  [[package]]
442
  name = "blake3"
 
483
 
484
  [[package]]
485
  name = "bstr"
486
+ version = "1.9.1"
487
  source = "registry+https://github.com/rust-lang/crates.io-index"
488
+ checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
489
  dependencies = [
490
  "memchr",
491
  "serde",
 
493
 
494
  [[package]]
495
  name = "bumpalo"
496
+ version = "3.15.4"
497
  source = "registry+https://github.com/rust-lang/crates.io-index"
498
+ checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
499
 
500
  [[package]]
501
  name = "bytecount"
 
546
 
547
  [[package]]
548
  name = "cargo-platform"
549
+ version = "0.1.7"
550
  source = "registry+https://github.com/rust-lang/crates.io-index"
551
+ checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f"
552
  dependencies = [
553
  "serde",
554
  ]
 
561
  dependencies = [
562
  "camino",
563
  "cargo-platform",
564
+ "semver 1.0.22",
565
  "serde",
566
  "serde_json",
567
  ]
 
574
 
575
  [[package]]
576
  name = "cc"
577
+ version = "1.0.90"
578
  source = "registry+https://github.com/rust-lang/crates.io-index"
579
+ checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
 
 
 
580
 
581
  [[package]]
582
  name = "cfg-if"
 
625
 
626
  [[package]]
627
  name = "ciborium"
628
+ version = "0.2.2"
629
  source = "registry+https://github.com/rust-lang/crates.io-index"
630
+ checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
631
  dependencies = [
632
  "ciborium-io",
633
  "ciborium-ll",
 
636
 
637
  [[package]]
638
  name = "ciborium-io"
639
+ version = "0.2.2"
640
  source = "registry+https://github.com/rust-lang/crates.io-index"
641
+ checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
642
 
643
  [[package]]
644
  name = "ciborium-ll"
645
+ version = "0.2.2"
646
  source = "registry+https://github.com/rust-lang/crates.io-index"
647
+ checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
648
  dependencies = [
649
  "ciborium-io",
650
  "half",
 
663
 
664
  [[package]]
665
  name = "clap"
666
+ version = "4.5.2"
667
  source = "registry+https://github.com/rust-lang/crates.io-index"
668
+ checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651"
669
  dependencies = [
670
  "clap_builder",
671
  ]
672
 
673
  [[package]]
674
  name = "clap_builder"
675
+ version = "4.5.2"
676
  source = "registry+https://github.com/rust-lang/crates.io-index"
677
+ checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
678
  dependencies = [
679
  "anstyle",
680
  "clap_lex",
 
682
 
683
  [[package]]
684
  name = "clap_lex"
685
+ version = "0.7.0"
686
  source = "registry+https://github.com/rust-lang/crates.io-index"
687
+ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
688
 
689
  [[package]]
690
  name = "cloudabi"
 
705
  "futures-core",
706
  "memchr",
707
  "pin-project-lite",
708
+ "tokio 1.36.0",
709
  "tokio-util",
710
  ]
711
 
 
758
  checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
759
  dependencies = [
760
  "percent-encoding 2.3.1",
761
+ "time 0.3.34",
762
  "version_check",
763
  ]
764
 
 
798
 
799
  [[package]]
800
  name = "cpufeatures"
801
+ version = "0.2.12"
802
  source = "registry+https://github.com/rust-lang/crates.io-index"
803
+ checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
804
  dependencies = [
805
  "libc",
806
  ]
807
 
808
  [[package]]
809
  name = "crc32fast"
810
+ version = "1.4.0"
811
  source = "registry+https://github.com/rust-lang/crates.io-index"
812
+ checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
813
  dependencies = [
814
  "cfg-if 1.0.0",
815
  ]
 
850
 
851
  [[package]]
852
  name = "crossbeam-channel"
853
+ version = "0.5.12"
854
  source = "registry+https://github.com/rust-lang/crates.io-index"
855
+ checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95"
856
  dependencies = [
857
+ "crossbeam-utils 0.8.19",
 
858
  ]
859
 
860
  [[package]]
 
907
 
908
  [[package]]
909
  name = "crossbeam-utils"
910
+ version = "0.8.19"
911
  source = "registry+https://github.com/rust-lang/crates.io-index"
912
+ checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
913
+
914
+ [[package]]
915
+ name = "crunchy"
916
+ version = "0.2.2"
917
+ source = "registry+https://github.com/rust-lang/crates.io-index"
918
+ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
919
 
920
  [[package]]
921
  name = "crypto-common"
 
970
  checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
971
  dependencies = [
972
  "quote 1.0.35",
973
+ "syn 2.0.52",
974
  ]
975
 
976
  [[package]]
 
994
 
995
  [[package]]
996
  name = "deranged"
997
+ version = "0.3.11"
998
  source = "registry+https://github.com/rust-lang/crates.io-index"
999
+ checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
1000
  dependencies = [
1001
  "powerfmt",
1002
  ]
 
1069
 
1070
  [[package]]
1071
  name = "either"
1072
+ version = "1.10.0"
1073
  source = "registry+https://github.com/rust-lang/crates.io-index"
1074
+ checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
1075
 
1076
  [[package]]
1077
  name = "encoding_rs"
 
1093
 
1094
  [[package]]
1095
  name = "env_logger"
1096
+ version = "0.11.3"
1097
  source = "registry+https://github.com/rust-lang/crates.io-index"
1098
+ checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
1099
  dependencies = [
1100
  "env_filter",
1101
  "log",
 
1335
  dependencies = [
1336
  "proc-macro2 1.0.78",
1337
  "quote 1.0.35",
1338
+ "syn 2.0.52",
1339
  ]
1340
 
1341
  [[package]]
 
1352
 
1353
  [[package]]
1354
  name = "futures-timer"
1355
+ version = "3.0.3"
1356
  source = "registry+https://github.com/rust-lang/crates.io-index"
1357
+ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
1358
 
1359
  [[package]]
1360
  name = "futures-util"
 
1404
 
1405
  [[package]]
1406
  name = "getrandom"
1407
+ version = "0.2.12"
1408
  source = "registry+https://github.com/rust-lang/crates.io-index"
1409
+ checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
1410
  dependencies = [
1411
  "cfg-if 1.0.0",
1412
  "libc",
 
1427
 
1428
  [[package]]
1429
  name = "governor"
1430
+ version = "0.6.3"
1431
  source = "registry+https://github.com/rust-lang/crates.io-index"
1432
+ checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b"
1433
  dependencies = [
1434
  "cfg-if 1.0.0",
1435
  "dashmap",
 
1438
  "no-std-compat",
1439
  "nonzero_ext",
1440
  "parking_lot 0.12.1",
1441
+ "portable-atomic",
1442
  "quanta",
1443
  "rand 0.8.5",
1444
  "smallvec 1.13.1",
1445
+ "spinning_top",
1446
  ]
1447
 
1448
  [[package]]
 
1465
 
1466
  [[package]]
1467
  name = "h2"
1468
+ version = "0.3.24"
1469
  source = "registry+https://github.com/rust-lang/crates.io-index"
1470
+ checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
1471
  dependencies = [
1472
  "bytes 1.5.0",
1473
  "fnv",
1474
  "futures-core",
1475
  "futures-sink",
1476
  "futures-util",
1477
+ "http 0.2.12",
1478
+ "indexmap 2.2.5",
1479
  "slab",
1480
+ "tokio 1.36.0",
1481
  "tokio-util",
1482
  "tracing",
1483
  ]
1484
 
1485
  [[package]]
1486
  name = "half"
1487
+ version = "2.4.0"
1488
  source = "registry+https://github.com/rust-lang/crates.io-index"
1489
+ checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e"
1490
+ dependencies = [
1491
+ "cfg-if 1.0.0",
1492
+ "crunchy",
1493
+ ]
1494
 
1495
  [[package]]
1496
  name = "hashbrown"
 
1504
  source = "registry+https://github.com/rust-lang/crates.io-index"
1505
  checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
1506
  dependencies = [
1507
+ "ahash",
1508
  "bumpalo",
1509
  ]
1510
 
 
1516
 
1517
  [[package]]
1518
  name = "hermit-abi"
1519
+ version = "0.3.9"
1520
  source = "registry+https://github.com/rust-lang/crates.io-index"
1521
+ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
1522
 
1523
  [[package]]
1524
  name = "home"
 
1570
 
1571
  [[package]]
1572
  name = "http"
1573
+ version = "0.2.12"
1574
  source = "registry+https://github.com/rust-lang/crates.io-index"
1575
+ checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
1576
  dependencies = [
1577
  "bytes 1.5.0",
1578
  "fnv",
 
1598
  checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
1599
  dependencies = [
1600
  "bytes 1.5.0",
1601
+ "http 0.2.12",
1602
  "pin-project-lite",
1603
  ]
1604
 
 
1660
  "futures-channel",
1661
  "futures-core",
1662
  "futures-util",
1663
+ "h2 0.3.24",
1664
+ "http 0.2.12",
1665
  "http-body 0.4.6",
1666
  "httparse",
1667
  "httpdate",
1668
  "itoa 1.0.10",
1669
  "pin-project-lite",
1670
  "socket2",
1671
+ "tokio 1.36.0",
1672
  "tower-service",
1673
  "tracing",
1674
  "want 0.3.1",
 
1681
  checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
1682
  dependencies = [
1683
  "futures-util",
1684
+ "http 0.2.12",
1685
  "hyper 0.14.28",
1686
  "rustls",
1687
+ "tokio 1.36.0",
1688
  "tokio-rustls",
1689
  ]
1690
 
 
1745
 
1746
  [[package]]
1747
  name = "indexmap"
1748
+ version = "2.2.5"
1749
  source = "registry+https://github.com/rust-lang/crates.io-index"
1750
+ checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
1751
  dependencies = [
1752
  "equivalent",
1753
  "hashbrown 0.14.3",
 
1779
 
1780
  [[package]]
1781
  name = "is-terminal"
1782
+ version = "0.4.12"
1783
  source = "registry+https://github.com/rust-lang/crates.io-index"
1784
+ checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
1785
  dependencies = [
1786
  "hermit-abi",
1787
+ "libc",
1788
  "windows-sys 0.52.0",
1789
  ]
1790
 
 
1811
 
1812
  [[package]]
1813
  name = "js-sys"
1814
+ version = "0.3.69"
1815
  source = "registry+https://github.com/rust-lang/crates.io-index"
1816
+ checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
1817
  dependencies = [
1818
  "wasm-bindgen",
1819
  ]
 
1858
 
1859
  [[package]]
1860
  name = "lightningcss"
1861
+ version = "1.0.0-alpha.54"
1862
  source = "registry+https://github.com/rust-lang/crates.io-index"
1863
+ checksum = "07d306844e5af1753490c420c0d6ae3d814b00725092d106332762827ca8f0fe"
1864
  dependencies = [
1865
+ "ahash",
1866
+ "bitflags 2.4.2",
1867
  "const-str",
1868
  "cssparser 0.33.0",
1869
  "cssparser-color",
1870
  "data-encoding",
1871
+ "getrandom",
1872
  "itertools",
1873
  "lazy_static",
1874
  "parcel_selectors",
 
1879
 
1880
  [[package]]
1881
  name = "linux-raw-sys"
1882
+ version = "0.4.13"
1883
  source = "registry+https://github.com/rust-lang/crates.io-index"
1884
+ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
1885
 
1886
  [[package]]
1887
  name = "local-channel"
 
1936
 
1937
  [[package]]
1938
  name = "luajit-src"
1939
+ version = "210.5.6+9cc2e42"
1940
  source = "registry+https://github.com/rust-lang/crates.io-index"
1941
+ checksum = "23b365d859c9ffc187f48bb3e25ec80c3b40cf3f68f53544f4adeaee70554157"
1942
  dependencies = [
1943
  "cc",
1944
  "which",
 
1950
  source = "registry+https://github.com/rust-lang/crates.io-index"
1951
  checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
1952
 
 
 
 
 
 
 
 
 
 
1953
  [[package]]
1954
  name = "markup5ever"
1955
  version = "0.8.1"
 
2059
 
2060
  [[package]]
2061
  name = "mini-moka"
2062
+ version = "0.10.3"
2063
  source = "registry+https://github.com/rust-lang/crates.io-index"
2064
+ checksum = "c325dfab65f261f386debee8b0969da215b3fa0037e74c8a1234db7ba986d803"
2065
  dependencies = [
2066
  "crossbeam-channel",
2067
+ "crossbeam-utils 0.8.19",
2068
  "dashmap",
2069
  "skeptic",
2070
  "smallvec 1.13.1",
 
2085
 
2086
  [[package]]
2087
  name = "miniz_oxide"
2088
+ version = "0.7.2"
2089
  source = "registry+https://github.com/rust-lang/crates.io-index"
2090
+ checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
2091
  dependencies = [
2092
  "adler",
2093
  ]
2094
 
2095
  [[package]]
2096
  name = "mintex"
2097
+ version = "0.1.3"
2098
  source = "registry+https://github.com/rust-lang/crates.io-index"
2099
+ checksum = "9bec4598fddb13cc7b528819e697852653252b760f1228b7642679bf2ff2cd07"
 
 
 
 
2100
 
2101
  [[package]]
2102
  name = "mio"
 
2119
 
2120
  [[package]]
2121
  name = "mio"
2122
+ version = "0.8.11"
2123
  source = "registry+https://github.com/rust-lang/crates.io-index"
2124
+ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
2125
  dependencies = [
2126
  "libc",
2127
  "log",
 
2143
 
2144
  [[package]]
2145
  name = "mlua"
2146
+ version = "0.9.6"
2147
  source = "registry+https://github.com/rust-lang/crates.io-index"
2148
+ checksum = "868d02cb5eb97761bbf6bd6922c1c7a88b8ea252bbf43bd8350a0bf8497a1fc0"
2149
  dependencies = [
2150
  "bstr",
2151
  "mlua-sys",
 
2156
 
2157
  [[package]]
2158
  name = "mlua-sys"
2159
+ version = "0.5.1"
2160
  source = "registry+https://github.com/rust-lang/crates.io-index"
2161
+ checksum = "2847b42764435201d8cbee1f517edb79c4cca4181877b90047587c89e1b7bce4"
2162
  dependencies = [
2163
  "cc",
2164
  "cfg-if 1.0.0",
 
2220
  source = "registry+https://github.com/rust-lang/crates.io-index"
2221
  checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
2222
 
2223
+ [[package]]
2224
+ name = "num-conv"
2225
+ version = "0.1.0"
2226
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2227
+ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
2228
+
2229
  [[package]]
2230
  name = "num-traits"
2231
+ version = "0.2.18"
2232
  source = "registry+https://github.com/rust-lang/crates.io-index"
2233
+ checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
2234
  dependencies = [
2235
  "autocfg 1.1.0",
2236
  ]
 
2268
 
2269
  [[package]]
2270
  name = "opaque-debug"
2271
+ version = "0.3.1"
2272
  source = "registry+https://github.com/rust-lang/crates.io-index"
2273
+ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
2274
 
2275
  [[package]]
2276
  name = "openssl"
2277
+ version = "0.10.64"
2278
  source = "registry+https://github.com/rust-lang/crates.io-index"
2279
+ checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
2280
  dependencies = [
2281
+ "bitflags 2.4.2",
2282
  "cfg-if 1.0.0",
2283
  "foreign-types",
2284
  "libc",
 
2295
  dependencies = [
2296
  "proc-macro2 1.0.78",
2297
  "quote 1.0.35",
2298
+ "syn 2.0.52",
2299
  ]
2300
 
2301
  [[package]]
 
2306
 
2307
  [[package]]
2308
  name = "openssl-sys"
2309
+ version = "0.9.101"
2310
  source = "registry+https://github.com/rust-lang/crates.io-index"
2311
+ checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff"
2312
  dependencies = [
2313
  "cc",
2314
  "libc",
 
2322
  source = "registry+https://github.com/rust-lang/crates.io-index"
2323
  checksum = "05d74befe2d076330d9a58bf9ca2da424568724ab278adf15fb5718253133887"
2324
  dependencies = [
2325
+ "bitflags 2.4.2",
2326
  "cssparser 0.33.0",
2327
  "fxhash",
2328
  "log",
 
2506
  "phf_shared 0.11.2",
2507
  "proc-macro2 1.0.78",
2508
  "quote 1.0.35",
2509
+ "syn 2.0.52",
2510
  ]
2511
 
2512
  [[package]]
 
2538
 
2539
  [[package]]
2540
  name = "pin-project"
2541
+ version = "1.1.5"
2542
  source = "registry+https://github.com/rust-lang/crates.io-index"
2543
+ checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
2544
  dependencies = [
2545
  "pin-project-internal",
2546
  ]
2547
 
2548
  [[package]]
2549
  name = "pin-project-internal"
2550
+ version = "1.1.5"
2551
  source = "registry+https://github.com/rust-lang/crates.io-index"
2552
+ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
2553
  dependencies = [
2554
  "proc-macro2 1.0.78",
2555
  "quote 1.0.35",
2556
+ "syn 2.0.52",
2557
  ]
2558
 
2559
  [[package]]
 
2570
 
2571
  [[package]]
2572
  name = "pkg-config"
2573
+ version = "0.3.30"
2574
  source = "registry+https://github.com/rust-lang/crates.io-index"
2575
+ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
2576
 
2577
  [[package]]
2578
  name = "poly1305"
 
2585
  "universal-hash",
2586
  ]
2587
 
2588
+ [[package]]
2589
+ name = "portable-atomic"
2590
+ version = "1.6.0"
2591
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2592
+ checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
2593
+
2594
  [[package]]
2595
  name = "powerfmt"
2596
  version = "0.2.0"
 
2663
 
2664
  [[package]]
2665
  name = "pulldown-cmark"
2666
+ version = "0.9.6"
2667
  source = "registry+https://github.com/rust-lang/crates.io-index"
2668
+ checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
2669
  dependencies = [
2670
+ "bitflags 2.4.2",
2671
  "memchr",
2672
  "unicase",
2673
  ]
2674
 
2675
  [[package]]
2676
  name = "quanta"
2677
+ version = "0.12.2"
2678
  source = "registry+https://github.com/rust-lang/crates.io-index"
2679
+ checksum = "9ca0b7bac0b97248c40bb77288fc52029cf1459c0461ea1b05ee32ccf011de2c"
2680
  dependencies = [
2681
+ "crossbeam-utils 0.8.19",
2682
  "libc",
 
2683
  "once_cell",
2684
  "raw-cpuid",
2685
  "wasi 0.11.0+wasi-snapshot-preview1",
 
2843
 
2844
  [[package]]
2845
  name = "raw-cpuid"
2846
+ version = "11.0.1"
2847
  source = "registry+https://github.com/rust-lang/crates.io-index"
2848
+ checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1"
2849
  dependencies = [
2850
+ "bitflags 2.4.2",
2851
  ]
2852
 
2853
  [[package]]
 
2875
  "percent-encoding 2.3.1",
2876
  "pin-project-lite",
2877
  "ryu",
2878
+ "tokio 1.36.0",
2879
  "tokio-retry",
2880
  "tokio-util",
2881
  "url 2.5.0",
 
2898
 
2899
  [[package]]
2900
  name = "regex"
2901
+ version = "1.10.3"
2902
  source = "registry+https://github.com/rust-lang/crates.io-index"
2903
+ checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
2904
  dependencies = [
2905
  "aho-corasick 1.1.2",
2906
  "memchr",
 
2910
 
2911
  [[package]]
2912
  name = "regex-automata"
2913
+ version = "0.4.6"
2914
  source = "registry+https://github.com/rust-lang/crates.io-index"
2915
+ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
2916
  dependencies = [
2917
  "aho-corasick 1.1.2",
2918
  "memchr",
 
2961
 
2962
  [[package]]
2963
  name = "reqwest"
2964
+ version = "0.11.25"
2965
  source = "registry+https://github.com/rust-lang/crates.io-index"
2966
+ checksum = "0eea5a9eb898d3783f17c6407670e3592fd174cb81a10e51d4c37f49450b9946"
2967
  dependencies = [
2968
  "async-compression",
2969
+ "base64 0.21.7",
2970
  "bytes 1.5.0",
2971
  "encoding_rs",
2972
  "futures-core",
2973
  "futures-util",
2974
+ "h2 0.3.24",
2975
+ "http 0.2.12",
2976
  "http-body 0.4.6",
2977
  "hyper 0.14.28",
2978
  "hyper-rustls",
 
2990
  "serde_urlencoded 0.7.1",
2991
  "sync_wrapper",
2992
  "system-configuration",
2993
+ "tokio 1.36.0",
2994
  "tokio-rustls",
2995
  "tokio-util",
2996
  "tower-service",
 
3004
 
3005
  [[package]]
3006
  name = "ring"
3007
+ version = "0.17.8"
3008
  source = "registry+https://github.com/rust-lang/crates.io-index"
3009
+ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
3010
  dependencies = [
3011
  "cc",
3012
+ "cfg-if 1.0.0",
3013
  "getrandom",
3014
  "libc",
3015
  "spin",
3016
  "untrusted",
3017
+ "windows-sys 0.52.0",
3018
  ]
3019
 
3020
  [[package]]
 
3044
  source = "registry+https://github.com/rust-lang/crates.io-index"
3045
  checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
3046
  dependencies = [
3047
+ "semver 1.0.22",
3048
  ]
3049
 
3050
  [[package]]
 
3053
  source = "registry+https://github.com/rust-lang/crates.io-index"
3054
  checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
3055
  dependencies = [
3056
+ "bitflags 2.4.2",
3057
  "errno",
3058
  "libc",
3059
  "linux-raw-sys",
 
3078
  source = "registry+https://github.com/rust-lang/crates.io-index"
3079
  checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
3080
  dependencies = [
3081
+ "base64 0.21.7",
3082
  ]
3083
 
3084
  [[package]]
 
3105
 
3106
  [[package]]
3107
  name = "ryu"
3108
+ version = "1.0.17"
3109
  source = "registry+https://github.com/rust-lang/crates.io-index"
3110
+ checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
3111
 
3112
  [[package]]
3113
  name = "same-file"
 
3139
  source = "registry+https://github.com/rust-lang/crates.io-index"
3140
  checksum = "585480e3719b311b78a573db1c9d9c4c1f8010c2dee4cc59c2efe58ea4dbc3e1"
3141
  dependencies = [
3142
+ "ahash",
3143
  "cssparser 0.31.2",
3144
  "ego-tree",
3145
  "html5ever 0.26.0",
 
3197
  source = "registry+https://github.com/rust-lang/crates.io-index"
3198
  checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06"
3199
  dependencies = [
3200
+ "bitflags 2.4.2",
3201
  "cssparser 0.31.2",
3202
  "derive_more",
3203
  "fxhash",
 
3221
 
3222
  [[package]]
3223
  name = "semver"
3224
+ version = "1.0.22"
3225
  source = "registry+https://github.com/rust-lang/crates.io-index"
3226
+ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
3227
  dependencies = [
3228
  "serde",
3229
  ]
 
3236
 
3237
  [[package]]
3238
  name = "serde"
3239
+ version = "1.0.197"
3240
  source = "registry+https://github.com/rust-lang/crates.io-index"
3241
+ checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
3242
  dependencies = [
3243
  "serde_derive",
3244
  ]
3245
 
3246
  [[package]]
3247
  name = "serde_derive"
3248
+ version = "1.0.197"
3249
  source = "registry+https://github.com/rust-lang/crates.io-index"
3250
+ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
3251
  dependencies = [
3252
  "proc-macro2 1.0.78",
3253
  "quote 1.0.35",
3254
+ "syn 2.0.52",
3255
  ]
3256
 
3257
  [[package]]
3258
  name = "serde_json"
3259
+ version = "1.0.114"
3260
  source = "registry+https://github.com/rust-lang/crates.io-index"
3261
+ checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
3262
  dependencies = [
3263
  "itoa 1.0.10",
3264
  "ryu",
 
3374
 
3375
  [[package]]
3376
  name = "socket2"
3377
+ version = "0.5.6"
3378
  source = "registry+https://github.com/rust-lang/crates.io-index"
3379
+ checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871"
3380
  dependencies = [
3381
  "libc",
3382
+ "windows-sys 0.52.0",
3383
  ]
3384
 
3385
  [[package]]
 
3388
  source = "registry+https://github.com/rust-lang/crates.io-index"
3389
  checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
3390
 
3391
+ [[package]]
3392
+ name = "spinning_top"
3393
+ version = "0.3.0"
3394
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3395
+ checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
3396
+ dependencies = [
3397
+ "lock_api 0.4.11",
3398
+ ]
3399
+
3400
  [[package]]
3401
  name = "stable_deref_trait"
3402
  version = "1.2.0"
 
3502
 
3503
  [[package]]
3504
  name = "syn"
3505
+ version = "2.0.52"
3506
  source = "registry+https://github.com/rust-lang/crates.io-index"
3507
+ checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
3508
  dependencies = [
3509
  "proc-macro2 1.0.78",
3510
  "quote 1.0.35",
 
3529
  "unicode-xid 0.2.4",
3530
  ]
3531
 
 
 
 
 
 
 
 
 
 
 
3532
  [[package]]
3533
  name = "system-configuration"
3534
+ version = "0.6.0"
3535
  source = "registry+https://github.com/rust-lang/crates.io-index"
3536
+ checksum = "658bc6ee10a9b4fcf576e9b0819d95ec16f4d2c02d39fd83ac1c8789785c4a42"
3537
  dependencies = [
3538
+ "bitflags 2.4.2",
3539
  "core-foundation",
3540
  "system-configuration-sys",
3541
  ]
3542
 
3543
  [[package]]
3544
  name = "system-configuration-sys"
3545
+ version = "0.6.0"
3546
  source = "registry+https://github.com/rust-lang/crates.io-index"
3547
+ checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
3548
  dependencies = [
3549
  "core-foundation-sys",
3550
  "libc",
 
3598
 
3599
  [[package]]
3600
  name = "time"
3601
+ version = "0.3.34"
3602
  source = "registry+https://github.com/rust-lang/crates.io-index"
3603
+ checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
3604
  dependencies = [
3605
  "deranged",
3606
  "itoa 1.0.10",
3607
+ "num-conv",
3608
  "powerfmt",
3609
  "serde",
3610
  "time-core",
 
3619
 
3620
  [[package]]
3621
  name = "time-macros"
3622
+ version = "0.2.17"
3623
  source = "registry+https://github.com/rust-lang/crates.io-index"
3624
+ checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
3625
  dependencies = [
3626
+ "num-conv",
3627
  "time-core",
3628
  ]
3629
 
 
3673
 
3674
  [[package]]
3675
  name = "tokio"
3676
+ version = "1.36.0"
3677
  source = "registry+https://github.com/rust-lang/crates.io-index"
3678
+ checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
3679
  dependencies = [
3680
  "backtrace",
3681
  "bytes 1.5.0",
3682
  "libc",
3683
+ "mio 0.8.11",
3684
  "num_cpus",
3685
  "parking_lot 0.12.1",
3686
  "pin-project-lite",
 
3740
  dependencies = [
3741
  "proc-macro2 1.0.78",
3742
  "quote 1.0.35",
3743
+ "syn 2.0.52",
3744
  ]
3745
 
3746
  [[package]]
 
3770
  dependencies = [
3771
  "pin-project",
3772
  "rand 0.8.5",
3773
+ "tokio 1.36.0",
3774
  ]
3775
 
3776
  [[package]]
 
3780
  checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
3781
  dependencies = [
3782
  "rustls",
3783
+ "tokio 1.36.0",
3784
  ]
3785
 
3786
  [[package]]
 
3846
  "futures-core",
3847
  "futures-sink",
3848
  "pin-project-lite",
3849
+ "tokio 1.36.0",
3850
  "tracing",
3851
  ]
3852
 
 
3923
 
3924
  [[package]]
3925
  name = "unicode-bidi"
3926
+ version = "0.3.15"
3927
  source = "registry+https://github.com/rust-lang/crates.io-index"
3928
+ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
3929
 
3930
  [[package]]
3931
  name = "unicode-ident"
 
3935
 
3936
  [[package]]
3937
  name = "unicode-normalization"
3938
+ version = "0.1.23"
3939
  source = "registry+https://github.com/rust-lang/crates.io-index"
3940
+ checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
3941
  dependencies = [
3942
  "tinyvec",
3943
  ]
 
4033
 
4034
  [[package]]
4035
  name = "walkdir"
4036
+ version = "2.5.0"
4037
  source = "registry+https://github.com/rust-lang/crates.io-index"
4038
+ checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
4039
  dependencies = [
4040
  "same-file",
4041
  "winapi-util",
 
4075
 
4076
  [[package]]
4077
  name = "wasm-bindgen"
4078
+ version = "0.2.92"
4079
  source = "registry+https://github.com/rust-lang/crates.io-index"
4080
+ checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
4081
  dependencies = [
4082
  "cfg-if 1.0.0",
4083
  "wasm-bindgen-macro",
 
4085
 
4086
  [[package]]
4087
  name = "wasm-bindgen-backend"
4088
+ version = "0.2.92"
4089
  source = "registry+https://github.com/rust-lang/crates.io-index"
4090
+ checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
4091
  dependencies = [
4092
  "bumpalo",
4093
  "log",
4094
  "once_cell",
4095
  "proc-macro2 1.0.78",
4096
  "quote 1.0.35",
4097
+ "syn 2.0.52",
4098
  "wasm-bindgen-shared",
4099
  ]
4100
 
4101
  [[package]]
4102
  name = "wasm-bindgen-futures"
4103
+ version = "0.4.42"
4104
  source = "registry+https://github.com/rust-lang/crates.io-index"
4105
+ checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
4106
  dependencies = [
4107
  "cfg-if 1.0.0",
4108
  "js-sys",
 
4112
 
4113
  [[package]]
4114
  name = "wasm-bindgen-macro"
4115
+ version = "0.2.92"
4116
  source = "registry+https://github.com/rust-lang/crates.io-index"
4117
+ checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
4118
  dependencies = [
4119
  "quote 1.0.35",
4120
  "wasm-bindgen-macro-support",
 
4122
 
4123
  [[package]]
4124
  name = "wasm-bindgen-macro-support"
4125
+ version = "0.2.92"
4126
  source = "registry+https://github.com/rust-lang/crates.io-index"
4127
+ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
4128
  dependencies = [
4129
  "proc-macro2 1.0.78",
4130
  "quote 1.0.35",
4131
+ "syn 2.0.52",
4132
  "wasm-bindgen-backend",
4133
  "wasm-bindgen-shared",
4134
  ]
4135
 
4136
  [[package]]
4137
  name = "wasm-bindgen-shared"
4138
+ version = "0.2.92"
4139
  source = "registry+https://github.com/rust-lang/crates.io-index"
4140
+ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
4141
 
4142
  [[package]]
4143
  name = "web-sys"
4144
+ version = "0.3.69"
4145
  source = "registry+https://github.com/rust-lang/crates.io-index"
4146
+ checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
4147
  dependencies = [
4148
  "js-sys",
4149
  "wasm-bindgen",
 
4151
 
4152
  [[package]]
4153
  name = "webpki-roots"
4154
+ version = "0.25.4"
4155
  source = "registry+https://github.com/rust-lang/crates.io-index"
4156
+ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
4157
 
4158
  [[package]]
4159
  name = "websurfx"
4160
+ version = "1.10.9"
4161
  dependencies = [
4162
  "actix-cors",
4163
  "actix-files",
4164
  "actix-governor",
4165
  "actix-web",
4166
+ "async-compression",
4167
  "async-once-cell",
4168
  "async-trait",
4169
+ "base64 0.21.7",
4170
  "blake3",
 
4171
  "cfg-if 1.0.0",
4172
  "chacha20",
4173
  "chacha20poly1305",
 
4186
  "mlua",
4187
  "redis",
4188
  "regex",
4189
+ "reqwest 0.11.25",
4190
  "rusty-hook",
4191
  "scraper",
4192
  "serde",
4193
  "serde_json",
4194
  "smallvec 1.13.1",
4195
  "tempfile",
4196
+ "tokio 1.36.0",
4197
  ]
4198
 
4199
  [[package]]
4200
  name = "which"
4201
+ version = "6.0.0"
4202
  source = "registry+https://github.com/rust-lang/crates.io-index"
4203
+ checksum = "7fa5e0c10bf77f44aac573e498d1a82d5fbd5e91f6fc0a99e7be4b38e85e101c"
4204
  dependencies = [
4205
  "either",
4206
  "home",
4207
  "once_cell",
4208
  "rustix",
4209
+ "windows-sys 0.52.0",
4210
  ]
4211
 
4212
  [[package]]
 
4267
  source = "registry+https://github.com/rust-lang/crates.io-index"
4268
  checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
4269
  dependencies = [
4270
+ "windows-targets 0.52.4",
4271
  ]
4272
 
4273
  [[package]]
 
4287
 
4288
  [[package]]
4289
  name = "windows-targets"
4290
+ version = "0.52.4"
4291
  source = "registry+https://github.com/rust-lang/crates.io-index"
4292
+ checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
4293
  dependencies = [
4294
+ "windows_aarch64_gnullvm 0.52.4",
4295
+ "windows_aarch64_msvc 0.52.4",
4296
+ "windows_i686_gnu 0.52.4",
4297
+ "windows_i686_msvc 0.52.4",
4298
+ "windows_x86_64_gnu 0.52.4",
4299
+ "windows_x86_64_gnullvm 0.52.4",
4300
+ "windows_x86_64_msvc 0.52.4",
4301
  ]
4302
 
4303
  [[package]]
 
4308
 
4309
  [[package]]
4310
  name = "windows_aarch64_gnullvm"
4311
+ version = "0.52.4"
4312
  source = "registry+https://github.com/rust-lang/crates.io-index"
4313
+ checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
4314
 
4315
  [[package]]
4316
  name = "windows_aarch64_msvc"
 
4320
 
4321
  [[package]]
4322
  name = "windows_aarch64_msvc"
4323
+ version = "0.52.4"
4324
  source = "registry+https://github.com/rust-lang/crates.io-index"
4325
+ checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
4326
 
4327
  [[package]]
4328
  name = "windows_i686_gnu"
 
4332
 
4333
  [[package]]
4334
  name = "windows_i686_gnu"
4335
+ version = "0.52.4"
4336
  source = "registry+https://github.com/rust-lang/crates.io-index"
4337
+ checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
4338
 
4339
  [[package]]
4340
  name = "windows_i686_msvc"
 
4344
 
4345
  [[package]]
4346
  name = "windows_i686_msvc"
4347
+ version = "0.52.4"
4348
  source = "registry+https://github.com/rust-lang/crates.io-index"
4349
+ checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
4350
 
4351
  [[package]]
4352
  name = "windows_x86_64_gnu"
 
4356
 
4357
  [[package]]
4358
  name = "windows_x86_64_gnu"
4359
+ version = "0.52.4"
4360
  source = "registry+https://github.com/rust-lang/crates.io-index"
4361
+ checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
4362
 
4363
  [[package]]
4364
  name = "windows_x86_64_gnullvm"
 
4368
 
4369
  [[package]]
4370
  name = "windows_x86_64_gnullvm"
4371
+ version = "0.52.4"
4372
  source = "registry+https://github.com/rust-lang/crates.io-index"
4373
+ checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
4374
 
4375
  [[package]]
4376
  name = "windows_x86_64_msvc"
 
4380
 
4381
  [[package]]
4382
  name = "windows_x86_64_msvc"
4383
+ version = "0.52.4"
4384
  source = "registry+https://github.com/rust-lang/crates.io-index"
4385
+ checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
4386
 
4387
  [[package]]
4388
  name = "winreg"
 
4430
  dependencies = [
4431
  "proc-macro2 1.0.78",
4432
  "quote 1.0.35",
4433
+ "syn 2.0.52",
4434
  ]
4435
 
4436
  [[package]]
Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
  [package]
2
  name = "websurfx"
3
- version = "1.9.20"
4
  edition = "2021"
5
  description = "An open-source alternative to Searx that provides clean, ad-free, and organic results with incredible speed while keeping privacy and security in mind."
6
  repository = "https://github.com/neon-mmd/websurfx"
@@ -14,7 +14,7 @@ path = "src/bin/websurfx.rs"
14
 
15
  [dependencies]
16
  reqwest = {version="0.11.24", default-features=false, features=["rustls-tls","brotli", "gzip"]}
17
- tokio = {version="1.32.0",features=["rt-multi-thread","macros"], default-features = false}
18
  serde = {version="1.0.196", default-features=false, features=["derive"]}
19
  serde_json = {version="1.0.109", default-features=false}
20
  maud = {version="0.25.0", default-features=false, features=["actix-web"]}
@@ -32,13 +32,13 @@ error-stack = {version="0.4.0", default-features=false, features=["std"]}
32
  async-trait = {version="0.1.76", default-features=false}
33
  regex = {version="1.9.4", features=["perf"], default-features = false}
34
  smallvec = {version="1.13.1", features=["union", "serde"], default-features=false}
35
- futures = {version="0.3.28", default-features=false}
36
- dhat = {version="0.3.3", optional = true, default-features=false}
37
  mimalloc = { version = "0.1.38", default-features = false }
38
  async-once-cell = {version="0.5.3", default-features=false}
39
  actix-governor = {version="0.5.0", default-features=false}
40
  mini-moka = { version="0.10", optional = true, default-features=false, features=["sync"]}
41
- brotli = { version = "3.4.0", default-features = false, features=["std"], optional=true}
42
  chacha20poly1305={version="0.10.1", default-features=false, features=["alloc","getrandom"], optional=true}
43
  chacha20 = {version="0.9.1", default-features=false, optional=true}
44
  base64 = {version="0.21.5", default-features=false, features=["std"], optional=true}
@@ -84,7 +84,7 @@ default = ["memory-cache"]
84
  dhat-heap = ["dep:dhat"]
85
  memory-cache = ["dep:mini-moka"]
86
  redis-cache = ["dep:redis","dep:base64"]
87
- compress-cache-results = ["dep:brotli","dep:cfg-if"]
88
  encrypt-cache-results = ["dep:chacha20poly1305","dep:chacha20"]
89
  cec-cache-results = ["compress-cache-results","encrypt-cache-results"]
90
 
 
1
  [package]
2
  name = "websurfx"
3
+ version = "1.10.9"
4
  edition = "2021"
5
  description = "An open-source alternative to Searx that provides clean, ad-free, and organic results with incredible speed while keeping privacy and security in mind."
6
  repository = "https://github.com/neon-mmd/websurfx"
 
14
 
15
  [dependencies]
16
  reqwest = {version="0.11.24", default-features=false, features=["rustls-tls","brotli", "gzip"]}
17
+ tokio = {version="1.32.0",features=["rt-multi-thread","macros", "fs", "io-util"], default-features = false}
18
  serde = {version="1.0.196", default-features=false, features=["derive"]}
19
  serde_json = {version="1.0.109", default-features=false}
20
  maud = {version="0.25.0", default-features=false, features=["actix-web"]}
 
32
  async-trait = {version="0.1.76", default-features=false}
33
  regex = {version="1.9.4", features=["perf"], default-features = false}
34
  smallvec = {version="1.13.1", features=["union", "serde"], default-features=false}
35
+ futures = {version="0.3.30", default-features=false, features=["alloc"]}
36
+ dhat = {version="0.3.2", optional = true, default-features=false}
37
  mimalloc = { version = "0.1.38", default-features = false }
38
  async-once-cell = {version="0.5.3", default-features=false}
39
  actix-governor = {version="0.5.0", default-features=false}
40
  mini-moka = { version="0.10", optional = true, default-features=false, features=["sync"]}
41
+ async-compression = { version = "0.4.6", default-features = false, features=["brotli","tokio"], optional=true}
42
  chacha20poly1305={version="0.10.1", default-features=false, features=["alloc","getrandom"], optional=true}
43
  chacha20 = {version="0.9.1", default-features=false, optional=true}
44
  base64 = {version="0.21.5", default-features=false, features=["std"], optional=true}
 
84
  dhat-heap = ["dep:dhat"]
85
  memory-cache = ["dep:mini-moka"]
86
  redis-cache = ["dep:redis","dep:base64"]
87
+ compress-cache-results = ["dep:async-compression","dep:cfg-if"]
88
  encrypt-cache-results = ["dep:chacha20poly1305","dep:chacha20"]
89
  cec-cache-results = ["compress-cache-results","encrypt-cache-results"]
90
 
src/bin/websurfx.rs CHANGED
@@ -5,7 +5,7 @@
5
  #[cfg(not(feature = "dhat-heap"))]
6
  use mimalloc::MiMalloc;
7
 
8
- use std::net::TcpListener;
9
  use websurfx::{cache::cacher::create_cache, config::parser::Config, run};
10
 
11
  /// A dhat heap memory profiler
@@ -17,6 +17,9 @@ static ALLOC: dhat::Alloc = dhat::Alloc;
17
  #[global_allocator]
18
  static GLOBAL: MiMalloc = MiMalloc;
19
 
 
 
 
20
  /// The function that launches the main server and registers all the routes of the website.
21
  ///
22
  /// # Error
@@ -29,10 +32,10 @@ async fn main() -> std::io::Result<()> {
29
  #[cfg(feature = "dhat-heap")]
30
  let _profiler = dhat::Profiler::new_heap();
31
 
32
- // Initialize the parsed config file.
33
- let config = Config::parse(false).unwrap();
34
 
35
- let cache = create_cache(&config).await;
36
 
37
  log::info!(
38
  "started server on port {} and IP {}",
@@ -45,7 +48,7 @@ async fn main() -> std::io::Result<()> {
45
  config.port,
46
  );
47
 
48
- let listener = TcpListener::bind((config.binding_ip.clone(), config.port))?;
49
 
50
  run(listener, config, cache)?.await
51
  }
 
5
  #[cfg(not(feature = "dhat-heap"))]
6
  use mimalloc::MiMalloc;
7
 
8
+ use std::{net::TcpListener, sync::OnceLock};
9
  use websurfx::{cache::cacher::create_cache, config::parser::Config, run};
10
 
11
  /// A dhat heap memory profiler
 
17
  #[global_allocator]
18
  static GLOBAL: MiMalloc = MiMalloc;
19
 
20
+ /// A static constant for holding the parsed config.
21
+ static CONFIG: OnceLock<Config> = OnceLock::new();
22
+
23
  /// The function that launches the main server and registers all the routes of the website.
24
  ///
25
  /// # Error
 
32
  #[cfg(feature = "dhat-heap")]
33
  let _profiler = dhat::Profiler::new_heap();
34
 
35
+ // Initialize the parsed config globally.
36
+ let config = CONFIG.get_or_init(|| Config::parse(false).unwrap());
37
 
38
+ let cache = create_cache(config).await;
39
 
40
  log::info!(
41
  "started server on port {} and IP {}",
 
48
  config.port,
49
  );
50
 
51
+ let listener = TcpListener::bind((config.binding_ip.as_str(), config.port))?;
52
 
53
  run(listener, config, cache)?.await
54
  }
src/cache/cacher.rs CHANGED
@@ -93,7 +93,7 @@ pub trait Cacher: Send + Sync {
93
  feature = "encrypt-cache-results",
94
  feature = "cec-cache-results"
95
  ))]
96
- fn encrypt_or_decrypt_results(
97
  &mut self,
98
  mut bytes: Vec<u8>,
99
  encrypt: bool,
@@ -137,11 +137,19 @@ pub trait Cacher: Send + Sync {
137
  /// Returns the compressed bytes on success otherwise it returns a CacheError
138
  /// on failure.
139
  #[cfg(any(feature = "compress-cache-results", feature = "cec-cache-results"))]
140
- fn compress_results(&mut self, mut bytes: Vec<u8>) -> Result<Vec<u8>, Report<CacheError>> {
141
- use std::io::Write;
142
- let mut writer = brotli::CompressorWriter::new(Vec::new(), 4096, 11, 22);
 
 
 
143
  writer
144
  .write_all(&bytes)
 
 
 
 
 
145
  .map_err(|_| CacheError::CompressionError)?;
146
  bytes = writer.into_inner();
147
  Ok(bytes)
@@ -159,17 +167,17 @@ pub trait Cacher: Send + Sync {
159
  /// Returns the compressed and encrypted bytes on success otherwise it returns a CacheError
160
  /// on failure.
161
  #[cfg(feature = "cec-cache-results")]
162
- fn compress_encrypt_compress_results(
163
  &mut self,
164
  mut bytes: Vec<u8>,
165
  ) -> Result<Vec<u8>, Report<CacheError>> {
166
  // compress first
167
- bytes = self.compress_results(bytes)?;
168
  // encrypt
169
- bytes = self.encrypt_or_decrypt_results(bytes, true)?;
170
 
171
  // compress again;
172
- bytes = self.compress_results(bytes)?;
173
 
174
  Ok(bytes)
175
  }
@@ -187,11 +195,11 @@ pub trait Cacher: Send + Sync {
187
  /// on failure.
188
 
189
  #[cfg(any(feature = "compress-cache-results", feature = "cec-cache-results"))]
190
- fn decompress_results(&mut self, bytes: &[u8]) -> Result<Vec<u8>, Report<CacheError>> {
191
  cfg_if::cfg_if! {
192
  if #[cfg(feature = "compress-cache-results")]
193
  {
194
- decompress_util(bytes)
195
 
196
  }
197
  else if #[cfg(feature = "cec-cache-results")]
@@ -199,7 +207,7 @@ pub trait Cacher: Send + Sync {
199
  let decompressed = decompress_util(bytes)?;
200
  let decrypted = self.encrypt_or_decrypt_results(decompressed, false)?;
201
 
202
- decompress_util(&decrypted)
203
 
204
  }
205
  }
@@ -216,7 +224,7 @@ pub trait Cacher: Send + Sync {
216
  /// # Error
217
  /// Returns a Vec of compressed or encrypted bytes on success otherwise it returns a CacheError
218
  /// on failure.
219
- fn pre_process_search_results(
220
  &mut self,
221
  search_results: &SearchResults,
222
  ) -> Result<Vec<u8>, Report<CacheError>> {
@@ -224,19 +232,20 @@ pub trait Cacher: Send + Sync {
224
  let mut bytes: Vec<u8> = search_results.try_into()?;
225
  #[cfg(feature = "compress-cache-results")]
226
  {
227
- let compressed = self.compress_results(bytes)?;
228
  bytes = compressed;
229
  }
230
 
231
  #[cfg(feature = "encrypt-cache-results")]
232
  {
233
- let encrypted = self.encrypt_or_decrypt_results(bytes, true)?;
234
  bytes = encrypted;
235
  }
236
 
237
  #[cfg(feature = "cec-cache-results")]
238
  {
239
- let compressed_encrypted_compressed = self.compress_encrypt_compress_results(bytes)?;
 
240
  bytes = compressed_encrypted_compressed;
241
  }
242
 
@@ -256,25 +265,25 @@ pub trait Cacher: Send + Sync {
256
  /// on failure.
257
 
258
  #[allow(unused_mut)] // needs to be mutable when any of the features is enabled
259
- fn post_process_search_results(
260
  &mut self,
261
  mut bytes: Vec<u8>,
262
  ) -> Result<SearchResults, Report<CacheError>> {
263
  #[cfg(feature = "compress-cache-results")]
264
  {
265
- let decompressed = self.decompress_results(&bytes)?;
266
  bytes = decompressed
267
  }
268
 
269
  #[cfg(feature = "encrypt-cache-results")]
270
  {
271
- let decrypted = self.encrypt_or_decrypt_results(bytes, false)?;
272
  bytes = decrypted
273
  }
274
 
275
  #[cfg(feature = "cec-cache-results")]
276
  {
277
- let decompressed_decrypted = self.decompress_results(&bytes)?;
278
  bytes = decompressed_decrypted;
279
  }
280
 
@@ -295,16 +304,19 @@ pub trait Cacher: Send + Sync {
295
  /// on failure.
296
 
297
  #[cfg(any(feature = "compress-cache-results", feature = "cec-cache-results"))]
298
- fn decompress_util(input: &[u8]) -> Result<Vec<u8>, Report<CacheError>> {
299
- use std::io::Write;
300
- let mut writer = brotli::DecompressorWriter::new(Vec::new(), 4096);
301
 
302
  writer
303
  .write_all(input)
 
304
  .map_err(|_| CacheError::CompressionError)?;
305
- let bytes = writer
306
- .into_inner()
 
307
  .map_err(|_| CacheError::CompressionError)?;
 
308
  Ok(bytes)
309
  }
310
 
@@ -329,7 +341,7 @@ impl Cacher for RedisCache {
329
  let bytes = base64::engine::general_purpose::STANDARD_NO_PAD
330
  .decode(base64_string)
331
  .map_err(|_| CacheError::Base64DecodingOrEncodingError)?;
332
- self.post_process_search_results(bytes)
333
  }
334
 
335
  async fn cache_results(
@@ -345,7 +357,7 @@ impl Cacher for RedisCache {
345
  let mut bytes = Vec::with_capacity(search_results_len);
346
 
347
  for result in search_results {
348
- let processed = self.pre_process_search_results(result)?;
349
  bytes.push(processed);
350
  }
351
 
@@ -405,7 +417,7 @@ impl Cacher for InMemoryCache {
405
  async fn cached_results(&mut self, url: &str) -> Result<SearchResults, Report<CacheError>> {
406
  let hashed_url_string = self.hash_url(url);
407
  match self.cache.get(&hashed_url_string) {
408
- Some(res) => self.post_process_search_results(res),
409
  None => Err(Report::new(CacheError::MissingValue)),
410
  }
411
  }
@@ -417,7 +429,7 @@ impl Cacher for InMemoryCache {
417
  ) -> Result<(), Report<CacheError>> {
418
  for (url, search_result) in urls.iter().zip(search_results.iter()) {
419
  let hashed_url_string = self.hash_url(url);
420
- let bytes = self.pre_process_search_results(search_result)?;
421
  self.cache.insert(hashed_url_string, bytes);
422
  }
423
 
 
93
  feature = "encrypt-cache-results",
94
  feature = "cec-cache-results"
95
  ))]
96
+ async fn encrypt_or_decrypt_results(
97
  &mut self,
98
  mut bytes: Vec<u8>,
99
  encrypt: bool,
 
137
  /// Returns the compressed bytes on success otherwise it returns a CacheError
138
  /// on failure.
139
  #[cfg(any(feature = "compress-cache-results", feature = "cec-cache-results"))]
140
+ async fn compress_results(
141
+ &mut self,
142
+ mut bytes: Vec<u8>,
143
+ ) -> Result<Vec<u8>, Report<CacheError>> {
144
+ use tokio::io::AsyncWriteExt;
145
+ let mut writer = async_compression::tokio::write::BrotliEncoder::new(Vec::new());
146
  writer
147
  .write_all(&bytes)
148
+ .await
149
+ .map_err(|_| CacheError::CompressionError)?;
150
+ writer
151
+ .shutdown()
152
+ .await
153
  .map_err(|_| CacheError::CompressionError)?;
154
  bytes = writer.into_inner();
155
  Ok(bytes)
 
167
  /// Returns the compressed and encrypted bytes on success otherwise it returns a CacheError
168
  /// on failure.
169
  #[cfg(feature = "cec-cache-results")]
170
+ async fn compress_encrypt_compress_results(
171
  &mut self,
172
  mut bytes: Vec<u8>,
173
  ) -> Result<Vec<u8>, Report<CacheError>> {
174
  // compress first
175
+ bytes = self.compress_results(bytes).await?;
176
  // encrypt
177
+ bytes = self.encrypt_or_decrypt_results(bytes, true).await?;
178
 
179
  // compress again;
180
+ bytes = self.compress_results(bytes).await?;
181
 
182
  Ok(bytes)
183
  }
 
195
  /// on failure.
196
 
197
  #[cfg(any(feature = "compress-cache-results", feature = "cec-cache-results"))]
198
+ async fn decompress_results(&mut self, bytes: &[u8]) -> Result<Vec<u8>, Report<CacheError>> {
199
  cfg_if::cfg_if! {
200
  if #[cfg(feature = "compress-cache-results")]
201
  {
202
+ decompress_util(bytes).await
203
 
204
  }
205
  else if #[cfg(feature = "cec-cache-results")]
 
207
  let decompressed = decompress_util(bytes)?;
208
  let decrypted = self.encrypt_or_decrypt_results(decompressed, false)?;
209
 
210
+ decompress_util(&decrypted).await
211
 
212
  }
213
  }
 
224
  /// # Error
225
  /// Returns a Vec of compressed or encrypted bytes on success otherwise it returns a CacheError
226
  /// on failure.
227
+ async fn pre_process_search_results(
228
  &mut self,
229
  search_results: &SearchResults,
230
  ) -> Result<Vec<u8>, Report<CacheError>> {
 
232
  let mut bytes: Vec<u8> = search_results.try_into()?;
233
  #[cfg(feature = "compress-cache-results")]
234
  {
235
+ let compressed = self.compress_results(bytes).await?;
236
  bytes = compressed;
237
  }
238
 
239
  #[cfg(feature = "encrypt-cache-results")]
240
  {
241
+ let encrypted = self.encrypt_or_decrypt_results(bytes, true).await?;
242
  bytes = encrypted;
243
  }
244
 
245
  #[cfg(feature = "cec-cache-results")]
246
  {
247
+ let compressed_encrypted_compressed =
248
+ self.compress_encrypt_compress_results(bytes).await?;
249
  bytes = compressed_encrypted_compressed;
250
  }
251
 
 
265
  /// on failure.
266
 
267
  #[allow(unused_mut)] // needs to be mutable when any of the features is enabled
268
+ async fn post_process_search_results(
269
  &mut self,
270
  mut bytes: Vec<u8>,
271
  ) -> Result<SearchResults, Report<CacheError>> {
272
  #[cfg(feature = "compress-cache-results")]
273
  {
274
+ let decompressed = self.decompress_results(&bytes).await?;
275
  bytes = decompressed
276
  }
277
 
278
  #[cfg(feature = "encrypt-cache-results")]
279
  {
280
+ let decrypted = self.encrypt_or_decrypt_results(bytes, false).await?;
281
  bytes = decrypted
282
  }
283
 
284
  #[cfg(feature = "cec-cache-results")]
285
  {
286
+ let decompressed_decrypted = self.decompress_results(&bytes).await?;
287
  bytes = decompressed_decrypted;
288
  }
289
 
 
304
  /// on failure.
305
 
306
  #[cfg(any(feature = "compress-cache-results", feature = "cec-cache-results"))]
307
+ async fn decompress_util(input: &[u8]) -> Result<Vec<u8>, Report<CacheError>> {
308
+ use tokio::io::AsyncWriteExt;
309
+ let mut writer = async_compression::tokio::write::BrotliDecoder::new(Vec::new());
310
 
311
  writer
312
  .write_all(input)
313
+ .await
314
  .map_err(|_| CacheError::CompressionError)?;
315
+ writer
316
+ .shutdown()
317
+ .await
318
  .map_err(|_| CacheError::CompressionError)?;
319
+ let bytes = writer.into_inner();
320
  Ok(bytes)
321
  }
322
 
 
341
  let bytes = base64::engine::general_purpose::STANDARD_NO_PAD
342
  .decode(base64_string)
343
  .map_err(|_| CacheError::Base64DecodingOrEncodingError)?;
344
+ self.post_process_search_results(bytes).await
345
  }
346
 
347
  async fn cache_results(
 
357
  let mut bytes = Vec::with_capacity(search_results_len);
358
 
359
  for result in search_results {
360
+ let processed = self.pre_process_search_results(result).await?;
361
  bytes.push(processed);
362
  }
363
 
 
417
  async fn cached_results(&mut self, url: &str) -> Result<SearchResults, Report<CacheError>> {
418
  let hashed_url_string = self.hash_url(url);
419
  match self.cache.get(&hashed_url_string) {
420
+ Some(res) => self.post_process_search_results(res).await,
421
  None => Err(Report::new(CacheError::MissingValue)),
422
  }
423
  }
 
429
  ) -> Result<(), Report<CacheError>> {
430
  for (url, search_result) in urls.iter().zip(search_results.iter()) {
431
  let hashed_url_string = self.hash_url(url);
432
+ let bytes = self.pre_process_search_results(search_result).await?;
433
  self.cache.insert(hashed_url_string, bytes);
434
  }
435
 
src/cache/redis_cacher.rs CHANGED
@@ -1,15 +1,16 @@
1
  //! This module provides the functionality to cache the aggregated results fetched and aggregated
2
  //! from the upstream search engines in a json format.
3
 
 
4
  use error_stack::Report;
5
- use futures::future::try_join_all;
6
  use redis::{aio::ConnectionManager, AsyncCommands, Client, RedisError};
7
 
8
- use super::error::CacheError;
 
9
 
10
  /// A named struct which stores the redis Connection url address to which the client will
11
  /// connect to.
12
- #[derive(Clone)]
13
  pub struct RedisCache {
14
  /// It stores a pool of connections ready to be used.
15
  connection_pool: Vec<ConnectionManager>,
@@ -20,6 +21,8 @@ pub struct RedisCache {
20
  current_connection: u8,
21
  /// It stores the max TTL for keys.
22
  cache_ttl: u16,
 
 
23
  }
24
 
25
  impl RedisCache {
@@ -30,6 +33,8 @@ impl RedisCache {
30
  /// * `redis_connection_url` - It takes the redis Connection url address.
31
  /// * `pool_size` - It takes the size of the connection pool (in other words the number of
32
  /// connections that should be stored in the pool).
 
 
33
  ///
34
  /// # Error
35
  ///
@@ -41,18 +46,28 @@ impl RedisCache {
41
  cache_ttl: u16,
42
  ) -> Result<Self, Box<dyn std::error::Error>> {
43
  let client = Client::open(redis_connection_url)?;
44
- let mut tasks: Vec<_> = Vec::new();
45
 
46
  for _ in 0..pool_size {
47
- tasks.push(client.get_connection_manager());
 
 
 
 
 
 
 
 
48
  }
49
 
50
  let redis_cache = RedisCache {
51
- connection_pool: try_join_all(tasks).await?,
52
  pool_size,
53
  current_connection: Default::default(),
54
  cache_ttl,
 
55
  };
 
56
  Ok(redis_cache)
57
  }
58
 
@@ -122,13 +137,14 @@ impl RedisCache {
122
  keys: impl Iterator<Item = String>,
123
  ) -> Result<(), Report<CacheError>> {
124
  self.current_connection = Default::default();
125
- let mut pipeline = redis::Pipeline::with_capacity(3);
126
 
127
  for (key, json_result) in keys.zip(json_results) {
128
- pipeline.set_ex(key, json_result, self.cache_ttl.into());
 
129
  }
130
 
131
- let mut result: Result<(), RedisError> = pipeline
 
132
  .query_async(&mut self.connection_pool[self.current_connection as usize])
133
  .await;
134
 
@@ -149,7 +165,8 @@ impl RedisCache {
149
  CacheError::PoolExhaustionWithConnectionDropError,
150
  ));
151
  }
152
- result = pipeline
 
153
  .query_async(
154
  &mut self.connection_pool[self.current_connection as usize],
155
  )
 
1
  //! This module provides the functionality to cache the aggregated results fetched and aggregated
2
  //! from the upstream search engines in a json format.
3
 
4
+ use super::error::CacheError;
5
  use error_stack::Report;
6
+ use futures::stream::FuturesUnordered;
7
  use redis::{aio::ConnectionManager, AsyncCommands, Client, RedisError};
8
 
9
+ /// A constant holding the redis pipeline size.
10
+ const REDIS_PIPELINE_SIZE: usize = 3;
11
 
12
  /// A named struct which stores the redis Connection url address to which the client will
13
  /// connect to.
 
14
  pub struct RedisCache {
15
  /// It stores a pool of connections ready to be used.
16
  connection_pool: Vec<ConnectionManager>,
 
21
  current_connection: u8,
22
  /// It stores the max TTL for keys.
23
  cache_ttl: u16,
24
+ /// It stores the redis pipeline struct of size 3.
25
+ pipeline: redis::Pipeline,
26
  }
27
 
28
  impl RedisCache {
 
33
  /// * `redis_connection_url` - It takes the redis Connection url address.
34
  /// * `pool_size` - It takes the size of the connection pool (in other words the number of
35
  /// connections that should be stored in the pool).
36
+ /// * `cache_ttl` - It takes the the time to live for cached results to live in the redis
37
+ /// server.
38
  ///
39
  /// # Error
40
  ///
 
46
  cache_ttl: u16,
47
  ) -> Result<Self, Box<dyn std::error::Error>> {
48
  let client = Client::open(redis_connection_url)?;
49
+ let tasks: FuturesUnordered<_> = FuturesUnordered::new();
50
 
51
  for _ in 0..pool_size {
52
+ let client_partially_cloned = client.clone();
53
+ tasks.push(tokio::spawn(async move {
54
+ client_partially_cloned.get_connection_manager().await
55
+ }));
56
+ }
57
+
58
+ let mut outputs = Vec::new();
59
+ for task in tasks {
60
+ outputs.push(task.await??);
61
  }
62
 
63
  let redis_cache = RedisCache {
64
+ connection_pool: outputs,
65
  pool_size,
66
  current_connection: Default::default(),
67
  cache_ttl,
68
+ pipeline: redis::Pipeline::with_capacity(REDIS_PIPELINE_SIZE),
69
  };
70
+
71
  Ok(redis_cache)
72
  }
73
 
 
137
  keys: impl Iterator<Item = String>,
138
  ) -> Result<(), Report<CacheError>> {
139
  self.current_connection = Default::default();
 
140
 
141
  for (key, json_result) in keys.zip(json_results) {
142
+ self.pipeline
143
+ .set_ex(key, json_result, self.cache_ttl.into());
144
  }
145
 
146
+ let mut result: Result<(), RedisError> = self
147
+ .pipeline
148
  .query_async(&mut self.connection_pool[self.current_connection as usize])
149
  .await;
150
 
 
165
  CacheError::PoolExhaustionWithConnectionDropError,
166
  ));
167
  }
168
+ result = self
169
+ .pipeline
170
  .query_async(
171
  &mut self.connection_pool[self.current_connection as usize],
172
  )
src/config/parser.rs CHANGED
@@ -9,7 +9,6 @@ use mlua::Lua;
9
  use std::{collections::HashMap, fs, thread::available_parallelism};
10
 
11
  /// A named struct which stores the parsed config file options.
12
- #[derive(Clone)]
13
  pub struct Config {
14
  /// It stores the parsed port number option on which the server should launch.
15
  pub port: u16,
 
9
  use std::{collections::HashMap, fs, thread::available_parallelism};
10
 
11
  /// A named struct which stores the parsed config file options.
 
12
  pub struct Config {
13
  /// It stores the parsed port number option on which the server should launch.
14
  pub port: u16,
src/engines/bing.rs CHANGED
@@ -48,7 +48,7 @@ impl SearchEngine for Bing {
48
  user_agent: &str,
49
  client: &Client,
50
  _safe_search: u8,
51
- ) -> Result<HashMap<String, SearchResult>, EngineError> {
52
  // Bing uses `start results from this number` convention
53
  // So, for 10 results per page, page 0 starts at 1, page 1
54
  // starts at 11, and so on.
 
48
  user_agent: &str,
49
  client: &Client,
50
  _safe_search: u8,
51
+ ) -> Result<Vec<(String, SearchResult)>, EngineError> {
52
  // Bing uses `start results from this number` convention
53
  // So, for 10 results per page, page 0 starts at 1, page 1
54
  // starts at 11, and so on.
src/engines/brave.rs CHANGED
@@ -44,7 +44,7 @@ impl SearchEngine for Brave {
44
  user_agent: &str,
45
  client: &Client,
46
  safe_search: u8,
47
- ) -> Result<HashMap<String, SearchResult>, EngineError> {
48
  let url = format!("https://search.brave.com/search?q={query}&offset={page}");
49
 
50
  let safe_search_level = match safe_search {
 
44
  user_agent: &str,
45
  client: &Client,
46
  safe_search: u8,
47
+ ) -> Result<Vec<(String, SearchResult)>, EngineError> {
48
  let url = format!("https://search.brave.com/search?q={query}&offset={page}");
49
 
50
  let safe_search_level = match safe_search {
src/engines/duckduckgo.rs CHANGED
@@ -47,7 +47,7 @@ impl SearchEngine for DuckDuckGo {
47
  user_agent: &str,
48
  client: &Client,
49
  _safe_search: u8,
50
- ) -> Result<HashMap<String, SearchResult>, EngineError> {
51
  // Page number can be missing or empty string and so appropriate handling is required
52
  // so that upstream server recieves valid page number.
53
  let url: String = match page {
 
47
  user_agent: &str,
48
  client: &Client,
49
  _safe_search: u8,
50
+ ) -> Result<Vec<(String, SearchResult)>, EngineError> {
51
  // Page number can be missing or empty string and so appropriate handling is required
52
  // so that upstream server recieves valid page number.
53
  let url: String = match page {
src/engines/librex.rs CHANGED
@@ -62,7 +62,7 @@ impl SearchEngine for LibreX {
62
  user_agent: &str,
63
  client: &Client,
64
  _safe_search: u8,
65
- ) -> Result<HashMap<String, SearchResult>, EngineError> {
66
  // Page number can be missing or empty string and so appropriate handling is required
67
  // so that upstream server recieves valid page number.
68
  let url: String = format!(
 
62
  user_agent: &str,
63
  client: &Client,
64
  _safe_search: u8,
65
+ ) -> Result<Vec<(String, SearchResult)>, EngineError> {
66
  // Page number can be missing or empty string and so appropriate handling is required
67
  // so that upstream server recieves valid page number.
68
  let url: String = format!(
src/engines/mojeek.rs CHANGED
@@ -47,7 +47,7 @@ impl SearchEngine for Mojeek {
47
  user_agent: &str,
48
  client: &Client,
49
  safe_search: u8,
50
- ) -> Result<HashMap<String, SearchResult>, EngineError> {
51
  // Mojeek uses `start results from this number` convention
52
  // So, for 10 results per page, page 0 starts at 1, page 1
53
  // starts at 11, and so on.
@@ -72,8 +72,23 @@ impl SearchEngine for Mojeek {
72
  "Yep",
73
  "You",
74
  ];
 
75
  let qss = search_engines.join("%2C");
76
- let safe = if safe_search == 0 { "0" } else { "1" };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
  // Mojeek detects automated requests, these are preferences that are
79
  // able to circumvent the countermeasure. Some of these are
@@ -89,7 +104,7 @@ impl SearchEngine for Mojeek {
89
  ("hp", "minimal"),
90
  ("lb", "en"),
91
  ("qss", &qss),
92
- ("safe", safe),
93
  ];
94
 
95
  let mut query_params_string = String::new();
 
47
  user_agent: &str,
48
  client: &Client,
49
  safe_search: u8,
50
+ ) -> Result<Vec<(String, SearchResult)>, EngineError> {
51
  // Mojeek uses `start results from this number` convention
52
  // So, for 10 results per page, page 0 starts at 1, page 1
53
  // starts at 11, and so on.
 
72
  "Yep",
73
  "You",
74
  ];
75
+
76
  let qss = search_engines.join("%2C");
77
+
78
+ // A branchless condition to check whether the `safe_search` parameter has the
79
+ // value 0 or not. If it is zero then it sets the value 0 otherwise it sets
80
+ // the value to 1 for all other values of `safe_search`
81
+ //
82
+ // Moreover, the below branchless code is equivalent to the following code below:
83
+ //
84
+ // ```rust
85
+ // let safe = if safe_search == 0 { 0 } else { 1 }.to_string();
86
+ // ```
87
+ //
88
+ // For more information on branchless programming. See:
89
+ //
90
+ // * https://piped.video/watch?v=bVJ-mWWL7cE
91
+ let safe = u8::from(safe_search != 0).to_string();
92
 
93
  // Mojeek detects automated requests, these are preferences that are
94
  // able to circumvent the countermeasure. Some of these are
 
104
  ("hp", "minimal"),
105
  ("lb", "en"),
106
  ("qss", &qss),
107
+ ("safe", &safe),
108
  ];
109
 
110
  let mut query_params_string = String::new();
src/engines/search_result_parser.rs CHANGED
@@ -1,5 +1,4 @@
1
  //! This modules provides helper functionalities for parsing a html document into internal SearchResult.
2
- use std::collections::HashMap;
3
 
4
  use crate::models::{aggregation_models::SearchResult, engine_models::EngineError};
5
  use error_stack::{Report, Result};
@@ -47,7 +46,7 @@ impl SearchResultParser {
47
  &self,
48
  document: &Html,
49
  builder: impl Fn(&ElementRef<'_>, &ElementRef<'_>, &ElementRef<'_>) -> Option<SearchResult>,
50
- ) -> Result<HashMap<String, SearchResult>, EngineError> {
51
  let res = document
52
  .select(&self.results)
53
  .filter_map(|result| {
 
1
  //! This modules provides helper functionalities for parsing a html document into internal SearchResult.
 
2
 
3
  use crate::models::{aggregation_models::SearchResult, engine_models::EngineError};
4
  use error_stack::{Report, Result};
 
46
  &self,
47
  document: &Html,
48
  builder: impl Fn(&ElementRef<'_>, &ElementRef<'_>, &ElementRef<'_>) -> Option<SearchResult>,
49
+ ) -> Result<Vec<(String, SearchResult)>, EngineError> {
50
  let res = document
51
  .select(&self.results)
52
  .filter_map(|result| {
src/engines/searx.rs CHANGED
@@ -43,12 +43,21 @@ impl SearchEngine for Searx {
43
  user_agent: &str,
44
  client: &Client,
45
  mut safe_search: u8,
46
- ) -> Result<HashMap<String, SearchResult>, EngineError> {
47
- // Page number can be missing or empty string and so appropriate handling is required
48
- // so that upstream server recieves valid page number.
49
- if safe_search == 3 {
50
- safe_search = 2;
51
- };
 
 
 
 
 
 
 
 
 
52
 
53
  let url: String = format!(
54
  "https://searx.be/search?q={query}&pageno={}&safesearch={safe_search}",
 
43
  user_agent: &str,
44
  client: &Client,
45
  mut safe_search: u8,
46
+ ) -> Result<Vec<(String, SearchResult)>, EngineError> {
47
+ // A branchless condition to check whether the `safe_search` parameter has the
48
+ // value greater than equal to three or not. If it is, then it modifies the
49
+ // `safesearch` parameters value to 2.
50
+ //
51
+ // Moreover, the below branchless code is equivalent to the following code below:
52
+ //
53
+ // ```rust
54
+ // safe_search = u8::from(safe_search == 3) * 2;
55
+ // ```
56
+ //
57
+ // For more information on branchless programming. See:
58
+ //
59
+ // * https://piped.video/watch?v=bVJ-mWWL7cE
60
+ safe_search = u8::from(safe_search >= 3) * 2;
61
 
62
  let url: String = format!(
63
  "https://searx.be/search?q={query}&pageno={}&safesearch={safe_search}",
src/engines/startpage.rs CHANGED
@@ -47,7 +47,7 @@ impl SearchEngine for Startpage {
47
  user_agent: &str,
48
  client: &Client,
49
  _safe_search: u8,
50
- ) -> Result<HashMap<String, SearchResult>, EngineError> {
51
  // Page number can be missing or empty string and so appropriate handling is required
52
  // so that upstream server recieves valid page number.
53
  let url: String = format!(
 
47
  user_agent: &str,
48
  client: &Client,
49
  _safe_search: u8,
50
+ ) -> Result<Vec<(String, SearchResult)>, EngineError> {
51
  // Page number can be missing or empty string and so appropriate handling is required
52
  // so that upstream server recieves valid page number.
53
  let url: String = format!(
src/lib.rs CHANGED
@@ -14,7 +14,7 @@ pub mod results;
14
  pub mod server;
15
  pub mod templates;
16
 
17
- use std::net::TcpListener;
18
 
19
  use crate::server::router;
20
 
@@ -31,6 +31,9 @@ use cache::cacher::{Cacher, SharedCache};
31
  use config::parser::Config;
32
  use handler::{file_path, FileType};
33
 
 
 
 
34
  /// Runs the web server on the provided TCP listener and returns a `Server` instance.
35
  ///
36
  /// # Arguments
@@ -44,27 +47,29 @@ use handler::{file_path, FileType};
44
  /// # Example
45
  ///
46
  /// ```rust
47
- /// use std::net::TcpListener;
48
  /// use websurfx::{config::parser::Config, run, cache::cacher::create_cache};
49
  ///
 
 
 
50
  /// #[tokio::main]
51
  /// async fn main(){
52
- /// let config = Config::parse(true).unwrap();
 
53
  /// let listener = TcpListener::bind("127.0.0.1:8080").expect("Failed to bind address");
54
- /// let cache = create_cache(&config).await;
55
- /// let server = run(listener,config,cache).expect("Failed to start server");
56
  /// }
57
  /// ```
58
  pub fn run(
59
  listener: TcpListener,
60
- config: Config,
61
  cache: impl Cacher + 'static,
62
  ) -> std::io::Result<Server> {
63
  let public_folder_path: &str = file_path(FileType::Theme)?;
64
 
65
- let cloned_config_threads_opt: u8 = config.threads;
66
-
67
- let cache = web::Data::new(SharedCache::new(cache));
68
 
69
  let server = HttpServer::new(move || {
70
  let cors: Cors = Cors::default()
@@ -81,8 +86,8 @@ pub fn run(
81
  // Compress the responses provided by the server for the client requests.
82
  .wrap(Compress::default())
83
  .wrap(Logger::default()) // added logging middleware for logging.
84
- .app_data(web::Data::new(config.clone()))
85
- .app_data(cache.clone())
86
  .wrap(cors)
87
  .wrap(Governor::new(
88
  &GovernorConfigBuilder::default()
@@ -107,7 +112,7 @@ pub fn run(
107
  .service(router::settings) // settings page
108
  .default_service(web::route().to(router::not_found)) // error page
109
  })
110
- .workers(cloned_config_threads_opt as usize)
111
  // Start server on 127.0.0.1 with the user provided port number. for example 127.0.0.1:8080.
112
  .listen(listener)?
113
  .run();
 
14
  pub mod server;
15
  pub mod templates;
16
 
17
+ use std::{net::TcpListener, sync::OnceLock};
18
 
19
  use crate::server::router;
20
 
 
31
  use config::parser::Config;
32
  use handler::{file_path, FileType};
33
 
34
+ /// A static constant for holding the cache struct.
35
+ static SHARED_CACHE: OnceLock<SharedCache> = OnceLock::new();
36
+
37
  /// Runs the web server on the provided TCP listener and returns a `Server` instance.
38
  ///
39
  /// # Arguments
 
47
  /// # Example
48
  ///
49
  /// ```rust
50
+ /// use std::{net::TcpListener, sync::OnceLock};
51
  /// use websurfx::{config::parser::Config, run, cache::cacher::create_cache};
52
  ///
53
+ /// /// A static constant for holding the parsed config.
54
+ /// static CONFIG: OnceLock<Config> = OnceLock::new();
55
+ ///
56
  /// #[tokio::main]
57
  /// async fn main(){
58
+ /// // Initialize the parsed config globally.
59
+ /// let config = CONFIG.get_or_init(|| Config::parse(true).unwrap());
60
  /// let listener = TcpListener::bind("127.0.0.1:8080").expect("Failed to bind address");
61
+ /// let cache = create_cache(config).await;
62
+ /// let server = run(listener,&config,cache).expect("Failed to start server");
63
  /// }
64
  /// ```
65
  pub fn run(
66
  listener: TcpListener,
67
+ config: &'static Config,
68
  cache: impl Cacher + 'static,
69
  ) -> std::io::Result<Server> {
70
  let public_folder_path: &str = file_path(FileType::Theme)?;
71
 
72
+ let cache = SHARED_CACHE.get_or_init(|| SharedCache::new(cache));
 
 
73
 
74
  let server = HttpServer::new(move || {
75
  let cors: Cors = Cors::default()
 
86
  // Compress the responses provided by the server for the client requests.
87
  .wrap(Compress::default())
88
  .wrap(Logger::default()) // added logging middleware for logging.
89
+ .app_data(web::Data::new(config))
90
+ .app_data(web::Data::new(cache))
91
  .wrap(cors)
92
  .wrap(Governor::new(
93
  &GovernorConfigBuilder::default()
 
112
  .service(router::settings) // settings page
113
  .default_service(web::route().to(router::not_found)) // error page
114
  })
115
+ .workers(config.threads as usize)
116
  // Start server on 127.0.0.1 with the user provided port number. for example 127.0.0.1:8080.
117
  .listen(listener)?
118
  .run();
src/models/aggregation_models.rs CHANGED
@@ -154,8 +154,8 @@ impl SearchResults {
154
  }
155
 
156
  /// A setter function that sets the filtered to true.
157
- pub fn set_filtered(&mut self) {
158
- self.filtered = true;
159
  }
160
 
161
  /// A getter function that gets the value of `engine_errors_info`.
 
154
  }
155
 
156
  /// A setter function that sets the filtered to true.
157
+ pub fn set_filtered(&mut self, filtered: bool) {
158
+ self.filtered = filtered;
159
  }
160
 
161
  /// A getter function that gets the value of `engine_errors_info`.
src/models/engine_models.rs CHANGED
@@ -4,7 +4,7 @@
4
  use super::aggregation_models::SearchResult;
5
  use error_stack::{Report, Result, ResultExt};
6
  use reqwest::Client;
7
- use std::{collections::HashMap, fmt};
8
 
9
  /// A custom error type used for handle engine associated errors.
10
  #[derive(Debug)]
@@ -147,7 +147,7 @@ pub trait SearchEngine: Sync + Send {
147
  user_agent: &str,
148
  client: &Client,
149
  safe_search: u8,
150
- ) -> Result<HashMap<String, SearchResult>, EngineError>;
151
  }
152
 
153
  /// A named struct which stores the engine struct with the name of the associated engine.
 
4
  use super::aggregation_models::SearchResult;
5
  use error_stack::{Report, Result, ResultExt};
6
  use reqwest::Client;
7
+ use std::fmt;
8
 
9
  /// A custom error type used for handle engine associated errors.
10
  #[derive(Debug)]
 
147
  user_agent: &str,
148
  client: &Client,
149
  safe_search: u8,
150
+ ) -> Result<Vec<(String, SearchResult)>, EngineError>;
151
  }
152
 
153
  /// A named struct which stores the engine struct with the name of the associated engine.
src/models/parser_models.rs CHANGED
@@ -10,7 +10,7 @@
10
  /// order to allow the deserializing the json back to struct in aggregate function in
11
  /// aggregator.rs and create a new struct out of it and then serialize it back to json and pass
12
  /// it to the template files.
13
- #[derive(Clone, Default)]
14
  pub struct Style {
15
  /// It stores the parsed theme option used to set a theme for the website.
16
  pub theme: String,
@@ -40,7 +40,6 @@ impl Style {
40
  }
41
 
42
  /// Configuration options for the aggregator.
43
- #[derive(Clone)]
44
  pub struct AggregatorConfig {
45
  /// It stores the option to whether enable or disable random delays between
46
  /// requests.
@@ -48,7 +47,6 @@ pub struct AggregatorConfig {
48
  }
49
 
50
  /// Configuration options for the rate limiter middleware.
51
- #[derive(Clone)]
52
  pub struct RateLimiter {
53
  /// The number of request that are allowed within a provided time limit.
54
  pub number_of_requests: u8,
 
10
  /// order to allow the deserializing the json back to struct in aggregate function in
11
  /// aggregator.rs and create a new struct out of it and then serialize it back to json and pass
12
  /// it to the template files.
13
+ #[derive(Default)]
14
  pub struct Style {
15
  /// It stores the parsed theme option used to set a theme for the website.
16
  pub theme: String,
 
40
  }
41
 
42
  /// Configuration options for the aggregator.
 
43
  pub struct AggregatorConfig {
44
  /// It stores the option to whether enable or disable random delays between
45
  /// requests.
 
47
  }
48
 
49
  /// Configuration options for the rate limiter middleware.
 
50
  pub struct RateLimiter {
51
  /// The number of request that are allowed within a provided time limit.
52
  pub number_of_requests: u8,
src/results/aggregator.rs CHANGED
@@ -9,22 +9,25 @@ use crate::models::{
9
  engine_models::{EngineError, EngineHandler},
10
  };
11
  use error_stack::Report;
 
12
  use regex::Regex;
13
  use reqwest::{Client, ClientBuilder};
 
14
  use std::time::{SystemTime, UNIX_EPOCH};
15
- use std::{
16
- collections::HashMap,
17
- io::{BufReader, Read},
 
18
  time::Duration,
19
  };
20
- use std::{fs::File, io::BufRead};
21
- use tokio::task::JoinHandle;
22
 
23
  /// A constant for holding the prebuilt Client globally in the app.
24
  static CLIENT: std::sync::OnceLock<Client> = std::sync::OnceLock::new();
25
 
26
  /// Aliases for long type annotations
27
- type FutureVec = Vec<JoinHandle<Result<HashMap<String, SearchResult>, Report<EngineError>>>>;
 
 
28
 
29
  /// The function aggregates the scraped results from the user-selected upstream search engines.
30
  /// These engines can be chosen either from the user interface (UI) or from the configuration file.
@@ -37,7 +40,7 @@ type FutureVec = Vec<JoinHandle<Result<HashMap<String, SearchResult>, Report<Eng
37
  ///
38
  /// Additionally, the function eliminates duplicate results. If two results are identified as coming from
39
  /// multiple engines, their names are combined to indicate that the results were fetched from these upstream
40
- /// engines. After this, all the data in the `HashMap` is removed and placed into a struct that contains all
41
  /// the aggregated results in a vector. Furthermore, the query used is also added to the struct. This step is
42
  /// necessary to ensure that the search bar in the search remains populated even when searched from the query URL.
43
  ///
@@ -94,15 +97,22 @@ pub async fn aggregate(
94
  let mut names: Vec<&str> = Vec::with_capacity(0);
95
 
96
  // create tasks for upstream result fetching
97
- let mut tasks: FutureVec = FutureVec::new();
98
 
 
99
  for engine_handler in upstream_search_engines {
100
- let (name, search_engine) = engine_handler.to_owned().into_name_engine();
101
  names.push(name);
102
- let query: String = query.to_owned();
103
  tasks.push(tokio::spawn(async move {
104
  search_engine
105
- .results(&query, page, user_agent, client, safe_search)
 
 
 
 
 
 
106
  .await
107
  }));
108
  }
@@ -117,7 +127,7 @@ pub async fn aggregate(
117
  }
118
 
119
  // aggregate search results, removing duplicates and handling errors the upstream engines returned
120
- let mut result_map: HashMap<String, SearchResult> = HashMap::new();
121
  let mut engine_errors_info: Vec<EngineErrorInfo> = Vec::new();
122
 
123
  let mut handle_error = |error: &Report<EngineError>, engine_name: &'static str| {
@@ -134,51 +144,45 @@ pub async fn aggregate(
134
 
135
  if result_map.is_empty() {
136
  match response {
137
- Ok(results) => {
138
- result_map = results.clone();
139
- }
140
- Err(error) => {
141
- handle_error(&error, engine);
142
- }
143
- }
144
  continue;
145
  }
146
 
147
  match response {
148
  Ok(result) => {
149
  result.into_iter().for_each(|(key, value)| {
150
- result_map
151
- .entry(key)
152
- .and_modify(|result| {
153
- result.add_engines(engine);
154
- })
155
- .or_insert_with(|| -> SearchResult { value });
156
  });
157
  }
158
- Err(error) => {
159
- handle_error(&error, engine);
160
- }
161
- }
162
  }
163
 
164
  if safe_search >= 3 {
165
- let mut blacklist_map: HashMap<String, SearchResult> = HashMap::new();
166
  filter_with_lists(
167
  &mut result_map,
168
  &mut blacklist_map,
169
  file_path(FileType::BlockList)?,
170
- )?;
 
171
 
172
  filter_with_lists(
173
  &mut blacklist_map,
174
  &mut result_map,
175
  file_path(FileType::AllowList)?,
176
- )?;
 
177
 
178
  drop(blacklist_map);
179
  }
180
 
181
- let results: Vec<SearchResult> = result_map.into_values().collect();
182
 
183
  Ok(SearchResults::new(results, &engine_errors_info))
184
  }
@@ -187,35 +191,41 @@ pub async fn aggregate(
187
  ///
188
  /// # Arguments
189
  ///
190
- /// * `map_to_be_filtered` - A mutable reference to a `HashMap` of search results to filter, where the filtered results will be removed from.
191
- /// * `resultant_map` - A mutable reference to a `HashMap` to hold the filtered results.
192
  /// * `file_path` - A `&str` representing the path to a file containing regex patterns to use for filtering.
193
  ///
194
  /// # Errors
195
  ///
196
  /// Returns an error if the file at `file_path` cannot be opened or read, or if a regex pattern is invalid.
197
- pub fn filter_with_lists(
198
- map_to_be_filtered: &mut HashMap<String, SearchResult>,
199
- resultant_map: &mut HashMap<String, SearchResult>,
200
  file_path: &str,
201
  ) -> Result<(), Box<dyn std::error::Error>> {
202
- let mut reader = BufReader::new(File::open(file_path)?);
 
203
 
204
- for line in reader.by_ref().lines() {
205
- let re = Regex::new(line?.trim())?;
206
 
 
 
207
  // Iterate over each search result in the map and check if it matches the regex pattern
208
- for (url, search_result) in map_to_be_filtered.clone().into_iter() {
209
- if re.is_match(&url.to_lowercase())
210
- || re.is_match(&search_result.title.to_lowercase())
211
- || re.is_match(&search_result.description.to_lowercase())
 
 
212
  {
213
- // If the search result matches the regex pattern, move it from the original map to the resultant map
214
- resultant_map.insert(
215
- url.to_owned(),
216
- map_to_be_filtered.remove(&url.to_owned()).unwrap(),
217
- );
218
- }
 
219
  }
220
  }
221
 
@@ -226,15 +236,14 @@ pub fn filter_with_lists(
226
  mod tests {
227
  use super::*;
228
  use smallvec::smallvec;
229
- use std::collections::HashMap;
230
  use std::io::Write;
231
  use tempfile::NamedTempFile;
232
 
233
- #[test]
234
- fn test_filter_with_lists() -> Result<(), Box<dyn std::error::Error>> {
235
  // Create a map of search results to filter
236
- let mut map_to_be_filtered = HashMap::new();
237
- map_to_be_filtered.insert(
238
  "https://www.example.com".to_owned(),
239
  SearchResult {
240
  title: "Example Domain".to_owned(),
@@ -243,15 +252,15 @@ mod tests {
243
  .to_owned(),
244
  engine: smallvec!["Google".to_owned(), "Bing".to_owned()],
245
  },
246
- );
247
- map_to_be_filtered.insert(
248
  "https://www.rust-lang.org/".to_owned(),
249
  SearchResult {
250
  title: "Rust Programming Language".to_owned(),
251
  url: "https://www.rust-lang.org/".to_owned(),
252
  description: "A systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.".to_owned(),
253
  engine: smallvec!["Google".to_owned(), "DuckDuckGo".to_owned()],
254
- },
255
  );
256
 
257
  // Create a temporary file with regex patterns
@@ -260,25 +269,30 @@ mod tests {
260
  writeln!(file, "rust")?;
261
  file.flush()?;
262
 
263
- let mut resultant_map = HashMap::new();
264
  filter_with_lists(
265
  &mut map_to_be_filtered,
266
  &mut resultant_map,
267
  file.path().to_str().unwrap(),
268
- )?;
 
269
 
270
  assert_eq!(resultant_map.len(), 2);
271
- assert!(resultant_map.contains_key("https://www.example.com"));
272
- assert!(resultant_map.contains_key("https://www.rust-lang.org/"));
 
 
 
 
273
  assert_eq!(map_to_be_filtered.len(), 0);
274
 
275
  Ok(())
276
  }
277
 
278
- #[test]
279
- fn test_filter_with_lists_wildcard() -> Result<(), Box<dyn std::error::Error>> {
280
- let mut map_to_be_filtered = HashMap::new();
281
- map_to_be_filtered.insert(
282
  "https://www.example.com".to_owned(),
283
  SearchResult {
284
  title: "Example Domain".to_owned(),
@@ -287,8 +301,8 @@ mod tests {
287
  .to_owned(),
288
  engine: smallvec!["Google".to_owned(), "Bing".to_owned()],
289
  },
290
- );
291
- map_to_be_filtered.insert(
292
  "https://www.rust-lang.org/".to_owned(),
293
  SearchResult {
294
  title: "Rust Programming Language".to_owned(),
@@ -296,34 +310,39 @@ mod tests {
296
  description: "A systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.".to_owned(),
297
  engine: smallvec!["Google".to_owned(), "DuckDuckGo".to_owned()],
298
  },
299
- );
300
 
301
  // Create a temporary file with a regex pattern containing a wildcard
302
  let mut file = NamedTempFile::new()?;
303
  writeln!(file, "ex.*le")?;
304
  file.flush()?;
305
 
306
- let mut resultant_map = HashMap::new();
307
 
308
  filter_with_lists(
309
  &mut map_to_be_filtered,
310
  &mut resultant_map,
311
  file.path().to_str().unwrap(),
312
- )?;
 
313
 
314
  assert_eq!(resultant_map.len(), 1);
315
- assert!(resultant_map.contains_key("https://www.example.com"));
 
 
316
  assert_eq!(map_to_be_filtered.len(), 1);
317
- assert!(map_to_be_filtered.contains_key("https://www.rust-lang.org/"));
 
 
318
 
319
  Ok(())
320
  }
321
 
322
- #[test]
323
- fn test_filter_with_lists_file_not_found() {
324
- let mut map_to_be_filtered = HashMap::new();
325
 
326
- let mut resultant_map = HashMap::new();
327
 
328
  // Call the `filter_with_lists` function with a non-existent file path
329
  let result = filter_with_lists(
@@ -332,13 +351,13 @@ mod tests {
332
  "non-existent-file.txt",
333
  );
334
 
335
- assert!(result.is_err());
336
  }
337
 
338
- #[test]
339
- fn test_filter_with_lists_invalid_regex() {
340
- let mut map_to_be_filtered = HashMap::new();
341
- map_to_be_filtered.insert(
342
  "https://www.example.com".to_owned(),
343
  SearchResult {
344
  title: "Example Domain".to_owned(),
@@ -347,9 +366,9 @@ mod tests {
347
  .to_owned(),
348
  engine: smallvec!["Google".to_owned(), "Bing".to_owned()],
349
  },
350
- );
351
 
352
- let mut resultant_map = HashMap::new();
353
 
354
  // Create a temporary file with an invalid regex pattern
355
  let mut file = NamedTempFile::new().unwrap();
@@ -362,6 +381,6 @@ mod tests {
362
  file.path().to_str().unwrap(),
363
  );
364
 
365
- assert!(result.is_err());
366
  }
367
  }
 
9
  engine_models::{EngineError, EngineHandler},
10
  };
11
  use error_stack::Report;
12
+ use futures::stream::FuturesUnordered;
13
  use regex::Regex;
14
  use reqwest::{Client, ClientBuilder};
15
+ use std::sync::Arc;
16
  use std::time::{SystemTime, UNIX_EPOCH};
17
+ use tokio::{
18
+ fs::File,
19
+ io::{AsyncBufReadExt, BufReader},
20
+ task::JoinHandle,
21
  time::Duration,
22
  };
 
 
23
 
24
  /// A constant for holding the prebuilt Client globally in the app.
25
  static CLIENT: std::sync::OnceLock<Client> = std::sync::OnceLock::new();
26
 
27
  /// Aliases for long type annotations
28
+
29
+ type FutureVec =
30
+ FuturesUnordered<JoinHandle<Result<Vec<(String, SearchResult)>, Report<EngineError>>>>;
31
 
32
  /// The function aggregates the scraped results from the user-selected upstream search engines.
33
  /// These engines can be chosen either from the user interface (UI) or from the configuration file.
 
40
  ///
41
  /// Additionally, the function eliminates duplicate results. If two results are identified as coming from
42
  /// multiple engines, their names are combined to indicate that the results were fetched from these upstream
43
+ /// engines. After this, all the data in the `Vec` is removed and placed into a struct that contains all
44
  /// the aggregated results in a vector. Furthermore, the query used is also added to the struct. This step is
45
  /// necessary to ensure that the search bar in the search remains populated even when searched from the query URL.
46
  ///
 
97
  let mut names: Vec<&str> = Vec::with_capacity(0);
98
 
99
  // create tasks for upstream result fetching
100
+ let tasks: FutureVec = FutureVec::new();
101
 
102
+ let query: Arc<String> = Arc::new(query.to_string());
103
  for engine_handler in upstream_search_engines {
104
+ let (name, search_engine) = engine_handler.clone().into_name_engine();
105
  names.push(name);
106
+ let query_partially_cloned = query.clone();
107
  tasks.push(tokio::spawn(async move {
108
  search_engine
109
+ .results(
110
+ &query_partially_cloned,
111
+ page,
112
+ user_agent,
113
+ client,
114
+ safe_search,
115
+ )
116
  .await
117
  }));
118
  }
 
127
  }
128
 
129
  // aggregate search results, removing duplicates and handling errors the upstream engines returned
130
+ let mut result_map: Vec<(String, SearchResult)> = Vec::new();
131
  let mut engine_errors_info: Vec<EngineErrorInfo> = Vec::new();
132
 
133
  let mut handle_error = |error: &Report<EngineError>, engine_name: &'static str| {
 
144
 
145
  if result_map.is_empty() {
146
  match response {
147
+ Ok(results) => result_map = results,
148
+ Err(error) => handle_error(&error, engine),
149
+ };
 
 
 
 
150
  continue;
151
  }
152
 
153
  match response {
154
  Ok(result) => {
155
  result.into_iter().for_each(|(key, value)| {
156
+ match result_map.iter().find(|(key_s, _)| key_s == &key) {
157
+ Some(value) => value.1.to_owned().add_engines(engine),
158
+ None => result_map.push((key, value)),
159
+ };
 
 
160
  });
161
  }
162
+ Err(error) => handle_error(&error, engine),
163
+ };
 
 
164
  }
165
 
166
  if safe_search >= 3 {
167
+ let mut blacklist_map: Vec<(String, SearchResult)> = Vec::new();
168
  filter_with_lists(
169
  &mut result_map,
170
  &mut blacklist_map,
171
  file_path(FileType::BlockList)?,
172
+ )
173
+ .await?;
174
 
175
  filter_with_lists(
176
  &mut blacklist_map,
177
  &mut result_map,
178
  file_path(FileType::AllowList)?,
179
+ )
180
+ .await?;
181
 
182
  drop(blacklist_map);
183
  }
184
 
185
+ let results: Vec<SearchResult> = result_map.iter().map(|(_, value)| value.clone()).collect();
186
 
187
  Ok(SearchResults::new(results, &engine_errors_info))
188
  }
 
191
  ///
192
  /// # Arguments
193
  ///
194
+ /// * `map_to_be_filtered` - A mutable reference to a `Vec` of search results to filter, where the filtered results will be removed from.
195
+ /// * `resultant_map` - A mutable reference to a `Vec` to hold the filtered results.
196
  /// * `file_path` - A `&str` representing the path to a file containing regex patterns to use for filtering.
197
  ///
198
  /// # Errors
199
  ///
200
  /// Returns an error if the file at `file_path` cannot be opened or read, or if a regex pattern is invalid.
201
+ pub async fn filter_with_lists(
202
+ map_to_be_filtered: &mut Vec<(String, SearchResult)>,
203
+ resultant_map: &mut Vec<(String, SearchResult)>,
204
  file_path: &str,
205
  ) -> Result<(), Box<dyn std::error::Error>> {
206
+ let reader = BufReader::new(File::open(file_path).await?);
207
+ let mut lines = reader.lines();
208
 
209
+ while let Some(line) = lines.next_line().await? {
210
+ let re = Regex::new(line.trim())?;
211
 
212
+ let mut length = map_to_be_filtered.len();
213
+ let mut idx: usize = Default::default();
214
  // Iterate over each search result in the map and check if it matches the regex pattern
215
+ while idx < length {
216
+ let ele = &map_to_be_filtered[idx];
217
+ let ele_inner = &ele.1;
218
+ match re.is_match(&ele.0.to_lowercase())
219
+ || re.is_match(&ele_inner.title.to_lowercase())
220
+ || re.is_match(&ele_inner.description.to_lowercase())
221
  {
222
+ true => {
223
+ // If the search result matches the regex pattern, move it from the original map to the resultant map
224
+ resultant_map.push(map_to_be_filtered.swap_remove(idx));
225
+ length -= 1;
226
+ }
227
+ false => idx += 1,
228
+ };
229
  }
230
  }
231
 
 
236
  mod tests {
237
  use super::*;
238
  use smallvec::smallvec;
 
239
  use std::io::Write;
240
  use tempfile::NamedTempFile;
241
 
242
+ #[tokio::test]
243
+ async fn test_filter_with_lists() -> Result<(), Box<dyn std::error::Error>> {
244
  // Create a map of search results to filter
245
+ let mut map_to_be_filtered = Vec::new();
246
+ map_to_be_filtered.push((
247
  "https://www.example.com".to_owned(),
248
  SearchResult {
249
  title: "Example Domain".to_owned(),
 
252
  .to_owned(),
253
  engine: smallvec!["Google".to_owned(), "Bing".to_owned()],
254
  },
255
+ ));
256
+ map_to_be_filtered.push((
257
  "https://www.rust-lang.org/".to_owned(),
258
  SearchResult {
259
  title: "Rust Programming Language".to_owned(),
260
  url: "https://www.rust-lang.org/".to_owned(),
261
  description: "A systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.".to_owned(),
262
  engine: smallvec!["Google".to_owned(), "DuckDuckGo".to_owned()],
263
+ },)
264
  );
265
 
266
  // Create a temporary file with regex patterns
 
269
  writeln!(file, "rust")?;
270
  file.flush()?;
271
 
272
+ let mut resultant_map = Vec::new();
273
  filter_with_lists(
274
  &mut map_to_be_filtered,
275
  &mut resultant_map,
276
  file.path().to_str().unwrap(),
277
+ )
278
+ .await?;
279
 
280
  assert_eq!(resultant_map.len(), 2);
281
+ assert!(resultant_map
282
+ .iter()
283
+ .any(|(key, _)| key == "https://www.example.com"));
284
+ assert!(resultant_map
285
+ .iter()
286
+ .any(|(key, _)| key == "https://www.rust-lang.org/"));
287
  assert_eq!(map_to_be_filtered.len(), 0);
288
 
289
  Ok(())
290
  }
291
 
292
+ #[tokio::test]
293
+ async fn test_filter_with_lists_wildcard() -> Result<(), Box<dyn std::error::Error>> {
294
+ let mut map_to_be_filtered = Vec::new();
295
+ map_to_be_filtered.push((
296
  "https://www.example.com".to_owned(),
297
  SearchResult {
298
  title: "Example Domain".to_owned(),
 
301
  .to_owned(),
302
  engine: smallvec!["Google".to_owned(), "Bing".to_owned()],
303
  },
304
+ ));
305
+ map_to_be_filtered.push((
306
  "https://www.rust-lang.org/".to_owned(),
307
  SearchResult {
308
  title: "Rust Programming Language".to_owned(),
 
310
  description: "A systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.".to_owned(),
311
  engine: smallvec!["Google".to_owned(), "DuckDuckGo".to_owned()],
312
  },
313
+ ));
314
 
315
  // Create a temporary file with a regex pattern containing a wildcard
316
  let mut file = NamedTempFile::new()?;
317
  writeln!(file, "ex.*le")?;
318
  file.flush()?;
319
 
320
+ let mut resultant_map = Vec::new();
321
 
322
  filter_with_lists(
323
  &mut map_to_be_filtered,
324
  &mut resultant_map,
325
  file.path().to_str().unwrap(),
326
+ )
327
+ .await?;
328
 
329
  assert_eq!(resultant_map.len(), 1);
330
+ assert!(resultant_map
331
+ .iter()
332
+ .any(|(key, _)| key == "https://www.example.com"));
333
  assert_eq!(map_to_be_filtered.len(), 1);
334
+ assert!(map_to_be_filtered
335
+ .iter()
336
+ .any(|(key, _)| key == "https://www.rust-lang.org/"));
337
 
338
  Ok(())
339
  }
340
 
341
+ #[tokio::test]
342
+ async fn test_filter_with_lists_file_not_found() {
343
+ let mut map_to_be_filtered = Vec::new();
344
 
345
+ let mut resultant_map = Vec::new();
346
 
347
  // Call the `filter_with_lists` function with a non-existent file path
348
  let result = filter_with_lists(
 
351
  "non-existent-file.txt",
352
  );
353
 
354
+ assert!(result.await.is_err());
355
  }
356
 
357
+ #[tokio::test]
358
+ async fn test_filter_with_lists_invalid_regex() {
359
+ let mut map_to_be_filtered = Vec::new();
360
+ map_to_be_filtered.push((
361
  "https://www.example.com".to_owned(),
362
  SearchResult {
363
  title: "Example Domain".to_owned(),
 
366
  .to_owned(),
367
  engine: smallvec!["Google".to_owned(), "Bing".to_owned()],
368
  },
369
+ ));
370
 
371
+ let mut resultant_map = Vec::new();
372
 
373
  // Create a temporary file with an invalid regex pattern
374
  let mut file = NamedTempFile::new().unwrap();
 
381
  file.path().to_str().unwrap(),
382
  );
383
 
384
+ assert!(result.await.is_err());
385
  }
386
  }
src/server/router.rs CHANGED
@@ -7,11 +7,13 @@ use crate::{
7
  handler::{file_path, FileType},
8
  };
9
  use actix_web::{get, http::header::ContentType, web, HttpRequest, HttpResponse};
10
- use std::fs::read_to_string;
11
 
12
  /// Handles the route of index page or main page of the `websurfx` meta search engine website.
13
  #[get("/")]
14
- pub async fn index(config: web::Data<Config>) -> Result<HttpResponse, Box<dyn std::error::Error>> {
 
 
15
  Ok(HttpResponse::Ok().content_type(ContentType::html()).body(
16
  crate::templates::views::index::index(
17
  &config.style.colorscheme,
@@ -25,7 +27,7 @@ pub async fn index(config: web::Data<Config>) -> Result<HttpResponse, Box<dyn st
25
  /// Handles the route of any other accessed route/page which is not provided by the
26
  /// website essentially the 404 error page.
27
  pub async fn not_found(
28
- config: web::Data<Config>,
29
  ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
30
  Ok(HttpResponse::Ok().content_type(ContentType::html()).body(
31
  crate::templates::views::not_found::not_found(
@@ -41,7 +43,7 @@ pub async fn not_found(
41
  #[get("/robots.txt")]
42
  pub async fn robots_data(_req: HttpRequest) -> Result<HttpResponse, Box<dyn std::error::Error>> {
43
  let page_content: String =
44
- read_to_string(format!("{}/robots.txt", file_path(FileType::Theme)?))?;
45
  Ok(HttpResponse::Ok()
46
  .content_type(ContentType::plaintext())
47
  .body(page_content))
@@ -49,7 +51,9 @@ pub async fn robots_data(_req: HttpRequest) -> Result<HttpResponse, Box<dyn std:
49
 
50
  /// Handles the route of about page of the `websurfx` meta search engine website.
51
  #[get("/about")]
52
- pub async fn about(config: web::Data<Config>) -> Result<HttpResponse, Box<dyn std::error::Error>> {
 
 
53
  Ok(HttpResponse::Ok().content_type(ContentType::html()).body(
54
  crate::templates::views::about::about(
55
  &config.style.colorscheme,
@@ -63,7 +67,7 @@ pub async fn about(config: web::Data<Config>) -> Result<HttpResponse, Box<dyn st
63
  /// Handles the route of settings page of the `websurfx` meta search engine website.
64
  #[get("/settings")]
65
  pub async fn settings(
66
- config: web::Data<Config>,
67
  ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
68
  Ok(HttpResponse::Ok().content_type(ContentType::html()).body(
69
  crate::templates::views::settings::settings(
 
7
  handler::{file_path, FileType},
8
  };
9
  use actix_web::{get, http::header::ContentType, web, HttpRequest, HttpResponse};
10
+ use tokio::fs::read_to_string;
11
 
12
  /// Handles the route of index page or main page of the `websurfx` meta search engine website.
13
  #[get("/")]
14
+ pub async fn index(
15
+ config: web::Data<&'static Config>,
16
+ ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
17
  Ok(HttpResponse::Ok().content_type(ContentType::html()).body(
18
  crate::templates::views::index::index(
19
  &config.style.colorscheme,
 
27
  /// Handles the route of any other accessed route/page which is not provided by the
28
  /// website essentially the 404 error page.
29
  pub async fn not_found(
30
+ config: web::Data<&'static Config>,
31
  ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
32
  Ok(HttpResponse::Ok().content_type(ContentType::html()).body(
33
  crate::templates::views::not_found::not_found(
 
43
  #[get("/robots.txt")]
44
  pub async fn robots_data(_req: HttpRequest) -> Result<HttpResponse, Box<dyn std::error::Error>> {
45
  let page_content: String =
46
+ read_to_string(format!("{}/robots.txt", file_path(FileType::Theme)?)).await?;
47
  Ok(HttpResponse::Ok()
48
  .content_type(ContentType::plaintext())
49
  .body(page_content))
 
51
 
52
  /// Handles the route of about page of the `websurfx` meta search engine website.
53
  #[get("/about")]
54
+ pub async fn about(
55
+ config: web::Data<&'static Config>,
56
+ ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
57
  Ok(HttpResponse::Ok().content_type(ContentType::html()).body(
58
  crate::templates::views::about::about(
59
  &config.style.colorscheme,
 
67
  /// Handles the route of settings page of the `websurfx` meta search engine website.
68
  #[get("/settings")]
69
  pub async fn settings(
70
+ config: web::Data<&'static Config>,
71
  ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
72
  Ok(HttpResponse::Ok().content_type(ContentType::html()).body(
73
  crate::templates::views::settings::settings(
src/server/routes/search.rs CHANGED
@@ -13,12 +13,12 @@ use crate::{
13
  };
14
  use actix_web::{get, http::header::ContentType, web, HttpRequest, HttpResponse};
15
  use regex::Regex;
16
- use std::{
17
- borrow::Cow,
18
  fs::File,
19
- io::{BufRead, BufReader, Read},
 
20
  };
21
- use tokio::join;
22
 
23
  /// Handles the route of search page of the `websurfx` meta search engine website and it takes
24
  /// two search url parameters `q` and `page` where `page` parameter is optional.
@@ -37,8 +37,8 @@ use tokio::join;
37
  #[get("/search")]
38
  pub async fn search(
39
  req: HttpRequest,
40
- config: web::Data<Config>,
41
- cache: web::Data<SharedCache>,
42
  ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
43
  use std::sync::Arc;
44
  let params = web::Query::<SearchParams>::from_query(req.query_string())?;
@@ -70,8 +70,8 @@ pub async fn search(
70
  });
71
 
72
  search_settings.safe_search_level = get_safesearch_level(
73
- &Some(search_settings.safe_search_level),
74
- &params.safesearch,
75
  config.safe_search,
76
  );
77
 
@@ -158,8 +158,8 @@ pub async fn search(
158
  /// It returns the `SearchResults` struct if the search results could be successfully fetched from
159
  /// the cache or from the upstream search engines otherwise it returns an appropriate error.
160
  async fn results(
161
- config: &Config,
162
- cache: &web::Data<SharedCache>,
163
  query: &str,
164
  page: u32,
165
  search_settings: &server_models::Cookie<'_>,
@@ -188,7 +188,7 @@ async fn results(
188
  let mut results: SearchResults = SearchResults::default();
189
 
190
  let flag: bool =
191
- !is_match_from_filter_list(file_path(FileType::BlockList)?, query)?;
192
  // Return early when query contains disallowed words,
193
  if flag {
194
  results.set_disallowed();
@@ -225,12 +225,12 @@ async fn results(
225
  search_results
226
  }
227
  };
228
- if results.engine_errors_info().is_empty()
229
- && results.results().is_empty()
230
- && !results.no_engines_selected()
231
- {
232
- results.set_filtered();
233
- }
234
  cache
235
  .cache_results(&[results.clone()], &[cache_key.clone()])
236
  .await?;
@@ -252,13 +252,14 @@ async fn results(
252
  ///
253
  /// Returns a bool indicating whether the results were found in the list or not on success
254
  /// otherwise returns a standard error type on a failure.
255
- fn is_match_from_filter_list(
256
  file_path: &str,
257
  query: &str,
258
  ) -> Result<bool, Box<dyn std::error::Error>> {
259
- let mut reader = BufReader::new(File::open(file_path)?);
260
- for line in reader.by_ref().lines() {
261
- let re = Regex::new(&line?)?;
 
262
  if re.is_match(query) {
263
  return Ok(true);
264
  }
@@ -267,24 +268,95 @@ fn is_match_from_filter_list(
267
  Ok(false)
268
  }
269
 
270
- /// A helper function to modify the safe search level based on the url params.
271
- /// The `safe_search` is the one in the user's cookie or
272
- /// the default set by the server config if the cookie was missing.
273
  ///
274
  /// # Argurments
275
  ///
276
- /// * `url_level` - Safe search level from the url.
277
- /// * `safe_search` - User's cookie, or the safe search level set by the server
278
- /// * `config_level` - Safe search level to fall back to
279
- fn get_safesearch_level(cookie_level: &Option<u8>, url_level: &Option<u8>, config_level: u8) -> u8 {
280
- match url_level {
281
- Some(url_level) => {
282
- if *url_level >= 3 {
283
- config_level
284
- } else {
285
- *url_level
286
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  }
288
- None => cookie_level.unwrap_or(config_level),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  }
290
  }
 
13
  };
14
  use actix_web::{get, http::header::ContentType, web, HttpRequest, HttpResponse};
15
  use regex::Regex;
16
+ use std::borrow::Cow;
17
+ use tokio::{
18
  fs::File,
19
+ io::{AsyncBufReadExt, BufReader},
20
+ join,
21
  };
 
22
 
23
  /// Handles the route of search page of the `websurfx` meta search engine website and it takes
24
  /// two search url parameters `q` and `page` where `page` parameter is optional.
 
37
  #[get("/search")]
38
  pub async fn search(
39
  req: HttpRequest,
40
+ config: web::Data<&'static Config>,
41
+ cache: web::Data<&'static SharedCache>,
42
  ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
43
  use std::sync::Arc;
44
  let params = web::Query::<SearchParams>::from_query(req.query_string())?;
 
70
  });
71
 
72
  search_settings.safe_search_level = get_safesearch_level(
73
+ params.safesearch,
74
+ search_settings.safe_search_level,
75
  config.safe_search,
76
  );
77
 
 
158
  /// It returns the `SearchResults` struct if the search results could be successfully fetched from
159
  /// the cache or from the upstream search engines otherwise it returns an appropriate error.
160
  async fn results(
161
+ config: &'static Config,
162
+ cache: &'static SharedCache,
163
  query: &str,
164
  page: u32,
165
  search_settings: &server_models::Cookie<'_>,
 
188
  let mut results: SearchResults = SearchResults::default();
189
 
190
  let flag: bool =
191
+ !is_match_from_filter_list(file_path(FileType::BlockList)?, query).await?;
192
  // Return early when query contains disallowed words,
193
  if flag {
194
  results.set_disallowed();
 
225
  search_results
226
  }
227
  };
228
+ let (engine_errors_info, results_empty_check, no_engines_selected) = (
229
+ results.engine_errors_info().is_empty(),
230
+ results.results().is_empty(),
231
+ results.no_engines_selected(),
232
+ );
233
+ results.set_filtered(engine_errors_info & results_empty_check & !no_engines_selected);
234
  cache
235
  .cache_results(&[results.clone()], &[cache_key.clone()])
236
  .await?;
 
252
  ///
253
  /// Returns a bool indicating whether the results were found in the list or not on success
254
  /// otherwise returns a standard error type on a failure.
255
+ async fn is_match_from_filter_list(
256
  file_path: &str,
257
  query: &str,
258
  ) -> Result<bool, Box<dyn std::error::Error>> {
259
+ let reader = BufReader::new(File::open(file_path).await?);
260
+ let mut lines = reader.lines();
261
+ while let Some(line) = lines.next_line().await? {
262
+ let re = Regex::new(&line)?;
263
  if re.is_match(query) {
264
  return Ok(true);
265
  }
 
268
  Ok(false)
269
  }
270
 
271
+ /// A helper function to choose the safe search level value based on the URL parameters,
272
+ /// cookie value and config value.
 
273
  ///
274
  /// # Argurments
275
  ///
276
+ /// * `safe_search_level_from_url` - Safe search level from the URL parameters.
277
+ /// * `cookie_safe_search_level` - Safe search level value from the cookie.
278
+ /// * `config_safe_search_level` - Safe search level value from the config file.
279
+ ///
280
+ /// # Returns
281
+ ///
282
+ /// Returns an appropriate safe search level value based on the safe search level values
283
+ /// from the URL parameters, cookie and the config file.
284
+ fn get_safesearch_level(
285
+ safe_search_level_from_url: Option<u8>,
286
+ cookie_safe_search_level: u8,
287
+ config_safe_search_level: u8,
288
+ ) -> u8 {
289
+ (u8::from(safe_search_level_from_url.is_some())
290
+ * ((u8::from(config_safe_search_level >= 3) * config_safe_search_level)
291
+ + (u8::from(config_safe_search_level < 3) * safe_search_level_from_url.unwrap_or(0))))
292
+ + (u8::from(safe_search_level_from_url.is_none())
293
+ * ((u8::from(config_safe_search_level >= 3) * config_safe_search_level)
294
+ + (u8::from(config_safe_search_level < 3) * cookie_safe_search_level)))
295
+ }
296
+
297
+ #[cfg(test)]
298
+ mod tests {
299
+ use std::time::{SystemTime, UNIX_EPOCH};
300
+
301
+ /// A helper function which creates a random mock safe search level value.
302
+ ///
303
+ /// # Returns
304
+ ///
305
+ /// Returns an optional u8 value.
306
+ fn mock_safe_search_level_value() -> Option<u8> {
307
+ let nanos = SystemTime::now()
308
+ .duration_since(UNIX_EPOCH)
309
+ .unwrap_or_default()
310
+ .subsec_nanos() as f32;
311
+ let delay = ((nanos / 1_0000_0000 as f32).floor() as i8) - 1;
312
+
313
+ match delay {
314
+ -1 => None,
315
+ some_num => Some(if some_num > 4 { some_num - 4 } else { some_num } as u8),
316
  }
317
+ }
318
+
319
+ #[test]
320
+ /// A test function to test whether the output of the branchless and branched code
321
+ /// for the code to choose the appropriate safe search level is same or not.
322
+ fn get_safesearch_level_branched_branchless_code_test() {
323
+ // Get mock values for the safe search level values for URL parameters, cookie
324
+ // and config.
325
+ let safe_search_level_from_url = mock_safe_search_level_value();
326
+ let cookie_safe_search_level = mock_safe_search_level_value().unwrap_or(0);
327
+ let config_safe_search_level = mock_safe_search_level_value().unwrap_or(0);
328
+
329
+ // Branched code
330
+ let safe_search_level_value_from_branched_code = match safe_search_level_from_url {
331
+ Some(safe_search_level_from_url_parsed) => {
332
+ if config_safe_search_level >= 3 {
333
+ config_safe_search_level
334
+ } else {
335
+ safe_search_level_from_url_parsed
336
+ }
337
+ }
338
+ None => {
339
+ if config_safe_search_level >= 3 {
340
+ config_safe_search_level
341
+ } else {
342
+ cookie_safe_search_level
343
+ }
344
+ }
345
+ };
346
+
347
+ // branchless code
348
+ let safe_search_level_value_from_branchless_code =
349
+ (u8::from(safe_search_level_from_url.is_some())
350
+ * ((u8::from(config_safe_search_level >= 3) * config_safe_search_level)
351
+ + (u8::from(config_safe_search_level < 3)
352
+ * safe_search_level_from_url.unwrap_or(0))))
353
+ + (u8::from(safe_search_level_from_url.is_none())
354
+ * ((u8::from(config_safe_search_level >= 3) * config_safe_search_level)
355
+ + (u8::from(config_safe_search_level < 3) * cookie_safe_search_level)));
356
+
357
+ assert_eq!(
358
+ safe_search_level_value_from_branched_code,
359
+ safe_search_level_value_from_branchless_code
360
+ );
361
  }
362
  }
src/templates/partials/settings_tabs/engines.rs CHANGED
@@ -55,7 +55,7 @@ pub fn engines(engine_names: &HashMap<String, bool>) -> Markup {
55
  input type="checkbox" class="engine" checked;
56
  span class="slider round"{}
57
  }
58
- (format!("{}{}",engine_name[..1].to_uppercase().to_owned(), engine_name[1..].to_owned()))
59
  }
60
  }
61
  @else {
@@ -64,7 +64,7 @@ pub fn engines(engine_names: &HashMap<String, bool>) -> Markup {
64
  input type="checkbox" class="engine";
65
  span class="slider round"{}
66
  }
67
- (format!("{}{}",engine_name[..1].to_uppercase().to_owned(), engine_name[1..].to_owned()))
68
  }
69
  }
70
  }
 
55
  input type="checkbox" class="engine" checked;
56
  span class="slider round"{}
57
  }
58
+ (format!("{}{}",&engine_name[..1].to_uppercase(), &engine_name[1..]))
59
  }
60
  }
61
  @else {
 
64
  input type="checkbox" class="engine";
65
  span class="slider round"{}
66
  }
67
+ (format!("{}{}",&engine_name[..1], &engine_name[1..]))
68
  }
69
  }
70
  }
src/templates/partials/settings_tabs/user_interface.rs CHANGED
@@ -36,7 +36,7 @@ fn style_option_list(
36
  }
37
 
38
  if style_type == "animations" {
39
- style_option_names.push(("".to_owned(), "none".to_owned()))
40
  }
41
 
42
  Ok(style_option_names)
@@ -83,9 +83,11 @@ pub fn user_interface(
83
  "Select the animation for your theme to be used in user interface"
84
  }
85
  select name="animations"{
 
 
86
  // Sets the user selected animation name from the config file as the first option in the selection list.
87
- option value=(animation.as_ref().unwrap_or(&"".to_owned())){(animation.as_ref().unwrap_or(&"".to_owned()).replace('-'," "))}
88
- @for (k,v) in style_option_list("animations", animation.as_ref().unwrap_or(&"".to_owned()))?{
89
  option value=(k){(v)}
90
  }
91
  }
 
36
  }
37
 
38
  if style_type == "animations" {
39
+ style_option_names.push((String::default(), "none".to_owned()))
40
  }
41
 
42
  Ok(style_option_names)
 
83
  "Select the animation for your theme to be used in user interface"
84
  }
85
  select name="animations"{
86
+ @let default_animation = &String::default();
87
+ @let animation = animation.as_ref().unwrap_or(default_animation);
88
  // Sets the user selected animation name from the config file as the first option in the selection list.
89
+ option value=(animation){(animation.replace('-'," "))}
90
+ @for (k,v) in style_option_list("animations", animation)?{
91
  option value=(k){(v)}
92
  }
93
  }
src/templates/views/search.rs CHANGED
@@ -38,7 +38,7 @@ pub fn search(
38
  small{(result.url)}
39
  p{(PreEscaped(&result.description))}
40
  .upstream_engines{
41
- @for name in result.clone().engine{
42
  span{(name)}
43
  }
44
  }
 
38
  small{(result.url)}
39
  p{(PreEscaped(&result.description))}
40
  .upstream_engines{
41
+ @for name in &result.engine {
42
  span{(name)}
43
  }
44
  }
tests/index.rs CHANGED
@@ -1,14 +1,17 @@
1
- use std::net::TcpListener;
2
 
3
  use websurfx::{config::parser::Config, run, templates::views};
4
 
 
 
 
5
  // Starts a new instance of the HTTP server, bound to a random available port
6
  async fn spawn_app() -> String {
7
  // Binding to port 0 will trigger the OS to assign a port for us.
8
  let listener = TcpListener::bind("127.0.0.1:0").expect("Failed to bind random port");
9
  let port = listener.local_addr().unwrap().port();
10
- let config = Config::parse(false).unwrap();
11
- let cache = websurfx::cache::cacher::create_cache(&config).await;
12
  let server = run(listener, config, cache).expect("Failed to bind address");
13
 
14
  tokio::spawn(server);
 
1
+ use std::{net::TcpListener, sync::OnceLock};
2
 
3
  use websurfx::{config::parser::Config, run, templates::views};
4
 
5
+ /// A static constant for holding the parsed config.
6
+ static CONFIG: OnceLock<Config> = OnceLock::new();
7
+
8
  // Starts a new instance of the HTTP server, bound to a random available port
9
  async fn spawn_app() -> String {
10
  // Binding to port 0 will trigger the OS to assign a port for us.
11
  let listener = TcpListener::bind("127.0.0.1:0").expect("Failed to bind random port");
12
  let port = listener.local_addr().unwrap().port();
13
+ let config = CONFIG.get_or_init(|| Config::parse(false).unwrap());
14
+ let cache = websurfx::cache::cacher::create_cache(config).await;
15
  let server = run(listener, config, cache).expect("Failed to bind address");
16
 
17
  tokio::spawn(server);