+5
.github/ISSUE_TEMPLATE/config.yml
+5
.github/ISSUE_TEMPLATE/config.yml
+2
.github/workflows/rust.yml
+2
.github/workflows/rust.yml
+26
-3
CHANGELOG.md
+26
-3
CHANGELOG.md
···
2
2
3
3
## [Unreleased] - _TBD_
4
4
5
+
## [v0.4.0] - 2024-03-19
6
+
7
+
### Added
8
+
9
+
- Implemented the function histories command.
10
+
- Configurable time limits.
11
+
12
+
### Fixed
13
+
14
+
- RPC HelloResult will now report if deletes are enabled.
15
+
16
+
### Changes
17
+
18
+
- Applied code formatting using `cargo fmt`
19
+
5
20
## [v0.3.0] - 2023-08-22
21
+
6
22
### Added
23
+
7
24
- This changelog.
8
25
- Support for IDA 8.1+ delete command.
9
26
- Pooling for connections to database.
···
13
30
- Add Metrics for prometheus.
14
31
15
32
### Fixed
33
+
16
34
- 8K stack size is too small for debug builds.
17
35
18
36
## [v0.2.0] - 2022-10-12
37
+
19
38
### Added
39
+
20
40
- Protocol: support for IDA 8.1+ user authentication.
21
41
- Client connection duration limitations.
42
+
22
43
### Changed
44
+
23
45
- Tokio's thread size is reduced from 4M to 8K.
24
46
25
-
## [v0.1.0] - 2021-01-21
47
+
## [v0.1.0] - 2021-01-21
48
+
26
49
This is Lumen's first tagged release. It contains a few fixes and dependency updates since the initial commit (2020-12-17).
27
50
28
-
29
-
[Unreleased]: https://github.com/naim94a/lumen/compare/v0.3.0...HEAD
51
+
[Unreleased]: https://github.com/naim94a/lumen/compare/v0.4.0...HEAD
52
+
[v0.4.0]: https://github.com/naim94a/lumen/compare/v0.3.0...v0.4.0
30
53
[v0.3.0]: https://github.com/naim94a/lumen/compare/v0.2.0...v0.3.0
31
54
[v0.2.0]: https://github.com/naim94a/lumen/compare/v0.1.0...v0.2.0
32
55
[v0.1.0]: https://github.com/naim94a/lumen/releases/tag/v0.1.0
+930
-494
Cargo.lock
+930
-494
Cargo.lock
···
1
1
# This file is automatically @generated by Cargo.
2
2
# It is not intended for manual editing.
3
-
version = 3
3
+
version = 4
4
4
5
5
[[package]]
6
6
name = "addr2line"
7
-
version = "0.20.0"
7
+
version = "0.24.2"
8
8
source = "registry+https://github.com/rust-lang/crates.io-index"
9
-
checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
9
+
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
10
10
dependencies = [
11
11
"gimli",
12
12
]
13
13
14
14
[[package]]
15
-
name = "adler"
16
-
version = "1.0.2"
15
+
name = "adler2"
16
+
version = "2.0.0"
17
17
source = "registry+https://github.com/rust-lang/crates.io-index"
18
-
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
18
+
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
19
19
20
20
[[package]]
21
21
name = "aho-corasick"
22
-
version = "1.0.4"
22
+
version = "1.1.3"
23
23
source = "registry+https://github.com/rust-lang/crates.io-index"
24
-
checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a"
24
+
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
25
25
dependencies = [
26
26
"memchr",
27
27
]
28
28
29
29
[[package]]
30
30
name = "anstream"
31
-
version = "0.3.2"
31
+
version = "0.6.19"
32
32
source = "registry+https://github.com/rust-lang/crates.io-index"
33
-
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
33
+
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
34
34
dependencies = [
35
35
"anstyle",
36
36
"anstyle-parse",
37
37
"anstyle-query",
38
38
"anstyle-wincon",
39
39
"colorchoice",
40
-
"is-terminal",
40
+
"is_terminal_polyfill",
41
41
"utf8parse",
42
42
]
43
43
44
44
[[package]]
45
45
name = "anstyle"
46
-
version = "1.0.1"
46
+
version = "1.0.11"
47
47
source = "registry+https://github.com/rust-lang/crates.io-index"
48
-
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
48
+
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
49
49
50
50
[[package]]
51
51
name = "anstyle-parse"
52
-
version = "0.2.1"
52
+
version = "0.2.7"
53
53
source = "registry+https://github.com/rust-lang/crates.io-index"
54
-
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
54
+
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
55
55
dependencies = [
56
56
"utf8parse",
57
57
]
58
58
59
59
[[package]]
60
60
name = "anstyle-query"
61
-
version = "1.0.0"
61
+
version = "1.1.3"
62
62
source = "registry+https://github.com/rust-lang/crates.io-index"
63
-
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
63
+
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
64
64
dependencies = [
65
-
"windows-sys",
65
+
"windows-sys 0.59.0",
66
66
]
67
67
68
68
[[package]]
69
69
name = "anstyle-wincon"
70
-
version = "1.0.2"
70
+
version = "3.0.9"
71
71
source = "registry+https://github.com/rust-lang/crates.io-index"
72
-
checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c"
72
+
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
73
73
dependencies = [
74
74
"anstyle",
75
-
"windows-sys",
75
+
"once_cell_polyfill",
76
+
"windows-sys 0.59.0",
76
77
]
77
78
78
79
[[package]]
79
80
name = "anyhow"
80
-
version = "1.0.75"
81
+
version = "1.0.98"
81
82
source = "registry+https://github.com/rust-lang/crates.io-index"
82
-
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
83
+
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
83
84
84
85
[[package]]
85
86
name = "async-trait"
86
-
version = "0.1.73"
87
+
version = "0.1.88"
87
88
source = "registry+https://github.com/rust-lang/crates.io-index"
88
-
checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
89
+
checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
89
90
dependencies = [
90
91
"proc-macro2",
91
92
"quote",
···
94
95
95
96
[[package]]
96
97
name = "autocfg"
97
-
version = "1.1.0"
98
+
version = "1.4.0"
98
99
source = "registry+https://github.com/rust-lang/crates.io-index"
99
-
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
100
+
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
100
101
101
102
[[package]]
102
103
name = "backtrace"
103
-
version = "0.3.68"
104
+
version = "0.3.75"
104
105
source = "registry+https://github.com/rust-lang/crates.io-index"
105
-
checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
106
+
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
106
107
dependencies = [
107
108
"addr2line",
108
-
"cc",
109
109
"cfg-if",
110
110
"libc",
111
111
"miniz_oxide",
112
112
"object",
113
113
"rustc-demangle",
114
+
"windows-targets",
114
115
]
115
116
116
117
[[package]]
117
118
name = "base64"
118
-
version = "0.13.1"
119
+
version = "0.21.7"
119
120
source = "registry+https://github.com/rust-lang/crates.io-index"
120
-
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
121
+
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
121
122
122
123
[[package]]
123
124
name = "base64"
124
-
version = "0.21.2"
125
+
version = "0.22.1"
125
126
source = "registry+https://github.com/rust-lang/crates.io-index"
126
-
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
127
+
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
127
128
128
129
[[package]]
129
130
name = "bb8"
130
-
version = "0.8.1"
131
+
version = "0.8.6"
131
132
source = "registry+https://github.com/rust-lang/crates.io-index"
132
-
checksum = "98b4b0f25f18bcdc3ac72bdb486ed0acf7e185221fd4dc985bc15db5800b0ba2"
133
+
checksum = "d89aabfae550a5c44b43ab941844ffcd2e993cb6900b342debf59e9ea74acdb8"
133
134
dependencies = [
134
135
"async-trait",
135
-
"futures-channel",
136
136
"futures-util",
137
137
"parking_lot",
138
138
"tokio",
···
146
146
147
147
[[package]]
148
148
name = "bitflags"
149
-
version = "1.3.2"
150
-
source = "registry+https://github.com/rust-lang/crates.io-index"
151
-
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
152
-
153
-
[[package]]
154
-
name = "bitflags"
155
-
version = "2.4.0"
149
+
version = "2.9.1"
156
150
source = "registry+https://github.com/rust-lang/crates.io-index"
157
-
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
151
+
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
158
152
159
153
[[package]]
160
154
name = "block-buffer"
···
166
160
]
167
161
168
162
[[package]]
163
+
name = "bumpalo"
164
+
version = "3.18.1"
165
+
source = "registry+https://github.com/rust-lang/crates.io-index"
166
+
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
167
+
168
+
[[package]]
169
169
name = "byteorder"
170
-
version = "1.4.3"
170
+
version = "1.5.0"
171
171
source = "registry+https://github.com/rust-lang/crates.io-index"
172
-
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
172
+
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
173
173
174
174
[[package]]
175
175
name = "bytes"
176
-
version = "1.4.0"
176
+
version = "1.10.1"
177
177
source = "registry+https://github.com/rust-lang/crates.io-index"
178
-
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
178
+
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
179
179
180
180
[[package]]
181
181
name = "cc"
182
-
version = "1.0.82"
182
+
version = "1.2.26"
183
183
source = "registry+https://github.com/rust-lang/crates.io-index"
184
-
checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
184
+
checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac"
185
185
dependencies = [
186
-
"libc",
186
+
"shlex",
187
187
]
188
188
189
189
[[package]]
···
194
194
195
195
[[package]]
196
196
name = "clap"
197
-
version = "4.3.22"
197
+
version = "4.5.39"
198
198
source = "registry+https://github.com/rust-lang/crates.io-index"
199
-
checksum = "b417ae4361bca3f5de378294fc7472d3c4ed86a5ef9f49e93ae722f432aae8d2"
199
+
checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
200
200
dependencies = [
201
201
"clap_builder",
202
202
]
203
203
204
204
[[package]]
205
205
name = "clap_builder"
206
-
version = "4.3.22"
206
+
version = "4.5.39"
207
207
source = "registry+https://github.com/rust-lang/crates.io-index"
208
-
checksum = "9c90dc0f0e42c64bff177ca9d7be6fcc9ddb0f26a6e062174a61c84dd6c644d4"
208
+
checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
209
209
dependencies = [
210
210
"anstream",
211
211
"anstyle",
···
215
215
216
216
[[package]]
217
217
name = "clap_lex"
218
-
version = "0.5.0"
218
+
version = "0.7.4"
219
219
source = "registry+https://github.com/rust-lang/crates.io-index"
220
-
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
220
+
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
221
221
222
222
[[package]]
223
223
name = "colorchoice"
224
-
version = "1.0.0"
224
+
version = "1.0.4"
225
225
source = "registry+https://github.com/rust-lang/crates.io-index"
226
-
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
226
+
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
227
227
228
228
[[package]]
229
229
name = "common"
···
239
239
"postgres-native-tls",
240
240
"prometheus-client",
241
241
"serde",
242
+
"time",
242
243
"tokio",
243
244
"tokio-postgres",
244
245
"toml",
···
247
248
248
249
[[package]]
249
250
name = "core-foundation"
250
-
version = "0.9.3"
251
+
version = "0.9.4"
251
252
source = "registry+https://github.com/rust-lang/crates.io-index"
252
-
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
253
+
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
253
254
dependencies = [
254
255
"core-foundation-sys",
255
256
"libc",
···
257
258
258
259
[[package]]
259
260
name = "core-foundation-sys"
260
-
version = "0.8.4"
261
+
version = "0.8.7"
261
262
source = "registry+https://github.com/rust-lang/crates.io-index"
262
-
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
263
+
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
263
264
264
265
[[package]]
265
266
name = "cpufeatures"
266
-
version = "0.2.9"
267
+
version = "0.2.17"
267
268
source = "registry+https://github.com/rust-lang/crates.io-index"
268
-
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
269
+
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
269
270
dependencies = [
270
271
"libc",
271
272
]
···
281
282
]
282
283
283
284
[[package]]
285
+
name = "darling"
286
+
version = "0.20.11"
287
+
source = "registry+https://github.com/rust-lang/crates.io-index"
288
+
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
289
+
dependencies = [
290
+
"darling_core",
291
+
"darling_macro",
292
+
]
293
+
294
+
[[package]]
295
+
name = "darling_core"
296
+
version = "0.20.11"
297
+
source = "registry+https://github.com/rust-lang/crates.io-index"
298
+
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
299
+
dependencies = [
300
+
"fnv",
301
+
"ident_case",
302
+
"proc-macro2",
303
+
"quote",
304
+
"strsim",
305
+
"syn",
306
+
]
307
+
308
+
[[package]]
309
+
name = "darling_macro"
310
+
version = "0.20.11"
311
+
source = "registry+https://github.com/rust-lang/crates.io-index"
312
+
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
313
+
dependencies = [
314
+
"darling_core",
315
+
"quote",
316
+
"syn",
317
+
]
318
+
319
+
[[package]]
320
+
name = "data-encoding"
321
+
version = "2.9.0"
322
+
source = "registry+https://github.com/rust-lang/crates.io-index"
323
+
checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
324
+
325
+
[[package]]
284
326
name = "deranged"
285
-
version = "0.3.7"
327
+
version = "0.4.0"
286
328
source = "registry+https://github.com/rust-lang/crates.io-index"
287
-
checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929"
329
+
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
330
+
dependencies = [
331
+
"powerfmt",
332
+
]
288
333
289
334
[[package]]
290
335
name = "diesel"
291
-
version = "2.1.0"
336
+
version = "2.2.10"
292
337
source = "registry+https://github.com/rust-lang/crates.io-index"
293
-
checksum = "f7a532c1f99a0f596f6960a60d1e119e91582b24b39e2d83a190e61262c3ef0c"
338
+
checksum = "ff3e1edb1f37b4953dd5176916347289ed43d7119cc2e6c7c3f7849ff44ea506"
294
339
dependencies = [
295
-
"bitflags 2.4.0",
340
+
"bitflags",
296
341
"byteorder",
297
342
"diesel_derives",
298
343
"itoa",
···
301
346
302
347
[[package]]
303
348
name = "diesel-async"
304
-
version = "0.3.2"
349
+
version = "0.5.2"
305
350
source = "registry+https://github.com/rust-lang/crates.io-index"
306
-
checksum = "c7e7974099f0d9bde0e010dd3a673555276a474f3362a7a52ab535a57b7c5056"
351
+
checksum = "51a307ac00f7c23f526a04a77761a0519b9f0eb2838ebf5b905a58580095bdcb"
307
352
dependencies = [
308
353
"async-trait",
309
354
"bb8",
···
316
361
317
362
[[package]]
318
363
name = "diesel_derives"
319
-
version = "2.1.0"
364
+
version = "2.2.5"
320
365
source = "registry+https://github.com/rust-lang/crates.io-index"
321
-
checksum = "74398b79d81e52e130d991afeed9c86034bb1b7735f46d2f5bf7deb261d80303"
366
+
checksum = "68d4216021b3ea446fd2047f5c8f8fe6e98af34508a254a01e4d6bc1e844f84d"
322
367
dependencies = [
323
368
"diesel_table_macro_syntax",
369
+
"dsl_auto_type",
324
370
"proc-macro2",
325
371
"quote",
326
372
"syn",
···
328
374
329
375
[[package]]
330
376
name = "diesel_table_macro_syntax"
331
-
version = "0.1.0"
377
+
version = "0.2.0"
332
378
source = "registry+https://github.com/rust-lang/crates.io-index"
333
-
checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5"
379
+
checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25"
334
380
dependencies = [
335
381
"syn",
336
382
]
···
347
393
]
348
394
349
395
[[package]]
396
+
name = "displaydoc"
397
+
version = "0.2.5"
398
+
source = "registry+https://github.com/rust-lang/crates.io-index"
399
+
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
400
+
dependencies = [
401
+
"proc-macro2",
402
+
"quote",
403
+
"syn",
404
+
]
405
+
406
+
[[package]]
407
+
name = "dsl_auto_type"
408
+
version = "0.1.3"
409
+
source = "registry+https://github.com/rust-lang/crates.io-index"
410
+
checksum = "139ae9aca7527f85f26dd76483eb38533fd84bd571065da1739656ef71c5ff5b"
411
+
dependencies = [
412
+
"darling",
413
+
"either",
414
+
"heck",
415
+
"proc-macro2",
416
+
"quote",
417
+
"syn",
418
+
]
419
+
420
+
[[package]]
350
421
name = "dtoa"
351
-
version = "1.0.9"
422
+
version = "1.0.10"
352
423
source = "registry+https://github.com/rust-lang/crates.io-index"
353
-
checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653"
424
+
checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04"
425
+
426
+
[[package]]
427
+
name = "either"
428
+
version = "1.15.0"
429
+
source = "registry+https://github.com/rust-lang/crates.io-index"
430
+
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
354
431
355
432
[[package]]
356
433
name = "encoding_rs"
357
-
version = "0.8.32"
434
+
version = "0.8.35"
358
435
source = "registry+https://github.com/rust-lang/crates.io-index"
359
-
checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
436
+
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
360
437
dependencies = [
361
438
"cfg-if",
362
439
]
363
440
364
441
[[package]]
365
442
name = "env_logger"
366
-
version = "0.10.0"
443
+
version = "0.10.2"
367
444
source = "registry+https://github.com/rust-lang/crates.io-index"
368
-
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
445
+
checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
369
446
dependencies = [
370
447
"humantime",
371
448
"is-terminal",
···
376
453
377
454
[[package]]
378
455
name = "equivalent"
379
-
version = "1.0.1"
456
+
version = "1.0.2"
380
457
source = "registry+https://github.com/rust-lang/crates.io-index"
381
-
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
458
+
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
382
459
383
460
[[package]]
384
461
name = "errno"
385
-
version = "0.3.2"
386
-
source = "registry+https://github.com/rust-lang/crates.io-index"
387
-
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
388
-
dependencies = [
389
-
"errno-dragonfly",
390
-
"libc",
391
-
"windows-sys",
392
-
]
393
-
394
-
[[package]]
395
-
name = "errno-dragonfly"
396
-
version = "0.1.2"
462
+
version = "0.3.12"
397
463
source = "registry+https://github.com/rust-lang/crates.io-index"
398
-
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
464
+
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
399
465
dependencies = [
400
-
"cc",
401
466
"libc",
467
+
"windows-sys 0.59.0",
402
468
]
403
469
404
470
[[package]]
···
409
475
410
476
[[package]]
411
477
name = "fastrand"
412
-
version = "2.0.0"
478
+
version = "2.3.0"
413
479
source = "registry+https://github.com/rust-lang/crates.io-index"
414
-
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
480
+
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
415
481
416
482
[[package]]
417
483
name = "fnv"
···
436
502
437
503
[[package]]
438
504
name = "form_urlencoded"
439
-
version = "1.2.0"
505
+
version = "1.2.1"
440
506
source = "registry+https://github.com/rust-lang/crates.io-index"
441
-
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
507
+
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
442
508
dependencies = [
443
509
"percent-encoding",
444
510
]
445
511
446
512
[[package]]
447
-
name = "futures"
448
-
version = "0.3.28"
449
-
source = "registry+https://github.com/rust-lang/crates.io-index"
450
-
checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
451
-
dependencies = [
452
-
"futures-channel",
453
-
"futures-core",
454
-
"futures-executor",
455
-
"futures-io",
456
-
"futures-sink",
457
-
"futures-task",
458
-
"futures-util",
459
-
]
460
-
461
-
[[package]]
462
513
name = "futures-channel"
463
-
version = "0.3.28"
514
+
version = "0.3.31"
464
515
source = "registry+https://github.com/rust-lang/crates.io-index"
465
-
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
516
+
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
466
517
dependencies = [
467
518
"futures-core",
468
519
"futures-sink",
···
470
521
471
522
[[package]]
472
523
name = "futures-core"
473
-
version = "0.3.28"
474
-
source = "registry+https://github.com/rust-lang/crates.io-index"
475
-
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
476
-
477
-
[[package]]
478
-
name = "futures-executor"
479
-
version = "0.3.28"
480
-
source = "registry+https://github.com/rust-lang/crates.io-index"
481
-
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
482
-
dependencies = [
483
-
"futures-core",
484
-
"futures-task",
485
-
"futures-util",
486
-
]
487
-
488
-
[[package]]
489
-
name = "futures-io"
490
-
version = "0.3.28"
524
+
version = "0.3.31"
491
525
source = "registry+https://github.com/rust-lang/crates.io-index"
492
-
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
526
+
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
493
527
494
528
[[package]]
495
529
name = "futures-macro"
496
-
version = "0.3.28"
530
+
version = "0.3.31"
497
531
source = "registry+https://github.com/rust-lang/crates.io-index"
498
-
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
532
+
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
499
533
dependencies = [
500
534
"proc-macro2",
501
535
"quote",
···
504
538
505
539
[[package]]
506
540
name = "futures-sink"
507
-
version = "0.3.28"
541
+
version = "0.3.31"
508
542
source = "registry+https://github.com/rust-lang/crates.io-index"
509
-
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
543
+
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
510
544
511
545
[[package]]
512
546
name = "futures-task"
513
-
version = "0.3.28"
547
+
version = "0.3.31"
514
548
source = "registry+https://github.com/rust-lang/crates.io-index"
515
-
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
549
+
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
516
550
517
551
[[package]]
518
552
name = "futures-util"
519
-
version = "0.3.28"
553
+
version = "0.3.31"
520
554
source = "registry+https://github.com/rust-lang/crates.io-index"
521
-
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
555
+
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
522
556
dependencies = [
523
-
"futures-channel",
524
557
"futures-core",
525
-
"futures-io",
526
558
"futures-macro",
527
559
"futures-sink",
528
560
"futures-task",
529
-
"memchr",
530
561
"pin-project-lite",
531
562
"pin-utils",
532
563
"slab",
···
544
575
545
576
[[package]]
546
577
name = "getrandom"
547
-
version = "0.2.10"
578
+
version = "0.2.16"
548
579
source = "registry+https://github.com/rust-lang/crates.io-index"
549
-
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
580
+
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
550
581
dependencies = [
551
582
"cfg-if",
552
583
"libc",
553
-
"wasi",
584
+
"wasi 0.11.0+wasi-snapshot-preview1",
585
+
]
586
+
587
+
[[package]]
588
+
name = "getrandom"
589
+
version = "0.3.3"
590
+
source = "registry+https://github.com/rust-lang/crates.io-index"
591
+
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
592
+
dependencies = [
593
+
"cfg-if",
594
+
"libc",
595
+
"r-efi",
596
+
"wasi 0.14.2+wasi-0.2.4",
554
597
]
555
598
556
599
[[package]]
557
600
name = "gimli"
558
-
version = "0.27.3"
601
+
version = "0.31.1"
559
602
source = "registry+https://github.com/rust-lang/crates.io-index"
560
-
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
603
+
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
561
604
562
605
[[package]]
563
606
name = "h2"
564
-
version = "0.3.20"
607
+
version = "0.3.26"
565
608
source = "registry+https://github.com/rust-lang/crates.io-index"
566
-
checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049"
609
+
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
567
610
dependencies = [
568
611
"bytes",
569
612
"fnv",
570
613
"futures-core",
571
614
"futures-sink",
572
615
"futures-util",
573
-
"http",
574
-
"indexmap 1.9.3",
616
+
"http 0.2.12",
617
+
"indexmap",
575
618
"slab",
576
619
"tokio",
577
620
"tokio-util",
···
580
623
581
624
[[package]]
582
625
name = "hashbrown"
583
-
version = "0.12.3"
626
+
version = "0.15.4"
584
627
source = "registry+https://github.com/rust-lang/crates.io-index"
585
-
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
586
-
587
-
[[package]]
588
-
name = "hashbrown"
589
-
version = "0.14.0"
590
-
source = "registry+https://github.com/rust-lang/crates.io-index"
591
-
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
628
+
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
592
629
593
630
[[package]]
594
631
name = "headers"
595
-
version = "0.3.8"
632
+
version = "0.3.9"
596
633
source = "registry+https://github.com/rust-lang/crates.io-index"
597
-
checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584"
634
+
checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270"
598
635
dependencies = [
599
-
"base64 0.13.1",
600
-
"bitflags 1.3.2",
636
+
"base64 0.21.7",
601
637
"bytes",
602
638
"headers-core",
603
-
"http",
639
+
"http 0.2.12",
604
640
"httpdate",
605
641
"mime",
606
642
"sha1",
···
612
648
source = "registry+https://github.com/rust-lang/crates.io-index"
613
649
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
614
650
dependencies = [
615
-
"http",
651
+
"http 0.2.12",
616
652
]
617
653
618
654
[[package]]
655
+
name = "heck"
656
+
version = "0.5.0"
657
+
source = "registry+https://github.com/rust-lang/crates.io-index"
658
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
659
+
660
+
[[package]]
619
661
name = "hermit-abi"
620
-
version = "0.3.2"
662
+
version = "0.5.1"
621
663
source = "registry+https://github.com/rust-lang/crates.io-index"
622
-
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
664
+
checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
623
665
624
666
[[package]]
625
667
name = "hmac"
···
632
674
633
675
[[package]]
634
676
name = "http"
635
-
version = "0.2.9"
677
+
version = "0.2.12"
678
+
source = "registry+https://github.com/rust-lang/crates.io-index"
679
+
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
680
+
dependencies = [
681
+
"bytes",
682
+
"fnv",
683
+
"itoa",
684
+
]
685
+
686
+
[[package]]
687
+
name = "http"
688
+
version = "1.3.1"
636
689
source = "registry+https://github.com/rust-lang/crates.io-index"
637
-
checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
690
+
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
638
691
dependencies = [
639
692
"bytes",
640
693
"fnv",
···
643
696
644
697
[[package]]
645
698
name = "http-body"
646
-
version = "0.4.5"
699
+
version = "0.4.6"
647
700
source = "registry+https://github.com/rust-lang/crates.io-index"
648
-
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
701
+
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
649
702
dependencies = [
650
703
"bytes",
651
-
"http",
704
+
"http 0.2.12",
652
705
"pin-project-lite",
653
706
]
654
707
655
708
[[package]]
656
709
name = "httparse"
657
-
version = "1.8.0"
710
+
version = "1.10.1"
658
711
source = "registry+https://github.com/rust-lang/crates.io-index"
659
-
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
712
+
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
660
713
661
714
[[package]]
662
715
name = "httpdate"
···
666
719
667
720
[[package]]
668
721
name = "humantime"
669
-
version = "2.1.0"
722
+
version = "2.2.0"
670
723
source = "registry+https://github.com/rust-lang/crates.io-index"
671
-
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
724
+
checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f"
672
725
673
726
[[package]]
674
727
name = "hyper"
675
-
version = "0.14.27"
728
+
version = "0.14.32"
676
729
source = "registry+https://github.com/rust-lang/crates.io-index"
677
-
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
730
+
checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
678
731
dependencies = [
679
732
"bytes",
680
733
"futures-channel",
681
734
"futures-core",
682
735
"futures-util",
683
736
"h2",
684
-
"http",
737
+
"http 0.2.12",
685
738
"http-body",
686
739
"httparse",
687
740
"httpdate",
688
741
"itoa",
689
742
"pin-project-lite",
690
-
"socket2 0.4.9",
743
+
"socket2",
691
744
"tokio",
692
745
"tower-service",
693
746
"tracing",
···
695
748
]
696
749
697
750
[[package]]
751
+
name = "icu_collections"
752
+
version = "2.0.0"
753
+
source = "registry+https://github.com/rust-lang/crates.io-index"
754
+
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
755
+
dependencies = [
756
+
"displaydoc",
757
+
"potential_utf",
758
+
"yoke",
759
+
"zerofrom",
760
+
"zerovec",
761
+
]
762
+
763
+
[[package]]
764
+
name = "icu_locale_core"
765
+
version = "2.0.0"
766
+
source = "registry+https://github.com/rust-lang/crates.io-index"
767
+
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
768
+
dependencies = [
769
+
"displaydoc",
770
+
"litemap",
771
+
"tinystr",
772
+
"writeable",
773
+
"zerovec",
774
+
]
775
+
776
+
[[package]]
777
+
name = "icu_normalizer"
778
+
version = "2.0.0"
779
+
source = "registry+https://github.com/rust-lang/crates.io-index"
780
+
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
781
+
dependencies = [
782
+
"displaydoc",
783
+
"icu_collections",
784
+
"icu_normalizer_data",
785
+
"icu_properties",
786
+
"icu_provider",
787
+
"smallvec",
788
+
"zerovec",
789
+
]
790
+
791
+
[[package]]
792
+
name = "icu_normalizer_data"
793
+
version = "2.0.0"
794
+
source = "registry+https://github.com/rust-lang/crates.io-index"
795
+
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
796
+
797
+
[[package]]
798
+
name = "icu_properties"
799
+
version = "2.0.1"
800
+
source = "registry+https://github.com/rust-lang/crates.io-index"
801
+
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
802
+
dependencies = [
803
+
"displaydoc",
804
+
"icu_collections",
805
+
"icu_locale_core",
806
+
"icu_properties_data",
807
+
"icu_provider",
808
+
"potential_utf",
809
+
"zerotrie",
810
+
"zerovec",
811
+
]
812
+
813
+
[[package]]
814
+
name = "icu_properties_data"
815
+
version = "2.0.1"
816
+
source = "registry+https://github.com/rust-lang/crates.io-index"
817
+
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
818
+
819
+
[[package]]
820
+
name = "icu_provider"
821
+
version = "2.0.0"
822
+
source = "registry+https://github.com/rust-lang/crates.io-index"
823
+
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
824
+
dependencies = [
825
+
"displaydoc",
826
+
"icu_locale_core",
827
+
"stable_deref_trait",
828
+
"tinystr",
829
+
"writeable",
830
+
"yoke",
831
+
"zerofrom",
832
+
"zerotrie",
833
+
"zerovec",
834
+
]
835
+
836
+
[[package]]
837
+
name = "ident_case"
838
+
version = "1.0.1"
839
+
source = "registry+https://github.com/rust-lang/crates.io-index"
840
+
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
841
+
842
+
[[package]]
698
843
name = "idna"
699
-
version = "0.4.0"
844
+
version = "1.0.3"
700
845
source = "registry+https://github.com/rust-lang/crates.io-index"
701
-
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
846
+
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
702
847
dependencies = [
703
-
"unicode-bidi",
704
-
"unicode-normalization",
848
+
"idna_adapter",
849
+
"smallvec",
850
+
"utf8_iter",
705
851
]
706
852
707
853
[[package]]
708
-
name = "indexmap"
709
-
version = "1.9.3"
854
+
name = "idna_adapter"
855
+
version = "1.2.1"
710
856
source = "registry+https://github.com/rust-lang/crates.io-index"
711
-
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
857
+
checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
712
858
dependencies = [
713
-
"autocfg",
714
-
"hashbrown 0.12.3",
859
+
"icu_normalizer",
860
+
"icu_properties",
715
861
]
716
862
717
863
[[package]]
718
864
name = "indexmap"
719
-
version = "2.0.0"
865
+
version = "2.9.0"
720
866
source = "registry+https://github.com/rust-lang/crates.io-index"
721
-
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
867
+
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
722
868
dependencies = [
723
869
"equivalent",
724
-
"hashbrown 0.14.0",
870
+
"hashbrown",
725
871
]
726
872
727
873
[[package]]
728
874
name = "is-terminal"
729
-
version = "0.4.9"
875
+
version = "0.4.16"
730
876
source = "registry+https://github.com/rust-lang/crates.io-index"
731
-
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
877
+
checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
732
878
dependencies = [
733
879
"hermit-abi",
734
-
"rustix",
735
-
"windows-sys",
880
+
"libc",
881
+
"windows-sys 0.59.0",
736
882
]
737
883
738
884
[[package]]
885
+
name = "is_terminal_polyfill"
886
+
version = "1.70.1"
887
+
source = "registry+https://github.com/rust-lang/crates.io-index"
888
+
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
889
+
890
+
[[package]]
739
891
name = "itoa"
740
-
version = "1.0.9"
892
+
version = "1.0.15"
741
893
source = "registry+https://github.com/rust-lang/crates.io-index"
742
-
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
894
+
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
743
895
744
896
[[package]]
745
-
name = "lazy_static"
746
-
version = "1.4.0"
897
+
name = "js-sys"
898
+
version = "0.3.77"
747
899
source = "registry+https://github.com/rust-lang/crates.io-index"
748
-
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
900
+
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
901
+
dependencies = [
902
+
"once_cell",
903
+
"wasm-bindgen",
904
+
]
749
905
750
906
[[package]]
751
907
name = "libc"
752
-
version = "0.2.147"
908
+
version = "0.2.172"
753
909
source = "registry+https://github.com/rust-lang/crates.io-index"
754
-
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
910
+
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
755
911
756
912
[[package]]
757
913
name = "linux-raw-sys"
758
-
version = "0.4.5"
914
+
version = "0.9.4"
915
+
source = "registry+https://github.com/rust-lang/crates.io-index"
916
+
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
917
+
918
+
[[package]]
919
+
name = "litemap"
920
+
version = "0.8.0"
759
921
source = "registry+https://github.com/rust-lang/crates.io-index"
760
-
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
922
+
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
761
923
762
924
[[package]]
763
925
name = "lock_api"
764
-
version = "0.4.10"
926
+
version = "0.4.13"
765
927
source = "registry+https://github.com/rust-lang/crates.io-index"
766
-
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
928
+
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
767
929
dependencies = [
768
930
"autocfg",
769
931
"scopeguard",
···
771
933
772
934
[[package]]
773
935
name = "log"
774
-
version = "0.4.20"
936
+
version = "0.4.27"
775
937
source = "registry+https://github.com/rust-lang/crates.io-index"
776
-
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
938
+
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
777
939
778
940
[[package]]
779
941
name = "lumen"
···
792
954
793
955
[[package]]
794
956
name = "md-5"
795
-
version = "0.10.5"
957
+
version = "0.10.6"
796
958
source = "registry+https://github.com/rust-lang/crates.io-index"
797
-
checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca"
959
+
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
798
960
dependencies = [
961
+
"cfg-if",
799
962
"digest",
800
963
]
801
964
802
965
[[package]]
803
966
name = "memchr"
804
-
version = "2.5.0"
967
+
version = "2.7.4"
805
968
source = "registry+https://github.com/rust-lang/crates.io-index"
806
-
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
969
+
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
807
970
808
971
[[package]]
809
972
name = "mime"
···
813
976
814
977
[[package]]
815
978
name = "mime_guess"
816
-
version = "2.0.4"
979
+
version = "2.0.5"
817
980
source = "registry+https://github.com/rust-lang/crates.io-index"
818
-
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
981
+
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
819
982
dependencies = [
820
983
"mime",
821
984
"unicase",
···
823
986
824
987
[[package]]
825
988
name = "miniz_oxide"
826
-
version = "0.7.1"
989
+
version = "0.8.8"
827
990
source = "registry+https://github.com/rust-lang/crates.io-index"
828
-
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
991
+
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
829
992
dependencies = [
830
-
"adler",
993
+
"adler2",
831
994
]
832
995
833
996
[[package]]
834
997
name = "mio"
835
-
version = "0.8.8"
998
+
version = "1.0.4"
836
999
source = "registry+https://github.com/rust-lang/crates.io-index"
837
-
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
1000
+
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
838
1001
dependencies = [
839
1002
"libc",
840
-
"wasi",
841
-
"windows-sys",
1003
+
"wasi 0.11.0+wasi-snapshot-preview1",
1004
+
"windows-sys 0.59.0",
842
1005
]
843
1006
844
1007
[[package]]
···
850
1013
"bytes",
851
1014
"encoding_rs",
852
1015
"futures-util",
853
-
"http",
1016
+
"http 0.2.12",
854
1017
"httparse",
855
1018
"log",
856
1019
"memchr",
···
861
1024
862
1025
[[package]]
863
1026
name = "native-tls"
864
-
version = "0.2.11"
1027
+
version = "0.2.14"
865
1028
source = "registry+https://github.com/rust-lang/crates.io-index"
866
-
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
1029
+
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
867
1030
dependencies = [
868
-
"lazy_static",
869
1031
"libc",
870
1032
"log",
871
1033
"openssl",
···
878
1040
]
879
1041
880
1042
[[package]]
881
-
name = "num_cpus"
882
-
version = "1.16.0"
1043
+
name = "num-conv"
1044
+
version = "0.1.0"
883
1045
source = "registry+https://github.com/rust-lang/crates.io-index"
884
-
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
885
-
dependencies = [
886
-
"hermit-abi",
887
-
"libc",
888
-
]
1046
+
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
889
1047
890
1048
[[package]]
891
1049
name = "object"
892
-
version = "0.31.1"
1050
+
version = "0.36.7"
893
1051
source = "registry+https://github.com/rust-lang/crates.io-index"
894
-
checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
1052
+
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
895
1053
dependencies = [
896
1054
"memchr",
897
1055
]
898
1056
899
1057
[[package]]
900
1058
name = "once_cell"
901
-
version = "1.18.0"
1059
+
version = "1.21.3"
1060
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1061
+
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
1062
+
1063
+
[[package]]
1064
+
name = "once_cell_polyfill"
1065
+
version = "1.70.1"
902
1066
source = "registry+https://github.com/rust-lang/crates.io-index"
903
-
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
1067
+
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
904
1068
905
1069
[[package]]
906
1070
name = "openssl"
907
-
version = "0.10.56"
1071
+
version = "0.10.73"
908
1072
source = "registry+https://github.com/rust-lang/crates.io-index"
909
-
checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e"
1073
+
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
910
1074
dependencies = [
911
-
"bitflags 1.3.2",
1075
+
"bitflags",
912
1076
"cfg-if",
913
1077
"foreign-types",
914
1078
"libc",
···
930
1094
931
1095
[[package]]
932
1096
name = "openssl-probe"
933
-
version = "0.1.5"
1097
+
version = "0.1.6"
934
1098
source = "registry+https://github.com/rust-lang/crates.io-index"
935
-
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
1099
+
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
936
1100
937
1101
[[package]]
938
1102
name = "openssl-sys"
939
-
version = "0.9.91"
1103
+
version = "0.9.109"
940
1104
source = "registry+https://github.com/rust-lang/crates.io-index"
941
-
checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac"
1105
+
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
942
1106
dependencies = [
943
1107
"cc",
944
1108
"libc",
···
948
1112
949
1113
[[package]]
950
1114
name = "parking_lot"
951
-
version = "0.12.1"
1115
+
version = "0.12.4"
952
1116
source = "registry+https://github.com/rust-lang/crates.io-index"
953
-
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
1117
+
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
954
1118
dependencies = [
955
1119
"lock_api",
956
1120
"parking_lot_core",
···
958
1122
959
1123
[[package]]
960
1124
name = "parking_lot_core"
961
-
version = "0.9.8"
1125
+
version = "0.9.11"
962
1126
source = "registry+https://github.com/rust-lang/crates.io-index"
963
-
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
1127
+
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
964
1128
dependencies = [
965
1129
"cfg-if",
966
1130
"libc",
···
971
1135
972
1136
[[package]]
973
1137
name = "percent-encoding"
974
-
version = "2.3.0"
1138
+
version = "2.3.1"
975
1139
source = "registry+https://github.com/rust-lang/crates.io-index"
976
-
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
1140
+
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
977
1141
978
1142
[[package]]
979
1143
name = "phf"
980
-
version = "0.11.2"
1144
+
version = "0.11.3"
981
1145
source = "registry+https://github.com/rust-lang/crates.io-index"
982
-
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
1146
+
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
983
1147
dependencies = [
984
1148
"phf_shared",
985
1149
]
986
1150
987
1151
[[package]]
988
1152
name = "phf_shared"
989
-
version = "0.11.2"
1153
+
version = "0.11.3"
990
1154
source = "registry+https://github.com/rust-lang/crates.io-index"
991
-
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
1155
+
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
992
1156
dependencies = [
993
1157
"siphasher",
994
1158
]
995
1159
996
1160
[[package]]
997
1161
name = "pin-project"
998
-
version = "1.1.3"
1162
+
version = "1.1.10"
999
1163
source = "registry+https://github.com/rust-lang/crates.io-index"
1000
-
checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
1164
+
checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
1001
1165
dependencies = [
1002
1166
"pin-project-internal",
1003
1167
]
1004
1168
1005
1169
[[package]]
1006
1170
name = "pin-project-internal"
1007
-
version = "1.1.3"
1171
+
version = "1.1.10"
1008
1172
source = "registry+https://github.com/rust-lang/crates.io-index"
1009
-
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
1173
+
checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
1010
1174
dependencies = [
1011
1175
"proc-macro2",
1012
1176
"quote",
···
1015
1179
1016
1180
[[package]]
1017
1181
name = "pin-project-lite"
1018
-
version = "0.2.12"
1182
+
version = "0.2.16"
1019
1183
source = "registry+https://github.com/rust-lang/crates.io-index"
1020
-
checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05"
1184
+
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
1021
1185
1022
1186
[[package]]
1023
1187
name = "pin-utils"
···
1027
1191
1028
1192
[[package]]
1029
1193
name = "pkg-config"
1030
-
version = "0.3.27"
1194
+
version = "0.3.32"
1031
1195
source = "registry+https://github.com/rust-lang/crates.io-index"
1032
-
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
1196
+
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
1033
1197
1034
1198
[[package]]
1035
1199
name = "postgres-native-tls"
1036
-
version = "0.5.0"
1200
+
version = "0.5.1"
1037
1201
source = "registry+https://github.com/rust-lang/crates.io-index"
1038
-
checksum = "2d442770e2b1e244bb5eb03b31c79b65bb2568f413b899eaba850fa945a65954"
1202
+
checksum = "a1f39498473c92f7b6820ae970382c1d83178a3454c618161cb772e8598d9f6f"
1039
1203
dependencies = [
1040
-
"futures",
1041
1204
"native-tls",
1042
1205
"tokio",
1043
1206
"tokio-native-tls",
···
1046
1209
1047
1210
[[package]]
1048
1211
name = "postgres-protocol"
1049
-
version = "0.6.5"
1212
+
version = "0.6.8"
1050
1213
source = "registry+https://github.com/rust-lang/crates.io-index"
1051
-
checksum = "78b7fa9f396f51dffd61546fd8573ee20592287996568e6175ceb0f8699ad75d"
1214
+
checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54"
1052
1215
dependencies = [
1053
-
"base64 0.21.2",
1216
+
"base64 0.22.1",
1054
1217
"byteorder",
1055
1218
"bytes",
1056
1219
"fallible-iterator",
1057
1220
"hmac",
1058
1221
"md-5",
1059
1222
"memchr",
1060
-
"rand",
1223
+
"rand 0.9.1",
1061
1224
"sha2",
1062
1225
"stringprep",
1063
1226
]
1064
1227
1065
1228
[[package]]
1066
1229
name = "postgres-types"
1067
-
version = "0.2.5"
1230
+
version = "0.2.9"
1068
1231
source = "registry+https://github.com/rust-lang/crates.io-index"
1069
-
checksum = "f028f05971fe20f512bcc679e2c10227e57809a3af86a7606304435bc8896cd6"
1232
+
checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48"
1070
1233
dependencies = [
1071
1234
"bytes",
1072
1235
"fallible-iterator",
···
1074
1237
]
1075
1238
1076
1239
[[package]]
1240
+
name = "potential_utf"
1241
+
version = "0.1.2"
1242
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1243
+
checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
1244
+
dependencies = [
1245
+
"zerovec",
1246
+
]
1247
+
1248
+
[[package]]
1249
+
name = "powerfmt"
1250
+
version = "0.2.0"
1251
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1252
+
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
1253
+
1254
+
[[package]]
1077
1255
name = "ppv-lite86"
1078
-
version = "0.2.17"
1256
+
version = "0.2.21"
1079
1257
source = "registry+https://github.com/rust-lang/crates.io-index"
1080
-
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
1258
+
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
1259
+
dependencies = [
1260
+
"zerocopy",
1261
+
]
1081
1262
1082
1263
[[package]]
1083
1264
name = "pretty_env_logger"
···
1091
1272
1092
1273
[[package]]
1093
1274
name = "proc-macro2"
1094
-
version = "1.0.66"
1275
+
version = "1.0.95"
1095
1276
source = "registry+https://github.com/rust-lang/crates.io-index"
1096
-
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
1277
+
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
1097
1278
dependencies = [
1098
1279
"unicode-ident",
1099
1280
]
1100
1281
1101
1282
[[package]]
1102
1283
name = "prometheus-client"
1103
-
version = "0.21.2"
1284
+
version = "0.22.3"
1104
1285
source = "registry+https://github.com/rust-lang/crates.io-index"
1105
-
checksum = "3c99afa9a01501019ac3a14d71d9f94050346f55ca471ce90c799a15c58f61e2"
1286
+
checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca"
1106
1287
dependencies = [
1107
1288
"dtoa",
1108
1289
"itoa",
···
1123
1304
1124
1305
[[package]]
1125
1306
name = "quote"
1126
-
version = "1.0.33"
1307
+
version = "1.0.40"
1127
1308
source = "registry+https://github.com/rust-lang/crates.io-index"
1128
-
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
1309
+
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
1129
1310
dependencies = [
1130
1311
"proc-macro2",
1131
1312
]
1132
1313
1133
1314
[[package]]
1315
+
name = "r-efi"
1316
+
version = "5.2.0"
1317
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1318
+
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
1319
+
1320
+
[[package]]
1134
1321
name = "rand"
1135
1322
version = "0.8.5"
1136
1323
source = "registry+https://github.com/rust-lang/crates.io-index"
1137
1324
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
1138
1325
dependencies = [
1139
1326
"libc",
1140
-
"rand_chacha",
1141
-
"rand_core",
1327
+
"rand_chacha 0.3.1",
1328
+
"rand_core 0.6.4",
1329
+
]
1330
+
1331
+
[[package]]
1332
+
name = "rand"
1333
+
version = "0.9.1"
1334
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1335
+
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
1336
+
dependencies = [
1337
+
"rand_chacha 0.9.0",
1338
+
"rand_core 0.9.3",
1142
1339
]
1143
1340
1144
1341
[[package]]
···
1148
1345
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
1149
1346
dependencies = [
1150
1347
"ppv-lite86",
1151
-
"rand_core",
1348
+
"rand_core 0.6.4",
1349
+
]
1350
+
1351
+
[[package]]
1352
+
name = "rand_chacha"
1353
+
version = "0.9.0"
1354
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1355
+
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
1356
+
dependencies = [
1357
+
"ppv-lite86",
1358
+
"rand_core 0.9.3",
1152
1359
]
1153
1360
1154
1361
[[package]]
···
1157
1364
source = "registry+https://github.com/rust-lang/crates.io-index"
1158
1365
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
1159
1366
dependencies = [
1160
-
"getrandom",
1367
+
"getrandom 0.2.16",
1368
+
]
1369
+
1370
+
[[package]]
1371
+
name = "rand_core"
1372
+
version = "0.9.3"
1373
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1374
+
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
1375
+
dependencies = [
1376
+
"getrandom 0.3.3",
1161
1377
]
1162
1378
1163
1379
[[package]]
1164
1380
name = "redox_syscall"
1165
-
version = "0.3.5"
1381
+
version = "0.5.12"
1166
1382
source = "registry+https://github.com/rust-lang/crates.io-index"
1167
-
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
1383
+
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
1168
1384
dependencies = [
1169
-
"bitflags 1.3.2",
1385
+
"bitflags",
1170
1386
]
1171
1387
1172
1388
[[package]]
1173
1389
name = "regex"
1174
-
version = "1.9.3"
1390
+
version = "1.11.1"
1175
1391
source = "registry+https://github.com/rust-lang/crates.io-index"
1176
-
checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a"
1392
+
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
1177
1393
dependencies = [
1178
1394
"aho-corasick",
1179
1395
"memchr",
···
1183
1399
1184
1400
[[package]]
1185
1401
name = "regex-automata"
1186
-
version = "0.3.6"
1402
+
version = "0.4.9"
1187
1403
source = "registry+https://github.com/rust-lang/crates.io-index"
1188
-
checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69"
1404
+
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
1189
1405
dependencies = [
1190
1406
"aho-corasick",
1191
1407
"memchr",
···
1194
1410
1195
1411
[[package]]
1196
1412
name = "regex-syntax"
1197
-
version = "0.7.4"
1413
+
version = "0.8.5"
1198
1414
source = "registry+https://github.com/rust-lang/crates.io-index"
1199
-
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
1415
+
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
1200
1416
1201
1417
[[package]]
1202
1418
name = "rustc-demangle"
1203
-
version = "0.1.23"
1419
+
version = "0.1.24"
1204
1420
source = "registry+https://github.com/rust-lang/crates.io-index"
1205
-
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
1421
+
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
1206
1422
1207
1423
[[package]]
1208
1424
name = "rustix"
1209
-
version = "0.38.8"
1425
+
version = "1.0.7"
1210
1426
source = "registry+https://github.com/rust-lang/crates.io-index"
1211
-
checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
1427
+
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
1212
1428
dependencies = [
1213
-
"bitflags 2.4.0",
1429
+
"bitflags",
1214
1430
"errno",
1215
1431
"libc",
1216
1432
"linux-raw-sys",
1217
-
"windows-sys",
1218
-
]
1219
-
1220
-
[[package]]
1221
-
name = "rustls-pemfile"
1222
-
version = "1.0.3"
1223
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1224
-
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
1225
-
dependencies = [
1226
-
"base64 0.21.2",
1433
+
"windows-sys 0.59.0",
1227
1434
]
1228
1435
1229
1436
[[package]]
1230
1437
name = "ryu"
1231
-
version = "1.0.15"
1438
+
version = "1.0.20"
1232
1439
source = "registry+https://github.com/rust-lang/crates.io-index"
1233
-
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
1440
+
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
1234
1441
1235
1442
[[package]]
1236
1443
name = "schannel"
1237
-
version = "0.1.22"
1444
+
version = "0.1.27"
1238
1445
source = "registry+https://github.com/rust-lang/crates.io-index"
1239
-
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
1446
+
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
1240
1447
dependencies = [
1241
-
"windows-sys",
1448
+
"windows-sys 0.59.0",
1242
1449
]
1243
1450
1244
1451
[[package]]
1245
1452
name = "scoped-futures"
1246
-
version = "0.1.3"
1453
+
version = "0.1.4"
1247
1454
source = "registry+https://github.com/rust-lang/crates.io-index"
1248
-
checksum = "b1473e24c637950c9bd38763220bea91ec3e095a89f672bbd7a10d03e77ba467"
1455
+
checksum = "1b24aae2d0636530f359e9d5ef0c04669d11c5e756699b27a6a6d845d8329091"
1249
1456
dependencies = [
1250
-
"cfg-if",
1251
-
"pin-utils",
1457
+
"pin-project-lite",
1252
1458
]
1253
1459
1254
1460
[[package]]
···
1265
1471
1266
1472
[[package]]
1267
1473
name = "security-framework"
1268
-
version = "2.9.2"
1474
+
version = "2.11.1"
1269
1475
source = "registry+https://github.com/rust-lang/crates.io-index"
1270
-
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
1476
+
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
1271
1477
dependencies = [
1272
-
"bitflags 1.3.2",
1478
+
"bitflags",
1273
1479
"core-foundation",
1274
1480
"core-foundation-sys",
1275
1481
"libc",
···
1278
1484
1279
1485
[[package]]
1280
1486
name = "security-framework-sys"
1281
-
version = "2.9.1"
1487
+
version = "2.14.0"
1282
1488
source = "registry+https://github.com/rust-lang/crates.io-index"
1283
-
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
1489
+
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
1284
1490
dependencies = [
1285
1491
"core-foundation-sys",
1286
1492
"libc",
···
1288
1494
1289
1495
[[package]]
1290
1496
name = "serde"
1291
-
version = "1.0.183"
1497
+
version = "1.0.219"
1292
1498
source = "registry+https://github.com/rust-lang/crates.io-index"
1293
-
checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
1499
+
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
1294
1500
dependencies = [
1295
1501
"serde_derive",
1296
1502
]
1297
1503
1298
1504
[[package]]
1299
1505
name = "serde_derive"
1300
-
version = "1.0.183"
1506
+
version = "1.0.219"
1301
1507
source = "registry+https://github.com/rust-lang/crates.io-index"
1302
-
checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
1508
+
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
1303
1509
dependencies = [
1304
1510
"proc-macro2",
1305
1511
"quote",
···
1308
1514
1309
1515
[[package]]
1310
1516
name = "serde_json"
1311
-
version = "1.0.105"
1517
+
version = "1.0.140"
1312
1518
source = "registry+https://github.com/rust-lang/crates.io-index"
1313
-
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
1519
+
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
1314
1520
dependencies = [
1315
1521
"itoa",
1522
+
"memchr",
1316
1523
"ryu",
1317
1524
"serde",
1318
1525
]
1319
1526
1320
1527
[[package]]
1321
1528
name = "serde_spanned"
1322
-
version = "0.6.3"
1529
+
version = "0.6.9"
1323
1530
source = "registry+https://github.com/rust-lang/crates.io-index"
1324
-
checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
1531
+
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
1325
1532
dependencies = [
1326
1533
"serde",
1327
1534
]
···
1340
1547
1341
1548
[[package]]
1342
1549
name = "sha1"
1343
-
version = "0.10.5"
1550
+
version = "0.10.6"
1344
1551
source = "registry+https://github.com/rust-lang/crates.io-index"
1345
-
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
1552
+
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
1346
1553
dependencies = [
1347
1554
"cfg-if",
1348
1555
"cpufeatures",
···
1351
1558
1352
1559
[[package]]
1353
1560
name = "sha2"
1354
-
version = "0.10.7"
1561
+
version = "0.10.9"
1355
1562
source = "registry+https://github.com/rust-lang/crates.io-index"
1356
-
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
1563
+
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
1357
1564
dependencies = [
1358
1565
"cfg-if",
1359
1566
"cpufeatures",
···
1361
1568
]
1362
1569
1363
1570
[[package]]
1571
+
name = "shlex"
1572
+
version = "1.3.0"
1573
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1574
+
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
1575
+
1576
+
[[package]]
1364
1577
name = "signal-hook-registry"
1365
-
version = "1.4.1"
1578
+
version = "1.4.5"
1366
1579
source = "registry+https://github.com/rust-lang/crates.io-index"
1367
-
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
1580
+
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
1368
1581
dependencies = [
1369
1582
"libc",
1370
1583
]
1371
1584
1372
1585
[[package]]
1373
1586
name = "siphasher"
1374
-
version = "0.3.10"
1587
+
version = "1.0.1"
1375
1588
source = "registry+https://github.com/rust-lang/crates.io-index"
1376
-
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
1589
+
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
1377
1590
1378
1591
[[package]]
1379
1592
name = "slab"
1380
-
version = "0.4.8"
1593
+
version = "0.4.9"
1381
1594
source = "registry+https://github.com/rust-lang/crates.io-index"
1382
-
checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
1595
+
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
1383
1596
dependencies = [
1384
1597
"autocfg",
1385
1598
]
1386
1599
1387
1600
[[package]]
1388
1601
name = "smallvec"
1389
-
version = "1.11.0"
1602
+
version = "1.15.1"
1390
1603
source = "registry+https://github.com/rust-lang/crates.io-index"
1391
-
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
1604
+
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
1392
1605
1393
1606
[[package]]
1394
1607
name = "socket2"
1395
-
version = "0.4.9"
1608
+
version = "0.5.10"
1396
1609
source = "registry+https://github.com/rust-lang/crates.io-index"
1397
-
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
1398
-
dependencies = [
1399
-
"libc",
1400
-
"winapi",
1401
-
]
1402
-
1403
-
[[package]]
1404
-
name = "socket2"
1405
-
version = "0.5.3"
1406
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1407
-
checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
1610
+
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
1408
1611
dependencies = [
1409
1612
"libc",
1410
-
"windows-sys",
1613
+
"windows-sys 0.52.0",
1411
1614
]
1412
1615
1413
1616
[[package]]
···
1417
1620
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
1418
1621
1419
1622
[[package]]
1623
+
name = "stable_deref_trait"
1624
+
version = "1.2.0"
1625
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1626
+
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
1627
+
1628
+
[[package]]
1420
1629
name = "stringprep"
1421
-
version = "0.1.3"
1630
+
version = "0.1.5"
1422
1631
source = "registry+https://github.com/rust-lang/crates.io-index"
1423
-
checksum = "db3737bde7edce97102e0e2b15365bf7a20bfdb5f60f4f9e8d7004258a51a8da"
1632
+
checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1"
1424
1633
dependencies = [
1425
1634
"unicode-bidi",
1426
1635
"unicode-normalization",
1636
+
"unicode-properties",
1427
1637
]
1428
1638
1429
1639
[[package]]
1430
1640
name = "strsim"
1431
-
version = "0.10.0"
1641
+
version = "0.11.1"
1432
1642
source = "registry+https://github.com/rust-lang/crates.io-index"
1433
-
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
1643
+
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
1434
1644
1435
1645
[[package]]
1436
1646
name = "subtle"
1437
-
version = "2.5.0"
1647
+
version = "2.6.1"
1438
1648
source = "registry+https://github.com/rust-lang/crates.io-index"
1439
-
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
1649
+
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
1440
1650
1441
1651
[[package]]
1442
1652
name = "syn"
1443
-
version = "2.0.29"
1653
+
version = "2.0.101"
1444
1654
source = "registry+https://github.com/rust-lang/crates.io-index"
1445
-
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
1655
+
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
1446
1656
dependencies = [
1447
1657
"proc-macro2",
1448
1658
"quote",
···
1450
1660
]
1451
1661
1452
1662
[[package]]
1663
+
name = "synstructure"
1664
+
version = "0.13.2"
1665
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1666
+
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
1667
+
dependencies = [
1668
+
"proc-macro2",
1669
+
"quote",
1670
+
"syn",
1671
+
]
1672
+
1673
+
[[package]]
1453
1674
name = "tempfile"
1454
-
version = "3.7.1"
1675
+
version = "3.20.0"
1455
1676
source = "registry+https://github.com/rust-lang/crates.io-index"
1456
-
checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651"
1677
+
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
1457
1678
dependencies = [
1458
-
"cfg-if",
1459
1679
"fastrand",
1460
-
"redox_syscall",
1680
+
"getrandom 0.3.3",
1681
+
"once_cell",
1461
1682
"rustix",
1462
-
"windows-sys",
1683
+
"windows-sys 0.59.0",
1463
1684
]
1464
1685
1465
1686
[[package]]
1466
1687
name = "termcolor"
1467
-
version = "1.2.0"
1688
+
version = "1.4.1"
1468
1689
source = "registry+https://github.com/rust-lang/crates.io-index"
1469
-
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
1690
+
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
1470
1691
dependencies = [
1471
1692
"winapi-util",
1472
1693
]
1473
1694
1474
1695
[[package]]
1475
1696
name = "thiserror"
1476
-
version = "1.0.47"
1697
+
version = "1.0.69"
1477
1698
source = "registry+https://github.com/rust-lang/crates.io-index"
1478
-
checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
1699
+
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
1479
1700
dependencies = [
1480
1701
"thiserror-impl",
1481
1702
]
1482
1703
1483
1704
[[package]]
1484
1705
name = "thiserror-impl"
1485
-
version = "1.0.47"
1706
+
version = "1.0.69"
1486
1707
source = "registry+https://github.com/rust-lang/crates.io-index"
1487
-
checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
1708
+
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
1488
1709
dependencies = [
1489
1710
"proc-macro2",
1490
1711
"quote",
···
1493
1714
1494
1715
[[package]]
1495
1716
name = "time"
1496
-
version = "0.3.25"
1717
+
version = "0.3.41"
1497
1718
source = "registry+https://github.com/rust-lang/crates.io-index"
1498
-
checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea"
1719
+
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
1499
1720
dependencies = [
1500
1721
"deranged",
1722
+
"num-conv",
1723
+
"powerfmt",
1501
1724
"serde",
1502
1725
"time-core",
1503
1726
"time-macros",
···
1505
1728
1506
1729
[[package]]
1507
1730
name = "time-core"
1508
-
version = "0.1.1"
1731
+
version = "0.1.4"
1509
1732
source = "registry+https://github.com/rust-lang/crates.io-index"
1510
-
checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
1733
+
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
1511
1734
1512
1735
[[package]]
1513
1736
name = "time-macros"
1514
-
version = "0.2.11"
1737
+
version = "0.2.22"
1515
1738
source = "registry+https://github.com/rust-lang/crates.io-index"
1516
-
checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd"
1739
+
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
1517
1740
dependencies = [
1741
+
"num-conv",
1518
1742
"time-core",
1519
1743
]
1520
1744
1521
1745
[[package]]
1746
+
name = "tinystr"
1747
+
version = "0.8.1"
1748
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1749
+
checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
1750
+
dependencies = [
1751
+
"displaydoc",
1752
+
"zerovec",
1753
+
]
1754
+
1755
+
[[package]]
1522
1756
name = "tinyvec"
1523
-
version = "1.6.0"
1757
+
version = "1.9.0"
1524
1758
source = "registry+https://github.com/rust-lang/crates.io-index"
1525
-
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
1759
+
checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71"
1526
1760
dependencies = [
1527
1761
"tinyvec_macros",
1528
1762
]
···
1535
1769
1536
1770
[[package]]
1537
1771
name = "tokio"
1538
-
version = "1.32.0"
1772
+
version = "1.45.1"
1539
1773
source = "registry+https://github.com/rust-lang/crates.io-index"
1540
-
checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
1774
+
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
1541
1775
dependencies = [
1542
1776
"backtrace",
1543
1777
"bytes",
1544
1778
"libc",
1545
1779
"mio",
1546
-
"num_cpus",
1547
1780
"parking_lot",
1548
1781
"pin-project-lite",
1549
1782
"signal-hook-registry",
1550
-
"socket2 0.5.3",
1783
+
"socket2",
1551
1784
"tokio-macros",
1552
-
"windows-sys",
1785
+
"windows-sys 0.52.0",
1553
1786
]
1554
1787
1555
1788
[[package]]
1556
1789
name = "tokio-macros"
1557
-
version = "2.1.0"
1790
+
version = "2.5.0"
1558
1791
source = "registry+https://github.com/rust-lang/crates.io-index"
1559
-
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
1792
+
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
1560
1793
dependencies = [
1561
1794
"proc-macro2",
1562
1795
"quote",
···
1575
1808
1576
1809
[[package]]
1577
1810
name = "tokio-postgres"
1578
-
version = "0.7.8"
1811
+
version = "0.7.13"
1579
1812
source = "registry+https://github.com/rust-lang/crates.io-index"
1580
-
checksum = "6e89f6234aa8fd43779746012fcf53603cdb91fdd8399aa0de868c2d56b6dde1"
1813
+
checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0"
1581
1814
dependencies = [
1582
1815
"async-trait",
1583
1816
"byteorder",
···
1592
1825
"pin-project-lite",
1593
1826
"postgres-protocol",
1594
1827
"postgres-types",
1595
-
"socket2 0.5.3",
1828
+
"rand 0.9.1",
1829
+
"socket2",
1596
1830
"tokio",
1597
1831
"tokio-util",
1598
-
]
1599
-
1600
-
[[package]]
1601
-
name = "tokio-stream"
1602
-
version = "0.1.14"
1603
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1604
-
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
1605
-
dependencies = [
1606
-
"futures-core",
1607
-
"pin-project-lite",
1608
-
"tokio",
1832
+
"whoami",
1609
1833
]
1610
1834
1611
1835
[[package]]
1612
1836
name = "tokio-tungstenite"
1613
-
version = "0.18.0"
1837
+
version = "0.21.0"
1614
1838
source = "registry+https://github.com/rust-lang/crates.io-index"
1615
-
checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd"
1839
+
checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38"
1616
1840
dependencies = [
1617
1841
"futures-util",
1618
1842
"log",
···
1622
1846
1623
1847
[[package]]
1624
1848
name = "tokio-util"
1625
-
version = "0.7.8"
1849
+
version = "0.7.15"
1626
1850
source = "registry+https://github.com/rust-lang/crates.io-index"
1627
-
checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
1851
+
checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
1628
1852
dependencies = [
1629
1853
"bytes",
1630
1854
"futures-core",
1631
1855
"futures-sink",
1632
1856
"pin-project-lite",
1633
1857
"tokio",
1634
-
"tracing",
1635
1858
]
1636
1859
1637
1860
[[package]]
1638
1861
name = "toml"
1639
-
version = "0.7.6"
1862
+
version = "0.8.23"
1640
1863
source = "registry+https://github.com/rust-lang/crates.io-index"
1641
-
checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
1864
+
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
1642
1865
dependencies = [
1643
1866
"serde",
1644
1867
"serde_spanned",
···
1648
1871
1649
1872
[[package]]
1650
1873
name = "toml_datetime"
1651
-
version = "0.6.3"
1874
+
version = "0.6.11"
1652
1875
source = "registry+https://github.com/rust-lang/crates.io-index"
1653
-
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
1876
+
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
1654
1877
dependencies = [
1655
1878
"serde",
1656
1879
]
1657
1880
1658
1881
[[package]]
1659
1882
name = "toml_edit"
1660
-
version = "0.19.14"
1883
+
version = "0.22.27"
1661
1884
source = "registry+https://github.com/rust-lang/crates.io-index"
1662
-
checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
1885
+
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
1663
1886
dependencies = [
1664
-
"indexmap 2.0.0",
1887
+
"indexmap",
1665
1888
"serde",
1666
1889
"serde_spanned",
1667
1890
"toml_datetime",
1891
+
"toml_write",
1668
1892
"winnow",
1669
1893
]
1670
1894
1671
1895
[[package]]
1896
+
name = "toml_write"
1897
+
version = "0.1.2"
1898
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1899
+
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
1900
+
1901
+
[[package]]
1672
1902
name = "tower-service"
1673
-
version = "0.3.2"
1903
+
version = "0.3.3"
1674
1904
source = "registry+https://github.com/rust-lang/crates.io-index"
1675
-
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
1905
+
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
1676
1906
1677
1907
[[package]]
1678
1908
name = "tracing"
1679
-
version = "0.1.37"
1909
+
version = "0.1.41"
1680
1910
source = "registry+https://github.com/rust-lang/crates.io-index"
1681
-
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
1911
+
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
1682
1912
dependencies = [
1683
-
"cfg-if",
1684
1913
"log",
1685
1914
"pin-project-lite",
1686
1915
"tracing-core",
···
1688
1917
1689
1918
[[package]]
1690
1919
name = "tracing-core"
1691
-
version = "0.1.31"
1920
+
version = "0.1.34"
1692
1921
source = "registry+https://github.com/rust-lang/crates.io-index"
1693
-
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
1922
+
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
1694
1923
dependencies = [
1695
1924
"once_cell",
1696
1925
]
1697
1926
1698
1927
[[package]]
1699
1928
name = "try-lock"
1700
-
version = "0.2.4"
1929
+
version = "0.2.5"
1701
1930
source = "registry+https://github.com/rust-lang/crates.io-index"
1702
-
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
1931
+
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
1703
1932
1704
1933
[[package]]
1705
1934
name = "tungstenite"
1706
-
version = "0.18.0"
1935
+
version = "0.21.0"
1707
1936
source = "registry+https://github.com/rust-lang/crates.io-index"
1708
-
checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
1937
+
checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"
1709
1938
dependencies = [
1710
-
"base64 0.13.1",
1711
1939
"byteorder",
1712
1940
"bytes",
1713
-
"http",
1941
+
"data-encoding",
1942
+
"http 1.3.1",
1714
1943
"httparse",
1715
1944
"log",
1716
-
"rand",
1945
+
"rand 0.8.5",
1717
1946
"sha1",
1718
1947
"thiserror",
1719
1948
"url",
···
1722
1951
1723
1952
[[package]]
1724
1953
name = "typenum"
1725
-
version = "1.16.0"
1954
+
version = "1.18.0"
1726
1955
source = "registry+https://github.com/rust-lang/crates.io-index"
1727
-
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
1956
+
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
1728
1957
1729
1958
[[package]]
1730
1959
name = "unicase"
1731
-
version = "2.6.0"
1960
+
version = "2.8.1"
1732
1961
source = "registry+https://github.com/rust-lang/crates.io-index"
1733
-
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
1734
-
dependencies = [
1735
-
"version_check",
1736
-
]
1962
+
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
1737
1963
1738
1964
[[package]]
1739
1965
name = "unicode-bidi"
1740
-
version = "0.3.13"
1966
+
version = "0.3.18"
1741
1967
source = "registry+https://github.com/rust-lang/crates.io-index"
1742
-
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
1968
+
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
1743
1969
1744
1970
[[package]]
1745
1971
name = "unicode-ident"
1746
-
version = "1.0.11"
1972
+
version = "1.0.18"
1747
1973
source = "registry+https://github.com/rust-lang/crates.io-index"
1748
-
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
1974
+
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
1749
1975
1750
1976
[[package]]
1751
1977
name = "unicode-normalization"
1752
-
version = "0.1.22"
1978
+
version = "0.1.24"
1753
1979
source = "registry+https://github.com/rust-lang/crates.io-index"
1754
-
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
1980
+
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
1755
1981
dependencies = [
1756
1982
"tinyvec",
1757
1983
]
1758
1984
1759
1985
[[package]]
1986
+
name = "unicode-properties"
1987
+
version = "0.1.3"
1988
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1989
+
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
1990
+
1991
+
[[package]]
1760
1992
name = "url"
1761
-
version = "2.4.0"
1993
+
version = "2.5.4"
1762
1994
source = "registry+https://github.com/rust-lang/crates.io-index"
1763
-
checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
1995
+
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
1764
1996
dependencies = [
1765
1997
"form_urlencoded",
1766
1998
"idna",
···
1774
2006
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
1775
2007
1776
2008
[[package]]
2009
+
name = "utf8_iter"
2010
+
version = "1.0.4"
2011
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2012
+
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
2013
+
2014
+
[[package]]
1777
2015
name = "utf8parse"
1778
-
version = "0.2.1"
2016
+
version = "0.2.2"
1779
2017
source = "registry+https://github.com/rust-lang/crates.io-index"
1780
-
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
2018
+
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
1781
2019
1782
2020
[[package]]
1783
2021
name = "vcpkg"
···
1787
2025
1788
2026
[[package]]
1789
2027
name = "version_check"
1790
-
version = "0.9.4"
2028
+
version = "0.9.5"
1791
2029
source = "registry+https://github.com/rust-lang/crates.io-index"
1792
-
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
2030
+
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
1793
2031
1794
2032
[[package]]
1795
2033
name = "want"
···
1802
2040
1803
2041
[[package]]
1804
2042
name = "warp"
1805
-
version = "0.3.5"
2043
+
version = "0.3.7"
1806
2044
source = "registry+https://github.com/rust-lang/crates.io-index"
1807
-
checksum = "ba431ef570df1287f7f8b07e376491ad54f84d26ac473489427231e1718e1f69"
2045
+
checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c"
1808
2046
dependencies = [
1809
2047
"bytes",
1810
2048
"futures-channel",
1811
2049
"futures-util",
1812
2050
"headers",
1813
-
"http",
2051
+
"http 0.2.12",
1814
2052
"hyper",
1815
2053
"log",
1816
2054
"mime",
···
1818
2056
"multer",
1819
2057
"percent-encoding",
1820
2058
"pin-project",
1821
-
"rustls-pemfile",
1822
2059
"scoped-tls",
1823
2060
"serde",
1824
2061
"serde_json",
1825
2062
"serde_urlencoded",
1826
2063
"tokio",
1827
-
"tokio-stream",
1828
2064
"tokio-tungstenite",
1829
2065
"tokio-util",
1830
2066
"tower-service",
···
1838
2074
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1839
2075
1840
2076
[[package]]
1841
-
name = "winapi"
1842
-
version = "0.3.9"
2077
+
name = "wasi"
2078
+
version = "0.14.2+wasi-0.2.4"
2079
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2080
+
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
2081
+
dependencies = [
2082
+
"wit-bindgen-rt",
2083
+
]
2084
+
2085
+
[[package]]
2086
+
name = "wasite"
2087
+
version = "0.1.0"
2088
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2089
+
checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
2090
+
2091
+
[[package]]
2092
+
name = "wasm-bindgen"
2093
+
version = "0.2.100"
2094
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2095
+
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
2096
+
dependencies = [
2097
+
"cfg-if",
2098
+
"once_cell",
2099
+
"wasm-bindgen-macro",
2100
+
]
2101
+
2102
+
[[package]]
2103
+
name = "wasm-bindgen-backend"
2104
+
version = "0.2.100"
2105
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2106
+
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
2107
+
dependencies = [
2108
+
"bumpalo",
2109
+
"log",
2110
+
"proc-macro2",
2111
+
"quote",
2112
+
"syn",
2113
+
"wasm-bindgen-shared",
2114
+
]
2115
+
2116
+
[[package]]
2117
+
name = "wasm-bindgen-macro"
2118
+
version = "0.2.100"
2119
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2120
+
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
2121
+
dependencies = [
2122
+
"quote",
2123
+
"wasm-bindgen-macro-support",
2124
+
]
2125
+
2126
+
[[package]]
2127
+
name = "wasm-bindgen-macro-support"
2128
+
version = "0.2.100"
1843
2129
source = "registry+https://github.com/rust-lang/crates.io-index"
1844
-
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
2130
+
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
1845
2131
dependencies = [
1846
-
"winapi-i686-pc-windows-gnu",
1847
-
"winapi-x86_64-pc-windows-gnu",
2132
+
"proc-macro2",
2133
+
"quote",
2134
+
"syn",
2135
+
"wasm-bindgen-backend",
2136
+
"wasm-bindgen-shared",
1848
2137
]
1849
2138
1850
2139
[[package]]
1851
-
name = "winapi-i686-pc-windows-gnu"
1852
-
version = "0.4.0"
2140
+
name = "wasm-bindgen-shared"
2141
+
version = "0.2.100"
1853
2142
source = "registry+https://github.com/rust-lang/crates.io-index"
1854
-
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
2143
+
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
2144
+
dependencies = [
2145
+
"unicode-ident",
2146
+
]
2147
+
2148
+
[[package]]
2149
+
name = "web-sys"
2150
+
version = "0.3.77"
2151
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2152
+
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
2153
+
dependencies = [
2154
+
"js-sys",
2155
+
"wasm-bindgen",
2156
+
]
2157
+
2158
+
[[package]]
2159
+
name = "whoami"
2160
+
version = "1.6.0"
2161
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2162
+
checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7"
2163
+
dependencies = [
2164
+
"redox_syscall",
2165
+
"wasite",
2166
+
"web-sys",
2167
+
]
1855
2168
1856
2169
[[package]]
1857
2170
name = "winapi-util"
1858
-
version = "0.1.5"
2171
+
version = "0.1.9"
1859
2172
source = "registry+https://github.com/rust-lang/crates.io-index"
1860
-
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
2173
+
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
1861
2174
dependencies = [
1862
-
"winapi",
2175
+
"windows-sys 0.59.0",
1863
2176
]
1864
2177
1865
2178
[[package]]
1866
-
name = "winapi-x86_64-pc-windows-gnu"
1867
-
version = "0.4.0"
2179
+
name = "windows-sys"
2180
+
version = "0.52.0"
1868
2181
source = "registry+https://github.com/rust-lang/crates.io-index"
1869
-
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
2182
+
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
2183
+
dependencies = [
2184
+
"windows-targets",
2185
+
]
1870
2186
1871
2187
[[package]]
1872
2188
name = "windows-sys"
1873
-
version = "0.48.0"
2189
+
version = "0.59.0"
1874
2190
source = "registry+https://github.com/rust-lang/crates.io-index"
1875
-
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
2191
+
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
1876
2192
dependencies = [
1877
2193
"windows-targets",
1878
2194
]
1879
2195
1880
2196
[[package]]
1881
2197
name = "windows-targets"
1882
-
version = "0.48.3"
2198
+
version = "0.52.6"
1883
2199
source = "registry+https://github.com/rust-lang/crates.io-index"
1884
-
checksum = "27f51fb4c64f8b770a823c043c7fad036323e1c48f55287b7bbb7987b2fcdf3b"
2200
+
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
1885
2201
dependencies = [
1886
2202
"windows_aarch64_gnullvm",
1887
2203
"windows_aarch64_msvc",
1888
2204
"windows_i686_gnu",
2205
+
"windows_i686_gnullvm",
1889
2206
"windows_i686_msvc",
1890
2207
"windows_x86_64_gnu",
1891
2208
"windows_x86_64_gnullvm",
···
1894
2211
1895
2212
[[package]]
1896
2213
name = "windows_aarch64_gnullvm"
1897
-
version = "0.48.3"
2214
+
version = "0.52.6"
1898
2215
source = "registry+https://github.com/rust-lang/crates.io-index"
1899
-
checksum = "fde1bb55ae4ce76a597a8566d82c57432bc69c039449d61572a7a353da28f68c"
2216
+
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
1900
2217
1901
2218
[[package]]
1902
2219
name = "windows_aarch64_msvc"
1903
-
version = "0.48.3"
2220
+
version = "0.52.6"
1904
2221
source = "registry+https://github.com/rust-lang/crates.io-index"
1905
-
checksum = "1513e8d48365a78adad7322fd6b5e4c4e99d92a69db8df2d435b25b1f1f286d4"
2222
+
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
1906
2223
1907
2224
[[package]]
1908
2225
name = "windows_i686_gnu"
1909
-
version = "0.48.3"
2226
+
version = "0.52.6"
2227
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2228
+
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
2229
+
2230
+
[[package]]
2231
+
name = "windows_i686_gnullvm"
2232
+
version = "0.52.6"
1910
2233
source = "registry+https://github.com/rust-lang/crates.io-index"
1911
-
checksum = "60587c0265d2b842298f5858e1a5d79d146f9ee0c37be5782e92a6eb5e1d7a83"
2234
+
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
1912
2235
1913
2236
[[package]]
1914
2237
name = "windows_i686_msvc"
1915
-
version = "0.48.3"
2238
+
version = "0.52.6"
1916
2239
source = "registry+https://github.com/rust-lang/crates.io-index"
1917
-
checksum = "224fe0e0ffff5d2ea6a29f82026c8f43870038a0ffc247aa95a52b47df381ac4"
2240
+
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
1918
2241
1919
2242
[[package]]
1920
2243
name = "windows_x86_64_gnu"
1921
-
version = "0.48.3"
2244
+
version = "0.52.6"
1922
2245
source = "registry+https://github.com/rust-lang/crates.io-index"
1923
-
checksum = "62fc52a0f50a088de499712cbc012df7ebd94e2d6eb948435449d76a6287e7ad"
2246
+
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
1924
2247
1925
2248
[[package]]
1926
2249
name = "windows_x86_64_gnullvm"
1927
-
version = "0.48.3"
2250
+
version = "0.52.6"
1928
2251
source = "registry+https://github.com/rust-lang/crates.io-index"
1929
-
checksum = "2093925509d91ea3d69bcd20238f4c2ecdb1a29d3c281d026a09705d0dd35f3d"
2252
+
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
1930
2253
1931
2254
[[package]]
1932
2255
name = "windows_x86_64_msvc"
1933
-
version = "0.48.3"
2256
+
version = "0.52.6"
1934
2257
source = "registry+https://github.com/rust-lang/crates.io-index"
1935
-
checksum = "b6ade45bc8bf02ae2aa34a9d54ba660a1a58204da34ba793c00d83ca3730b5f1"
2258
+
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
1936
2259
1937
2260
[[package]]
1938
2261
name = "winnow"
1939
-
version = "0.5.12"
2262
+
version = "0.7.10"
1940
2263
source = "registry+https://github.com/rust-lang/crates.io-index"
1941
-
checksum = "83817bbecf72c73bad717ee86820ebf286203d2e04c3951f3cd538869c897364"
2264
+
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
1942
2265
dependencies = [
1943
2266
"memchr",
1944
2267
]
2268
+
2269
+
[[package]]
2270
+
name = "wit-bindgen-rt"
2271
+
version = "0.39.0"
2272
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2273
+
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
2274
+
dependencies = [
2275
+
"bitflags",
2276
+
]
2277
+
2278
+
[[package]]
2279
+
name = "writeable"
2280
+
version = "0.6.1"
2281
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2282
+
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
2283
+
2284
+
[[package]]
2285
+
name = "yoke"
2286
+
version = "0.8.0"
2287
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2288
+
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
2289
+
dependencies = [
2290
+
"serde",
2291
+
"stable_deref_trait",
2292
+
"yoke-derive",
2293
+
"zerofrom",
2294
+
]
2295
+
2296
+
[[package]]
2297
+
name = "yoke-derive"
2298
+
version = "0.8.0"
2299
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2300
+
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
2301
+
dependencies = [
2302
+
"proc-macro2",
2303
+
"quote",
2304
+
"syn",
2305
+
"synstructure",
2306
+
]
2307
+
2308
+
[[package]]
2309
+
name = "zerocopy"
2310
+
version = "0.8.25"
2311
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2312
+
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
2313
+
dependencies = [
2314
+
"zerocopy-derive",
2315
+
]
2316
+
2317
+
[[package]]
2318
+
name = "zerocopy-derive"
2319
+
version = "0.8.25"
2320
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2321
+
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
2322
+
dependencies = [
2323
+
"proc-macro2",
2324
+
"quote",
2325
+
"syn",
2326
+
]
2327
+
2328
+
[[package]]
2329
+
name = "zerofrom"
2330
+
version = "0.1.6"
2331
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2332
+
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
2333
+
dependencies = [
2334
+
"zerofrom-derive",
2335
+
]
2336
+
2337
+
[[package]]
2338
+
name = "zerofrom-derive"
2339
+
version = "0.1.6"
2340
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2341
+
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
2342
+
dependencies = [
2343
+
"proc-macro2",
2344
+
"quote",
2345
+
"syn",
2346
+
"synstructure",
2347
+
]
2348
+
2349
+
[[package]]
2350
+
name = "zerotrie"
2351
+
version = "0.2.2"
2352
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2353
+
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
2354
+
dependencies = [
2355
+
"displaydoc",
2356
+
"yoke",
2357
+
"zerofrom",
2358
+
]
2359
+
2360
+
[[package]]
2361
+
name = "zerovec"
2362
+
version = "0.11.2"
2363
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2364
+
checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
2365
+
dependencies = [
2366
+
"yoke",
2367
+
"zerofrom",
2368
+
"zerovec-derive",
2369
+
]
2370
+
2371
+
[[package]]
2372
+
name = "zerovec-derive"
2373
+
version = "0.11.1"
2374
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2375
+
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
2376
+
dependencies = [
2377
+
"proc-macro2",
2378
+
"quote",
2379
+
"syn",
2380
+
]
+5
-6
Dockerfile
+5
-6
Dockerfile
···
1
-
FROM rust:1.68.2-slim-buster
1
+
FROM rust:1.87.0-slim-bookworm
2
2
ARG DEBIAN_FRONTEND=noninteractive
3
3
RUN apt-get update && apt-get install -y --no-install-recommends --no-install-suggests ca-certificates pkg-config libssl-dev libpq-dev
4
4
ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
5
5
6
6
RUN --mount=type=cache,target=$CARGO_HOME/registry \
7
-
cargo install diesel_cli --version 2.0.1 --no-default-features --features postgres
7
+
cargo install diesel_cli --version 2.2.10 --no-default-features --features postgres
8
8
9
9
COPY common /lumen/common
10
10
COPY lumen /lumen/lumen
11
11
COPY Cargo.toml /lumen/
12
12
RUN --mount=type=cache,target=$CARGO_HOME/registry,target=/lumen/target \
13
-
cd /lumen && cargo build --release && cp /lumen/target/release/lumen /root/
13
+
cd /lumen && cargo build --release && cp /lumen/target/release/lumen /root/
14
14
15
-
FROM debian:buster-slim
15
+
FROM debian:bookworm-slim
16
16
ARG DEBIAN_FRONTEND=noninteractive
17
17
RUN apt-get update && apt-get install -y --no-install-recommends --no-install-suggests openssl libpq5 && \
18
-
sed -i -e 's,\[ v3_req \],\[ v3_req \]\nextendedKeyUsage = serverAuth,' /etc/ssl/openssl.cnf
18
+
sed -i -e 's,\[ v3_req \],\[ v3_req \]\nextendedKeyUsage = serverAuth,' /etc/ssl/openssl.cnf
19
19
RUN mkdir /usr/lib/lumen/
20
20
21
21
COPY --from=0 /usr/local/cargo/bin/diesel /usr/bin/diesel
···
26
26
COPY config-example.toml docker-init.sh /lumen/
27
27
RUN chmod a+x /lumen/docker-init.sh && chmod a+x /usr/bin/lumen
28
28
WORKDIR /lumen
29
-
STOPSIGNAL SIGINT
30
29
CMD /lumen/docker-init.sh
+125
-100
README.md
+125
-100
README.md
···
1
-
# Lumen
2
-
A private Lumina server that can be used with IDA Pro 7.2+.
3
-
4
-
[lumen.abda.nl](https://lumen.abda.nl/) runs this server.
5
-
6
-
You can read about the protocol research [here](https://abda.nl/posts/introducing-lumen/).
7
-
8
-
## Features
9
-
- Stores function signatures so you (and your team) can quickly identify functions that you found in the past using IDA's built-in Lumina features.
10
-
- Backed by PostgreSQL
11
-
- Experimental HTTP API that allows querying the database for comments by file or function hash.
12
-
13
-
## Getting Started
14
-
15
-
### Docker Method (Recommended)
16
-
In this method precompiled docker images will be downloaded, All you need is [docker-compose.yml](./docker-compose.yml).
17
-
18
-
1. Install `docker-engine` and `docker-compose`.
19
-
2. If using a custom TLS certificate, copy the private key (`.p12`/`.pfx` extension) to `./dockershare` and set the key password in `.env` as `PKCSPASSWD`.
20
-
3. If using a custom Lumen config, copy it to `./dockershare/config.toml`.
21
-
4. Otherwise, or if you have finished these steps, just run `docker-compose up`.
22
-
5. Regardless, if TLS is enabled in the `config.toml`, a `hexrays.crt` will be generated in `./dockershare` to be copied to the IDA install directory.
23
-
24
-
### Building from source with Rust
25
-
1. `git clone https://github.com/naim94a/lumen.git`
26
-
2. Get a rust toolchain: https://rustup.rs/
27
-
3. `cd lumen`
28
-
4. Setup a Postgres database and execute src/schema.sql on it
29
-
5. `cargo build --release`
30
-
31
-
### Usage
32
-
```
33
-
./lumen -c config.toml
34
-
```
35
-
36
-
### Configuring IDA
37
-
38
-
#### IDA Pro >= 8.1
39
-
If you used LUMEN in the past, remove the LUMINA settings in the ida.cfg or idauser.cfg files, otherwise you will get a warning about
40
-
bad config parameters.
41
-
42
-
##### Setup under Linux :
43
-
```
44
-
#!/bin/sh
45
-
export LUMINA_TLS=false
46
-
$1
47
-
```
48
-
- save as ida_lumen.sh, "chmod +x ida_lumen.sh", now you can run IDA using "./ida_lumen.sh ./ida" or "./ida_lumen ./ida64"
49
-
50
-
##### Setup under Windows :
51
-
```
52
-
set LUMINA_TLS=false
53
-
%1
54
-
```
55
-
- save as ida_lumen.bat, now you can run IDA using "./ida_lumen.bat ida.exe" or "./ida_lumen.bat ida64.exe"
56
-
57
-
##### Setup IDA
58
-
- Go to Options, General, Lumina. Select "Use a private server", then set your host and port and "guest" as username and password. Click on ok.
59
-
60
-
#### IDA Pro < 8.1
61
-
You will need IDA Pro 7.2 or above in order to use _lumen_.
62
-
63
-
> The following information may get sent to _lumen_ server: IDA key, Hostname, IDB path, original file path, file MD5, function signature, stack frames & comments.
64
-
65
-
- In your IDA's installation directory open "cfg\ida.cfg" with your favorite text editor _(Example: C:\Program Files\IDA Pro 7.5\cfg\ida.cfg)_
66
-
- Locate the commented out `LUMINA_HOST`, `LUMINA_PORT`, and change their values to the address of your _lumen_ server.
67
-
- If you didn't configure TLS, Add "LUMINA_TLS = NO" after the line with `LUMINA_PORT`.
68
-
69
-
Example:
70
-
```C
71
-
LUMINA_HOST = "192.168.1.1";
72
-
LUMINA_PORT = 1234
73
-
74
-
// Only if TLS isn't used:
75
-
LUMINA_TLS = NO
76
-
```
77
-
78
-
### Configuring TLS
79
-
IDA Pro uses a pinned certificate for Lumina's communcation, so adding a self-signed certificate to your root certificates won't work.
80
-
Luckily, we can override the hard-coded public key by writing a DER-base64 encoded certificate to "hexrays.crt" in IDA's install directory.
81
-
82
-
You may find the following commands useful:
83
-
```bash
84
-
# create a certificate
85
-
openssl req -x509 -newkey rsa:4096 -keyout lumen_key.pem -out lumen_crt.pem -days 365 -nodes
86
-
87
-
# convert to pkcs12 for lumen; used for `lumen.tls` in config
88
-
openssl pkcs12 -export -out lumen.p12 -inkey lumen_key.pem -in lumen_crt.pem
89
-
90
-
# export public-key for IDA; Copy hexrays.crt to IDA installation folder
91
-
openssl x509 -in lumen_crt.pem -out hexrays.crt
92
-
```
93
-
94
-
No attempt is made to merge function data - this may casuse a situation where metadata is inconsistent.
95
-
Instead, the metadata with the highest calculated score is returned to the user.
96
-
97
-
98
-
---
99
-
100
-
Developed by [Naim A.](https://github.com/naim94a); License: MIT.
1
+
# Lumen
2
+
3
+
A private Lumina server that can be used with IDA Pro 7.2+.
4
+
5
+
[lumen.abda.nl](https://lumen.abda.nl/) runs this server.
6
+
7
+
You can read about the protocol research [here](https://abda.nl/posts/introducing-lumen/).
8
+
9
+
## Features
10
+
11
+
- Stores function signatures so you (and your team) can quickly identify functions that you found in the past using IDA's built-in Lumina features.
12
+
- Backed by PostgreSQL
13
+
- Experimental HTTP API that allows querying the database for comments by file or function hash.
14
+
15
+
## Getting Started
16
+
17
+
### Docker Method (Recommended)
18
+
19
+
In this method precompiled docker images will be downloaded, All you need is [docker-compose.yml](./docker-compose.yml).
20
+
21
+
1. Install `docker-engine` and `docker-compose`.
22
+
2. If using a custom TLS certificate, copy the private key (`.p12`/`.pfx` extension) to `./dockershare` and set the key password in `.env` as `PKCSPASSWD`.
23
+
3. If using a custom Lumen config, copy it to `./dockershare/config.toml`.
24
+
4. Otherwise, or if you have finished these steps, just run `docker-compose up`.
25
+
5. Regardless, if TLS is enabled in the `config.toml`, a `hexrays.crt` will be generated in `./dockershare` to be copied to the IDA install directory.
26
+
27
+
### Building from source with Rust
28
+
29
+
1. `git clone https://github.com/naim94a/lumen.git`
30
+
2. Get a rust toolchain: https://rustup.rs/
31
+
3. `cd lumen`
32
+
4. Setup a the database
33
+
34
+
- install postgres
35
+
- install diesel-cli and run migrations:
36
+
37
+
```bash
38
+
cargo install diesel_cli --no-default-features -Fpostgres
39
+
diesel --config-file common/diesel.toml \
40
+
--database-url postgres://postgres:password@localhost/lumen \
41
+
migration run
42
+
```
43
+
44
+
5. `cargo build --release`
45
+
46
+
### Usage
47
+
48
+
```bash
49
+
./lumen -c config.toml
50
+
```
51
+
52
+
### Configuring IDA
53
+
54
+
#### IDA Pro >= 8.1
55
+
56
+
If you used LUMEN in the past, remove the LUMINA settings in the ida.cfg or idauser.cfg files, otherwise you will get a warning about
57
+
bad config parameters.
58
+
59
+
##### Setup under Linux :
60
+
61
+
```bash
62
+
#!/bin/sh
63
+
export LUMINA_TLS=false
64
+
$1
65
+
```
66
+
67
+
- save as ida_lumen.sh, "chmod +x ida_lumen.sh", now you can run IDA using "./ida_lumen.sh ./ida" or "./ida_lumen ./ida64"
68
+
69
+
##### Setup under Windows :
70
+
71
+
```batch
72
+
set LUMINA_TLS=false
73
+
%1
74
+
```
75
+
76
+
- save as ida_lumen.bat, now you can run IDA using "./ida_lumen.bat ida.exe" or "./ida_lumen.bat ida64.exe"
77
+
78
+
##### Setup IDA
79
+
80
+
- Go to Options, General, Lumina. Select "Use a private server", then set your host and port and "guest" as username and password. Click on ok.
81
+
82
+
#### IDA Pro < 8.1
83
+
84
+
You will need IDA Pro 7.2 or above in order to use _lumen_.
85
+
86
+
> The following information may get sent to _lumen_ server: IDA key, Hostname, IDB path, original file path, file MD5, function signature, stack frames & comments.
87
+
88
+
- In your IDA's installation directory open "cfg\ida.cfg" with your favorite text editor _(Example: C:\Program Files\IDA Pro 7.5\cfg\ida.cfg)_
89
+
- Locate the commented out `LUMINA_HOST`, `LUMINA_PORT`, and change their values to the address of your _lumen_ server.
90
+
- If you didn't configure TLS, Add "LUMINA_TLS = NO" after the line with `LUMINA_PORT`.
91
+
92
+
Example:
93
+
94
+
```C
95
+
LUMINA_HOST = "192.168.1.1";
96
+
LUMINA_PORT = 1234
97
+
98
+
// Only if TLS isn't used:
99
+
LUMINA_TLS = NO
100
+
```
101
+
102
+
### Configuring TLS
103
+
104
+
IDA Pro uses a pinned certificate for Lumina's communcation, so adding a self-signed certificate to your root certificates won't work.
105
+
Luckily, we can override the hard-coded public key by writing a DER-base64 encoded certificate to "hexrays.crt" in IDA's install directory.
106
+
107
+
You may find the following commands useful:
108
+
109
+
```bash
110
+
# create a certificate
111
+
openssl req -x509 -newkey rsa:4096 -keyout lumen_key.pem -out lumen_crt.pem -days 365 -nodes
112
+
113
+
# convert to pkcs12 for lumen; used for `lumen.tls` in config
114
+
openssl pkcs12 -export -out lumen.p12 -inkey lumen_key.pem -in lumen_crt.pem
115
+
116
+
# export public-key for IDA; Copy hexrays.crt to IDA installation folder
117
+
openssl x509 -in lumen_crt.pem -out hexrays.crt
118
+
```
119
+
120
+
No attempt is made to merge function data - this may cause a situation where metadata is inconsistent.
121
+
Instead, the metadata with the highest calculated score is returned to the user.
122
+
123
+
---
124
+
125
+
Developed by [Naim A.](https://github.com/naim94a); License: MIT.
+27
-12
common/Cargo.toml
+27
-12
common/Cargo.toml
···
7
7
publish = false
8
8
9
9
[dependencies]
10
-
tokio = {version = "1.32", features = ["full"], optional = true}
11
-
log = {version = "0.4", features = ["release_max_level_debug"]}
12
-
serde = {version = "1.0", features = ["derive"]}
13
-
postgres-native-tls = {version = "0.5", optional = true}
14
-
native-tls = {version = "0.2", optional = true}
10
+
tokio = { version = "1.39", features = ["full"], optional = true }
11
+
log = { version = "0.4", features = ["release_max_level_debug"] }
12
+
serde = { version = "1.0", features = ["derive"] }
13
+
postgres-native-tls = { version = "0.5", optional = true }
14
+
native-tls = { version = "0.2", optional = true }
15
15
futures-util = "0.3"
16
-
toml = "0.7"
17
-
warp = {version = "0.3", optional = true}
16
+
toml = "0.8"
17
+
warp = { version = "0.3", optional = true }
18
18
binascii = "0.1"
19
19
20
-
tokio-postgres = {version = "0.7", default-features = false, optional = true}
21
-
diesel = {version = "2.1", optional = true, default-features = false, features = ["postgres_backend", "time"]}
22
-
diesel-async = {version = "0.3", optional = true, features = ["postgres", "bb8"]}
20
+
tokio-postgres = { version = "0.7", default-features = false, optional = true }
21
+
diesel = { version = "2.2", optional = true, default-features = false, features = [
22
+
"postgres_backend",
23
+
"time",
24
+
] }
25
+
time = { version = "0.3.36", optional = true }
26
+
diesel-async = { version = "0.5", optional = true, features = [
27
+
"postgres",
28
+
"bb8",
29
+
] }
23
30
anyhow = "1.0"
24
-
prometheus-client = "0.21.2"
31
+
prometheus-client = "0.22"
25
32
26
33
[features]
27
34
default = ["web", "db"]
28
35
web = ["warp"]
29
-
db = ["tokio", "postgres-native-tls", "native-tls", "diesel", "diesel-async", "tokio-postgres"]
36
+
db = [
37
+
"tokio",
38
+
"postgres-native-tls",
39
+
"native-tls",
40
+
"diesel",
41
+
"diesel-async",
42
+
"tokio-postgres",
43
+
"time",
44
+
]
+3
-6
common/src/async_drop.rs
+3
-6
common/src/async_drop.rs
···
1
1
use futures_util::{future::BoxFuture, Future};
2
2
use log::trace;
3
-
use tokio::{sync::mpsc::{UnboundedSender, unbounded_channel, WeakUnboundedSender}};
3
+
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender, WeakUnboundedSender};
4
4
5
5
enum AsyncDropperMsg {
6
6
Future(BoxFuture<'static, ()>),
···
29
29
AsyncDropperMsg::Termination => {
30
30
trace!("term received for '{orig}'...");
31
31
break;
32
-
}
32
+
},
33
33
}
34
34
}
35
35
trace!("dropper '{orig}' exited.");
···
41
41
/// Defers execution of a future to when the returned `AsyncDropGuard` is dropped
42
42
pub fn defer<F: Future<Output = ()> + Send + 'static>(&self, fut: F) -> AsyncDropGuard {
43
43
let tx = self.tx.downgrade();
44
-
AsyncDropGuard {
45
-
tx,
46
-
run: Some(Box::pin(fut))
47
-
}
44
+
AsyncDropGuard { tx, run: Some(Box::pin(fut)) }
48
45
}
49
46
}
50
47
impl Drop for AsyncDropper {
+92
-57
common/src/config.rs
+92
-57
common/src/config.rs
···
1
-
use serde::Deserialize;
2
-
use toml::from_str;
3
-
use std::{net::SocketAddr, path::PathBuf};
4
-
5
-
#[derive(Deserialize)]
6
-
pub struct TlsIdentity {
7
-
pub server_cert: PathBuf,
8
-
}
9
-
10
-
#[derive(Deserialize)]
11
-
pub struct LuminaServer {
12
-
pub bind_addr: SocketAddr,
13
-
pub use_tls: Option<bool>,
14
-
pub tls: Option<TlsIdentity>,
15
-
pub server_name: Option<String>,
16
-
pub allow_deletes: Option<bool>,
17
-
}
18
-
19
-
#[derive(Deserialize)]
20
-
pub struct WebServer {
21
-
pub bind_addr: SocketAddr,
22
-
}
23
-
24
-
#[derive(Deserialize)]
25
-
pub struct Database {
26
-
pub connection_info: String,
27
-
28
-
pub use_tls: bool,
29
-
pub server_ca: Option<PathBuf>,
30
-
pub client_id: Option<PathBuf>,
31
-
}
32
-
33
-
#[derive(Deserialize)]
34
-
pub struct Config {
35
-
pub lumina: LuminaServer,
36
-
pub api_server: Option<WebServer>,
37
-
pub database: Database,
38
-
}
39
-
40
-
pub trait HasConfig {
41
-
fn get_config(&self) -> &Config;
42
-
}
43
-
44
-
impl HasConfig for Config {
45
-
fn get_config(&self) -> &Config {
46
-
self
47
-
}
48
-
}
49
-
50
-
pub fn load_config<R: std::io::Read>(mut fd: R) -> Config {
51
-
let mut buf = vec![];
52
-
fd.read_to_end(&mut buf).expect("failed to read config");
53
-
54
-
let buf = std::str::from_utf8(&buf).expect("file contains invalid utf-8");
55
-
56
-
from_str(buf).expect("failed to parse configuration")
57
-
}
1
+
use serde::Deserialize;
2
+
use std::time::Duration;
3
+
use std::{net::SocketAddr, path::PathBuf};
4
+
use toml::from_str;
5
+
6
+
#[derive(Deserialize)]
7
+
pub struct TlsIdentity {
8
+
pub server_cert: PathBuf,
9
+
}
10
+
11
+
#[derive(Deserialize)]
12
+
pub struct LuminaServer {
13
+
pub bind_addr: SocketAddr,
14
+
pub use_tls: Option<bool>,
15
+
pub tls: Option<TlsIdentity>,
16
+
pub server_name: Option<String>,
17
+
pub allow_deletes: Option<bool>,
18
+
19
+
/// limit of function histories to return per function.
20
+
/// `None`, or `Some(0)` will disable the feature on the server.
21
+
pub get_history_limit: Option<u32>,
22
+
}
23
+
24
+
#[derive(Deserialize)]
25
+
pub struct WebServer {
26
+
pub bind_addr: SocketAddr,
27
+
}
28
+
29
+
#[derive(Deserialize)]
30
+
pub struct Database {
31
+
pub connection_info: String,
32
+
33
+
pub use_tls: bool,
34
+
pub server_ca: Option<PathBuf>,
35
+
pub client_id: Option<PathBuf>,
36
+
}
37
+
38
+
#[derive(Deserialize, Debug)]
39
+
#[serde(default)]
40
+
pub struct Limits {
41
+
/// Maximum time to wait on an idle connection between commands.
42
+
pub command_timeout: Duration,
43
+
44
+
/// Maximum time to all `PULL_MD` queries.
45
+
pub pull_md_timeout: Duration,
46
+
47
+
/// Maximum time to wait for `HELO` message.
48
+
pub hello_timeout: Duration,
49
+
50
+
/// Maximum time allowed until TLS handshake completes.
51
+
pub tls_handshake_timeout: Duration,
52
+
}
53
+
54
+
impl Default for Limits {
55
+
fn default() -> Self {
56
+
Self {
57
+
command_timeout: Duration::from_secs(3600),
58
+
pull_md_timeout: Duration::from_secs(4 * 60),
59
+
hello_timeout: Duration::from_secs(15),
60
+
tls_handshake_timeout: Duration::from_secs(10),
61
+
}
62
+
}
63
+
}
64
+
65
+
#[derive(Deserialize)]
66
+
pub struct Config {
67
+
pub lumina: LuminaServer,
68
+
pub api_server: Option<WebServer>,
69
+
pub database: Database,
70
+
71
+
#[serde(default)]
72
+
pub limits: Limits,
73
+
}
74
+
75
+
pub trait HasConfig {
76
+
fn get_config(&self) -> &Config;
77
+
}
78
+
79
+
impl HasConfig for Config {
80
+
fn get_config(&self) -> &Config {
81
+
self
82
+
}
83
+
}
84
+
85
+
pub fn load_config<R: std::io::Read>(mut fd: R) -> Config {
86
+
let mut buf = vec![];
87
+
fd.read_to_end(&mut buf).expect("failed to read config");
88
+
89
+
let buf = std::str::from_utf8(&buf).expect("file contains invalid utf-8");
90
+
91
+
from_str(buf).expect("failed to parse configuration")
92
+
}
+478
-406
common/src/db/mod.rs
+478
-406
common/src/db/mod.rs
···
1
-
use log::*;
2
-
use postgres_native_tls::MakeTlsConnector;
3
-
use serde::Serialize;
4
-
use tokio_postgres::{tls::MakeTlsConnect, Socket, NoTls};
5
-
use std::{collections::HashMap};
6
-
use crate::async_drop::{AsyncDropper, AsyncDropGuard};
7
-
mod schema_auto;
8
-
pub mod schema;
9
-
10
-
use diesel::{upsert::excluded, ExpressionMethods, QueryDsl, NullableExpressionMethods, sql_types::{Array, Binary, VarChar, Integer}, query_builder::{QueryFragment, Query}};
11
-
use diesel_async::RunQueryDsl;
12
-
13
-
pub type DynConfig = dyn crate::config::HasConfig + Send + Sync;
14
-
15
-
pub struct Database {
16
-
tls_connector: Option<MakeTlsConnector>,
17
-
diesel: diesel_async::pooled_connection::bb8::Pool<diesel_async::AsyncPgConnection>,
18
-
dropper: AsyncDropper,
19
-
}
20
-
21
-
pub struct FunctionInfo {
22
-
pub name: String,
23
-
pub len: u32,
24
-
pub data: Vec<u8>,
25
-
pub popularity: u32,
26
-
}
27
-
28
-
#[derive(Debug, Serialize)]
29
-
pub struct DbStats {
30
-
unique_lics: i32,
31
-
unique_hosts_per_lic: i32,
32
-
33
-
unique_funcs: i32,
34
-
total_funcs: i32,
35
-
36
-
dbs: i32,
37
-
unique_files: i32,
38
-
}
39
-
40
-
impl Database {
41
-
pub async fn open(config: &crate::config::Database) -> Result<Self, anyhow::Error> {
42
-
let connection_string = config.connection_info.as_str();
43
-
let tls_connector = if config.use_tls {
44
-
Some(Self::make_tls(config).await)
45
-
} else {
46
-
None
47
-
};
48
-
49
-
let (dropper, worker) = AsyncDropper::new();
50
-
tokio::task::spawn(worker);
51
-
52
-
let diesel = Self::make_bb8_pool(connection_string, tls_connector.clone()).await?;
53
-
54
-
Ok(Database{
55
-
tls_connector,
56
-
dropper,
57
-
diesel,
58
-
})
59
-
}
60
-
61
-
async fn make_pg_client<T>(db_url: &str, tls: T) -> diesel::result::ConnectionResult<diesel_async::AsyncPgConnection>
62
-
where T: MakeTlsConnect<Socket>,
63
-
T::Stream: Send + 'static {
64
-
let (cli, conn) = tokio_postgres::connect(db_url, tls)
65
-
.await
66
-
.map_err(|e| {
67
-
error!("failed to connect db: {e}");
68
-
diesel::result::ConnectionError::BadConnection(format!("{e}"))
69
-
})?;
70
-
71
-
tokio::spawn(async move {
72
-
if let Err(e) = conn.await {
73
-
error!("connection task error: {e}");
74
-
}
75
-
});
76
-
77
-
diesel_async::AsyncPgConnection::try_from(cli).await
78
-
}
79
-
80
-
async fn make_bb8_pool(db_url: &str, tls: Option<MakeTlsConnector>) -> Result<diesel_async::pooled_connection::bb8::Pool<diesel_async::AsyncPgConnection>, anyhow::Error> {
81
-
let cfg = diesel_async::pooled_connection::AsyncDieselConnectionManager::<diesel_async::AsyncPgConnection>::new_with_setup(db_url, move |db_url| {
82
-
let tls = tls.clone();
83
-
Box::pin( async move {
84
-
if let Some(tls) = tls {
85
-
Self::make_pg_client(db_url, tls).await
86
-
} else {
87
-
Self::make_pg_client(db_url, NoTls).await
88
-
}
89
-
})
90
-
});
91
-
92
-
let pool = diesel_async::pooled_connection::bb8::Pool::builder()
93
-
.min_idle(Some(1))
94
-
.build(cfg)
95
-
.await?;
96
-
Ok(pool)
97
-
}
98
-
99
-
async fn make_tls(database: &crate::config::Database) -> MakeTlsConnector {
100
-
use native_tls::{TlsConnector, Certificate, Identity};
101
-
102
-
let mut tls_connector = TlsConnector::builder();
103
-
104
-
if let Some(ref client_identity) = database.client_id {
105
-
let client_identity = tokio::fs::read(client_identity).await.expect("failed to read db's client id");
106
-
let client_identity = Identity::from_pkcs12(&client_identity, "").expect("failed to load db's client identity (PKCS12)");
107
-
tls_connector.identity(client_identity);
108
-
}
109
-
110
-
if let Some(ref server_ca) = database.server_ca {
111
-
let server_ca = tokio::fs::read(server_ca).await.expect("failed to read db's server ca");
112
-
let server_ca = Certificate::from_pem(&server_ca).expect("failed to load db's server ca (PEM)");
113
-
tls_connector.add_root_certificate(server_ca);
114
-
}
115
-
116
-
let tls_connector = tls_connector
117
-
.danger_accept_invalid_hostnames(true)
118
-
.build()
119
-
.expect("failed to build TlsConnector");
120
-
121
-
MakeTlsConnector::new(tls_connector)
122
-
}
123
-
124
-
pub async fn get_funcs(&self, funcs: &[crate::rpc::PullMetadataFunc<'_>]) -> Result<Vec<Option<FunctionInfo>>, anyhow::Error> {
125
-
let chksums: Vec<&[u8]> = funcs.iter().map(|v| v.mb_hash).collect();
126
-
127
-
let rows: Vec<(String, i32, Vec<u8>, Vec<u8>)> = {
128
-
let conn = &mut self.diesel.get().await?;
129
-
130
-
let ct = self.cancel_guard(&*conn);
131
-
132
-
let res: Vec<_> = BestMds(chksums.as_slice())
133
-
.get_results::<_>(conn).await?;
134
-
ct.consume();
135
-
res
136
-
};
137
-
138
-
let mut partial: HashMap<Vec<u8>, FunctionInfo> = rows
139
-
.into_iter()
140
-
.map(|row| {
141
-
let v = FunctionInfo {
142
-
name: row.0,
143
-
len: row.1 as u32,
144
-
data: row.2,
145
-
popularity: 0,
146
-
};
147
-
148
-
(row.3, v)
149
-
})
150
-
.collect();
151
-
152
-
let results = partial.len();
153
-
154
-
let res: Vec<Option<FunctionInfo>> = chksums.iter().map(|&chksum| {
155
-
partial.remove(chksum)
156
-
}).collect();
157
-
158
-
trace!("found {}/{} results", results, chksums.len());
159
-
debug_assert_eq!(chksums.len(), res.len());
160
-
Ok(res)
161
-
}
162
-
163
-
pub async fn get_or_create_user<'a>(&self, user: &'a crate::rpc::RpcHello<'a>, hostname: &str) -> Result<i32, anyhow::Error> {
164
-
use schema::users;
165
-
166
-
let conn = &mut self.diesel.get().await?;
167
-
168
-
let lic_id = &user.lic_number[..];
169
-
let lic_data = user.license_data;
170
-
171
-
let get_user = || users::table.select(users::id)
172
-
.filter(users::lic_data.eq(lic_data))
173
-
.filter(users::lic_id.eq(lic_id))
174
-
.filter(users::hostname.eq(hostname));
175
-
176
-
match get_user().get_result::<i32>(conn).await {
177
-
Ok(v) => return Ok(v),
178
-
Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()),
179
-
_ => {},
180
-
};
181
-
182
-
match diesel::insert_into(users::table)
183
-
.values(vec![
184
-
(
185
-
users::lic_id.eq(lic_id),
186
-
users::lic_data.eq(lic_data),
187
-
users::hostname.eq(hostname),
188
-
)
189
-
])
190
-
.returning(users::id) // xmax = 0 if the row is new
191
-
.get_result::<i32>(conn)
192
-
.await {
193
-
Ok(v) => return Ok(v),
194
-
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _)) => {},
195
-
Err(e) => return Err(e.into()),
196
-
}
197
-
198
-
Ok(get_user().get_result::<i32>(conn).await?)
199
-
}
200
-
201
-
async fn get_or_create_file<'a>(&self, funcs: &'a crate::rpc::PushMetadata<'a>) -> Result<i32, anyhow::Error> {
202
-
use schema::files::{table as files, chksum, id};
203
-
204
-
let hash = &funcs.md5[..];
205
-
206
-
let conn = &mut self.diesel.get().await?;
207
-
208
-
let get_file = || files.filter(chksum.eq(hash)).select(id);
209
-
210
-
match get_file().get_result::<i32>(conn).await {
211
-
Ok(v) => return Ok(v),
212
-
Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()),
213
-
_ => {},
214
-
}
215
-
216
-
match diesel::insert_into(files)
217
-
.values(vec![(chksum.eq(hash),)])
218
-
.returning(id)
219
-
.get_result::<i32>(conn)
220
-
.await {
221
-
Ok(v) => return Ok(v),
222
-
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _)) => {},
223
-
Err(e) => return Err(e.into()),
224
-
}
225
-
Ok(get_file().get_result::<i32>(conn).await?)
226
-
}
227
-
228
-
async fn get_or_create_db<'a>(&self, user: &'a crate::rpc::RpcHello<'a>, funcs: &'a crate::rpc::PushMetadata<'a>) -> Result<i32, anyhow::Error> {
229
-
use schema::dbs::{table as dbs, id as db_id, user_id as db_user, file_id as db_file_id, file_path, idb_path};
230
-
231
-
let file_id = self.get_or_create_file(funcs);
232
-
let user_id = self.get_or_create_user(user, funcs.hostname);
233
-
234
-
let (file_id, user_id): (i32, i32) = futures_util::try_join!(file_id, user_id)?;
235
-
236
-
let conn = &mut self.diesel.get().await?;
237
-
238
-
let get_db = || {
239
-
dbs.select(db_id)
240
-
.filter(db_user.eq(user_id))
241
-
.filter(db_file_id.eq(file_id))
242
-
.filter(file_path.eq(funcs.file_path))
243
-
.filter(idb_path.eq(funcs.idb_path))
244
-
};
245
-
246
-
match get_db().get_result::<i32>(conn).await {
247
-
Ok(v) => return Ok(v),
248
-
Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()),
249
-
_ => {},
250
-
};
251
-
252
-
match diesel::insert_into(dbs)
253
-
.values(vec![(
254
-
db_user.eq(user_id),
255
-
db_file_id.eq(file_id),
256
-
file_path.eq(funcs.file_path),
257
-
idb_path.eq(funcs.idb_path),
258
-
)])
259
-
.returning(db_id)
260
-
.get_result::<i32>(conn)
261
-
.await {
262
-
Ok(id) => return Ok(id),
263
-
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _)) => {},
264
-
Err(e) => return Err(e.into()),
265
-
};
266
-
Ok(get_db().get_result::<i32>(conn).await?)
267
-
}
268
-
269
-
pub async fn push_funcs<'a, 'b>(&'b self, user: &'a crate::rpc::RpcHello<'a>, funcs: &'a crate::rpc::PushMetadata<'a>, scores: &[u32]) -> Result<Vec<bool>, anyhow::Error> {
270
-
use futures_util::TryStreamExt;
271
-
272
-
// postgres has a limitation of binding per statement (i16::MAX). Split large push requests into smaller chunks.
273
-
const PUSH_FUNC_CHUNK_SIZE: usize = 3000;
274
-
275
-
let db_id = self.get_or_create_db(user, funcs).await?;
276
-
277
-
let mut rows = Vec::with_capacity(funcs.funcs.len().min(PUSH_FUNC_CHUNK_SIZE));
278
-
let mut is_new = Vec::with_capacity(funcs.funcs.len());
279
-
let conn = &mut self.diesel.get().await?;
280
-
let f2 = diesel::alias!(schema::funcs as f2);
281
-
282
-
for (idx, (func, &score)) in funcs.funcs.iter().zip(scores.iter()).enumerate() {
283
-
let name = func.name;
284
-
let len = func.func_len as i32;
285
-
let chksum = func.hash;
286
-
let md = func.func_data;
287
-
let score = score as i32;
288
-
289
-
rows.push((
290
-
schema::funcs::name.eq(name),
291
-
schema::funcs::len.eq(len),
292
-
schema::funcs::chksum.eq(chksum),
293
-
schema::funcs::metadata.eq(md),
294
-
schema::funcs::rank.eq(score),
295
-
schema::funcs::db_id.eq(db_id),
296
-
));
297
-
298
-
if rows.len() < PUSH_FUNC_CHUNK_SIZE && idx < funcs.funcs.len() - 1 {
299
-
continue;
300
-
}
301
-
302
-
let mut current_rows = Vec::with_capacity((funcs.funcs.len() - (idx + 1)).max(PUSH_FUNC_CHUNK_SIZE));
303
-
std::mem::swap(&mut current_rows, &mut rows);
304
-
305
-
diesel::insert_into(schema::funcs::table)
306
-
.values(current_rows)
307
-
.on_conflict((schema::funcs::chksum, schema::funcs::db_id))
308
-
.do_update()
309
-
.set((
310
-
schema::funcs::name.eq(excluded(schema::funcs::name)),
311
-
schema::funcs::metadata.eq(excluded(schema::funcs::metadata)),
312
-
schema::funcs::rank.eq(excluded(schema::funcs::rank)),
313
-
schema::funcs::update_dt.eq(diesel::dsl::now)
314
-
))
315
-
.returning(diesel::dsl::not(diesel::dsl::exists(f2.filter(f2.field(schema::funcs::chksum).eq(schema::funcs::chksum))))) // xmax=0 when a new row is created.
316
-
.load_stream::<bool>(conn)
317
-
.await?
318
-
.try_fold(&mut is_new, |acc, item: bool| {
319
-
acc.push(item);
320
-
futures_util::future::ready(Ok(acc))
321
-
})
322
-
.await?;
323
-
}
324
-
325
-
Ok(is_new)
326
-
}
327
-
328
-
pub async fn get_file_funcs(&self, md5: &[u8], offset: i64, limit: i64) -> Result<Vec<(String, i32, Vec<u8>)>, anyhow::Error> {
329
-
let conn = &mut self.diesel.get().await?;
330
-
let results = schema::funcs::table
331
-
.left_join(schema::dbs::table.left_join(schema::files::table))
332
-
.select((schema::funcs::name.assume_not_null(), schema::funcs::len.assume_not_null(), schema::funcs::chksum.assume_not_null()))
333
-
.filter(schema::files::chksum.eq(md5))
334
-
.offset(offset)
335
-
.limit(limit)
336
-
.get_results::<(String, i32, Vec<u8>)>(conn).await?;
337
-
Ok(results)
338
-
}
339
-
340
-
pub async fn get_files_with_func(&self, func: &[u8]) -> Result<Vec<Vec<u8>>, anyhow::Error> {
341
-
let conn = &mut self.diesel.get().await?;
342
-
343
-
let res = schema::files::table
344
-
.left_join(schema::dbs::table.left_join(schema::funcs::table))
345
-
.select(schema::files::chksum.assume_not_null())
346
-
.distinct()
347
-
.filter(schema::funcs::chksum.eq(func))
348
-
.get_results::<Vec<u8>>(conn)
349
-
.await?;
350
-
Ok(res)
351
-
}
352
-
353
-
fn cancel_guard(&self, conn: &diesel_async::pooled_connection::bb8::PooledConnection<'_, diesel_async::AsyncPgConnection>) -> AsyncDropGuard {
354
-
let token = conn.cancel_token();
355
-
let tls_connector = self.tls_connector.clone();
356
-
self.dropper.defer(async move {
357
-
debug!("cancelling query...");
358
-
359
-
if let Some(tls) = tls_connector {
360
-
let _ = token.cancel_query(tls).await;
361
-
} else {
362
-
let _ = token.cancel_query(NoTls).await;
363
-
}
364
-
})
365
-
}
366
-
367
-
pub async fn delete_metadata(&self, req: &crate::rpc::DelHistory<'_>) -> Result<(), anyhow::Error> {
368
-
use schema::funcs::{table as funcs, chksum};
369
-
370
-
let chksums = req.funcs.iter()
371
-
.map(|v| v.as_slice())
372
-
.collect::<Vec<_>>();
373
-
374
-
let conn = &mut self.diesel.get().await?;
375
-
let rows_modified = diesel::delete(funcs.filter(chksum.eq_any(&chksums)))
376
-
.execute(conn)
377
-
.await?;
378
-
379
-
debug!("deleted {rows_modified} rows");
380
-
381
-
Ok(())
382
-
}
383
-
}
384
-
385
-
// This is eww, but it's the fastest.
386
-
struct BestMds<'a>(&'a [&'a [u8]]);
387
-
impl<'a> QueryFragment<diesel::pg::Pg> for BestMds<'a> {
388
-
fn walk_ast<'b>(&'b self, mut pass: diesel::query_builder::AstPass<'_, 'b, diesel::pg::Pg>) -> diesel::QueryResult<()> {
389
-
pass.push_sql(r#"WITH best AS (
390
-
select chksum,MAX(rank) as maxrank from funcs f1
391
-
WHERE chksum = ANY("#);
392
-
pass.push_bind_param::<Array<Binary>, _>(&self.0)?;
393
-
pass.push_sql(r#")
394
-
GROUP BY chksum
395
-
)
396
-
SELECT f2.name,f2.len,f2.metadata,f2.chksum FROM best
397
-
LEFT JOIN funcs f2 ON (best.chksum=f2.chksum AND best.maxrank=f2.rank)"#);
398
-
Ok(())
399
-
}
400
-
}
401
-
impl<'a> diesel::query_builder::QueryId for BestMds<'a> {
402
-
type QueryId = BestMds<'static>;
403
-
}
404
-
impl<'a> Query for BestMds<'a> {
405
-
type SqlType = (VarChar, Integer, Binary, Binary);
406
-
}
1
+
use crate::async_drop::{AsyncDropGuard, AsyncDropper};
2
+
use log::*;
3
+
use postgres_native_tls::MakeTlsConnector;
4
+
use serde::Serialize;
5
+
use std::collections::HashMap;
6
+
use time::OffsetDateTime;
7
+
use tokio_postgres::{tls::MakeTlsConnect, NoTls, Socket};
8
+
pub mod schema;
9
+
mod schema_auto;
10
+
11
+
use diesel::{
12
+
query_builder::{Query, QueryFragment},
13
+
sql_types::{Array, Binary, Integer, VarChar},
14
+
upsert::excluded,
15
+
ExpressionMethods, NullableExpressionMethods, QueryDsl,
16
+
};
17
+
use diesel_async::{pooled_connection::ManagerConfig, RunQueryDsl};
18
+
19
+
pub type DynConfig = dyn crate::config::HasConfig + Send + Sync;
20
+
21
+
pub struct Database {
22
+
tls_connector: Option<MakeTlsConnector>,
23
+
diesel: diesel_async::pooled_connection::bb8::Pool<diesel_async::AsyncPgConnection>,
24
+
dropper: AsyncDropper,
25
+
}
26
+
27
+
pub struct FunctionInfo {
28
+
pub name: String,
29
+
pub len: u32,
30
+
pub data: Vec<u8>,
31
+
pub popularity: u32,
32
+
}
33
+
34
+
#[derive(Debug, Serialize)]
35
+
pub struct DbStats {
36
+
unique_lics: i32,
37
+
unique_hosts_per_lic: i32,
38
+
39
+
unique_funcs: i32,
40
+
total_funcs: i32,
41
+
42
+
dbs: i32,
43
+
unique_files: i32,
44
+
}
45
+
46
+
impl Database {
47
+
pub async fn open(config: &crate::config::Database) -> Result<Self, anyhow::Error> {
48
+
let connection_string = config.connection_info.as_str();
49
+
let tls_connector = if config.use_tls { Some(Self::make_tls(config).await) } else { None };
50
+
51
+
let (dropper, worker) = AsyncDropper::new();
52
+
tokio::task::spawn(worker);
53
+
54
+
let diesel = Self::make_bb8_pool(connection_string, tls_connector.clone()).await?;
55
+
56
+
Ok(Database { tls_connector, dropper, diesel })
57
+
}
58
+
59
+
async fn make_pg_client<T>(
60
+
db_url: &str, tls: T,
61
+
) -> diesel::result::ConnectionResult<diesel_async::AsyncPgConnection>
62
+
where
63
+
T: MakeTlsConnect<Socket>,
64
+
T::Stream: Send + 'static,
65
+
{
66
+
let (cli, conn) = tokio_postgres::connect(db_url, tls).await.map_err(|e| {
67
+
error!("failed to connect db: {e}");
68
+
diesel::result::ConnectionError::BadConnection(format!("{e}"))
69
+
})?;
70
+
71
+
tokio::spawn(async move {
72
+
if let Err(e) = conn.await {
73
+
error!("connection task error: {e}");
74
+
}
75
+
});
76
+
77
+
diesel_async::AsyncPgConnection::try_from(cli).await
78
+
}
79
+
80
+
async fn make_bb8_pool(
81
+
db_url: &str, tls: Option<MakeTlsConnector>,
82
+
) -> Result<
83
+
diesel_async::pooled_connection::bb8::Pool<diesel_async::AsyncPgConnection>,
84
+
anyhow::Error,
85
+
> {
86
+
let mut config = ManagerConfig::default();
87
+
config.custom_setup = Box::new(move |db_url| {
88
+
let tls = tls.clone();
89
+
Box::pin(async move {
90
+
if let Some(tls) = tls {
91
+
Self::make_pg_client(db_url, tls).await
92
+
} else {
93
+
Self::make_pg_client(db_url, NoTls).await
94
+
}
95
+
})
96
+
});
97
+
let cfg = diesel_async::pooled_connection::AsyncDieselConnectionManager::<
98
+
diesel_async::AsyncPgConnection,
99
+
>::new_with_config(db_url, config);
100
+
101
+
let pool = diesel_async::pooled_connection::bb8::Pool::builder()
102
+
.min_idle(Some(1))
103
+
.build(cfg)
104
+
.await?;
105
+
Ok(pool)
106
+
}
107
+
108
+
async fn make_tls(database: &crate::config::Database) -> MakeTlsConnector {
109
+
use native_tls::{Certificate, Identity, TlsConnector};
110
+
111
+
let mut tls_connector = TlsConnector::builder();
112
+
113
+
if let Some(ref client_identity) = database.client_id {
114
+
let client_identity =
115
+
tokio::fs::read(client_identity).await.expect("failed to read db's client id");
116
+
let client_identity = Identity::from_pkcs12(&client_identity, "")
117
+
.expect("failed to load db's client identity (PKCS12)");
118
+
tls_connector.identity(client_identity);
119
+
}
120
+
121
+
if let Some(ref server_ca) = database.server_ca {
122
+
let server_ca =
123
+
tokio::fs::read(server_ca).await.expect("failed to read db's server ca");
124
+
let server_ca =
125
+
Certificate::from_pem(&server_ca).expect("failed to load db's server ca (PEM)");
126
+
tls_connector.add_root_certificate(server_ca);
127
+
}
128
+
129
+
let tls_connector = tls_connector
130
+
.danger_accept_invalid_hostnames(true)
131
+
.build()
132
+
.expect("failed to build TlsConnector");
133
+
134
+
MakeTlsConnector::new(tls_connector)
135
+
}
136
+
137
+
pub async fn get_funcs(
138
+
&self, funcs: &[crate::rpc::PullMetadataFunc<'_>],
139
+
) -> Result<Vec<Option<FunctionInfo>>, anyhow::Error> {
140
+
let chksums: Vec<&[u8]> = funcs.iter().map(|v| v.mb_hash).collect();
141
+
142
+
let rows: Vec<(String, i32, Vec<u8>, Vec<u8>)> = {
143
+
let conn = &mut self.diesel.get().await?;
144
+
145
+
let ct = self.cancel_guard(&*conn);
146
+
147
+
let res: Vec<_> = BestMds(chksums.as_slice()).get_results::<_>(conn).await?;
148
+
ct.consume();
149
+
res
150
+
};
151
+
152
+
let mut partial: HashMap<Vec<u8>, FunctionInfo> = rows
153
+
.into_iter()
154
+
.map(|row| {
155
+
let v = FunctionInfo { name: row.0, len: row.1 as u32, data: row.2, popularity: 0 };
156
+
157
+
(row.3, v)
158
+
})
159
+
.collect();
160
+
161
+
let results = partial.len();
162
+
163
+
let res: Vec<Option<FunctionInfo>> =
164
+
chksums.iter().map(|&chksum| partial.remove(chksum)).collect();
165
+
166
+
trace!("found {}/{} results", results, chksums.len());
167
+
debug_assert_eq!(chksums.len(), res.len());
168
+
Ok(res)
169
+
}
170
+
171
+
pub async fn get_or_create_user<'a>(
172
+
&self, user: &'a crate::rpc::RpcHello<'a>, hostname: &str,
173
+
) -> Result<i32, anyhow::Error> {
174
+
use schema::users;
175
+
176
+
let conn = &mut self.diesel.get().await?;
177
+
178
+
let lic_id = &user.lic_number[..];
179
+
let lic_data = user.license_data;
180
+
181
+
let get_user = || {
182
+
users::table
183
+
.select(users::id)
184
+
.filter(users::lic_data.eq(lic_data))
185
+
.filter(users::lic_id.eq(lic_id))
186
+
.filter(users::hostname.eq(hostname))
187
+
};
188
+
189
+
match get_user().get_result::<i32>(conn).await {
190
+
Ok(v) => return Ok(v),
191
+
Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()),
192
+
_ => {},
193
+
};
194
+
195
+
match diesel::insert_into(users::table)
196
+
.values(vec![(
197
+
users::lic_id.eq(lic_id),
198
+
users::lic_data.eq(lic_data),
199
+
users::hostname.eq(hostname),
200
+
)])
201
+
.returning(users::id) // xmax = 0 if the row is new
202
+
.get_result::<i32>(conn)
203
+
.await
204
+
{
205
+
Ok(v) => return Ok(v),
206
+
Err(diesel::result::Error::DatabaseError(
207
+
diesel::result::DatabaseErrorKind::UniqueViolation,
208
+
_,
209
+
)) => {},
210
+
Err(e) => return Err(e.into()),
211
+
}
212
+
213
+
Ok(get_user().get_result::<i32>(conn).await?)
214
+
}
215
+
216
+
async fn get_or_create_file<'a>(
217
+
&self, funcs: &'a crate::rpc::PushMetadata<'a>,
218
+
) -> Result<i32, anyhow::Error> {
219
+
use schema::files::{chksum, id, table as files};
220
+
221
+
let hash = &funcs.md5[..];
222
+
223
+
let conn = &mut self.diesel.get().await?;
224
+
225
+
let get_file = || files.filter(chksum.eq(hash)).select(id);
226
+
227
+
match get_file().get_result::<i32>(conn).await {
228
+
Ok(v) => return Ok(v),
229
+
Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()),
230
+
_ => {},
231
+
}
232
+
233
+
match diesel::insert_into(files)
234
+
.values(vec![(chksum.eq(hash),)])
235
+
.returning(id)
236
+
.get_result::<i32>(conn)
237
+
.await
238
+
{
239
+
Ok(v) => return Ok(v),
240
+
Err(diesel::result::Error::DatabaseError(
241
+
diesel::result::DatabaseErrorKind::UniqueViolation,
242
+
_,
243
+
)) => {},
244
+
Err(e) => return Err(e.into()),
245
+
}
246
+
Ok(get_file().get_result::<i32>(conn).await?)
247
+
}
248
+
249
+
async fn get_or_create_db<'a>(
250
+
&self, user: &'a crate::rpc::RpcHello<'a>, funcs: &'a crate::rpc::PushMetadata<'a>,
251
+
) -> Result<i32, anyhow::Error> {
252
+
use schema::dbs::{
253
+
file_id as db_file_id, file_path, id as db_id, idb_path, table as dbs,
254
+
user_id as db_user,
255
+
};
256
+
257
+
let file_id = self.get_or_create_file(funcs);
258
+
let user_id = self.get_or_create_user(user, funcs.hostname);
259
+
260
+
let (file_id, user_id): (i32, i32) = futures_util::try_join!(file_id, user_id)?;
261
+
262
+
let conn = &mut self.diesel.get().await?;
263
+
264
+
let get_db = || {
265
+
dbs.select(db_id)
266
+
.filter(db_user.eq(user_id))
267
+
.filter(db_file_id.eq(file_id))
268
+
.filter(file_path.eq(funcs.file_path))
269
+
.filter(idb_path.eq(funcs.idb_path))
270
+
};
271
+
272
+
match get_db().get_result::<i32>(conn).await {
273
+
Ok(v) => return Ok(v),
274
+
Err(err) if err != diesel::result::Error::NotFound => return Err(err.into()),
275
+
_ => {},
276
+
};
277
+
278
+
match diesel::insert_into(dbs)
279
+
.values(vec![(
280
+
db_user.eq(user_id),
281
+
db_file_id.eq(file_id),
282
+
file_path.eq(funcs.file_path),
283
+
idb_path.eq(funcs.idb_path),
284
+
)])
285
+
.returning(db_id)
286
+
.get_result::<i32>(conn)
287
+
.await
288
+
{
289
+
Ok(id) => return Ok(id),
290
+
Err(diesel::result::Error::DatabaseError(
291
+
diesel::result::DatabaseErrorKind::UniqueViolation,
292
+
_,
293
+
)) => {},
294
+
Err(e) => return Err(e.into()),
295
+
};
296
+
Ok(get_db().get_result::<i32>(conn).await?)
297
+
}
298
+
299
+
pub async fn push_funcs<'a, 'b>(
300
+
&'b self, user: &'a crate::rpc::RpcHello<'a>, funcs: &'a crate::rpc::PushMetadata<'a>,
301
+
scores: &[u32],
302
+
) -> Result<Vec<bool>, anyhow::Error> {
303
+
use futures_util::TryStreamExt;
304
+
305
+
// postgres has a limitation of binding per statement (i16::MAX). Split large push requests into smaller chunks.
306
+
const PUSH_FUNC_CHUNK_SIZE: usize = 3000;
307
+
308
+
let db_id = self.get_or_create_db(user, funcs).await?;
309
+
310
+
let mut rows = Vec::with_capacity(funcs.funcs.len().min(PUSH_FUNC_CHUNK_SIZE));
311
+
let mut is_new = Vec::with_capacity(funcs.funcs.len());
312
+
let conn = &mut self.diesel.get().await?;
313
+
let f2 = diesel::alias!(schema::funcs as f2);
314
+
315
+
for (idx, (func, &score)) in funcs.funcs.iter().zip(scores.iter()).enumerate() {
316
+
let name = func.name;
317
+
let len = func.func_len as i32;
318
+
let chksum = func.hash;
319
+
let md = func.func_data;
320
+
let score = score as i32;
321
+
322
+
rows.push((
323
+
schema::funcs::name.eq(name),
324
+
schema::funcs::len.eq(len),
325
+
schema::funcs::chksum.eq(chksum),
326
+
schema::funcs::metadata.eq(md),
327
+
schema::funcs::rank.eq(score),
328
+
schema::funcs::db_id.eq(db_id),
329
+
));
330
+
331
+
if rows.len() < PUSH_FUNC_CHUNK_SIZE && idx < funcs.funcs.len() - 1 {
332
+
continue;
333
+
}
334
+
335
+
let mut current_rows =
336
+
Vec::with_capacity((funcs.funcs.len() - (idx + 1)).max(PUSH_FUNC_CHUNK_SIZE));
337
+
std::mem::swap(&mut current_rows, &mut rows);
338
+
339
+
diesel::insert_into(schema::funcs::table)
340
+
.values(current_rows)
341
+
.on_conflict((schema::funcs::chksum, schema::funcs::db_id))
342
+
.do_update()
343
+
.set((
344
+
schema::funcs::name.eq(excluded(schema::funcs::name)),
345
+
schema::funcs::metadata.eq(excluded(schema::funcs::metadata)),
346
+
schema::funcs::rank.eq(excluded(schema::funcs::rank)),
347
+
schema::funcs::update_dt.eq(diesel::dsl::now),
348
+
))
349
+
.returning(diesel::dsl::not(diesel::dsl::exists(
350
+
f2.filter(f2.field(schema::funcs::chksum).eq(schema::funcs::chksum)),
351
+
))) // xmax=0 when a new row is created.
352
+
.load_stream::<bool>(conn)
353
+
.await?
354
+
.try_fold(&mut is_new, |acc, item: bool| {
355
+
acc.push(item);
356
+
futures_util::future::ready(Ok(acc))
357
+
})
358
+
.await?;
359
+
}
360
+
361
+
Ok(is_new)
362
+
}
363
+
364
+
pub async fn get_file_funcs(
365
+
&self, md5: &[u8], offset: i64, limit: i64,
366
+
) -> Result<Vec<(String, i32, Vec<u8>)>, anyhow::Error> {
367
+
let conn = &mut self.diesel.get().await?;
368
+
let results = schema::funcs::table
369
+
.left_join(schema::dbs::table.left_join(schema::files::table))
370
+
.select((
371
+
schema::funcs::name.assume_not_null(),
372
+
schema::funcs::len.assume_not_null(),
373
+
schema::funcs::chksum.assume_not_null(),
374
+
))
375
+
.filter(schema::files::chksum.eq(md5))
376
+
.offset(offset)
377
+
.limit(limit)
378
+
.get_results::<(String, i32, Vec<u8>)>(conn)
379
+
.await?;
380
+
Ok(results)
381
+
}
382
+
383
+
pub async fn get_files_with_func(&self, func: &[u8]) -> Result<Vec<Vec<u8>>, anyhow::Error> {
384
+
let conn = &mut self.diesel.get().await?;
385
+
386
+
let res = schema::files::table
387
+
.left_join(schema::dbs::table.left_join(schema::funcs::table))
388
+
.select(schema::files::chksum.assume_not_null())
389
+
.distinct()
390
+
.filter(schema::funcs::chksum.eq(func))
391
+
.get_results::<Vec<u8>>(conn)
392
+
.await?;
393
+
Ok(res)
394
+
}
395
+
396
+
fn cancel_guard(
397
+
&self,
398
+
conn: &diesel_async::pooled_connection::bb8::PooledConnection<
399
+
'_,
400
+
diesel_async::AsyncPgConnection,
401
+
>,
402
+
) -> AsyncDropGuard {
403
+
let token = conn.cancel_token();
404
+
let tls_connector = self.tls_connector.clone();
405
+
self.dropper.defer(async move {
406
+
debug!("cancelling query...");
407
+
408
+
if let Some(tls) = tls_connector {
409
+
let _ = token.cancel_query(tls).await;
410
+
} else {
411
+
let _ = token.cancel_query(NoTls).await;
412
+
}
413
+
})
414
+
}
415
+
416
+
pub async fn delete_metadata(
417
+
&self, req: &crate::rpc::DelHistory<'_>,
418
+
) -> Result<(), anyhow::Error> {
419
+
use schema::funcs::{chksum, table as funcs};
420
+
421
+
let chksums = req.funcs.iter().map(|v| v.as_slice()).collect::<Vec<_>>();
422
+
423
+
let conn = &mut self.diesel.get().await?;
424
+
let rows_modified =
425
+
diesel::delete(funcs.filter(chksum.eq_any(&chksums))).execute(conn).await?;
426
+
427
+
debug!("deleted {rows_modified} rows");
428
+
429
+
Ok(())
430
+
}
431
+
432
+
pub async fn get_func_histories(
433
+
&self, chksum: &[u8], limit: u32,
434
+
) -> Result<Vec<(OffsetDateTime, String, Vec<u8>)>, anyhow::Error> {
435
+
let conn = &mut self.diesel.get().await?;
436
+
let rows = &schema::funcs::table.select((
437
+
schema::funcs::update_dt.assume_not_null(),
438
+
schema::funcs::name,
439
+
schema::funcs::metadata.assume_not_null(),
440
+
));
441
+
let rows = rows
442
+
.limit(limit as i64)
443
+
.order_by(schema::funcs::update_dt.desc())
444
+
.filter(schema::funcs::chksum.eq(chksum))
445
+
.get_results::<(time::OffsetDateTime, String, Vec<u8>)>(conn)
446
+
.await?;
447
+
Ok(rows)
448
+
}
449
+
}
450
+
451
+
// This is eww, but it's the fastest.
452
+
struct BestMds<'a>(&'a [&'a [u8]]);
453
+
impl<'a> QueryFragment<diesel::pg::Pg> for BestMds<'a> {
454
+
fn walk_ast<'b>(
455
+
&'b self, mut pass: diesel::query_builder::AstPass<'_, 'b, diesel::pg::Pg>,
456
+
) -> diesel::QueryResult<()> {
457
+
pass.push_sql(
458
+
r#"WITH best AS (
459
+
select chksum,MAX(rank) as maxrank from funcs f1
460
+
WHERE chksum = ANY("#,
461
+
);
462
+
pass.push_bind_param::<Array<Binary>, _>(&self.0)?;
463
+
pass.push_sql(
464
+
r#")
465
+
GROUP BY chksum
466
+
)
467
+
SELECT f2.name,f2.len,f2.metadata,f2.chksum FROM best
468
+
LEFT JOIN funcs f2 ON (best.chksum=f2.chksum AND best.maxrank=f2.rank)"#,
469
+
);
470
+
Ok(())
471
+
}
472
+
}
473
+
impl<'a> diesel::query_builder::QueryId for BestMds<'a> {
474
+
type QueryId = BestMds<'static>;
475
+
}
476
+
impl<'a> Query for BestMds<'a> {
477
+
type SqlType = (VarChar, Integer, Binary, Binary);
478
+
}
+1
-6
common/src/db/schema_auto.rs
+1
-6
common/src/db/schema_auto.rs
+8
-4
common/src/lib.rs
+8
-4
common/src/lib.rs
···
3
3
4
4
use std::fmt::Write;
5
5
6
+
pub mod async_drop;
7
+
pub mod config;
6
8
pub mod db;
7
-
pub mod config;
8
9
pub mod md;
10
+
pub mod metrics;
9
11
pub mod rpc;
10
12
pub mod web;
11
-
pub mod async_drop;
12
-
pub mod metrics;
13
13
14
14
pub struct SharedState_ {
15
15
pub db: db::Database,
···
33
33
}
34
34
35
35
let _ = write!(&mut output, " | ");
36
-
for ch in chunk.iter().chain(std::iter::repeat(&b' ').take(padding)).map(|&v| std::char::from_u32(v as u32).unwrap_or('.')) {
36
+
for ch in chunk
37
+
.iter()
38
+
.chain(std::iter::repeat(&b' ').take(padding))
39
+
.map(|&v| std::char::from_u32(v as u32).unwrap_or('.'))
40
+
{
37
41
if !ch.is_ascii_graphic() {
38
42
output.push('.');
39
43
} else {
+218
-214
common/src/md.rs
+218
-214
common/src/md.rs
···
1
-
use std::collections::HashSet;
2
-
3
-
use serde::{Serialize, Deserialize};
4
-
use crate::rpc::de::from_slice;
5
-
6
-
#[derive(Serialize, Deserialize)]
7
-
pub struct MetadataChunk<'a> {
8
-
code: u32,
9
-
data: &'a [u8],
10
-
}
11
-
12
-
#[derive(Debug)]
13
-
pub enum FunctionMetadata<'a> {
14
-
FunctionComment(FunctionComment<'a>),
15
-
ByteComment(ByteComment<'a>),
16
-
ExtraComment(ExtraComment<'a>),
17
-
}
18
-
19
-
#[derive(Debug)]
20
-
pub struct FunctionComment<'a> {
21
-
pub is_repeatable: bool,
22
-
pub comment: &'a str,
23
-
}
24
-
25
-
#[derive(Debug)]
26
-
pub struct ByteComment<'a> {
27
-
pub is_repeatable: bool,
28
-
pub offset: u32,
29
-
pub comment: &'a str,
30
-
}
31
-
32
-
#[derive(Debug)]
33
-
pub struct ExtraComment<'a> {
34
-
pub offset: u32,
35
-
pub anterior: &'a str,
36
-
pub posterior: &'a str,
37
-
}
38
-
39
-
impl<'a> FunctionMetadata<'a> {
40
-
fn is_useful(&self) -> bool {
41
-
// TODO: rewrite using regex with configurable library names
42
-
match self {
43
-
FunctionMetadata::ExtraComment(cmt) => {
44
-
if cmt.anterior.starts_with("; Exported entry ") // offset=0
45
-
{
46
-
return false;
47
-
}
48
-
if cmt.anterior.is_empty() && cmt.posterior.is_empty() {
49
-
return false;
50
-
}
51
-
},
52
-
FunctionMetadata::FunctionComment(cmt) => {
53
-
if cmt.comment == "Microsoft VisualC v14 64bit runtime"
54
-
|| cmt.comment == "Microsoft VisualC 64bit universal runtime"
55
-
{
56
-
return false;
57
-
}
58
-
if cmt.comment.is_empty() {
59
-
return false;
60
-
}
61
-
},
62
-
FunctionMetadata::ByteComment(cmt) => {
63
-
if cmt.comment == "Trap to Debugger"
64
-
|| (cmt.comment.starts_with("jumptable ") && cmt.comment.contains(" case")) // repeatable=true
65
-
|| cmt.comment == "switch jump"
66
-
|| (cmt.comment.starts_with("switch ") && cmt.comment.ends_with(" cases "))
67
-
|| cmt.comment == "jump table for switch statement"
68
-
|| cmt.comment == "indirect table for switch statement"
69
-
|| cmt.comment == "Microsoft VisualC v7/14 64bit runtime"
70
-
|| cmt.comment == "Microsoft VisualC v7/14 64bit runtime\nMicrosoft VisualC v14 64bit runtime"
71
-
|| cmt.comment == "Microsoft VisualC v14 64bit runtime" {
72
-
return false;
73
-
}
74
-
if cmt.comment.is_empty() {
75
-
return false;
76
-
}
77
-
},
78
-
}
79
-
true
80
-
}
81
-
}
82
-
83
-
fn deserialize_seq<'de, T: Deserialize<'de>>(mut data: &'de [u8]) -> Result<Vec<(u32, T)>, crate::rpc::Error> {
84
-
let mut res = vec![];
85
-
let mut reset = true;
86
-
let (mut offset, used): (u32, usize) = from_slice(data)?;
87
-
data = &data[used..];
88
-
if data.is_empty() {
89
-
return Err(crate::rpc::Error::UnexpectedEof);
90
-
}
91
-
92
-
loop {
93
-
let (offset_diff, used): (u32, usize) = from_slice(data)?;
94
-
data = &data[used..];
95
-
if data.is_empty() {
96
-
return Err(crate::rpc::Error::UnexpectedEof);
97
-
}
98
-
99
-
if (offset_diff > 0) || reset {
100
-
offset += offset_diff;
101
-
let (e, used): (T, usize) = from_slice(data)?;
102
-
data = &data[used..];
103
-
104
-
res.push((offset, e));
105
-
106
-
reset = false;
107
-
} else {
108
-
let (offset_diff, used): (u32, usize) = from_slice(data)?;
109
-
data = &data[used..];
110
-
111
-
offset = offset_diff;
112
-
reset = true;
113
-
}
114
-
115
-
if data.is_empty() {
116
-
break;
117
-
}
118
-
}
119
-
120
-
Ok(res)
121
-
}
122
-
123
-
pub fn parse_metadata(mut data: &[u8]) -> Result<Vec<FunctionMetadata<'_>>, crate::rpc::Error> {
124
-
let mut res = vec![];
125
-
let mut bad_codes = HashSet::new();
126
-
127
-
while !data.is_empty() {
128
-
let (chunk, used) :(MetadataChunk, _) = from_slice(data)?;
129
-
data = &data[used..];
130
-
131
-
let data = chunk.data;
132
-
133
-
if data.is_empty() {
134
-
continue;
135
-
}
136
-
137
-
match chunk.code {
138
-
1 => {}, // TODO: parse typeinfo
139
-
2 => {}, // nop
140
-
3 | 4 => { // function comments
141
-
let is_repeatable = chunk.code == 4;
142
-
let cmt = std::str::from_utf8(data)?;
143
-
res.push(FunctionMetadata::FunctionComment(FunctionComment{
144
-
is_repeatable,
145
-
comment: cmt,
146
-
}));
147
-
},
148
-
5 | 6 => { // comments
149
-
let is_repeatable = chunk.code == 6;
150
-
let byte_comments: Vec<(_, &[u8])> = match deserialize_seq(data) {
151
-
Ok(v) => v,
152
-
Err(err) => {
153
-
log::error!("err: {}\n{}", err, super::make_pretty_hex(data));
154
-
return Err(err);
155
-
},
156
-
};
157
-
158
-
for comment in byte_comments {
159
-
let cmt = std::str::from_utf8(comment.1)?;
160
-
res.push(FunctionMetadata::ByteComment(
161
-
ByteComment{
162
-
is_repeatable,
163
-
offset: comment.0,
164
-
comment: cmt,
165
-
}
166
-
));
167
-
}
168
-
},
169
-
7 => { // extra comments
170
-
let byte_comments: Vec<(_, (&[u8], &[u8]))> = match deserialize_seq(data) {
171
-
Ok(v) => v,
172
-
Err(err) => {
173
-
log::error!("err: {}\n{}", err, super::make_pretty_hex(data));
174
-
return Err(err);
175
-
},
176
-
};
177
-
178
-
for comment in byte_comments {
179
-
res.push(FunctionMetadata::ExtraComment(ExtraComment{
180
-
offset: comment.0,
181
-
anterior: std::str::from_utf8(comment.1.0)?,
182
-
posterior: std::str::from_utf8(comment.1.1)?,
183
-
}));
184
-
}
185
-
},
186
-
9 | 10 => { /* TODO! */ },
187
-
_ => {
188
-
bad_codes.insert(chunk.code);
189
-
},
190
-
}
191
-
}
192
-
193
-
Ok(res)
194
-
}
195
-
196
-
pub fn get_score(md: &crate::rpc::PushMetadataFunc) -> u32 {
197
-
let mut score = 0;
198
-
199
-
let md = match parse_metadata(md.func_data) {
200
-
Ok(v) => v,
201
-
Err(e) => {
202
-
log::warn!("failed to parse metadata: {}", e);
203
-
return 0;
204
-
}
205
-
};
206
-
207
-
for md in md {
208
-
if md.is_useful() {
209
-
score += 10;
210
-
}
211
-
}
212
-
213
-
score
214
-
}
1
+
use std::collections::HashSet;
2
+
3
+
use crate::rpc::de::from_slice;
4
+
use serde::{Deserialize, Serialize};
5
+
6
+
#[derive(Serialize, Deserialize)]
7
+
pub struct MetadataChunk<'a> {
8
+
code: u32,
9
+
data: &'a [u8],
10
+
}
11
+
12
+
#[derive(Debug)]
13
+
pub enum FunctionMetadata<'a> {
14
+
FunctionComment(FunctionComment<'a>),
15
+
ByteComment(ByteComment<'a>),
16
+
ExtraComment(ExtraComment<'a>),
17
+
}
18
+
19
+
#[derive(Debug)]
20
+
pub struct FunctionComment<'a> {
21
+
pub is_repeatable: bool,
22
+
pub comment: &'a str,
23
+
}
24
+
25
+
#[derive(Debug)]
26
+
pub struct ByteComment<'a> {
27
+
pub is_repeatable: bool,
28
+
pub offset: u32,
29
+
pub comment: &'a str,
30
+
}
31
+
32
+
#[derive(Debug)]
33
+
pub struct ExtraComment<'a> {
34
+
pub offset: u32,
35
+
pub anterior: &'a str,
36
+
pub posterior: &'a str,
37
+
}
38
+
39
+
impl<'a> FunctionMetadata<'a> {
40
+
fn is_useful(&self) -> bool {
41
+
// TODO: rewrite using regex with configurable library names
42
+
match self {
43
+
FunctionMetadata::ExtraComment(cmt) => {
44
+
if cmt.anterior.starts_with("; Exported entry ")
45
+
// offset=0
46
+
{
47
+
return false;
48
+
}
49
+
if cmt.anterior.is_empty() && cmt.posterior.is_empty() {
50
+
return false;
51
+
}
52
+
},
53
+
FunctionMetadata::FunctionComment(cmt) => {
54
+
if cmt.comment == "Microsoft VisualC v14 64bit runtime"
55
+
|| cmt.comment == "Microsoft VisualC 64bit universal runtime"
56
+
{
57
+
return false;
58
+
}
59
+
if cmt.comment.is_empty() {
60
+
return false;
61
+
}
62
+
},
63
+
FunctionMetadata::ByteComment(cmt) => {
64
+
if cmt.comment == "Trap to Debugger"
65
+
|| (cmt.comment.starts_with("jumptable ") && cmt.comment.contains(" case")) // repeatable=true
66
+
|| cmt.comment == "switch jump"
67
+
|| (cmt.comment.starts_with("switch ") && cmt.comment.ends_with(" cases "))
68
+
|| cmt.comment == "jump table for switch statement"
69
+
|| cmt.comment == "indirect table for switch statement"
70
+
|| cmt.comment == "Microsoft VisualC v7/14 64bit runtime"
71
+
|| cmt.comment == "Microsoft VisualC v7/14 64bit runtime\nMicrosoft VisualC v14 64bit runtime"
72
+
|| cmt.comment == "Microsoft VisualC v14 64bit runtime" {
73
+
return false;
74
+
}
75
+
if cmt.comment.is_empty() {
76
+
return false;
77
+
}
78
+
},
79
+
}
80
+
true
81
+
}
82
+
}
83
+
84
+
fn deserialize_seq<'de, T: Deserialize<'de>>(
85
+
mut data: &'de [u8],
86
+
) -> Result<Vec<(u32, T)>, crate::rpc::Error> {
87
+
let mut res = vec![];
88
+
let mut reset = true;
89
+
let (mut offset, used): (u32, usize) = from_slice(data)?;
90
+
data = &data[used..];
91
+
if data.is_empty() {
92
+
return Err(crate::rpc::Error::UnexpectedEof);
93
+
}
94
+
95
+
loop {
96
+
let (offset_diff, used): (u32, usize) = from_slice(data)?;
97
+
data = &data[used..];
98
+
if data.is_empty() {
99
+
return Err(crate::rpc::Error::UnexpectedEof);
100
+
}
101
+
102
+
if (offset_diff > 0) || reset {
103
+
offset += offset_diff;
104
+
let (e, used): (T, usize) = from_slice(data)?;
105
+
data = &data[used..];
106
+
107
+
res.push((offset, e));
108
+
109
+
reset = false;
110
+
} else {
111
+
let (offset_diff, used): (u32, usize) = from_slice(data)?;
112
+
data = &data[used..];
113
+
114
+
offset = offset_diff;
115
+
reset = true;
116
+
}
117
+
118
+
if data.is_empty() {
119
+
break;
120
+
}
121
+
}
122
+
123
+
Ok(res)
124
+
}
125
+
126
+
pub fn parse_metadata(mut data: &[u8]) -> Result<Vec<FunctionMetadata<'_>>, crate::rpc::Error> {
127
+
let mut res = vec![];
128
+
let mut bad_codes = HashSet::new();
129
+
130
+
while !data.is_empty() {
131
+
let (chunk, used): (MetadataChunk, _) = from_slice(data)?;
132
+
data = &data[used..];
133
+
134
+
let data = chunk.data;
135
+
136
+
if data.is_empty() {
137
+
continue;
138
+
}
139
+
140
+
match chunk.code {
141
+
1 => {}, // TODO: parse typeinfo
142
+
2 => {}, // nop
143
+
3 | 4 => {
144
+
// function comments
145
+
let is_repeatable = chunk.code == 4;
146
+
let cmt = std::str::from_utf8(data)?;
147
+
res.push(FunctionMetadata::FunctionComment(FunctionComment {
148
+
is_repeatable,
149
+
comment: cmt,
150
+
}));
151
+
},
152
+
5 | 6 => {
153
+
// comments
154
+
let is_repeatable = chunk.code == 6;
155
+
let byte_comments: Vec<(_, &[u8])> = match deserialize_seq(data) {
156
+
Ok(v) => v,
157
+
Err(err) => {
158
+
log::error!("err: {}\n{}", err, super::make_pretty_hex(data));
159
+
return Err(err);
160
+
},
161
+
};
162
+
163
+
for comment in byte_comments {
164
+
let cmt = std::str::from_utf8(comment.1)?;
165
+
res.push(FunctionMetadata::ByteComment(ByteComment {
166
+
is_repeatable,
167
+
offset: comment.0,
168
+
comment: cmt,
169
+
}));
170
+
}
171
+
},
172
+
7 => {
173
+
// extra comments
174
+
let byte_comments: Vec<(_, (&[u8], &[u8]))> = match deserialize_seq(data) {
175
+
Ok(v) => v,
176
+
Err(err) => {
177
+
log::error!("err: {}\n{}", err, super::make_pretty_hex(data));
178
+
return Err(err);
179
+
},
180
+
};
181
+
182
+
for comment in byte_comments {
183
+
res.push(FunctionMetadata::ExtraComment(ExtraComment {
184
+
offset: comment.0,
185
+
anterior: std::str::from_utf8(comment.1 .0)?,
186
+
posterior: std::str::from_utf8(comment.1 .1)?,
187
+
}));
188
+
}
189
+
},
190
+
9 | 10 => { /* TODO! */ },
191
+
_ => {
192
+
bad_codes.insert(chunk.code);
193
+
},
194
+
}
195
+
}
196
+
197
+
Ok(res)
198
+
}
199
+
200
+
pub fn get_score(md: &crate::rpc::PushMetadataFunc) -> u32 {
201
+
let mut score = 0;
202
+
203
+
let md = match parse_metadata(md.func_data) {
204
+
Ok(v) => v,
205
+
Err(e) => {
206
+
log::warn!("failed to parse metadata: {}", e);
207
+
return 0;
208
+
},
209
+
};
210
+
211
+
for md in md {
212
+
if md.is_useful() {
213
+
score += 10;
214
+
}
215
+
}
216
+
217
+
score
218
+
}
+20
-4
common/src/metrics.rs
+20
-4
common/src/metrics.rs
···
1
1
use std::sync::atomic::AtomicI64;
2
2
3
-
use prometheus_client::{registry::Registry, metrics::{gauge::Gauge, family::Family, counter::Counter}, encoding::EncodeLabelSet};
3
+
use prometheus_client::{
4
+
encoding::EncodeLabelSet,
5
+
metrics::{counter::Counter, family::Family, gauge::Gauge},
6
+
registry::Registry,
7
+
};
4
8
5
9
pub struct Metrics {
6
10
pub registry: Registry,
···
34
38
let mut registry = Registry::default();
35
39
36
40
let active_connections = Gauge::default();
37
-
registry.register("lumen_active_connections", "Active Lumina connections", active_connections.clone());
41
+
registry.register(
42
+
"lumen_active_connections",
43
+
"Active Lumina connections",
44
+
active_connections.clone(),
45
+
);
38
46
39
47
let lumina_version = Family::<LuminaVersion, Gauge>::default();
40
-
registry.register("lumen_protocol_version", "Version of Lumina protocol being used", lumina_version.clone());
48
+
registry.register(
49
+
"lumen_protocol_version",
50
+
"Version of Lumina protocol being used",
51
+
lumina_version.clone(),
52
+
);
41
53
42
54
let new_funcs = Counter::default();
43
-
registry.register("lumen_new_funcs", "Pushes previously unknown functions", new_funcs.clone());
55
+
registry.register(
56
+
"lumen_new_funcs",
57
+
"Pushes previously unknown functions",
58
+
new_funcs.clone(),
59
+
);
44
60
45
61
let pushes = Counter::default();
46
62
registry.register("lumen_pushes_total", "Total pushes functions", pushes.clone());
+163
-159
common/src/rpc/de.rs
+163
-159
common/src/rpc/de.rs
···
1
-
use serde::Deserialize;
2
-
use serde::de::{self, DeserializeSeed, SeqAccess, Visitor};
3
-
use super::Error;
4
-
5
-
struct Deserializer<'de> {
6
-
input: &'de [u8],
7
-
}
8
-
9
-
impl<'de> Deserializer<'de> {
10
-
fn from_bytes(b: &'de [u8]) -> Self {
11
-
Self {
12
-
input: b,
13
-
}
14
-
}
15
-
16
-
fn unpack_dd(&mut self) -> Result<u32, Error> {
17
-
let (v, len) = super::packing::unpack_dd(self.input);
18
-
if len == 0 {
19
-
Err(Error::UnexpectedEof)
20
-
} else {
21
-
self.input = &self.input[len..];
22
-
Ok(v)
23
-
}
24
-
}
25
-
26
-
fn unpack_dq(&mut self) -> Result<u64, Error> {
27
-
let a = self.unpack_dd()? as u64;
28
-
let b = self.unpack_dd()? as u64;
29
-
Ok((a << 32) | b)
30
-
}
31
-
32
-
fn unpack_var_bytes(&mut self) -> Result<&'de [u8], Error> {
33
-
let bytes = self.unpack_dd()? as usize;
34
-
if bytes > self.input.len() {
35
-
return Err(Error::UnexpectedEof);
36
-
}
37
-
38
-
let payload = &self.input[..bytes];
39
-
self.input = &self.input[bytes..];
40
-
assert_eq!(payload.len(), bytes);
41
-
42
-
Ok(payload)
43
-
}
44
-
45
-
fn unpack_cstr(&mut self) -> Result<&'de str, Error> {
46
-
let len = self.input.iter().enumerate().find_map(|(idx, &v)| if v == 0 { Some(idx) } else { None });
47
-
let len = match len {
48
-
Some(v) => v,
49
-
None => return Err(Error::UnexpectedEof),
50
-
};
51
-
let res = match std::str::from_utf8(&self.input[..len]) {
52
-
Ok(v) => v,
53
-
Err(err) => {
54
-
return Err(err.into());
55
-
}
56
-
};
57
-
self.input = &self.input[len + 1..];
58
-
Ok(res)
59
-
}
60
-
61
-
fn take_byte(&mut self) -> Result<u8, Error> {
62
-
if self.input.is_empty() {
63
-
return Err(Error::UnexpectedEof);
64
-
}
65
-
66
-
let v = self.input[0];
67
-
self.input = &self.input[1..];
68
-
Ok(v)
69
-
}
70
-
}
71
-
72
-
/// Returns: a tuple containing the deserialized struct and the bytes used
73
-
pub fn from_slice<'a, T: Deserialize<'a>>(b: &'a [u8]) -> Result<(T, usize), Error> {
74
-
let mut de = Deserializer::from_bytes(b);
75
-
let v = T::deserialize(&mut de)?;
76
-
Ok((v, b.len() - de.input.len()))
77
-
}
78
-
79
-
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
80
-
type Error = Error;
81
-
82
-
fn deserialize_any<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Self::Error> {
83
-
unimplemented!()
84
-
}
85
-
86
-
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
87
-
visitor.visit_u8(self.take_byte()?)
88
-
}
89
-
90
-
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
91
-
visitor.visit_u32(self.unpack_dd()?)
92
-
}
93
-
94
-
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
95
-
visitor.visit_u64(self.unpack_dq()?)
96
-
}
97
-
98
-
fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
99
-
let len = self.unpack_dd()?;
100
-
101
-
visitor.visit_seq(Access {
102
-
len: len as usize,
103
-
de: &mut *self,
104
-
})
105
-
}
106
-
107
-
fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
108
-
visitor.visit_borrowed_str(self.unpack_cstr()?)
109
-
}
110
-
111
-
fn deserialize_bytes<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
112
-
let v = self.unpack_var_bytes()?;
113
-
visitor.visit_borrowed_bytes(v)
114
-
}
115
-
116
-
fn deserialize_tuple<V: Visitor<'de>>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> {
117
-
visitor.visit_seq(Access {
118
-
len,
119
-
de: &mut *self,
120
-
})
121
-
}
122
-
123
-
fn deserialize_tuple_struct<V: Visitor<'de>>(self, _name: &'static str, len: usize, visitor: V) -> Result<V::Value, Self::Error> {
124
-
self.deserialize_tuple(len, visitor)
125
-
}
126
-
127
-
fn deserialize_struct<V: Visitor<'de>>(self, name: &'static str, fields: &'static [&'static str], visitor: V) -> Result<V::Value, Self::Error> {
128
-
self.deserialize_tuple_struct(name, fields.len(), visitor)
129
-
}
130
-
131
-
serde::forward_to_deserialize_any! {
132
-
i8 i16 i32 i64 char u16 bool
133
-
f32 f64 string byte_buf option unit unit_struct newtype_struct map enum identifier ignored_any
134
-
}
135
-
}
136
-
137
-
struct Access<'a, 'de> {
138
-
de: &'a mut Deserializer<'de>,
139
-
len: usize,
140
-
}
141
-
142
-
impl<'de, 'a> SeqAccess<'a> for Access<'de, 'a> {
143
-
type Error = Error;
144
-
145
-
fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> {
146
-
if self.len > 0 {
147
-
self.len -= 1;
148
-
149
-
let v = serde::de::DeserializeSeed::deserialize(seed, &mut *self.de)?;
150
-
Ok(Some(v))
151
-
} else {
152
-
Ok(None)
153
-
}
154
-
}
155
-
156
-
fn size_hint(&self) -> Option<usize> {
157
-
Some(self.len)
158
-
}
159
-
}
1
+
use super::Error;
2
+
use serde::de::{self, DeserializeSeed, SeqAccess, Visitor};
3
+
use serde::Deserialize;
4
+
5
+
struct Deserializer<'de> {
6
+
input: &'de [u8],
7
+
}
8
+
9
+
impl<'de> Deserializer<'de> {
10
+
fn from_bytes(b: &'de [u8]) -> Self {
11
+
Self { input: b }
12
+
}
13
+
14
+
fn unpack_dd(&mut self) -> Result<u32, Error> {
15
+
let (v, len) = super::packing::unpack_dd(self.input);
16
+
if len == 0 {
17
+
Err(Error::UnexpectedEof)
18
+
} else {
19
+
self.input = &self.input[len..];
20
+
Ok(v)
21
+
}
22
+
}
23
+
24
+
fn unpack_dq(&mut self) -> Result<u64, Error> {
25
+
let a = self.unpack_dd()? as u64;
26
+
let b = self.unpack_dd()? as u64;
27
+
Ok((a << 32) | b)
28
+
}
29
+
30
+
fn unpack_var_bytes(&mut self) -> Result<&'de [u8], Error> {
31
+
let bytes = self.unpack_dd()? as usize;
32
+
if bytes > self.input.len() {
33
+
return Err(Error::UnexpectedEof);
34
+
}
35
+
36
+
let payload = &self.input[..bytes];
37
+
self.input = &self.input[bytes..];
38
+
assert_eq!(payload.len(), bytes);
39
+
40
+
Ok(payload)
41
+
}
42
+
43
+
fn unpack_cstr(&mut self) -> Result<&'de str, Error> {
44
+
let len = self
45
+
.input
46
+
.iter()
47
+
.enumerate()
48
+
.find_map(|(idx, &v)| if v == 0 { Some(idx) } else { None });
49
+
let len = match len {
50
+
Some(v) => v,
51
+
None => return Err(Error::UnexpectedEof),
52
+
};
53
+
let res = match std::str::from_utf8(&self.input[..len]) {
54
+
Ok(v) => v,
55
+
Err(err) => {
56
+
return Err(err.into());
57
+
},
58
+
};
59
+
self.input = &self.input[len + 1..];
60
+
Ok(res)
61
+
}
62
+
63
+
fn take_byte(&mut self) -> Result<u8, Error> {
64
+
if self.input.is_empty() {
65
+
return Err(Error::UnexpectedEof);
66
+
}
67
+
68
+
let v = self.input[0];
69
+
self.input = &self.input[1..];
70
+
Ok(v)
71
+
}
72
+
}
73
+
74
+
/// Returns: a tuple containing the deserialized struct and the bytes used
75
+
pub fn from_slice<'a, T: Deserialize<'a>>(b: &'a [u8]) -> Result<(T, usize), Error> {
76
+
let mut de = Deserializer::from_bytes(b);
77
+
let v = T::deserialize(&mut de)?;
78
+
Ok((v, b.len() - de.input.len()))
79
+
}
80
+
81
+
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
82
+
type Error = Error;
83
+
84
+
fn deserialize_any<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Self::Error> {
85
+
unimplemented!()
86
+
}
87
+
88
+
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
89
+
visitor.visit_u8(self.take_byte()?)
90
+
}
91
+
92
+
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
93
+
visitor.visit_u32(self.unpack_dd()?)
94
+
}
95
+
96
+
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
97
+
visitor.visit_u64(self.unpack_dq()?)
98
+
}
99
+
100
+
fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
101
+
let len = self.unpack_dd()?;
102
+
103
+
visitor.visit_seq(Access { len: len as usize, de: &mut *self })
104
+
}
105
+
106
+
fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
107
+
visitor.visit_borrowed_str(self.unpack_cstr()?)
108
+
}
109
+
110
+
fn deserialize_bytes<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
111
+
let v = self.unpack_var_bytes()?;
112
+
visitor.visit_borrowed_bytes(v)
113
+
}
114
+
115
+
fn deserialize_tuple<V: Visitor<'de>>(
116
+
self, len: usize, visitor: V,
117
+
) -> Result<V::Value, Self::Error> {
118
+
visitor.visit_seq(Access { len, de: &mut *self })
119
+
}
120
+
121
+
fn deserialize_tuple_struct<V: Visitor<'de>>(
122
+
self, _name: &'static str, len: usize, visitor: V,
123
+
) -> Result<V::Value, Self::Error> {
124
+
self.deserialize_tuple(len, visitor)
125
+
}
126
+
127
+
fn deserialize_struct<V: Visitor<'de>>(
128
+
self, name: &'static str, fields: &'static [&'static str], visitor: V,
129
+
) -> Result<V::Value, Self::Error> {
130
+
self.deserialize_tuple_struct(name, fields.len(), visitor)
131
+
}
132
+
133
+
serde::forward_to_deserialize_any! {
134
+
i8 i16 i32 i64 char u16 bool
135
+
f32 f64 string byte_buf option unit unit_struct newtype_struct map enum identifier ignored_any
136
+
}
137
+
}
138
+
139
+
struct Access<'a, 'de> {
140
+
de: &'a mut Deserializer<'de>,
141
+
len: usize,
142
+
}
143
+
144
+
impl<'de, 'a> SeqAccess<'a> for Access<'de, 'a> {
145
+
type Error = Error;
146
+
147
+
fn next_element_seed<T: DeserializeSeed<'a>>(
148
+
&mut self, seed: T,
149
+
) -> Result<Option<T::Value>, Self::Error> {
150
+
if self.len > 0 {
151
+
self.len -= 1;
152
+
153
+
let v = serde::de::DeserializeSeed::deserialize(seed, &mut *self.de)?;
154
+
Ok(Some(v))
155
+
} else {
156
+
Ok(None)
157
+
}
158
+
}
159
+
160
+
fn size_hint(&self) -> Option<usize> {
161
+
Some(self.len)
162
+
}
163
+
}
+156
-118
common/src/rpc/messages.rs
+156
-118
common/src/rpc/messages.rs
···
1
-
use serde::{Serialize, Deserialize};
2
-
use std::borrow::Cow;
3
-
4
-
#[derive(Deserialize, Serialize)]
5
-
pub struct RpcFail<'a> {
6
-
pub code: u32,
7
-
pub message: &'a str,
8
-
}
9
-
10
-
#[derive(Serialize, Deserialize)]
11
-
pub struct RpcNotify<'a> {
12
-
pub code: u32,
13
-
pub msg: &'a str,
14
-
}
15
-
16
-
#[derive(Serialize, Deserialize, Debug)]
17
-
pub struct Creds<'a> {
18
-
pub username: &'a str,
19
-
pub password: &'a str,
20
-
}
21
-
22
-
#[derive(Serialize, Deserialize)]
23
-
pub struct RpcHello<'a> {
24
-
pub protocol_version: u32,
25
-
pub license_data: &'a [u8],
26
-
pub lic_number: [u8; 6],
27
-
pub unk2: u32,
28
-
}
29
-
30
-
#[derive(Deserialize, Serialize, Clone)]
31
-
pub struct PullMetadataFunc<'a> {
32
-
pub unk0: u32,
33
-
pub mb_hash: &'a [u8],
34
-
}
35
-
36
-
#[derive(Deserialize, Serialize)]
37
-
pub struct PullMetadata<'a> {
38
-
pub unk0: u32,
39
-
pub unk1: Cow<'a, [u32]>,
40
-
41
-
#[serde(borrow)]
42
-
pub funcs: Cow<'a, [PullMetadataFunc<'a>]>,
43
-
}
44
-
45
-
#[derive(Deserialize, Serialize, Clone)]
46
-
pub struct PullMetadataResultFunc<'a> {
47
-
pub name: Cow<'a, str>,
48
-
pub len: u32,
49
-
pub mb_data: Cow<'a, [u8]>,
50
-
pub popularity: u32,
51
-
}
52
-
53
-
#[derive(Deserialize, Serialize)]
54
-
pub struct PullMetadataResult<'a> {
55
-
pub unk0: Cow<'a, [u32]>,
56
-
#[serde(borrow)]
57
-
pub funcs: Cow<'a, [PullMetadataResultFunc<'a>]>,
58
-
}
59
-
60
-
#[derive(Clone, Deserialize, Serialize)]
61
-
pub struct PushMetadataFunc<'a> {
62
-
pub name: &'a str,
63
-
pub func_len: u32,
64
-
pub func_data: &'a [u8],
65
-
66
-
// PullMetadata's fields (tuple 'unk2') are similar to these two
67
-
pub unk2: u32,
68
-
pub hash: &'a [u8],
69
-
}
70
-
71
-
#[derive(Deserialize, Serialize)]
72
-
pub struct PushMetadata<'a> {
73
-
pub unk0: u32,
74
-
pub idb_path: &'a str,
75
-
pub file_path: &'a str,
76
-
pub md5: [u8; 16],
77
-
pub hostname: &'a str,
78
-
pub funcs: Cow<'a, [PushMetadataFunc<'a>]>,
79
-
pub unk1: Cow<'a, [u64]>,
80
-
}
81
-
82
-
#[derive(Deserialize, Serialize)]
83
-
pub struct PushMetadataResult<'a> {
84
-
// array of 0=exists, 1=NEW
85
-
pub status: Cow<'a, [u32]>,
86
-
}
87
-
88
-
#[derive(Debug, Deserialize, Serialize)]
89
-
pub struct DelHistory<'a> {
90
-
pub unk0: u32, // =0x08
91
-
pub unk1: Cow<'a, [Cow<'a, str>]>,
92
-
pub unk2: Cow<'a, [[u64; 2]]>,
93
-
pub unk3: Cow<'a, [[u64; 2]]>,
94
-
pub unk4: Cow<'a, [Cow<'a, str>]>,
95
-
pub unk5: Cow<'a, [Cow<'a, str>]>,
96
-
pub unk6: Cow<'a, [Cow<'a, str>]>,
97
-
pub unk7: Cow<'a, [Cow<'a, str>]>,
98
-
pub unk8: Cow<'a, [Cow<'a, [u8; 16]>]>,
99
-
pub funcs: Cow<'a, [Cow<'a, [u8; 16]>]>,
100
-
pub unk10: Cow<'a, [[u64; 2]]>,
101
-
pub unk11: u64,
102
-
}
103
-
104
-
#[derive(Deserialize, Serialize)]
105
-
pub struct DelHistoryResult {
106
-
pub deleted_mds: u32,
107
-
}
108
-
109
-
#[derive(Debug, Deserialize, Serialize)]
110
-
pub struct HelloResult<'a> {
111
-
pub unk0: Cow<'a, str>,
112
-
pub unk1: Cow<'a, str>,
113
-
pub unk2: Cow<'a, str>,
114
-
pub unk3: Cow<'a, str>,
115
-
pub unk4: u32,
116
-
pub unk5: u64,
117
-
pub unk6: u32,
118
-
}
1
+
use serde::{Deserialize, Serialize};
2
+
use std::borrow::Cow;
3
+
4
+
#[derive(Deserialize, Serialize)]
5
+
pub struct RpcFail<'a> {
6
+
pub code: u32,
7
+
pub message: &'a str,
8
+
}
9
+
10
+
#[derive(Serialize, Deserialize)]
11
+
pub struct RpcNotify<'a> {
12
+
pub code: u32,
13
+
pub msg: &'a str,
14
+
}
15
+
16
+
#[derive(Serialize, Deserialize, Debug)]
17
+
pub struct Creds<'a> {
18
+
pub username: &'a str,
19
+
pub password: &'a str,
20
+
}
21
+
22
+
#[derive(Serialize, Deserialize)]
23
+
pub struct RpcHello<'a> {
24
+
pub protocol_version: u32,
25
+
pub license_data: &'a [u8],
26
+
pub lic_number: [u8; 6],
27
+
pub unk2: u32,
28
+
}
29
+
30
+
#[derive(Debug, Deserialize, Serialize, Clone)]
31
+
pub struct PullMetadataFunc<'a> {
32
+
pub unk0: u32,
33
+
pub mb_hash: &'a [u8],
34
+
}
35
+
36
+
#[derive(Deserialize, Serialize)]
37
+
pub struct PullMetadata<'a> {
38
+
pub unk0: u32,
39
+
pub unk1: Cow<'a, [u32]>,
40
+
41
+
#[serde(borrow)]
42
+
pub funcs: Cow<'a, [PullMetadataFunc<'a>]>,
43
+
}
44
+
45
+
#[derive(Deserialize, Serialize, Clone)]
46
+
pub struct PullMetadataResultFunc<'a> {
47
+
pub name: Cow<'a, str>,
48
+
pub len: u32,
49
+
pub mb_data: Cow<'a, [u8]>,
50
+
pub popularity: u32,
51
+
}
52
+
53
+
#[derive(Deserialize, Serialize)]
54
+
pub struct PullMetadataResult<'a> {
55
+
pub unk0: Cow<'a, [u32]>,
56
+
#[serde(borrow)]
57
+
pub funcs: Cow<'a, [PullMetadataResultFunc<'a>]>,
58
+
}
59
+
60
+
#[derive(Clone, Deserialize, Serialize)]
61
+
pub struct PushMetadataFunc<'a> {
62
+
pub name: &'a str,
63
+
pub func_len: u32,
64
+
pub func_data: &'a [u8],
65
+
66
+
// PullMetadata's fields (tuple 'unk2') are similar to these two
67
+
pub unk2: u32,
68
+
pub hash: &'a [u8],
69
+
}
70
+
71
+
#[derive(Deserialize, Serialize)]
72
+
pub struct PushMetadata<'a> {
73
+
pub unk0: u32,
74
+
pub idb_path: &'a str,
75
+
pub file_path: &'a str,
76
+
pub md5: [u8; 16],
77
+
pub hostname: &'a str,
78
+
pub funcs: Cow<'a, [PushMetadataFunc<'a>]>,
79
+
pub unk1: Cow<'a, [u64]>,
80
+
}
81
+
82
+
#[derive(Deserialize, Serialize)]
83
+
pub struct PushMetadataResult<'a> {
84
+
// array of 0=exists, 1=NEW
85
+
pub status: Cow<'a, [u32]>,
86
+
}
87
+
88
+
#[derive(Debug, Deserialize, Serialize)]
89
+
pub struct DelHistory<'a> {
90
+
pub unk0: u32, // =0x08
91
+
pub unk1: Cow<'a, [Cow<'a, str>]>,
92
+
pub unk2: Cow<'a, [[u64; 2]]>,
93
+
pub unk3: Cow<'a, [[u64; 2]]>,
94
+
pub unk4: Cow<'a, [Cow<'a, str>]>,
95
+
pub unk5: Cow<'a, [Cow<'a, str>]>,
96
+
pub unk6: Cow<'a, [Cow<'a, str>]>,
97
+
pub unk7: Cow<'a, [Cow<'a, str>]>,
98
+
pub unk8: Cow<'a, [Cow<'a, [u8; 16]>]>,
99
+
pub funcs: Cow<'a, [Cow<'a, [u8; 16]>]>,
100
+
pub unk10: Cow<'a, [[u64; 2]]>,
101
+
pub unk11: u64,
102
+
}
103
+
104
+
#[derive(Deserialize, Serialize)]
105
+
pub struct DelHistoryResult {
106
+
pub deleted_mds: u32,
107
+
}
108
+
109
+
#[derive(Debug, Deserialize, Serialize, Default)]
110
+
pub struct LicenseInfo<'a> {
111
+
pub id: Cow<'a, str>,
112
+
pub name: Cow<'a, str>,
113
+
pub email: Cow<'a, str>,
114
+
}
115
+
116
+
#[derive(Debug, Deserialize, Serialize, Default)]
117
+
pub struct HelloResult<'a> {
118
+
pub license_info: LicenseInfo<'a>,
119
+
pub username: Cow<'a, str>,
120
+
pub karma: u32,
121
+
pub last_active: u64,
122
+
pub features: u32,
123
+
}
124
+
125
+
#[derive(Debug, Deserialize, Serialize)]
126
+
pub struct GetFuncHistories<'a> {
127
+
#[serde(borrow)]
128
+
pub funcs: Cow<'a, [PullMetadataFunc<'a>]>,
129
+
pub unk0: u32,
130
+
}
131
+
132
+
#[derive(Debug, Deserialize, Serialize, Clone)]
133
+
pub struct FunctionHistory<'a> {
134
+
pub unk0: u64,
135
+
pub unk1: u64,
136
+
pub name: Cow<'a, str>,
137
+
pub metadata: Cow<'a, [u8]>,
138
+
pub timestamp: u64,
139
+
pub author_idx: u32,
140
+
pub idb_path_idx: u32,
141
+
}
142
+
143
+
#[derive(Debug, Deserialize, Serialize, Clone)]
144
+
pub struct FunctionHistories<'a> {
145
+
#[serde(borrow)]
146
+
pub log: Cow<'a, [FunctionHistory<'a>]>,
147
+
}
148
+
149
+
#[derive(Debug, Deserialize, Serialize)]
150
+
pub struct GetFuncHistoriesResult<'a> {
151
+
pub status: Cow<'a, [u32]>,
152
+
#[serde(borrow)]
153
+
pub funcs: Cow<'a, [FunctionHistories<'a>]>,
154
+
pub users: Cow<'a, [Cow<'a, str>]>,
155
+
pub dbs: Cow<'a, [Cow<'a, str>]>,
156
+
}
+257
-234
common/src/rpc/mod.rs
+257
-234
common/src/rpc/mod.rs
···
1
-
use tokio::io::{AsyncWriteExt, AsyncWrite, AsyncRead, AsyncReadExt};
2
-
use log::*;
3
-
mod ser;
4
-
pub(crate) mod de;
5
-
mod messages;
6
-
mod packing;
7
-
use serde::Serializer;
8
-
9
-
pub use messages::*;
10
-
11
-
#[derive(Debug)]
12
-
pub enum Error {
13
-
UnexpectedEof,
14
-
Utf8Error(std::str::Utf8Error),
15
-
IOError(std::io::Error),
16
-
Serde(String),
17
-
InvalidData,
18
-
OutOfMemory,
19
-
Todo,
20
-
Timeout,
21
-
Eof,
22
-
}
23
-
24
-
impl std::fmt::Display for Error {
25
-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26
-
std::fmt::Debug::fmt(self, f)
27
-
}
28
-
}
29
-
30
-
impl std::error::Error for Error {}
31
-
impl serde::ser::Error for Error {
32
-
fn custom<T: std::fmt::Display>(msg: T) -> Self {
33
-
Error::Serde(msg.to_string())
34
-
}
35
-
}
36
-
impl serde::de::Error for Error {
37
-
fn custom<T: std::fmt::Display>(msg: T) -> Self {
38
-
Error::Serde(msg.to_string())
39
-
}
40
-
}
41
-
impl From<std::io::Error> for Error {
42
-
fn from(v: std::io::Error) -> Self {
43
-
Error::IOError(v)
44
-
}
45
-
}
46
-
impl From<std::str::Utf8Error> for Error {
47
-
fn from(v: std::str::Utf8Error) -> Self {
48
-
Error::Utf8Error(v)
49
-
}
50
-
}
51
-
impl From<std::collections::TryReserveError> for Error {
52
-
fn from(v: std::collections::TryReserveError) -> Self {
53
-
error!("failed to allocate {} bytes", v);
54
-
Error::OutOfMemory
55
-
}
56
-
}
57
-
58
-
fn get_code_maxlen(code: u8) -> usize {
59
-
match code {
60
-
0x0e => 50 * 1024 * 1024, // PullMD: 50 MiB
61
-
0x10 => 200 * 1024 * 1024, // PushMD: 200 MiB
62
-
_ => 1024 * 50, // otherwise 50K
63
-
}
64
-
}
65
-
66
-
pub async fn read_packet<R: AsyncRead + Unpin>(mut reader: R) -> Result<Vec<u8>, Error> {
67
-
let mut head = [0u8; 5];
68
-
match reader.read_exact(&mut head).await {
69
-
Ok(_) => {},
70
-
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return Err(Error::Eof), // client decided to disconnect...
71
-
Err(e) => return Err(e.into()),
72
-
}
73
-
let code = head[4];
74
-
let mut buf_len = [0u8; 4];
75
-
buf_len.copy_from_slice(&head[..4]);
76
-
77
-
let buf_len = u32::from_be_bytes(buf_len) as usize;
78
-
if buf_len < 4 {
79
-
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "payload size is too small").into());
80
-
}
81
-
82
-
let max_len = get_code_maxlen(code);
83
-
84
-
if buf_len > max_len {
85
-
info!("maxium size exceeded: code={}: max={}; req={}", code, max_len, buf_len);
86
-
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "request length exceeded maximum limit").into());
87
-
}
88
-
89
-
// the additional byte is for the RPC code
90
-
trace!("expecting {} bytes...", buf_len);
91
-
let buf_len = buf_len + 1;
92
-
93
-
let mut data = Vec::new();
94
-
data.try_reserve_exact(buf_len)?;
95
-
data.resize(buf_len, 0);
96
-
data[0] = code;
97
-
reader.read_exact(&mut data[1..]).await?;
98
-
99
-
Ok(data)
100
-
}
101
-
102
-
async fn write_packet<W: AsyncWrite + Unpin>(mut w: W, data: &[u8]) -> Result<(), std::io::Error> {
103
-
let buf_len: u32 = (data.len() - 1) as u32;
104
-
let buf_len = buf_len.to_be_bytes();
105
-
w.write_all(&buf_len).await?;
106
-
w.write_all(data).await?;
107
-
Ok(())
108
-
}
109
-
110
-
pub enum RpcMessage<'a> {
111
-
Ok(()),
112
-
Fail(RpcFail<'a>),
113
-
Notify(RpcNotify<'a>),
114
-
Hello(RpcHello<'a>, Option<Creds<'a>>),
115
-
PullMetadata(PullMetadata<'a>),
116
-
PullMetadataResult(PullMetadataResult<'a>),
117
-
PushMetadata(PushMetadata<'a>),
118
-
PushMetadataResult(PushMetadataResult<'a>),
119
-
DelHistory(DelHistory<'a>),
120
-
DelHistoryResult(DelHistoryResult),
121
-
HelloResult(HelloResult<'a>),
122
-
}
123
-
124
-
impl<'a> serde::Serialize for RpcMessage<'a> {
125
-
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
126
-
use serde::ser::SerializeTuple;
127
-
128
-
let code = self.get_code();
129
-
let mut tuple = serializer.serialize_tuple(2)?;
130
-
131
-
// u8 is pushed without further encoding...
132
-
tuple.serialize_element(&code)?;
133
-
134
-
match self {
135
-
RpcMessage::Ok(msg) => tuple.serialize_element(msg)?,
136
-
RpcMessage::Fail(msg) => tuple.serialize_element(msg)?,
137
-
RpcMessage::Notify(msg) => tuple.serialize_element(msg)?,
138
-
RpcMessage::Hello(msg, _) => tuple.serialize_element(msg)?,
139
-
RpcMessage::PullMetadata(msg) => tuple.serialize_element(msg)?,
140
-
RpcMessage::PullMetadataResult(msg) => tuple.serialize_element(msg)?,
141
-
RpcMessage::PushMetadata(msg) => tuple.serialize_element(msg)?,
142
-
RpcMessage::PushMetadataResult(msg) => tuple.serialize_element(msg)?,
143
-
RpcMessage::DelHistory(msg) => tuple.serialize_element(msg)?,
144
-
RpcMessage::DelHistoryResult(msg) => tuple.serialize_element(msg)?,
145
-
RpcMessage::HelloResult(msg) => tuple.serialize_element(msg)?,
146
-
}
147
-
148
-
tuple.end()
149
-
}
150
-
}
151
-
152
-
impl<'a> RpcMessage<'a> {
153
-
fn deserialize_check<T: serde::Deserialize<'a>>(payload: &'a [u8]) -> Result<T, Error> {
154
-
let v = de::from_slice(payload)?;
155
-
if v.1 != payload.len() {
156
-
let bytes_remaining = crate::make_pretty_hex(&payload[v.1..]);
157
-
trace!("{} remaining bytes after deserializing {}\n{bytes_remaining}", payload.len() - v.1, std::any::type_name::<T>());
158
-
}
159
-
Ok(v.0)
160
-
}
161
-
162
-
pub fn deserialize(payload: &'a [u8]) -> Result<RpcMessage<'a>, Error> {
163
-
let msg_type = payload[0];
164
-
let payload = &payload[1..];
165
-
166
-
let res = match msg_type {
167
-
0x0a => {
168
-
if !payload.is_empty() {
169
-
trace!("Ok message with additional data: {} bytes: {payload:02x?}", payload.len());
170
-
}
171
-
RpcMessage::Ok(())
172
-
},
173
-
0x0b => RpcMessage::Fail(Self::deserialize_check(payload)?),
174
-
0x0c => RpcMessage::Notify(Self::deserialize_check(payload)?),
175
-
0x0d => {
176
-
let (hello, consumed) = de::from_slice::<messages::RpcHello>(payload)?;
177
-
let creds = if payload.len() > consumed && hello.protocol_version > 2 {
178
-
let payload = &payload[consumed..];
179
-
let (creds, consumed) = de::from_slice::<Creds>(payload)?;
180
-
if payload.len() != consumed {
181
-
trace!("bytes remaining after HelloV2: {payload:02x?}");
182
-
}
183
-
Some(creds)
184
-
} else {
185
-
if hello.protocol_version > 2 || payload.len() != consumed {
186
-
trace!("Unexpected Hello msg: {payload:02x?}");
187
-
}
188
-
None
189
-
};
190
-
RpcMessage::Hello(hello, creds)
191
-
},
192
-
0x0e => RpcMessage::PullMetadata(Self::deserialize_check(payload)?),
193
-
0x0f => RpcMessage::PullMetadataResult(Self::deserialize_check(payload)?),
194
-
0x10 => RpcMessage::PushMetadata(Self::deserialize_check(payload)?),
195
-
0x11 => RpcMessage::PushMetadataResult(Self::deserialize_check(payload)?),
196
-
0x18 => RpcMessage::DelHistory(Self::deserialize_check(payload)?),
197
-
0x19 => RpcMessage::DelHistoryResult(Self::deserialize_check(payload)?),
198
-
0x31 => RpcMessage::HelloResult(Self::deserialize_check(payload)?),
199
-
_ => {
200
-
trace!("got invalid message type '{:02x}'", msg_type);
201
-
return Err(Error::InvalidData);
202
-
},
203
-
};
204
-
205
-
Ok(res)
206
-
}
207
-
208
-
pub async fn async_write<W: AsyncWrite + Unpin>(&self, w: W) -> Result<(), Error> {
209
-
let mut output = Vec::with_capacity(32);
210
-
ser::to_writer(self, &mut output)?;
211
-
212
-
write_packet(w, &output).await?;
213
-
214
-
Ok(())
215
-
}
216
-
217
-
fn get_code(&self) -> u8 {
218
-
use RpcMessage::*;
219
-
220
-
match self {
221
-
Ok(_) => 0x0a,
222
-
Fail(_) => 0x0b,
223
-
Notify(_) => 0x0c,
224
-
Hello(..) => 0x0d,
225
-
PullMetadata(_) => 0x0e,
226
-
PullMetadataResult(_) => 0x0f,
227
-
PushMetadata(_) => 0x10,
228
-
PushMetadataResult(_) => 0x11,
229
-
DelHistory(_) => 0x18,
230
-
DelHistoryResult(_) => 0x19,
231
-
HelloResult(_) => 0x31,
232
-
}
233
-
}
234
-
}
1
+
use log::*;
2
+
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
3
+
pub(crate) mod de;
4
+
mod messages;
5
+
mod packing;
6
+
mod ser;
7
+
use serde::Serializer;
8
+
9
+
pub use messages::*;
10
+
11
+
#[derive(Debug)]
12
+
pub enum Error {
13
+
UnexpectedEof,
14
+
Utf8Error(std::str::Utf8Error),
15
+
IOError(std::io::Error),
16
+
Serde(String),
17
+
InvalidData,
18
+
OutOfMemory,
19
+
Todo,
20
+
Timeout,
21
+
Eof,
22
+
}
23
+
24
+
impl std::fmt::Display for Error {
25
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26
+
std::fmt::Debug::fmt(self, f)
27
+
}
28
+
}
29
+
30
+
impl std::error::Error for Error {}
31
+
impl serde::ser::Error for Error {
32
+
fn custom<T: std::fmt::Display>(msg: T) -> Self {
33
+
Error::Serde(msg.to_string())
34
+
}
35
+
}
36
+
impl serde::de::Error for Error {
37
+
fn custom<T: std::fmt::Display>(msg: T) -> Self {
38
+
Error::Serde(msg.to_string())
39
+
}
40
+
}
41
+
impl From<std::io::Error> for Error {
42
+
fn from(v: std::io::Error) -> Self {
43
+
Error::IOError(v)
44
+
}
45
+
}
46
+
impl From<std::str::Utf8Error> for Error {
47
+
fn from(v: std::str::Utf8Error) -> Self {
48
+
Error::Utf8Error(v)
49
+
}
50
+
}
51
+
impl From<std::collections::TryReserveError> for Error {
52
+
fn from(v: std::collections::TryReserveError) -> Self {
53
+
error!("failed to allocate {} bytes", v);
54
+
Error::OutOfMemory
55
+
}
56
+
}
57
+
58
+
fn get_code_maxlen(code: u8) -> usize {
59
+
match code {
60
+
0x0e => 50 * 1024 * 1024, // PullMD: 50 MiB
61
+
0x10 => 200 * 1024 * 1024, // PushMD: 200 MiB
62
+
_ => 1024 * 50, // otherwise 50K
63
+
}
64
+
}
65
+
66
+
pub async fn read_packet<R: AsyncRead + Unpin>(mut reader: R) -> Result<Vec<u8>, Error> {
67
+
let mut head = [0u8; 5];
68
+
match reader.read_exact(&mut head).await {
69
+
Ok(_) => {},
70
+
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return Err(Error::Eof), // client decided to disconnect...
71
+
Err(e) => return Err(e.into()),
72
+
}
73
+
let code = head[4];
74
+
let mut buf_len = [0u8; 4];
75
+
buf_len.copy_from_slice(&head[..4]);
76
+
77
+
let buf_len = u32::from_be_bytes(buf_len) as usize;
78
+
if buf_len < 4 {
79
+
return Err(std::io::Error::new(
80
+
std::io::ErrorKind::InvalidData,
81
+
"payload size is too small",
82
+
)
83
+
.into());
84
+
}
85
+
86
+
let max_len = get_code_maxlen(code);
87
+
88
+
if buf_len > max_len {
89
+
info!("maxium size exceeded: code={}: max={}; req={}", code, max_len, buf_len);
90
+
return Err(std::io::Error::new(
91
+
std::io::ErrorKind::InvalidData,
92
+
"request length exceeded maximum limit",
93
+
)
94
+
.into());
95
+
}
96
+
97
+
// the additional byte is for the RPC code
98
+
trace!("expecting {} bytes...", buf_len);
99
+
let buf_len = buf_len + 1;
100
+
101
+
let mut data = Vec::new();
102
+
data.try_reserve_exact(buf_len)?;
103
+
data.resize(buf_len, 0);
104
+
data[0] = code;
105
+
reader.read_exact(&mut data[1..]).await?;
106
+
107
+
Ok(data)
108
+
}
109
+
110
+
async fn write_packet<W: AsyncWrite + Unpin>(mut w: W, data: &[u8]) -> Result<(), std::io::Error> {
111
+
let buf_len: u32 = (data.len() - 1) as u32;
112
+
let buf_len = buf_len.to_be_bytes();
113
+
w.write_all(&buf_len).await?;
114
+
w.write_all(data).await?;
115
+
Ok(())
116
+
}
117
+
118
+
pub enum RpcMessage<'a> {
119
+
Ok(()),
120
+
Fail(RpcFail<'a>),
121
+
Notify(RpcNotify<'a>),
122
+
Hello(RpcHello<'a>, Option<Creds<'a>>),
123
+
PullMetadata(PullMetadata<'a>),
124
+
PullMetadataResult(PullMetadataResult<'a>),
125
+
PushMetadata(PushMetadata<'a>),
126
+
PushMetadataResult(PushMetadataResult<'a>),
127
+
DelHistory(DelHistory<'a>),
128
+
DelHistoryResult(DelHistoryResult),
129
+
GetFuncHistories(GetFuncHistories<'a>),
130
+
GetFuncHistoriesResult(GetFuncHistoriesResult<'a>),
131
+
HelloResult(HelloResult<'a>),
132
+
}
133
+
134
+
impl<'a> serde::Serialize for RpcMessage<'a> {
135
+
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
136
+
use serde::ser::SerializeTuple;
137
+
138
+
let code = self.get_code();
139
+
let mut tuple = serializer.serialize_tuple(2)?;
140
+
141
+
// u8 is pushed without further encoding...
142
+
tuple.serialize_element(&code)?;
143
+
144
+
match self {
145
+
RpcMessage::Ok(msg) => tuple.serialize_element(msg)?,
146
+
RpcMessage::Fail(msg) => tuple.serialize_element(msg)?,
147
+
RpcMessage::Notify(msg) => tuple.serialize_element(msg)?,
148
+
RpcMessage::Hello(msg, _) => tuple.serialize_element(msg)?,
149
+
RpcMessage::PullMetadata(msg) => tuple.serialize_element(msg)?,
150
+
RpcMessage::PullMetadataResult(msg) => tuple.serialize_element(msg)?,
151
+
RpcMessage::PushMetadata(msg) => tuple.serialize_element(msg)?,
152
+
RpcMessage::PushMetadataResult(msg) => tuple.serialize_element(msg)?,
153
+
RpcMessage::DelHistory(msg) => tuple.serialize_element(msg)?,
154
+
RpcMessage::DelHistoryResult(msg) => tuple.serialize_element(msg)?,
155
+
RpcMessage::GetFuncHistories(msg) => tuple.serialize_element(msg)?,
156
+
RpcMessage::GetFuncHistoriesResult(msg) => tuple.serialize_element(msg)?,
157
+
RpcMessage::HelloResult(msg) => tuple.serialize_element(msg)?,
158
+
}
159
+
160
+
tuple.end()
161
+
}
162
+
}
163
+
164
+
impl<'a> RpcMessage<'a> {
165
+
fn deserialize_check<T: serde::Deserialize<'a>>(payload: &'a [u8]) -> Result<T, Error> {
166
+
let v = de::from_slice(payload)?;
167
+
if v.1 != payload.len() {
168
+
let bytes_remaining = crate::make_pretty_hex(&payload[v.1..]);
169
+
trace!(
170
+
"{} remaining bytes after deserializing {}\n{bytes_remaining}",
171
+
payload.len() - v.1,
172
+
std::any::type_name::<T>()
173
+
);
174
+
}
175
+
Ok(v.0)
176
+
}
177
+
178
+
pub fn deserialize(payload: &'a [u8]) -> Result<RpcMessage<'a>, Error> {
179
+
let msg_type = payload[0];
180
+
let payload = &payload[1..];
181
+
182
+
let res = match msg_type {
183
+
0x0a => {
184
+
if !payload.is_empty() {
185
+
trace!(
186
+
"Ok message with additional data: {} bytes: {payload:02x?}",
187
+
payload.len()
188
+
);
189
+
}
190
+
RpcMessage::Ok(())
191
+
},
192
+
0x0b => RpcMessage::Fail(Self::deserialize_check(payload)?),
193
+
0x0c => RpcMessage::Notify(Self::deserialize_check(payload)?),
194
+
0x0d => {
195
+
let (hello, consumed) = de::from_slice::<messages::RpcHello>(payload)?;
196
+
let creds = if payload.len() > consumed && hello.protocol_version > 2 {
197
+
let payload = &payload[consumed..];
198
+
let (creds, consumed) = de::from_slice::<Creds>(payload)?;
199
+
if payload.len() != consumed {
200
+
trace!("bytes remaining after HelloV2: {payload:02x?}");
201
+
}
202
+
Some(creds)
203
+
} else {
204
+
if hello.protocol_version > 2 || payload.len() != consumed {
205
+
trace!("Unexpected Hello msg: {payload:02x?}");
206
+
}
207
+
None
208
+
};
209
+
RpcMessage::Hello(hello, creds)
210
+
},
211
+
0x0e => RpcMessage::PullMetadata(Self::deserialize_check(payload)?),
212
+
0x0f => RpcMessage::PullMetadataResult(Self::deserialize_check(payload)?),
213
+
0x10 => RpcMessage::PushMetadata(Self::deserialize_check(payload)?),
214
+
0x11 => RpcMessage::PushMetadataResult(Self::deserialize_check(payload)?),
215
+
0x18 => RpcMessage::DelHistory(Self::deserialize_check(payload)?),
216
+
0x19 => RpcMessage::DelHistoryResult(Self::deserialize_check(payload)?),
217
+
0x2f => RpcMessage::GetFuncHistories(Self::deserialize_check(payload)?),
218
+
0x30 => RpcMessage::GetFuncHistoriesResult(Self::deserialize_check(payload)?),
219
+
0x31 => RpcMessage::HelloResult(Self::deserialize_check(payload)?),
220
+
_ => {
221
+
trace!("got invalid message type '{:02x}'", msg_type);
222
+
return Err(Error::InvalidData);
223
+
},
224
+
};
225
+
226
+
Ok(res)
227
+
}
228
+
229
+
pub async fn async_write<W: AsyncWrite + Unpin>(&self, w: W) -> Result<(), Error> {
230
+
let mut output = Vec::with_capacity(32);
231
+
ser::to_writer(self, &mut output)?;
232
+
233
+
write_packet(w, &output).await?;
234
+
235
+
Ok(())
236
+
}
237
+
238
+
fn get_code(&self) -> u8 {
239
+
use RpcMessage::*;
240
+
241
+
match self {
242
+
Ok(_) => 0x0a,
243
+
Fail(_) => 0x0b,
244
+
Notify(_) => 0x0c,
245
+
Hello(..) => 0x0d,
246
+
PullMetadata(_) => 0x0e,
247
+
PullMetadataResult(_) => 0x0f,
248
+
PushMetadata(_) => 0x10,
249
+
PushMetadataResult(_) => 0x11,
250
+
DelHistory(_) => 0x18,
251
+
DelHistoryResult(_) => 0x19,
252
+
GetFuncHistories(_) => 0x2f,
253
+
GetFuncHistoriesResult(_) => 0x30,
254
+
HelloResult(_) => 0x31,
255
+
}
256
+
}
257
+
}
+111
-104
common/src/rpc/packing.rs
+111
-104
common/src/rpc/packing.rs
···
1
-
/// packs a dd into `buf` returning amout of bytes written.
2
-
/// Returns 0 if buffer is too small
3
-
pub fn pack_dd(v: u32, buf: &mut [u8]) -> usize {
4
-
let bytes = v.to_le_bytes();
5
-
match v {
6
-
0..=0x7f => { // 0..0XXXXXXX (7 bits)
7
-
if buf.is_empty() {
8
-
return 0;
9
-
}
10
-
buf[0] = bytes[0];
11
-
1
12
-
},
13
-
0x80..=0x3fff => { // 10AAAAAA..BBBBBBBB (14 bits)
14
-
if buf.len() < 2 {
15
-
return 0;
16
-
}
17
-
buf[0] = 0x80 | bytes[1];
18
-
buf[1] = bytes[0];
19
-
2
20
-
},
21
-
0x4000..=0x1fffff => { // 11000000_AAAAAAAA_BBBBBBBB_CCCCCCCC (24 bits)
22
-
if buf.len() < 3 {
23
-
return 0;
24
-
}
25
-
buf[0] = 0xc0;
26
-
buf[1] = bytes[2];
27
-
buf[2] = bytes[1];
28
-
buf[3] = bytes[0];
29
-
4
30
-
},
31
-
0x200000..=u32::MAX => { // 11111111_AAAAAAAA_BBBBBBBB_CCCCCCCC_DDDDDDDD (32 bits)
32
-
if buf.len() < 5 {
33
-
return 0;
34
-
}
35
-
buf[0] = 0xff;
36
-
buf[1] = bytes[3];
37
-
buf[2] = bytes[2];
38
-
buf[3] = bytes[1];
39
-
buf[4] = bytes[0];
40
-
5
41
-
}
42
-
}
43
-
}
44
-
45
-
/// unpacks a dd from `buf`, returning the amount (value, byte consumed)
46
-
pub fn unpack_dd(buf: &[u8]) -> (u32, usize) {
47
-
if buf.is_empty() {
48
-
return (0, 0);
49
-
}
50
-
51
-
let msb = buf[0];
52
-
let mut val = [0u8; 4];
53
-
54
-
if msb & 0x80 == 0 { // 0......
55
-
val[0] = msb;
56
-
return (u32::from_le_bytes(val), 1);
57
-
}
58
-
if msb & 0x40 == 0 { // 10....../0x80
59
-
if buf.len() < 2 {
60
-
return (0, 0);
61
-
}
62
-
val[1] = msb & 0x3f;
63
-
val[0] = buf[1];
64
-
return (u32::from_le_bytes(val), 2);
65
-
}
66
-
if msb & 0x20 == 0 { // 110...../0xC0
67
-
if buf.len() < 4 {
68
-
return (0, 0);
69
-
}
70
-
val[3] = msb & 0x1f;
71
-
val[2] = buf[1];
72
-
val[1] = buf[2];
73
-
val[0] = buf[3];
74
-
return (u32::from_le_bytes(val), 4);
75
-
}
76
-
77
-
if buf.len() < 5 {
78
-
return (0, 0);
79
-
}
80
-
81
-
val[3] = buf[1];
82
-
val[2] = buf[2];
83
-
val[1] = buf[3];
84
-
val[0] = buf[4];
85
-
86
-
(u32::from_le_bytes(val), 5)
87
-
}
88
-
89
-
#[cfg(test)]
90
-
mod tests {
91
-
#[test]
92
-
#[ignore = "this is a very time consuming test, it should be run in release/profiling mode"]
93
-
fn pack_all_nums() {
94
-
for num in 0..=u32::MAX {
95
-
let mut buf = [0u8; 5];
96
-
let rlen = super::pack_dd(num, &mut buf);
97
-
assert!(rlen > 0);
98
-
99
-
let unpacked = super::unpack_dd(&buf[..rlen]);
100
-
assert_eq!(unpacked.1, rlen, "bad unpack size");
101
-
assert_eq!(unpacked.0, num, "values don't match");
102
-
}
103
-
}
104
-
}
1
+
/// packs a dd into `buf` returning amout of bytes written.
2
+
/// Returns 0 if buffer is too small
3
+
pub fn pack_dd(v: u32, buf: &mut [u8]) -> usize {
4
+
let bytes = v.to_le_bytes();
5
+
match v {
6
+
0..=0x7f => {
7
+
// 0..0XXXXXXX (7 bits)
8
+
if buf.is_empty() {
9
+
return 0;
10
+
}
11
+
buf[0] = bytes[0];
12
+
1
13
+
},
14
+
0x80..=0x3fff => {
15
+
// 10AAAAAA..BBBBBBBB (14 bits)
16
+
if buf.len() < 2 {
17
+
return 0;
18
+
}
19
+
buf[0] = 0x80 | bytes[1];
20
+
buf[1] = bytes[0];
21
+
2
22
+
},
23
+
0x4000..=0x1fffff => {
24
+
// 11000000_AAAAAAAA_BBBBBBBB_CCCCCCCC (24 bits)
25
+
if buf.len() < 3 {
26
+
return 0;
27
+
}
28
+
buf[0] = 0xc0;
29
+
buf[1] = bytes[2];
30
+
buf[2] = bytes[1];
31
+
buf[3] = bytes[0];
32
+
4
33
+
},
34
+
0x200000..=u32::MAX => {
35
+
// 11111111_AAAAAAAA_BBBBBBBB_CCCCCCCC_DDDDDDDD (32 bits)
36
+
if buf.len() < 5 {
37
+
return 0;
38
+
}
39
+
buf[0] = 0xff;
40
+
buf[1] = bytes[3];
41
+
buf[2] = bytes[2];
42
+
buf[3] = bytes[1];
43
+
buf[4] = bytes[0];
44
+
5
45
+
},
46
+
}
47
+
}
48
+
49
+
/// unpacks a dd from `buf`, returning the amount (value, byte consumed)
50
+
pub fn unpack_dd(buf: &[u8]) -> (u32, usize) {
51
+
if buf.is_empty() {
52
+
return (0, 0);
53
+
}
54
+
55
+
let msb = buf[0];
56
+
let mut val = [0u8; 4];
57
+
58
+
if msb & 0x80 == 0 {
59
+
// 0......
60
+
val[0] = msb;
61
+
return (u32::from_le_bytes(val), 1);
62
+
}
63
+
if msb & 0x40 == 0 {
64
+
// 10....../0x80
65
+
if buf.len() < 2 {
66
+
return (0, 0);
67
+
}
68
+
val[1] = msb & 0x3f;
69
+
val[0] = buf[1];
70
+
return (u32::from_le_bytes(val), 2);
71
+
}
72
+
if msb & 0x20 == 0 {
73
+
// 110...../0xC0
74
+
if buf.len() < 4 {
75
+
return (0, 0);
76
+
}
77
+
val[3] = msb & 0x1f;
78
+
val[2] = buf[1];
79
+
val[1] = buf[2];
80
+
val[0] = buf[3];
81
+
return (u32::from_le_bytes(val), 4);
82
+
}
83
+
84
+
if buf.len() < 5 {
85
+
return (0, 0);
86
+
}
87
+
88
+
val[3] = buf[1];
89
+
val[2] = buf[2];
90
+
val[1] = buf[3];
91
+
val[0] = buf[4];
92
+
93
+
(u32::from_le_bytes(val), 5)
94
+
}
95
+
96
+
#[cfg(test)]
97
+
mod tests {
98
+
#[test]
99
+
#[ignore = "this is a very time consuming test, it should be run in release/profiling mode"]
100
+
fn pack_all_nums() {
101
+
for num in 0..=u32::MAX {
102
+
let mut buf = [0u8; 5];
103
+
let rlen = super::pack_dd(num, &mut buf);
104
+
assert!(rlen > 0);
105
+
106
+
let unpacked = super::unpack_dd(&buf[..rlen]);
107
+
assert_eq!(unpacked.1, rlen, "bad unpack size");
108
+
assert_eq!(unpacked.0, num, "values don't match");
109
+
}
110
+
}
111
+
}
+255
-241
common/src/rpc/ser.rs
+255
-241
common/src/rpc/ser.rs
···
1
-
use std::io::Write;
2
-
use serde::{ser, Serialize, ser::Impossible};
3
-
use super::Error;
4
-
5
-
struct Serializer<W: Write> {
6
-
output: W,
7
-
}
8
-
9
-
pub fn to_writer<T: Serialize, W: Write>(v: &T, w: W) -> Result<(), Error> {
10
-
let mut serializer = Serializer {
11
-
output: w,
12
-
};
13
-
v.serialize(&mut serializer)?;
14
-
Ok(())
15
-
}
16
-
17
-
#[allow(dead_code)]
18
-
pub fn to_vec<T: Serialize>(v: &T) -> Result<Vec<u8>, Error> {
19
-
let mut buf = vec![];
20
-
to_writer(v, &mut buf)?;
21
-
Ok(buf)
22
-
}
23
-
24
-
impl<W: Write> Serializer<W> {
25
-
fn pack_dd(&mut self, num: u32) -> Result<(), Error> {
26
-
let mut buf = [0u8; 5];
27
-
let bytes = super::packing::pack_dd(num, &mut buf);
28
-
self.output.write_all(&buf[..bytes])?;
29
-
Ok(())
30
-
}
31
-
32
-
fn pack_str(&mut self, s: &str) -> Result<(), Error> {
33
-
self.output.write_all(s.as_bytes())?;
34
-
self.output.write_all(&[0])?;
35
-
Ok(())
36
-
}
37
-
38
-
fn pack_bytes(&mut self, b: &[u8]) -> Result<(), Error> {
39
-
self.pack_dd(b.len() as u32)?;
40
-
self.output.write_all(b)?;
41
-
Ok(())
42
-
}
43
-
}
44
-
45
-
impl<'a, W: Write> ser::Serializer for &'a mut Serializer<W> {
46
-
type Ok = ();
47
-
type Error = Error;
48
-
49
-
type SerializeSeq = Self;
50
-
type SerializeTuple = Self;
51
-
type SerializeTupleStruct = Impossible<(), Self::Error>;
52
-
type SerializeTupleVariant = Impossible<(), Self::Error>;
53
-
type SerializeMap = Impossible<(), Self::Error>;
54
-
type SerializeStruct = Self;
55
-
type SerializeStructVariant = Impossible<(), Self::Error>;
56
-
57
-
fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
58
-
unreachable!()
59
-
}
60
-
61
-
fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
62
-
unreachable!()
63
-
}
64
-
65
-
fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
66
-
unreachable!()
67
-
}
68
-
69
-
fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
70
-
unreachable!()
71
-
}
72
-
73
-
fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
74
-
unreachable!()
75
-
}
76
-
77
-
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
78
-
self.output.write_all(&[v])?;
79
-
Ok(())
80
-
}
81
-
82
-
fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
83
-
unreachable!()
84
-
}
85
-
86
-
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
87
-
self.pack_dd(v)
88
-
}
89
-
90
-
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
91
-
let high = (v >> 32) & 0xffffffff;
92
-
let low = v & 0xffffffff;
93
-
self.pack_dd(high as u32)?;
94
-
self.pack_dd(low as u32)?;
95
-
Ok(())
96
-
}
97
-
98
-
fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
99
-
unreachable!()
100
-
}
101
-
102
-
fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
103
-
unreachable!()
104
-
}
105
-
106
-
fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
107
-
unreachable!()
108
-
}
109
-
110
-
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
111
-
self.pack_str(v)
112
-
}
113
-
114
-
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
115
-
self.pack_bytes(v)
116
-
}
117
-
118
-
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
119
-
unreachable!()
120
-
}
121
-
122
-
fn serialize_some<T: ?Sized + Serialize>(self, _value: &T) -> Result<Self::Ok, Self::Error> {
123
-
unreachable!()
124
-
}
125
-
126
-
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
127
-
// unit contains no information...
128
-
Ok(())
129
-
}
130
-
131
-
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
132
-
unreachable!()
133
-
}
134
-
135
-
fn serialize_unit_variant(self, _name: &'static str, _variant_index: u32, _variant: &'static str) -> Result<Self::Ok, Self::Error> {
136
-
unreachable!()
137
-
}
138
-
139
-
fn serialize_newtype_struct<T: ?Sized + Serialize>(self, _name: &'static str, _value: &T) -> Result<Self::Ok, Self::Error> {
140
-
unreachable!()
141
-
}
142
-
143
-
fn serialize_newtype_variant<T: ?Sized + Serialize>(self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T) -> Result<Self::Ok, Self::Error> {
144
-
unreachable!()
145
-
}
146
-
147
-
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
148
-
let len = len.unwrap();
149
-
self.pack_dd(len as u32)?;
150
-
Ok(self)
151
-
}
152
-
153
-
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
154
-
Ok(self)
155
-
}
156
-
157
-
fn serialize_tuple_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeTupleStruct, Self::Error> {
158
-
unreachable!();
159
-
}
160
-
161
-
fn serialize_tuple_variant(self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize) -> Result<Self::SerializeTupleVariant, Self::Error> {
162
-
unreachable!()
163
-
}
164
-
165
-
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
166
-
unreachable!()
167
-
}
168
-
169
-
fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct, Self::Error> {
170
-
// structs will simply be flattened
171
-
Ok(self)
172
-
}
173
-
174
-
fn serialize_struct_variant(self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize) -> Result<Self::SerializeStructVariant, Self::Error> {
175
-
unreachable!()
176
-
}
177
-
}
178
-
179
-
impl<'a, W: Write> ser::SerializeSeq for &'a mut Serializer<W> {
180
-
type Ok = ();
181
-
type Error = Error;
182
-
183
-
fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> {
184
-
value.serialize(&mut **self)
185
-
}
186
-
187
-
fn end(self) -> Result<Self::Ok, Self::Error> {
188
-
Ok(())
189
-
}
190
-
}
191
-
192
-
impl<'a, W: Write> ser::SerializeTuple for &'a mut Serializer<W> {
193
-
type Ok = ();
194
-
type Error = Error;
195
-
196
-
fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> {
197
-
value.serialize(&mut **self)
198
-
}
199
-
200
-
fn end(self) -> Result<Self::Ok, Self::Error> {
201
-
Ok(())
202
-
}
203
-
}
204
-
205
-
impl<'a, W: Write> ser::SerializeStruct for &'a mut Serializer<W> {
206
-
type Ok = ();
207
-
type Error = Error;
208
-
209
-
fn serialize_field<T: ?Sized + Serialize>(&mut self, _key: &'static str, value: &T) -> Result<(), Self::Error> {
210
-
// struct names have no meaning
211
-
value.serialize(&mut **self)
212
-
}
213
-
214
-
fn end(self) -> Result<Self::Ok, Self::Error> {
215
-
Ok(())
216
-
}
217
-
}
218
-
219
-
#[cfg(test)]
220
-
mod tests {
221
-
#[test]
222
-
fn ser_hello() {
223
-
#[derive(serde::Serialize)]
224
-
struct Test<'a> {
225
-
arr: [u8; 16],
226
-
s: &'a str,
227
-
b: &'a [u8],
228
-
i: u32,
229
-
q: u64,
230
-
}
231
-
let v = Test {
232
-
arr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
233
-
s: "somestring",
234
-
b: b"bytes",
235
-
i: 0x20,
236
-
q: 0x20,
237
-
};
238
-
let v = super::to_vec(&v).expect("failed to serialize dummy");
239
-
assert_eq!(v, b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10somestring\x00\x05bytes\x20\x00\x20");
240
-
}
241
-
}
1
+
use super::Error;
2
+
use serde::{ser, ser::Impossible, Serialize};
3
+
use std::io::Write;
4
+
5
+
struct Serializer<W: Write> {
6
+
output: W,
7
+
}
8
+
9
+
pub fn to_writer<T: Serialize, W: Write>(v: &T, w: W) -> Result<(), Error> {
10
+
let mut serializer = Serializer { output: w };
11
+
v.serialize(&mut serializer)?;
12
+
Ok(())
13
+
}
14
+
15
+
#[allow(dead_code)]
16
+
pub fn to_vec<T: Serialize>(v: &T) -> Result<Vec<u8>, Error> {
17
+
let mut buf = vec![];
18
+
to_writer(v, &mut buf)?;
19
+
Ok(buf)
20
+
}
21
+
22
+
impl<W: Write> Serializer<W> {
23
+
fn pack_dd(&mut self, num: u32) -> Result<(), Error> {
24
+
let mut buf = [0u8; 5];
25
+
let bytes = super::packing::pack_dd(num, &mut buf);
26
+
self.output.write_all(&buf[..bytes])?;
27
+
Ok(())
28
+
}
29
+
30
+
fn pack_str(&mut self, s: &str) -> Result<(), Error> {
31
+
self.output.write_all(s.as_bytes())?;
32
+
self.output.write_all(&[0])?;
33
+
Ok(())
34
+
}
35
+
36
+
fn pack_bytes(&mut self, b: &[u8]) -> Result<(), Error> {
37
+
self.pack_dd(b.len() as u32)?;
38
+
self.output.write_all(b)?;
39
+
Ok(())
40
+
}
41
+
}
42
+
43
+
impl<'a, W: Write> ser::Serializer for &'a mut Serializer<W> {
44
+
type Ok = ();
45
+
type Error = Error;
46
+
47
+
type SerializeSeq = Self;
48
+
type SerializeTuple = Self;
49
+
type SerializeTupleStruct = Impossible<(), Self::Error>;
50
+
type SerializeTupleVariant = Impossible<(), Self::Error>;
51
+
type SerializeMap = Impossible<(), Self::Error>;
52
+
type SerializeStruct = Self;
53
+
type SerializeStructVariant = Impossible<(), Self::Error>;
54
+
55
+
fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
56
+
unreachable!()
57
+
}
58
+
59
+
fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
60
+
unreachable!()
61
+
}
62
+
63
+
fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
64
+
unreachable!()
65
+
}
66
+
67
+
fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
68
+
unreachable!()
69
+
}
70
+
71
+
fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
72
+
unreachable!()
73
+
}
74
+
75
+
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
76
+
self.output.write_all(&[v])?;
77
+
Ok(())
78
+
}
79
+
80
+
fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
81
+
unreachable!()
82
+
}
83
+
84
+
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
85
+
self.pack_dd(v)
86
+
}
87
+
88
+
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
89
+
let high = (v >> 32) & 0xffffffff;
90
+
let low = v & 0xffffffff;
91
+
self.pack_dd(high as u32)?;
92
+
self.pack_dd(low as u32)?;
93
+
Ok(())
94
+
}
95
+
96
+
fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
97
+
unreachable!()
98
+
}
99
+
100
+
fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
101
+
unreachable!()
102
+
}
103
+
104
+
fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
105
+
unreachable!()
106
+
}
107
+
108
+
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
109
+
self.pack_str(v)
110
+
}
111
+
112
+
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
113
+
self.pack_bytes(v)
114
+
}
115
+
116
+
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
117
+
unreachable!()
118
+
}
119
+
120
+
fn serialize_some<T: ?Sized + Serialize>(self, _value: &T) -> Result<Self::Ok, Self::Error> {
121
+
unreachable!()
122
+
}
123
+
124
+
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
125
+
// unit contains no information...
126
+
Ok(())
127
+
}
128
+
129
+
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
130
+
unreachable!()
131
+
}
132
+
133
+
fn serialize_unit_variant(
134
+
self, _name: &'static str, _variant_index: u32, _variant: &'static str,
135
+
) -> Result<Self::Ok, Self::Error> {
136
+
unreachable!()
137
+
}
138
+
139
+
fn serialize_newtype_struct<T: ?Sized + Serialize>(
140
+
self, _name: &'static str, _value: &T,
141
+
) -> Result<Self::Ok, Self::Error> {
142
+
unreachable!()
143
+
}
144
+
145
+
fn serialize_newtype_variant<T: ?Sized + Serialize>(
146
+
self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T,
147
+
) -> Result<Self::Ok, Self::Error> {
148
+
unreachable!()
149
+
}
150
+
151
+
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
152
+
let len = len.unwrap();
153
+
self.pack_dd(len as u32)?;
154
+
Ok(self)
155
+
}
156
+
157
+
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
158
+
Ok(self)
159
+
}
160
+
161
+
fn serialize_tuple_struct(
162
+
self, _name: &'static str, _len: usize,
163
+
) -> Result<Self::SerializeTupleStruct, Self::Error> {
164
+
unreachable!();
165
+
}
166
+
167
+
fn serialize_tuple_variant(
168
+
self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize,
169
+
) -> Result<Self::SerializeTupleVariant, Self::Error> {
170
+
unreachable!()
171
+
}
172
+
173
+
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
174
+
unreachable!()
175
+
}
176
+
177
+
fn serialize_struct(
178
+
self, _name: &'static str, _len: usize,
179
+
) -> Result<Self::SerializeStruct, Self::Error> {
180
+
// structs will simply be flattened
181
+
Ok(self)
182
+
}
183
+
184
+
fn serialize_struct_variant(
185
+
self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize,
186
+
) -> Result<Self::SerializeStructVariant, Self::Error> {
187
+
unreachable!()
188
+
}
189
+
}
190
+
191
+
impl<'a, W: Write> ser::SerializeSeq for &'a mut Serializer<W> {
192
+
type Ok = ();
193
+
type Error = Error;
194
+
195
+
fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> {
196
+
value.serialize(&mut **self)
197
+
}
198
+
199
+
fn end(self) -> Result<Self::Ok, Self::Error> {
200
+
Ok(())
201
+
}
202
+
}
203
+
204
+
impl<'a, W: Write> ser::SerializeTuple for &'a mut Serializer<W> {
205
+
type Ok = ();
206
+
type Error = Error;
207
+
208
+
fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> {
209
+
value.serialize(&mut **self)
210
+
}
211
+
212
+
fn end(self) -> Result<Self::Ok, Self::Error> {
213
+
Ok(())
214
+
}
215
+
}
216
+
217
+
impl<'a, W: Write> ser::SerializeStruct for &'a mut Serializer<W> {
218
+
type Ok = ();
219
+
type Error = Error;
220
+
221
+
fn serialize_field<T: ?Sized + Serialize>(
222
+
&mut self, _key: &'static str, value: &T,
223
+
) -> Result<(), Self::Error> {
224
+
// struct names have no meaning
225
+
value.serialize(&mut **self)
226
+
}
227
+
228
+
fn end(self) -> Result<Self::Ok, Self::Error> {
229
+
Ok(())
230
+
}
231
+
}
232
+
233
+
#[cfg(test)]
234
+
mod tests {
235
+
#[test]
236
+
fn ser_hello() {
237
+
#[derive(serde::Serialize)]
238
+
struct Test<'a> {
239
+
arr: [u8; 16],
240
+
s: &'a str,
241
+
b: &'a [u8],
242
+
i: u32,
243
+
q: u64,
244
+
}
245
+
let v = Test {
246
+
arr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
247
+
s: "somestring",
248
+
b: b"bytes",
249
+
i: 0x20,
250
+
q: 0x20,
251
+
};
252
+
let v = super::to_vec(&v).expect("failed to serialize dummy");
253
+
assert_eq!(v, b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10somestring\x00\x05bytes\x20\x00\x20");
254
+
}
255
+
}
+192
-204
common/src/web/api.rs
+192
-204
common/src/web/api.rs
···
1
-
use std::borrow::Cow;
2
-
use log::*;
3
-
use warp::{Filter, Reply, Rejection};
4
-
use serde::Serialize;
5
-
6
-
use super::SharedState;
7
-
8
-
struct Md5([u8; 16]);
9
-
impl std::str::FromStr for Md5 {
10
-
type Err = &'static str;
11
-
fn from_str(s: &str) -> Result<Md5, Self::Err> {
12
-
let mut res = [0u8; 16];
13
-
let s = s.trim();
14
-
if s.len() != 32 {
15
-
return Err("bad md5 length");
16
-
}
17
-
binascii::hex2bin(s.as_bytes(), &mut res)
18
-
.map_err(|_| "bad md5")?;
19
-
Ok(Md5(res))
20
-
}
21
-
}
22
-
23
-
#[derive(Serialize)]
24
-
struct Error<'a> {
25
-
error: &'a str,
26
-
}
27
-
28
-
impl std::fmt::Display for Md5 {
29
-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30
-
let mut out = [0u8; 32];
31
-
binascii::bin2hex(&self.0, &mut out).unwrap();
32
-
let out = std::str::from_utf8(&out).unwrap();
33
-
write!(f, "{}", &out)
34
-
}
35
-
}
36
-
37
-
impl Serialize for Md5 {
38
-
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
39
-
serializer.serialize_str(&format!("{}", &self))
40
-
}
41
-
}
42
-
43
-
pub fn api_root(state: SharedState) -> impl Filter<Extract = (impl Reply + 'static, ), Error=Rejection> + Clone {
44
-
let view_file = warp::get()
45
-
.and(warp::path("files"))
46
-
.and(super::with_state(state.clone()))
47
-
.and(warp::filters::path::param::<Md5>())
48
-
.and_then(view_file_by_hash);
49
-
let view_func = warp::get()
50
-
.and(warp::path("funcs"))
51
-
.and(super::with_state(state))
52
-
.and(warp::filters::path::param::<Md5>())
53
-
.and_then(view_func_by_hash);
54
-
55
-
view_file
56
-
.or(view_func)
57
-
}
58
-
59
-
// GET server/api/files/:md5
60
-
async fn view_file_by_hash(state: SharedState, md5: Md5) -> Result<impl Reply, Rejection> {
61
-
#[derive(Serialize)]
62
-
struct FileFunc {
63
-
hash: Md5,
64
-
len: u32,
65
-
name: String,
66
-
}
67
-
68
-
let v = match state.db.get_file_funcs(&md5.0[..], 0, 10_000).await {
69
-
Ok(v) => v,
70
-
Err(err) => {
71
-
error!("failed to get file's funcs {}: {}", &md5, err);
72
-
return Ok(warp::reply::json(&Error{error: "internal server error"}));
73
-
},
74
-
};
75
-
let v: Vec<_> = v.into_iter()
76
-
.map(|v| {
77
-
let mut hash = [0u8; 16];
78
-
hash.copy_from_slice(&v.2);
79
-
FileFunc {
80
-
name: v.0,
81
-
len: v.1 as u32,
82
-
hash: Md5(hash),
83
-
}
84
-
})
85
-
.collect();
86
-
87
-
Result::<_, Rejection>::Ok(warp::reply::json(&v))
88
-
}
89
-
90
-
// GET server/api/funcs/:md5
91
-
async fn view_func_by_hash(state: SharedState, md5: Md5) -> Result<impl Reply, Rejection> {
92
-
#[derive(Serialize)]
93
-
enum CommentType {
94
-
Posterior,
95
-
Anterior,
96
-
Function{ repeatable: bool },
97
-
Byte { repeatable: bool },
98
-
}
99
-
100
-
#[derive(Serialize)]
101
-
struct Comment<'a> {
102
-
#[serde(skip_serializing_if = "Option::is_none")]
103
-
offset: Option<u32>,
104
-
#[serde(rename = "type")]
105
-
type_: CommentType,
106
-
comment: Cow<'a, str>,
107
-
}
108
-
109
-
#[derive(Serialize)]
110
-
struct FuncInfo<'a> {
111
-
name: &'a str,
112
-
comments: Vec<Comment<'a>>,
113
-
length: u32,
114
-
in_files: &'a [Md5],
115
-
}
116
-
117
-
let funcs = [crate::rpc::PullMetadataFunc {
118
-
unk0: 1,
119
-
mb_hash: &md5.0
120
-
}];
121
-
122
-
let files_with = state.db.get_files_with_func(&md5.0[..]);
123
-
let files_info = state.db.get_funcs(&funcs);
124
-
125
-
let (files_with, files_info) = match futures_util::try_join!(files_with, files_info) {
126
-
Ok(v) => v,
127
-
Err(err) => {
128
-
error!("failed to execute db queries: {}", err);
129
-
return Ok(warp::reply::json(&Error {error: "internal server error"}));
130
-
}
131
-
};
132
-
133
-
let files_with: Vec<Md5> = files_with.into_iter().map(|v| {
134
-
let mut md5 = [0u8; 16];
135
-
md5.copy_from_slice(&v);
136
-
Md5(md5)
137
-
}).collect();
138
-
139
-
let v = files_info;
140
-
let v: Vec<FuncInfo> = v
141
-
.iter()
142
-
.take(1)
143
-
.filter_map(|v| v.as_ref())
144
-
.filter_map(|v| {
145
-
let md = match crate::md::parse_metadata(&v.data) {
146
-
Ok(v) => v,
147
-
Err(e) => {
148
-
error!("error parsing metadata for {}: {}", &md5, e);
149
-
return None;
150
-
}
151
-
};
152
-
let comments: Vec<Comment> = md.into_iter()
153
-
.filter_map(|md| {
154
-
match md {
155
-
crate::md::FunctionMetadata::ByteComment(c) => {
156
-
Some(vec![Comment {
157
-
offset: Some(c.offset),
158
-
type_: CommentType::Byte{ repeatable: c.is_repeatable },
159
-
comment: c.comment.into(),
160
-
}])
161
-
},
162
-
crate::md::FunctionMetadata::FunctionComment(c) => {
163
-
Some(vec![Comment {
164
-
offset: None,
165
-
type_: CommentType::Function{ repeatable: c.is_repeatable },
166
-
comment: c.comment.into(),
167
-
}])
168
-
},
169
-
crate::md::FunctionMetadata::ExtraComment(c) => {
170
-
let mut res = vec![];
171
-
if !c.anterior.is_empty() {
172
-
res.push(Comment {
173
-
offset: Some(c.offset),
174
-
type_: CommentType::Anterior,
175
-
comment: c.anterior.into(),
176
-
});
177
-
}
178
-
if !c.posterior.is_empty() {
179
-
res.push(Comment {
180
-
offset: Some(c.offset),
181
-
type_: CommentType::Posterior,
182
-
comment: c.posterior.into(),
183
-
});
184
-
}
185
-
if !res.is_empty() {
186
-
Some(res)
187
-
} else {
188
-
None
189
-
}
190
-
},
191
-
}
192
-
})
193
-
.flatten()
194
-
.collect();
195
-
Some(FuncInfo {
196
-
name: &v.name,
197
-
length: v.len,
198
-
comments,
199
-
in_files: &files_with,
200
-
})
201
-
}).collect();
202
-
203
-
Result::<_, Rejection>::Ok(warp::reply::json(&v))
204
-
}
1
+
use log::*;
2
+
use serde::Serialize;
3
+
use std::borrow::Cow;
4
+
use warp::{Filter, Rejection, Reply};
5
+
6
+
use super::SharedState;
7
+
8
+
struct Md5([u8; 16]);
9
+
impl std::str::FromStr for Md5 {
10
+
type Err = &'static str;
11
+
fn from_str(s: &str) -> Result<Md5, Self::Err> {
12
+
let mut res = [0u8; 16];
13
+
let s = s.trim();
14
+
if s.len() != 32 {
15
+
return Err("bad md5 length");
16
+
}
17
+
binascii::hex2bin(s.as_bytes(), &mut res).map_err(|_| "bad md5")?;
18
+
Ok(Md5(res))
19
+
}
20
+
}
21
+
22
+
#[derive(Serialize)]
23
+
struct Error<'a> {
24
+
error: &'a str,
25
+
}
26
+
27
+
impl std::fmt::Display for Md5 {
28
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29
+
let mut out = [0u8; 32];
30
+
binascii::bin2hex(&self.0, &mut out).unwrap();
31
+
let out = std::str::from_utf8(&out).unwrap();
32
+
write!(f, "{}", &out)
33
+
}
34
+
}
35
+
36
+
impl Serialize for Md5 {
37
+
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
38
+
serializer.serialize_str(&format!("{}", &self))
39
+
}
40
+
}
41
+
42
+
pub fn api_root(
43
+
state: SharedState,
44
+
) -> impl Filter<Extract = (impl Reply + 'static,), Error = Rejection> + Clone {
45
+
let view_file = warp::get()
46
+
.and(warp::path("files"))
47
+
.and(super::with_state(state.clone()))
48
+
.and(warp::filters::path::param::<Md5>())
49
+
.and_then(view_file_by_hash);
50
+
let view_func = warp::get()
51
+
.and(warp::path("funcs"))
52
+
.and(super::with_state(state))
53
+
.and(warp::filters::path::param::<Md5>())
54
+
.and_then(view_func_by_hash);
55
+
56
+
view_file.or(view_func)
57
+
}
58
+
59
+
// GET server/api/files/:md5
60
+
async fn view_file_by_hash(state: SharedState, md5: Md5) -> Result<impl Reply, Rejection> {
61
+
#[derive(Serialize)]
62
+
struct FileFunc {
63
+
hash: Md5,
64
+
len: u32,
65
+
name: String,
66
+
}
67
+
68
+
let v = match state.db.get_file_funcs(&md5.0[..], 0, 10_000).await {
69
+
Ok(v) => v,
70
+
Err(err) => {
71
+
error!("failed to get file's funcs {}: {}", &md5, err);
72
+
return Ok(warp::reply::json(&Error { error: "internal server error" }));
73
+
},
74
+
};
75
+
let v: Vec<_> = v
76
+
.into_iter()
77
+
.map(|v| {
78
+
let mut hash = [0u8; 16];
79
+
hash.copy_from_slice(&v.2);
80
+
FileFunc { name: v.0, len: v.1 as u32, hash: Md5(hash) }
81
+
})
82
+
.collect();
83
+
84
+
Result::<_, Rejection>::Ok(warp::reply::json(&v))
85
+
}
86
+
87
+
// GET server/api/funcs/:md5
88
+
async fn view_func_by_hash(state: SharedState, md5: Md5) -> Result<impl Reply, Rejection> {
89
+
#[derive(Serialize)]
90
+
enum CommentType {
91
+
Posterior,
92
+
Anterior,
93
+
Function { repeatable: bool },
94
+
Byte { repeatable: bool },
95
+
}
96
+
97
+
#[derive(Serialize)]
98
+
struct Comment<'a> {
99
+
#[serde(skip_serializing_if = "Option::is_none")]
100
+
offset: Option<u32>,
101
+
#[serde(rename = "type")]
102
+
type_: CommentType,
103
+
comment: Cow<'a, str>,
104
+
}
105
+
106
+
#[derive(Serialize)]
107
+
struct FuncInfo<'a> {
108
+
name: &'a str,
109
+
comments: Vec<Comment<'a>>,
110
+
length: u32,
111
+
in_files: &'a [Md5],
112
+
}
113
+
114
+
let funcs = [crate::rpc::PullMetadataFunc { unk0: 1, mb_hash: &md5.0 }];
115
+
116
+
let files_with = state.db.get_files_with_func(&md5.0[..]);
117
+
let files_info = state.db.get_funcs(&funcs);
118
+
119
+
let (files_with, files_info) = match futures_util::try_join!(files_with, files_info) {
120
+
Ok(v) => v,
121
+
Err(err) => {
122
+
error!("failed to execute db queries: {}", err);
123
+
return Ok(warp::reply::json(&Error { error: "internal server error" }));
124
+
},
125
+
};
126
+
127
+
let files_with: Vec<Md5> = files_with
128
+
.into_iter()
129
+
.map(|v| {
130
+
let mut md5 = [0u8; 16];
131
+
md5.copy_from_slice(&v);
132
+
Md5(md5)
133
+
})
134
+
.collect();
135
+
136
+
let v = files_info;
137
+
let v: Vec<FuncInfo> = v
138
+
.iter()
139
+
.take(1)
140
+
.filter_map(|v| v.as_ref())
141
+
.filter_map(|v| {
142
+
let md = match crate::md::parse_metadata(&v.data) {
143
+
Ok(v) => v,
144
+
Err(e) => {
145
+
error!("error parsing metadata for {}: {}", &md5, e);
146
+
return None;
147
+
},
148
+
};
149
+
let comments: Vec<Comment> = md
150
+
.into_iter()
151
+
.filter_map(|md| match md {
152
+
crate::md::FunctionMetadata::ByteComment(c) => Some(vec![Comment {
153
+
offset: Some(c.offset),
154
+
type_: CommentType::Byte { repeatable: c.is_repeatable },
155
+
comment: c.comment.into(),
156
+
}]),
157
+
crate::md::FunctionMetadata::FunctionComment(c) => Some(vec![Comment {
158
+
offset: None,
159
+
type_: CommentType::Function { repeatable: c.is_repeatable },
160
+
comment: c.comment.into(),
161
+
}]),
162
+
crate::md::FunctionMetadata::ExtraComment(c) => {
163
+
let mut res = vec![];
164
+
if !c.anterior.is_empty() {
165
+
res.push(Comment {
166
+
offset: Some(c.offset),
167
+
type_: CommentType::Anterior,
168
+
comment: c.anterior.into(),
169
+
});
170
+
}
171
+
if !c.posterior.is_empty() {
172
+
res.push(Comment {
173
+
offset: Some(c.offset),
174
+
type_: CommentType::Posterior,
175
+
comment: c.posterior.into(),
176
+
});
177
+
}
178
+
if !res.is_empty() {
179
+
Some(res)
180
+
} else {
181
+
None
182
+
}
183
+
},
184
+
})
185
+
.flatten()
186
+
.collect();
187
+
Some(FuncInfo { name: &v.name, length: v.len, comments, in_files: &files_with })
188
+
})
189
+
.collect();
190
+
191
+
Result::<_, Rejection>::Ok(warp::reply::json(&v))
192
+
}
+10
-8
common/src/web.rs
+10
-8
common/src/web.rs
···
1
-
use crate::SharedState;
2
-
use warp::Filter;
3
-
4
-
pub mod api;
5
-
6
-
pub fn with_state(state: SharedState) -> impl Filter<Extract=(SharedState,), Error= std::convert::Infallible> + Clone {
7
-
warp::any().map(move || state.clone())
8
-
}
1
+
use crate::SharedState;
2
+
use warp::Filter;
3
+
4
+
pub mod api;
5
+
6
+
pub fn with_state(
7
+
state: SharedState,
8
+
) -> impl Filter<Extract = (SharedState,), Error = std::convert::Infallible> + Clone {
9
+
warp::any().map(move || state.clone())
10
+
}
+2
config-example.toml
+2
config-example.toml
+6
-6
lumen/Cargo.toml
+6
-6
lumen/Cargo.toml
···
7
7
publish = false
8
8
9
9
[dependencies]
10
-
common = {path = "../common"}
11
-
tokio = {version = "1.32", features = ["full"]}
12
-
log = {version = "0.4", features = ["release_max_level_debug"]}
10
+
common = { path = "../common" }
11
+
tokio = { version = "1.39", features = ["full"] }
12
+
log = { version = "0.4", features = ["release_max_level_debug"] }
13
13
pretty_env_logger = "0.5"
14
-
clap = "4.3"
14
+
clap = "4.5"
15
15
tokio-native-tls = "0.3"
16
-
native-tls = {version = "0.2"}
16
+
native-tls = { version = "0.2" }
17
17
warp = "0.3"
18
-
prometheus-client = "0.21.2"
18
+
prometheus-client = "0.22"
+11
-409
lumen/src/main.rs
+11
-409
lumen/src/main.rs
···
4
4
#![warn(unused_crate_dependencies)]
5
5
#![deny(clippy::all)]
6
6
7
-
use common::async_drop::AsyncDropper;
8
-
use common::metrics::LuminaVersion;
9
-
use common::rpc::{RpcHello, RpcFail, HelloResult};
10
-
use native_tls::Identity;
11
7
use clap::Arg;
12
8
use log::*;
13
-
use tokio::time::timeout;
14
-
use std::collections::HashMap;
15
-
use std::mem::discriminant;
16
-
use std::time::{Duration, Instant};
17
-
use std::{borrow::Cow, sync::Arc};
18
-
use tokio::{net::TcpListener, io::AsyncWrite, io::AsyncRead};
19
-
use std::process::exit;
20
-
use common::{SharedState, SharedState_};
9
+
use server::do_lumen;
10
+
use std::sync::Arc;
21
11
12
+
mod server;
22
13
mod web;
23
14
24
-
use common::{config, make_pretty_hex, md, rpc::{self, Error}};
25
-
use common::db::Database;
26
-
use rpc::RpcMessage;
15
+
use common::config;
27
16
28
17
fn setup_logger() {
29
18
if std::env::var("RUST_LOG").is_err() {
···
32
21
pretty_env_logger::init_timed();
33
22
}
34
23
35
-
async fn handle_transaction<'a, S: AsyncRead + AsyncWrite + Unpin>(state: &SharedState, user: &'a RpcHello<'a>, mut stream: S) -> Result<(), Error> {
36
-
let db = &state.db;
37
-
let server_name = state.server_name.as_str();
38
-
39
-
trace!("waiting for command..");
40
-
let req = match timeout(Duration::from_secs(3600), rpc::read_packet(&mut stream)).await {
41
-
Ok(res) => match res {
42
-
Ok(v) => v,
43
-
Err(e) => return Err(e),
44
-
},
45
-
Err(_) => {
46
-
_ = RpcMessage::Fail(RpcFail {
47
-
code: 0,
48
-
message: &format!("{server_name} client idle for too long.\n"),
49
-
}).async_write(&mut stream).await;
50
-
return Err(Error::Timeout);
51
-
},
52
-
};
53
-
trace!("got command!");
54
-
let req = match RpcMessage::deserialize(&req) {
55
-
Ok(v) => v,
56
-
Err(err) => {
57
-
warn!("bad message: \n{}\n", make_pretty_hex(&req));
58
-
error!("failed to process rpc message: {}", err);
59
-
let resp = rpc::RpcFail{ code: 0, message: &format!("{server_name}: error: invalid data.\n")};
60
-
let resp = RpcMessage::Fail(resp);
61
-
resp.async_write(&mut stream).await?;
62
-
63
-
return Ok(());
64
-
},
65
-
};
66
-
match req {
67
-
RpcMessage::PullMetadata(md) => {
68
-
let start = Instant::now();
69
-
let funcs = match timeout(Duration::from_secs(4 * 60), db.get_funcs(&md.funcs)).await {
70
-
Ok(r) => match r {
71
-
Ok(v) => v,
72
-
Err(e) => {
73
-
error!("pull failed, db: {}", e);
74
-
rpc::RpcMessage::Fail(rpc::RpcFail {
75
-
code: 0,
76
-
message: &format!("{server_name}: db error; please try again later..\n")
77
-
}).async_write(&mut stream).await?;
78
-
return Ok(());
79
-
},
80
-
},
81
-
Err(_) => {
82
-
RpcMessage::Fail(RpcFail {
83
-
code: 0,
84
-
message: &format!("{server_name}: query took too long to execute.\n"),
85
-
}).async_write(&mut stream).await?;
86
-
debug!("pull query timeout");
87
-
return Err(Error::Timeout);
88
-
}
89
-
};
90
-
let pulled_funcs = funcs.iter().filter(|v| v.is_some()).count();
91
-
state.metrics.pulls.inc_by(pulled_funcs as _);
92
-
state.metrics.queried_funcs.inc_by(md.funcs.len() as _);
93
-
debug!("pull {pulled_funcs}/{} funcs ended after {:?}", md.funcs.len(), start.elapsed());
94
-
95
-
let statuses: Vec<u32> = funcs.iter().map(|v| u32::from(v.is_none())).collect();
96
-
let found = funcs
97
-
.into_iter()
98
-
.flatten()
99
-
.map(|v| {
100
-
rpc::PullMetadataResultFunc {
101
-
popularity: v.popularity,
102
-
len: v.len,
103
-
name: Cow::Owned(v.name),
104
-
mb_data: Cow::Owned(v.data),
105
-
}
106
-
}).collect();
107
-
108
-
RpcMessage::PullMetadataResult(rpc::PullMetadataResult{
109
-
unk0: Cow::Owned(statuses),
110
-
funcs: Cow::Owned(found),
111
-
}).async_write(&mut stream).await?;
112
-
},
113
-
RpcMessage::PushMetadata(mds) => {
114
-
// parse the function's metadata
115
-
let start = Instant::now();
116
-
let scores: Vec<u32> = mds.funcs.iter()
117
-
.map(md::get_score)
118
-
.collect();
119
-
120
-
let status = match db.push_funcs(user, &mds, &scores).await {
121
-
Ok(v) => {
122
-
v.into_iter().map(u32::from).collect::<Vec<u32>>()
123
-
},
124
-
Err(err) => {
125
-
log::error!("push failed, db: {}", err);
126
-
rpc::RpcMessage::Fail(rpc::RpcFail {
127
-
code: 0,
128
-
message: &format!("{server_name}: db error; please try again later.\n")
129
-
}).async_write(&mut stream).await?;
130
-
return Ok(());
131
-
}
132
-
};
133
-
state.metrics.pushes.inc_by(status.len() as _);
134
-
let new_funcs = status
135
-
.iter()
136
-
.fold(0u64, |counter, &v| if v > 0 { counter + 1 } else {counter});
137
-
state.metrics.new_funcs.inc_by(new_funcs);
138
-
debug!("push {} funcs ended after {:?} ({new_funcs} new)", status.len(), start.elapsed());
139
-
140
-
RpcMessage::PushMetadataResult(rpc::PushMetadataResult {
141
-
status: Cow::Owned(status),
142
-
}).async_write(&mut stream).await?;
143
-
},
144
-
RpcMessage::DelHistory(req) => {
145
-
let is_delete_allowed = state.config.lumina.allow_deletes.unwrap_or(false);
146
-
if !is_delete_allowed {
147
-
RpcMessage::Fail(rpc::RpcFail {
148
-
code: 2,
149
-
message: &format!("{server_name}: Delete command is disabled on this server.")
150
-
}).async_write(&mut stream).await?;
151
-
} else {
152
-
if let Err(err) = db.delete_metadata(&req).await {
153
-
error!("delete failed. db: {err}");
154
-
RpcMessage::Fail(rpc::RpcFail {
155
-
code: 3,
156
-
message: &format!("{server_name}: db error, please try again later.")
157
-
}).async_write(&mut stream).await?;
158
-
return Ok(());
159
-
}
160
-
RpcMessage::DelHistoryResult(rpc::DelHistoryResult {
161
-
deleted_mds: req.funcs.len() as u32,
162
-
}).async_write(&mut stream).await?;
163
-
}
164
-
},
165
-
_ => {
166
-
RpcMessage::Fail(rpc::RpcFail{code: 0, message: &format!("{server_name}: invalid data.\n")}).async_write(&mut stream).await?;
167
-
}
168
-
}
169
-
Ok(())
170
-
}
171
-
172
-
async fn handle_client<S: AsyncRead + AsyncWrite + Unpin>(state: &SharedState, mut stream: S) -> Result<(), rpc::Error> {
173
-
let server_name = &state.server_name;
174
-
let hello = match timeout(Duration::from_secs(15), rpc::read_packet(&mut stream)).await {
175
-
Ok(v) => v?,
176
-
Err(_) => {
177
-
debug!("didn't get hello in time.");
178
-
return Ok(());
179
-
},
180
-
};
181
-
182
-
let (hello, creds) = match RpcMessage::deserialize(&hello) {
183
-
Ok(RpcMessage::Hello(v, creds)) => {
184
-
debug!("hello protocol={}, login creds: {creds:?}", v.protocol_version);
185
-
(v, creds)
186
-
},
187
-
_ => {
188
-
// send error
189
-
error!("got bad hello message");
190
-
191
-
let resp = rpc::RpcFail{ code: 0, message: &format!("{server_name}: bad sequence.") };
192
-
let resp = rpc::RpcMessage::Fail(resp);
193
-
resp.async_write(&mut stream).await?;
194
-
195
-
return Ok(());
196
-
}
197
-
};
198
-
state.metrics.lumina_version.get_or_create(&LuminaVersion {
199
-
protocol_version: hello.protocol_version,
200
-
}).inc();
201
-
202
-
if let Some(ref creds) = creds {
203
-
if creds.username != "guest" {
204
-
// Only allow "guest" to connect for now.
205
-
rpc::RpcMessage::Fail(rpc::RpcFail {
206
-
code: 1,
207
-
message: &format!("{server_name}: invalid username or password. Try logging in with `guest` instead."),
208
-
}).async_write(&mut stream).await?;
209
-
return Ok(());
210
-
}
211
-
}
212
-
213
-
let resp = match hello.protocol_version {
214
-
0..=4 => rpc::RpcMessage::Ok(()),
215
-
216
-
// starting IDA 8.3
217
-
5.. => rpc::RpcMessage::HelloResult(HelloResult {
218
-
unk0: "".into(),
219
-
unk1: "".into(),
220
-
unk2: "".into(),
221
-
unk3: "".into(),
222
-
unk4: 0,
223
-
unk5: 0,
224
-
unk6: 0,
225
-
})
226
-
};
227
-
resp.async_write(&mut stream).await?;
228
-
229
-
loop {
230
-
handle_transaction(state, &hello, &mut stream).await?;
231
-
}
232
-
}
233
-
234
-
async fn handle_connection<S: AsyncRead + AsyncWrite + Unpin>(state: &SharedState, s: S) {
235
-
if let Err(err) = handle_client(state, s).await {
236
-
if discriminant(&err) != discriminant(&Error::Eof) {
237
-
warn!("err: {}", err);
238
-
}
239
-
}
240
-
}
241
-
242
-
async fn serve(listener: TcpListener, accpt: Option<tokio_native_tls::TlsAcceptor>, state: SharedState, mut shutdown_signal: tokio::sync::oneshot::Receiver<()>) {
243
-
let accpt = accpt.map(Arc::new);
244
-
245
-
let (async_drop, worker) = AsyncDropper::new();
246
-
tokio::task::spawn(worker);
247
-
248
-
let connections = Arc::new(tokio::sync::Mutex::new(HashMap::<std::net::SocketAddr, tokio::task::JoinHandle<()>>::new()));
249
-
250
-
loop {
251
-
let (client, addr) = tokio::select! {
252
-
_ = &mut shutdown_signal => {
253
-
drop(state);
254
-
info!("shutting down...");
255
-
let m = connections.lock().await;
256
-
m.iter().for_each(|(k, v)| {
257
-
debug!("aborting task for {k}...");
258
-
v.abort();
259
-
});
260
-
return;
261
-
},
262
-
res = listener.accept() => match res {
263
-
Ok(v) => v,
264
-
Err(err) => {
265
-
warn!("failed to accept(): {}", err);
266
-
continue;
267
-
}
268
-
},
269
-
};
270
-
271
-
let start = Instant::now();
272
-
273
-
let state = state.clone();
274
-
let accpt = accpt.clone();
275
-
276
-
let conns2 = connections.clone();
277
-
let counter = state.metrics.active_connections.clone();
278
-
let guard = async_drop.defer(async move {
279
-
let count = counter.dec() - 1;
280
-
debug!("connection with {:?} ended after {:?}; {} active connections", addr, start.elapsed(), count);
281
-
282
-
let mut guard = conns2.lock().await;
283
-
if guard.remove(&addr).is_none() {
284
-
error!("Couldn't remove connection from set {addr}");
285
-
}
286
-
});
287
-
288
-
let counter = state.metrics.active_connections.clone();
289
-
let handle = tokio::spawn(async move {
290
-
let _guard = guard;
291
-
let count = {
292
-
counter.inc() + 1
293
-
};
294
-
let protocol = if accpt.is_some() {" [TLS]"} else {""};
295
-
debug!("Connection from {:?}{}: {} active connections", &addr, protocol, count);
296
-
match accpt {
297
-
Some(accpt) => {
298
-
match timeout(Duration::from_secs(10), accpt.accept(client)).await {
299
-
Ok(r) => match r {
300
-
Ok(s) => {
301
-
handle_connection(&state, s).await;
302
-
},
303
-
Err(err) => debug!("tls accept ({}): {}", &addr, err),
304
-
},
305
-
Err(_) => {
306
-
debug!("client {} didn't complete ssl handshake in time.", &addr);
307
-
},
308
-
};
309
-
},
310
-
None => handle_connection(&state, client).await,
311
-
}
312
-
});
313
-
314
-
let mut guard = connections.lock().await;
315
-
guard.insert(addr, handle);
316
-
}
317
-
}
318
-
319
-
fn main() {
24
+
#[tokio::main]
25
+
async fn main() {
320
26
setup_logger();
321
27
let matches = clap::Command::new("lumen")
322
28
.version(env!("CARGO_PKG_VERSION"))
···
325
31
.arg(
326
32
Arg::new("config")
327
33
.short('c')
328
-
.required(true)
329
34
.default_value("config.toml")
330
35
.help("Configuration file path")
331
36
)
332
37
.get_matches();
333
38
334
39
let config = {
335
-
config::load_config(std::fs::File::open(matches.get_one::<String>("config").unwrap()).expect("failed to read config"))
40
+
config::load_config(
41
+
std::fs::File::open(matches.get_one::<String>("config").unwrap())
42
+
.expect("failed to read config"),
43
+
)
336
44
};
337
45
let config = Arc::new(config);
338
46
339
-
info!("starting private lumen server...");
340
-
341
-
let rt = match tokio::runtime::Builder::new_multi_thread()
342
-
.enable_all()
343
-
.build() {
344
-
Ok(v) => v,
345
-
Err(err) => {
346
-
error!("failed to create tokio runtime: {}", err);
347
-
exit(1);
348
-
},
349
-
};
350
-
351
-
let db = rt.block_on(async {
352
-
match Database::open(&config.database).await {
353
-
Ok(v) => v,
354
-
Err(err) => {
355
-
error!("failed to open database: {}", err);
356
-
exit(1);
357
-
}
358
-
}
359
-
});
360
-
361
-
let server_name = config.lumina.server_name.clone().unwrap_or_else(|| String::from("lumen"));
362
-
363
-
let state = Arc::new(SharedState_{
364
-
db,
365
-
config,
366
-
server_name,
367
-
metrics: common::metrics::Metrics::default(),
368
-
});
369
-
370
-
let tls_acceptor;
371
-
372
-
if state.config.lumina.use_tls.unwrap_or_default() {
373
-
let cert_path = &state.config.lumina.tls.as_ref().expect("tls section is missing").server_cert;
374
-
let mut crt = match std::fs::read(cert_path) {
375
-
Ok(v) => v,
376
-
Err(err) => {
377
-
error!("failed to read certificate file: {}", err);
378
-
exit(1);
379
-
}
380
-
};
381
-
let pkcs_passwd = std::env::var("PKCSPASSWD").unwrap_or_default();
382
-
let id = match Identity::from_pkcs12(&crt, &pkcs_passwd) {
383
-
Ok(v) => v,
384
-
Err(err) => {
385
-
error!("failed to parse tls certificate: {}", err);
386
-
exit(1);
387
-
}
388
-
};
389
-
let _ = pkcs_passwd;
390
-
crt.iter_mut().for_each(|v| *v = 0);
391
-
let _ = crt;
392
-
let mut accpt = native_tls::TlsAcceptor::builder(id);
393
-
accpt.min_protocol_version(Some(native_tls::Protocol::Sslv3));
394
-
let accpt = match accpt.build() {
395
-
Ok(v) => v,
396
-
Err(err) => {
397
-
error!("failed to build tls acceptor: {}", err);
398
-
exit(1);
399
-
},
400
-
};
401
-
let accpt = tokio_native_tls::TlsAcceptor::from(accpt);
402
-
tls_acceptor = Some(accpt);
403
-
} else {
404
-
tls_acceptor = None;
405
-
}
406
-
407
-
let web_handle = if let Some(ref webcfg) = state.config.api_server {
408
-
let bind_addr = webcfg.bind_addr;
409
-
let state = state.clone();
410
-
info!("starting http api server on {:?}", &bind_addr);
411
-
Some(rt.spawn(async move {
412
-
web::start_webserver(bind_addr, state).await;
413
-
}))
414
-
} else {
415
-
None
416
-
};
417
-
418
-
let (exit_signal_tx, exit_signal_rx) = tokio::sync::oneshot::channel::<()>();
419
-
420
-
let async_server = async move {
421
-
let server = match TcpListener::bind(state.config.lumina.bind_addr).await {
422
-
Ok(v) => v,
423
-
Err(err) => {
424
-
error!("failed to bind server port: {}", err);
425
-
exit(1);
426
-
},
427
-
};
428
-
429
-
info!("listening on {:?} secure={}", server.local_addr().unwrap(), tls_acceptor.is_some());
430
-
431
-
serve(server, tls_acceptor, state, exit_signal_rx).await;
432
-
};
433
-
434
-
rt.block_on(async {
435
-
let server_handle = tokio::task::spawn(async_server);
436
-
tokio::signal::ctrl_c().await.unwrap();
437
-
debug!("CTRL-C; exiting...");
438
-
if let Some(handle) = web_handle {
439
-
handle.abort();
440
-
}
441
-
exit_signal_tx.send(()).unwrap();
442
-
server_handle.await.unwrap();
443
-
});
444
-
drop(rt);
445
-
info!("Goodbye.");
47
+
do_lumen(config).await;
446
48
}
+513
lumen/src/server.rs
+513
lumen/src/server.rs
···
1
+
use std::{
2
+
borrow::Cow, collections::HashMap, mem::discriminant, process::exit, sync::Arc, time::Instant,
3
+
};
4
+
5
+
use common::{
6
+
async_drop::AsyncDropper,
7
+
config::Config,
8
+
db::Database,
9
+
make_pretty_hex, md,
10
+
metrics::LuminaVersion,
11
+
rpc::{self, Error, HelloResult, RpcFail, RpcHello, RpcMessage},
12
+
SharedState, SharedState_,
13
+
};
14
+
use log::{debug, error, info, trace, warn};
15
+
use native_tls::Identity;
16
+
use tokio::{
17
+
io::{AsyncRead, AsyncWrite},
18
+
net::TcpListener,
19
+
time::timeout,
20
+
};
21
+
22
+
use crate::web;
23
+
24
+
async fn handle_transaction<'a, S: AsyncRead + AsyncWrite + Unpin>(
25
+
state: &SharedState, user: &'a RpcHello<'a>, mut stream: S,
26
+
) -> Result<(), Error> {
27
+
let db = &state.db;
28
+
let server_name = state.server_name.as_str();
29
+
30
+
trace!("waiting for command..");
31
+
let req =
32
+
match timeout(state.config.limits.command_timeout, rpc::read_packet(&mut stream)).await {
33
+
Ok(res) => match res {
34
+
Ok(v) => v,
35
+
Err(e) => return Err(e),
36
+
},
37
+
Err(_) => {
38
+
_ = RpcMessage::Fail(RpcFail {
39
+
code: 0,
40
+
message: &format!("{server_name} client idle for too long.\n"),
41
+
})
42
+
.async_write(&mut stream)
43
+
.await;
44
+
return Err(Error::Timeout);
45
+
},
46
+
};
47
+
trace!("got command!");
48
+
let req = match RpcMessage::deserialize(&req) {
49
+
Ok(v) => v,
50
+
Err(err) => {
51
+
warn!("bad message: \n{}\n", make_pretty_hex(&req));
52
+
error!("failed to process rpc message: {}", err);
53
+
let resp = rpc::RpcFail {
54
+
code: 0,
55
+
message: &format!("{server_name}: error: invalid data.\n"),
56
+
};
57
+
let resp = RpcMessage::Fail(resp);
58
+
resp.async_write(&mut stream).await?;
59
+
60
+
return Ok(());
61
+
},
62
+
};
63
+
match req {
64
+
RpcMessage::PullMetadata(md) => {
65
+
let start = Instant::now();
66
+
let funcs =
67
+
match timeout(state.config.limits.pull_md_timeout, db.get_funcs(&md.funcs)).await {
68
+
Ok(r) => match r {
69
+
Ok(v) => v,
70
+
Err(e) => {
71
+
error!("pull failed, db: {}", e);
72
+
rpc::RpcMessage::Fail(rpc::RpcFail {
73
+
code: 0,
74
+
message: &format!(
75
+
"{server_name}: db error; please try again later..\n"
76
+
),
77
+
})
78
+
.async_write(&mut stream)
79
+
.await?;
80
+
return Ok(());
81
+
},
82
+
},
83
+
Err(_) => {
84
+
RpcMessage::Fail(RpcFail {
85
+
code: 0,
86
+
message: &format!("{server_name}: query took too long to execute.\n"),
87
+
})
88
+
.async_write(&mut stream)
89
+
.await?;
90
+
debug!("pull query timeout");
91
+
return Err(Error::Timeout);
92
+
},
93
+
};
94
+
let pulled_funcs = funcs.iter().filter(|v| v.is_some()).count();
95
+
state.metrics.pulls.inc_by(pulled_funcs as _);
96
+
state.metrics.queried_funcs.inc_by(md.funcs.len() as _);
97
+
debug!(
98
+
"pull {pulled_funcs}/{} funcs ended after {:?}",
99
+
md.funcs.len(),
100
+
start.elapsed()
101
+
);
102
+
103
+
let statuses: Vec<u32> = funcs.iter().map(|v| u32::from(v.is_none())).collect();
104
+
let found = funcs
105
+
.into_iter()
106
+
.flatten()
107
+
.map(|v| rpc::PullMetadataResultFunc {
108
+
popularity: v.popularity,
109
+
len: v.len,
110
+
name: Cow::Owned(v.name),
111
+
mb_data: Cow::Owned(v.data),
112
+
})
113
+
.collect();
114
+
115
+
RpcMessage::PullMetadataResult(rpc::PullMetadataResult {
116
+
unk0: Cow::Owned(statuses),
117
+
funcs: Cow::Owned(found),
118
+
})
119
+
.async_write(&mut stream)
120
+
.await?;
121
+
},
122
+
RpcMessage::PushMetadata(mds) => {
123
+
// parse the function's metadata
124
+
let start = Instant::now();
125
+
let scores: Vec<u32> = mds.funcs.iter().map(md::get_score).collect();
126
+
127
+
let status = match db.push_funcs(user, &mds, &scores).await {
128
+
Ok(v) => v.into_iter().map(u32::from).collect::<Vec<u32>>(),
129
+
Err(err) => {
130
+
log::error!("push failed, db: {}", err);
131
+
rpc::RpcMessage::Fail(rpc::RpcFail {
132
+
code: 0,
133
+
message: &format!("{server_name}: db error; please try again later.\n"),
134
+
})
135
+
.async_write(&mut stream)
136
+
.await?;
137
+
return Ok(());
138
+
},
139
+
};
140
+
state.metrics.pushes.inc_by(status.len() as _);
141
+
let new_funcs =
142
+
status.iter().fold(0u64, |counter, &v| if v > 0 { counter + 1 } else { counter });
143
+
state.metrics.new_funcs.inc_by(new_funcs);
144
+
debug!(
145
+
"push {} funcs ended after {:?} ({new_funcs} new)",
146
+
status.len(),
147
+
start.elapsed()
148
+
);
149
+
150
+
RpcMessage::PushMetadataResult(rpc::PushMetadataResult { status: Cow::Owned(status) })
151
+
.async_write(&mut stream)
152
+
.await?;
153
+
},
154
+
RpcMessage::DelHistory(req) => {
155
+
let is_delete_allowed = state.config.lumina.allow_deletes.unwrap_or(false);
156
+
if !is_delete_allowed {
157
+
RpcMessage::Fail(rpc::RpcFail {
158
+
code: 2,
159
+
message: &format!("{server_name}: Delete command is disabled on this server."),
160
+
})
161
+
.async_write(&mut stream)
162
+
.await?;
163
+
} else {
164
+
if let Err(err) = db.delete_metadata(&req).await {
165
+
error!("delete failed. db: {err}");
166
+
RpcMessage::Fail(rpc::RpcFail {
167
+
code: 3,
168
+
message: &format!("{server_name}: db error, please try again later."),
169
+
})
170
+
.async_write(&mut stream)
171
+
.await?;
172
+
return Ok(());
173
+
}
174
+
RpcMessage::DelHistoryResult(rpc::DelHistoryResult {
175
+
deleted_mds: req.funcs.len() as u32,
176
+
})
177
+
.async_write(&mut stream)
178
+
.await?;
179
+
}
180
+
},
181
+
RpcMessage::GetFuncHistories(req) => {
182
+
let limit = state.config.lumina.get_history_limit.unwrap_or(0);
183
+
184
+
if limit == 0 {
185
+
RpcMessage::Fail(rpc::RpcFail {
186
+
code: 4,
187
+
message: &format!(
188
+
"{server_name}: function histories are disabled on this server."
189
+
),
190
+
})
191
+
.async_write(&mut stream)
192
+
.await?;
193
+
return Ok(());
194
+
}
195
+
196
+
let mut statuses = vec![];
197
+
let mut res = vec![];
198
+
for chksum in req.funcs.iter().map(|v| v.mb_hash) {
199
+
let history = match db.get_func_histories(chksum, limit).await {
200
+
Ok(v) => v,
201
+
Err(err) => {
202
+
error!("failed to get function histories: {err:?}");
203
+
RpcMessage::Fail(rpc::RpcFail {
204
+
code: 3,
205
+
message: &format!("{server_name}: db error, please try again later."),
206
+
})
207
+
.async_write(&mut stream)
208
+
.await?;
209
+
return Ok(());
210
+
},
211
+
};
212
+
let status = !history.is_empty() as u32;
213
+
statuses.push(status);
214
+
if history.is_empty() {
215
+
continue;
216
+
}
217
+
let log = history
218
+
.into_iter()
219
+
.map(|(updated, name, metadata)| rpc::FunctionHistory {
220
+
unk0: 0,
221
+
unk1: 0,
222
+
name: Cow::Owned(name),
223
+
metadata: Cow::Owned(metadata),
224
+
timestamp: updated.unix_timestamp() as u64,
225
+
author_idx: 0,
226
+
idb_path_idx: 0,
227
+
})
228
+
.collect::<Vec<_>>();
229
+
res.push(rpc::FunctionHistories { log: Cow::Owned(log) });
230
+
}
231
+
232
+
trace!("returning {} histories", res.len());
233
+
234
+
RpcMessage::GetFuncHistoriesResult(rpc::GetFuncHistoriesResult {
235
+
status: statuses.into(),
236
+
funcs: Cow::Owned(res),
237
+
users: vec![].into(),
238
+
dbs: vec![].into(),
239
+
})
240
+
.async_write(&mut stream)
241
+
.await?;
242
+
},
243
+
_ => {
244
+
RpcMessage::Fail(rpc::RpcFail {
245
+
code: 0,
246
+
message: &format!("{server_name}: invalid data.\n"),
247
+
})
248
+
.async_write(&mut stream)
249
+
.await?;
250
+
},
251
+
}
252
+
Ok(())
253
+
}
254
+
255
+
async fn handle_client<S: AsyncRead + AsyncWrite + Unpin>(
256
+
state: &SharedState, mut stream: S,
257
+
) -> Result<(), rpc::Error> {
258
+
let server_name = &state.server_name;
259
+
let hello =
260
+
match timeout(state.config.limits.hello_timeout, rpc::read_packet(&mut stream)).await {
261
+
Ok(v) => v?,
262
+
Err(_) => {
263
+
debug!("didn't get hello in time.");
264
+
return Ok(());
265
+
},
266
+
};
267
+
268
+
let (hello, creds) = match RpcMessage::deserialize(&hello) {
269
+
Ok(RpcMessage::Hello(v, creds)) => {
270
+
debug!("hello protocol={}, login creds: {creds:?}", v.protocol_version);
271
+
(v, creds)
272
+
},
273
+
_ => {
274
+
// send error
275
+
error!("got bad hello message");
276
+
277
+
let resp = rpc::RpcFail { code: 0, message: &format!("{server_name}: bad sequence.") };
278
+
let resp = rpc::RpcMessage::Fail(resp);
279
+
resp.async_write(&mut stream).await?;
280
+
281
+
return Ok(());
282
+
},
283
+
};
284
+
state
285
+
.metrics
286
+
.lumina_version
287
+
.get_or_create(&LuminaVersion { protocol_version: hello.protocol_version })
288
+
.inc();
289
+
290
+
if let Some(ref creds) = creds {
291
+
if creds.username != "guest" {
292
+
// Only allow "guest" to connect for now.
293
+
rpc::RpcMessage::Fail(rpc::RpcFail {
294
+
code: 1,
295
+
message: &format!("{server_name}: invalid username or password. Try logging in with `guest` instead."),
296
+
}).async_write(&mut stream).await?;
297
+
return Ok(());
298
+
}
299
+
}
300
+
301
+
let resp = match hello.protocol_version {
302
+
0..=4 => rpc::RpcMessage::Ok(()),
303
+
304
+
// starting IDA 8.3
305
+
5.. => {
306
+
let mut features = 0;
307
+
308
+
if state.config.lumina.allow_deletes.unwrap_or(false) {
309
+
features |= 0x02;
310
+
}
311
+
312
+
rpc::RpcMessage::HelloResult(HelloResult { features, ..Default::default() })
313
+
},
314
+
};
315
+
resp.async_write(&mut stream).await?;
316
+
317
+
loop {
318
+
handle_transaction(state, &hello, &mut stream).await?;
319
+
}
320
+
}
321
+
322
+
async fn handle_connection<S: AsyncRead + AsyncWrite + Unpin>(state: &SharedState, s: S) {
323
+
if let Err(err) = handle_client(state, s).await {
324
+
if discriminant(&err) != discriminant(&Error::Eof) {
325
+
warn!("err: {}", err);
326
+
}
327
+
}
328
+
}
329
+
330
+
async fn serve(
331
+
listener: TcpListener, accpt: Option<tokio_native_tls::TlsAcceptor>, state: SharedState,
332
+
mut shutdown_signal: tokio::sync::oneshot::Receiver<()>,
333
+
) {
334
+
let accpt = accpt.map(Arc::new);
335
+
336
+
let (async_drop, worker) = AsyncDropper::new();
337
+
tokio::task::spawn(worker);
338
+
339
+
let connections = Arc::new(tokio::sync::Mutex::new(HashMap::<
340
+
std::net::SocketAddr,
341
+
tokio::task::JoinHandle<()>,
342
+
>::new()));
343
+
344
+
loop {
345
+
let (client, addr) = tokio::select! {
346
+
_ = &mut shutdown_signal => {
347
+
drop(state);
348
+
info!("shutting down...");
349
+
let m = connections.lock().await;
350
+
m.iter().for_each(|(k, v)| {
351
+
debug!("aborting task for {k}...");
352
+
v.abort();
353
+
});
354
+
return;
355
+
},
356
+
res = listener.accept() => match res {
357
+
Ok(v) => v,
358
+
Err(err) => {
359
+
warn!("failed to accept(): {}", err);
360
+
continue;
361
+
}
362
+
},
363
+
};
364
+
365
+
let start = Instant::now();
366
+
367
+
let state = state.clone();
368
+
let accpt = accpt.clone();
369
+
370
+
let conns2 = connections.clone();
371
+
let counter = state.metrics.active_connections.clone();
372
+
let guard = async_drop.defer(async move {
373
+
let count = counter.dec() - 1;
374
+
debug!(
375
+
"connection with {:?} ended after {:?}; {} active connections",
376
+
addr,
377
+
start.elapsed(),
378
+
count
379
+
);
380
+
381
+
let mut guard = conns2.lock().await;
382
+
if guard.remove(&addr).is_none() {
383
+
error!("Couldn't remove connection from set {addr}");
384
+
}
385
+
});
386
+
387
+
let counter = state.metrics.active_connections.clone();
388
+
let handle = tokio::spawn(async move {
389
+
let _guard = guard;
390
+
let count = { counter.inc() + 1 };
391
+
let protocol = if accpt.is_some() { " [TLS]" } else { "" };
392
+
debug!("Connection from {:?}{}: {} active connections", &addr, protocol, count);
393
+
match accpt {
394
+
Some(accpt) => {
395
+
match timeout(state.config.limits.tls_handshake_timeout, accpt.accept(client))
396
+
.await
397
+
{
398
+
Ok(r) => match r {
399
+
Ok(s) => {
400
+
handle_connection(&state, s).await;
401
+
},
402
+
Err(err) => debug!("tls accept ({}): {}", &addr, err),
403
+
},
404
+
Err(_) => {
405
+
debug!("client {} didn't complete ssl handshake in time.", &addr);
406
+
},
407
+
};
408
+
},
409
+
None => handle_connection(&state, client).await,
410
+
}
411
+
});
412
+
413
+
let mut guard = connections.lock().await;
414
+
guard.insert(addr, handle);
415
+
}
416
+
}
417
+
418
+
pub(crate) async fn do_lumen(config: Arc<Config>) {
419
+
info!("starting private lumen server...");
420
+
421
+
let db = match Database::open(&config.database).await {
422
+
Ok(v) => v,
423
+
Err(err) => {
424
+
error!("failed to open database: {}", err);
425
+
exit(1);
426
+
},
427
+
};
428
+
429
+
let server_name = config.lumina.server_name.clone().unwrap_or_else(|| String::from("lumen"));
430
+
431
+
let state = Arc::new(SharedState_ {
432
+
db,
433
+
config,
434
+
server_name,
435
+
metrics: common::metrics::Metrics::default(),
436
+
});
437
+
438
+
let tls_acceptor;
439
+
440
+
if state.config.lumina.use_tls.unwrap_or_default() {
441
+
let cert_path =
442
+
&state.config.lumina.tls.as_ref().expect("tls section is missing").server_cert;
443
+
let mut crt = match std::fs::read(cert_path) {
444
+
Ok(v) => v,
445
+
Err(err) => {
446
+
error!("failed to read certificate file: {}", err);
447
+
exit(1);
448
+
},
449
+
};
450
+
let pkcs_passwd = std::env::var("PKCSPASSWD").unwrap_or_default();
451
+
let id = match Identity::from_pkcs12(&crt, &pkcs_passwd) {
452
+
Ok(v) => v,
453
+
Err(err) => {
454
+
error!("failed to parse tls certificate: {}", err);
455
+
exit(1);
456
+
},
457
+
};
458
+
let _ = pkcs_passwd;
459
+
crt.iter_mut().for_each(|v| *v = 0);
460
+
let _ = crt;
461
+
let mut accpt = native_tls::TlsAcceptor::builder(id);
462
+
accpt.min_protocol_version(Some(native_tls::Protocol::Sslv3));
463
+
let accpt = match accpt.build() {
464
+
Ok(v) => v,
465
+
Err(err) => {
466
+
error!("failed to build tls acceptor: {}", err);
467
+
exit(1);
468
+
},
469
+
};
470
+
let accpt = tokio_native_tls::TlsAcceptor::from(accpt);
471
+
tls_acceptor = Some(accpt);
472
+
} else {
473
+
tls_acceptor = None;
474
+
}
475
+
476
+
let web_handle = if let Some(ref webcfg) = state.config.api_server {
477
+
let bind_addr = webcfg.bind_addr;
478
+
let state = state.clone();
479
+
info!("starting http api server on {:?}", &bind_addr);
480
+
Some(tokio::spawn(async move {
481
+
web::start_webserver(bind_addr, state).await;
482
+
}))
483
+
} else {
484
+
None
485
+
};
486
+
487
+
let (exit_signal_tx, exit_signal_rx) = tokio::sync::oneshot::channel::<()>();
488
+
489
+
let async_server = async move {
490
+
let server = match TcpListener::bind(state.config.lumina.bind_addr).await {
491
+
Ok(v) => v,
492
+
Err(err) => {
493
+
error!("failed to bind server port: {}", err);
494
+
exit(1);
495
+
},
496
+
};
497
+
498
+
info!("listening on {:?} secure={}", server.local_addr().unwrap(), tls_acceptor.is_some());
499
+
500
+
serve(server, tls_acceptor, state, exit_signal_rx).await;
501
+
};
502
+
503
+
let server_handle = tokio::task::spawn(async_server);
504
+
tokio::signal::ctrl_c().await.unwrap();
505
+
debug!("CTRL-C; exiting...");
506
+
if let Some(handle) = web_handle {
507
+
handle.abort();
508
+
}
509
+
exit_signal_tx.send(()).unwrap();
510
+
server_handle.await.unwrap();
511
+
512
+
info!("Goodbye.");
513
+
}
+33
-35
lumen/src/web.rs
+33
-35
lumen/src/web.rs
···
1
-
use std::net::SocketAddr;
2
-
3
-
use log::error;
4
-
use warp::{Filter, hyper::StatusCode, reply::Response};
5
-
use common::{SharedState, web::api::api_root};
6
-
7
-
pub async fn start_webserver<A: Into<SocketAddr> + 'static>(bind_addr: A, shared_state: SharedState) {
8
-
let root = warp::get()
9
-
.and(warp::path::end())
10
-
.map(|| warp::reply::html(include_str!("home.html")));
11
-
12
-
let shared_state1 = shared_state.clone();
13
-
let api = warp::path("api")
14
-
.and(api_root(shared_state1));
15
-
16
-
let metrics = warp::get().and(warp::path("metrics")).and(warp::path::end())
17
-
.map(move || {
18
-
let mut res = String::new();
19
-
if let Err(err) = prometheus_client::encoding::text::encode(&mut res, &shared_state.metrics.registry) {
20
-
error!("failed to encode metrics: {err}");
21
-
let mut r = Response::default();
22
-
*r.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
23
-
r
24
-
} else {
25
-
warp::reply::Response::new(res.into())
26
-
}
27
-
});
28
-
29
-
let routes = root
30
-
.or(api)
31
-
.or(metrics);
32
-
33
-
warp::serve(routes)
34
-
.run(bind_addr).await;
35
-
}
1
+
use std::net::SocketAddr;
2
+
3
+
use common::{web::api::api_root, SharedState};
4
+
use log::error;
5
+
use warp::{hyper::StatusCode, reply::Response, Filter};
6
+
7
+
pub async fn start_webserver<A: Into<SocketAddr> + 'static>(
8
+
bind_addr: A, shared_state: SharedState,
9
+
) {
10
+
let root =
11
+
warp::get().and(warp::path::end()).map(|| warp::reply::html(include_str!("home.html")));
12
+
13
+
let shared_state1 = shared_state.clone();
14
+
let api = warp::path("api").and(api_root(shared_state1));
15
+
16
+
let metrics = warp::get().and(warp::path("metrics")).and(warp::path::end()).map(move || {
17
+
let mut res = String::new();
18
+
if let Err(err) =
19
+
prometheus_client::encoding::text::encode(&mut res, &shared_state.metrics.registry)
20
+
{
21
+
error!("failed to encode metrics: {err}");
22
+
let mut r = Response::default();
23
+
*r.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
24
+
r
25
+
} else {
26
+
warp::reply::Response::new(res.into())
27
+
}
28
+
});
29
+
30
+
let routes = root.or(api).or(metrics);
31
+
32
+
warp::serve(routes).run(bind_addr).await;
33
+
}