aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock1277
-rw-r--r--Cargo.toml19
-rw-r--r--README.md15
-rw-r--r--TODO.md10
-rw-r--r--rustfmt.toml1
-rw-r--r--src/custom_filters.rs21
-rw-r--r--src/handlers.rs122
-rw-r--r--src/main.rs26
-rw-r--r--src/routes.rs359
-rw-r--r--src/schema.rs223
-rw-r--r--src/validators.rs44
12 files changed, 2118 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..c531d87
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,1277 @@
1# This file is automatically @generated by Cargo.
2# It is not intended for manual editing.
3[[package]]
4name = "aho-corasick"
5version = "0.7.15"
6source = "registry+https://github.com/rust-lang/crates.io-index"
7checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
8dependencies = [
9 "memchr",
10]
11
12[[package]]
13name = "atty"
14version = "0.2.14"
15source = "registry+https://github.com/rust-lang/crates.io-index"
16checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
17dependencies = [
18 "hermit-abi",
19 "libc",
20 "winapi 0.3.9",
21]
22
23[[package]]
24name = "autocfg"
25version = "1.0.1"
26source = "registry+https://github.com/rust-lang/crates.io-index"
27checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
28
29[[package]]
30name = "base64"
31version = "0.12.3"
32source = "registry+https://github.com/rust-lang/crates.io-index"
33checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
34
35[[package]]
36name = "base64"
37version = "0.13.0"
38source = "registry+https://github.com/rust-lang/crates.io-index"
39checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
40
41[[package]]
42name = "bitflags"
43version = "1.2.1"
44source = "registry+https://github.com/rust-lang/crates.io-index"
45checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
46
47[[package]]
48name = "block-buffer"
49version = "0.9.0"
50source = "registry+https://github.com/rust-lang/crates.io-index"
51checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
52dependencies = [
53 "generic-array",
54]
55
56[[package]]
57name = "buf_redux"
58version = "0.8.4"
59source = "registry+https://github.com/rust-lang/crates.io-index"
60checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f"
61dependencies = [
62 "memchr",
63 "safemem",
64]
65
66[[package]]
67name = "byteorder"
68version = "1.4.3"
69source = "registry+https://github.com/rust-lang/crates.io-index"
70checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
71
72[[package]]
73name = "bytes"
74version = "0.5.6"
75source = "registry+https://github.com/rust-lang/crates.io-index"
76checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
77
78[[package]]
79name = "bytes"
80version = "1.0.1"
81source = "registry+https://github.com/rust-lang/crates.io-index"
82checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
83
84[[package]]
85name = "cfg-if"
86version = "0.1.10"
87source = "registry+https://github.com/rust-lang/crates.io-index"
88checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
89
90[[package]]
91name = "cfg-if"
92version = "1.0.0"
93source = "registry+https://github.com/rust-lang/crates.io-index"
94checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
95
96[[package]]
97name = "chrono"
98version = "0.4.19"
99source = "registry+https://github.com/rust-lang/crates.io-index"
100checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
101dependencies = [
102 "libc",
103 "num-integer",
104 "num-traits",
105 "serde",
106 "time",
107 "winapi 0.3.9",
108]
109
110[[package]]
111name = "cpuid-bool"
112version = "0.1.2"
113source = "registry+https://github.com/rust-lang/crates.io-index"
114checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
115
116[[package]]
117name = "digest"
118version = "0.9.0"
119source = "registry+https://github.com/rust-lang/crates.io-index"
120checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
121dependencies = [
122 "generic-array",
123]
124
125[[package]]
126name = "dtoa"
127version = "0.4.8"
128source = "registry+https://github.com/rust-lang/crates.io-index"
129checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
130
131[[package]]
132name = "env_logger"
133version = "0.6.2"
134source = "registry+https://github.com/rust-lang/crates.io-index"
135checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
136dependencies = [
137 "atty",
138 "humantime",
139 "log",
140 "regex",
141 "termcolor",
142]
143
144[[package]]
145name = "fnv"
146version = "1.0.7"
147source = "registry+https://github.com/rust-lang/crates.io-index"
148checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
149
150[[package]]
151name = "form_urlencoded"
152version = "1.0.1"
153source = "registry+https://github.com/rust-lang/crates.io-index"
154checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
155dependencies = [
156 "matches",
157 "percent-encoding",
158]
159
160[[package]]
161name = "fuchsia-zircon"
162version = "0.3.3"
163source = "registry+https://github.com/rust-lang/crates.io-index"
164checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
165dependencies = [
166 "bitflags",
167 "fuchsia-zircon-sys",
168]
169
170[[package]]
171name = "fuchsia-zircon-sys"
172version = "0.3.3"
173source = "registry+https://github.com/rust-lang/crates.io-index"
174checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
175
176[[package]]
177name = "futures"
178version = "0.3.13"
179source = "registry+https://github.com/rust-lang/crates.io-index"
180checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1"
181dependencies = [
182 "futures-channel",
183 "futures-core",
184 "futures-io",
185 "futures-sink",
186 "futures-task",
187 "futures-util",
188]
189
190[[package]]
191name = "futures-channel"
192version = "0.3.13"
193source = "registry+https://github.com/rust-lang/crates.io-index"
194checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939"
195dependencies = [
196 "futures-core",
197 "futures-sink",
198]
199
200[[package]]
201name = "futures-core"
202version = "0.3.13"
203source = "registry+https://github.com/rust-lang/crates.io-index"
204checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94"
205
206[[package]]
207name = "futures-io"
208version = "0.3.13"
209source = "registry+https://github.com/rust-lang/crates.io-index"
210checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59"
211
212[[package]]
213name = "futures-sink"
214version = "0.3.13"
215source = "registry+https://github.com/rust-lang/crates.io-index"
216checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3"
217
218[[package]]
219name = "futures-task"
220version = "0.3.13"
221source = "registry+https://github.com/rust-lang/crates.io-index"
222checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80"
223
224[[package]]
225name = "futures-util"
226version = "0.3.13"
227source = "registry+https://github.com/rust-lang/crates.io-index"
228checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1"
229dependencies = [
230 "futures-core",
231 "futures-sink",
232 "futures-task",
233 "pin-project-lite 0.2.6",
234 "pin-utils",
235 "slab",
236]
237
238[[package]]
239name = "generic-array"
240version = "0.14.4"
241source = "registry+https://github.com/rust-lang/crates.io-index"
242checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
243dependencies = [
244 "typenum",
245 "version_check",
246]
247
248[[package]]
249name = "getrandom"
250version = "0.1.16"
251source = "registry+https://github.com/rust-lang/crates.io-index"
252checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
253dependencies = [
254 "cfg-if 1.0.0",
255 "libc",
256 "wasi 0.9.0+wasi-snapshot-preview1",
257]
258
259[[package]]
260name = "getrandom"
261version = "0.2.2"
262source = "registry+https://github.com/rust-lang/crates.io-index"
263checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
264dependencies = [
265 "cfg-if 1.0.0",
266 "libc",
267 "wasi 0.10.0+wasi-snapshot-preview1",
268]
269
270[[package]]
271name = "gradecoin"
272version = "0.1.0"
273dependencies = [
274 "chrono",
275 "log",
276 "pretty_env_logger",
277 "serde",
278 "serde_json",
279 "serde_test",
280 "tokio",
281 "warp",
282]
283
284[[package]]
285name = "h2"
286version = "0.2.7"
287source = "registry+https://github.com/rust-lang/crates.io-index"
288checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535"
289dependencies = [
290 "bytes 0.5.6",
291 "fnv",
292 "futures-core",
293 "futures-sink",
294 "futures-util",
295 "http",
296 "indexmap",
297 "slab",
298 "tokio",
299 "tokio-util",
300 "tracing",
301 "tracing-futures",
302]
303
304[[package]]
305name = "hashbrown"
306version = "0.9.1"
307source = "registry+https://github.com/rust-lang/crates.io-index"
308checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
309
310[[package]]
311name = "headers"
312version = "0.3.4"
313source = "registry+https://github.com/rust-lang/crates.io-index"
314checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855"
315dependencies = [
316 "base64 0.13.0",
317 "bitflags",
318 "bytes 1.0.1",
319 "headers-core",
320 "http",
321 "mime",
322 "sha-1",
323 "time",
324]
325
326[[package]]
327name = "headers-core"
328version = "0.2.0"
329source = "registry+https://github.com/rust-lang/crates.io-index"
330checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
331dependencies = [
332 "http",
333]
334
335[[package]]
336name = "hermit-abi"
337version = "0.1.18"
338source = "registry+https://github.com/rust-lang/crates.io-index"
339checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
340dependencies = [
341 "libc",
342]
343
344[[package]]
345name = "http"
346version = "0.2.3"
347source = "registry+https://github.com/rust-lang/crates.io-index"
348checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747"
349dependencies = [
350 "bytes 1.0.1",
351 "fnv",
352 "itoa",
353]
354
355[[package]]
356name = "http-body"
357version = "0.3.1"
358source = "registry+https://github.com/rust-lang/crates.io-index"
359checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"
360dependencies = [
361 "bytes 0.5.6",
362 "http",
363]
364
365[[package]]
366name = "httparse"
367version = "1.3.5"
368source = "registry+https://github.com/rust-lang/crates.io-index"
369checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691"
370
371[[package]]
372name = "httpdate"
373version = "0.3.2"
374source = "registry+https://github.com/rust-lang/crates.io-index"
375checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47"
376
377[[package]]
378name = "humantime"
379version = "1.3.0"
380source = "registry+https://github.com/rust-lang/crates.io-index"
381checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
382dependencies = [
383 "quick-error",
384]
385
386[[package]]
387name = "hyper"
388version = "0.13.10"
389source = "registry+https://github.com/rust-lang/crates.io-index"
390checksum = "8a6f157065790a3ed2f88679250419b5cdd96e714a0d65f7797fd337186e96bb"
391dependencies = [
392 "bytes 0.5.6",
393 "futures-channel",
394 "futures-core",
395 "futures-util",
396 "h2",
397 "http",
398 "http-body",
399 "httparse",
400 "httpdate",
401 "itoa",
402 "pin-project 1.0.6",
403 "socket2",
404 "tokio",
405 "tower-service",
406 "tracing",
407 "want",
408]
409
410[[package]]
411name = "idna"
412version = "0.2.2"
413source = "registry+https://github.com/rust-lang/crates.io-index"
414checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21"
415dependencies = [
416 "matches",
417 "unicode-bidi",
418 "unicode-normalization",
419]
420
421[[package]]
422name = "indexmap"
423version = "1.6.2"
424source = "registry+https://github.com/rust-lang/crates.io-index"
425checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
426dependencies = [
427 "autocfg",
428 "hashbrown",
429]
430
431[[package]]
432name = "input_buffer"
433version = "0.3.1"
434source = "registry+https://github.com/rust-lang/crates.io-index"
435checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754"
436dependencies = [
437 "bytes 0.5.6",
438]
439
440[[package]]
441name = "iovec"
442version = "0.1.4"
443source = "registry+https://github.com/rust-lang/crates.io-index"
444checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
445dependencies = [
446 "libc",
447]
448
449[[package]]
450name = "itoa"
451version = "0.4.7"
452source = "registry+https://github.com/rust-lang/crates.io-index"
453checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
454
455[[package]]
456name = "kernel32-sys"
457version = "0.2.2"
458source = "registry+https://github.com/rust-lang/crates.io-index"
459checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
460dependencies = [
461 "winapi 0.2.8",
462 "winapi-build",
463]
464
465[[package]]
466name = "lazy_static"
467version = "1.4.0"
468source = "registry+https://github.com/rust-lang/crates.io-index"
469checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
470
471[[package]]
472name = "libc"
473version = "0.2.93"
474source = "registry+https://github.com/rust-lang/crates.io-index"
475checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
476
477[[package]]
478name = "log"
479version = "0.4.14"
480source = "registry+https://github.com/rust-lang/crates.io-index"
481checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
482dependencies = [
483 "cfg-if 1.0.0",
484]
485
486[[package]]
487name = "matches"
488version = "0.1.8"
489source = "registry+https://github.com/rust-lang/crates.io-index"
490checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
491
492[[package]]
493name = "memchr"
494version = "2.3.4"
495source = "registry+https://github.com/rust-lang/crates.io-index"
496checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
497
498[[package]]
499name = "mime"
500version = "0.3.16"
501source = "registry+https://github.com/rust-lang/crates.io-index"
502checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
503
504[[package]]
505name = "mime_guess"
506version = "2.0.3"
507source = "registry+https://github.com/rust-lang/crates.io-index"
508checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
509dependencies = [
510 "mime",
511 "unicase",
512]
513
514[[package]]
515name = "mio"
516version = "0.6.23"
517source = "registry+https://github.com/rust-lang/crates.io-index"
518checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
519dependencies = [
520 "cfg-if 0.1.10",
521 "fuchsia-zircon",
522 "fuchsia-zircon-sys",
523 "iovec",
524 "kernel32-sys",
525 "libc",
526 "log",
527 "miow",
528 "net2",
529 "slab",
530 "winapi 0.2.8",
531]
532
533[[package]]
534name = "miow"
535version = "0.2.2"
536source = "registry+https://github.com/rust-lang/crates.io-index"
537checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
538dependencies = [
539 "kernel32-sys",
540 "net2",
541 "winapi 0.2.8",
542 "ws2_32-sys",
543]
544
545[[package]]
546name = "multipart"
547version = "0.17.1"
548source = "registry+https://github.com/rust-lang/crates.io-index"
549checksum = "d050aeedc89243f5347c3e237e3e13dc76fbe4ae3742a57b94dc14f69acf76d4"
550dependencies = [
551 "buf_redux",
552 "httparse",
553 "log",
554 "mime",
555 "mime_guess",
556 "quick-error",
557 "rand 0.7.3",
558 "safemem",
559 "tempfile",
560 "twoway",
561]
562
563[[package]]
564name = "net2"
565version = "0.2.37"
566source = "registry+https://github.com/rust-lang/crates.io-index"
567checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
568dependencies = [
569 "cfg-if 0.1.10",
570 "libc",
571 "winapi 0.3.9",
572]
573
574[[package]]
575name = "num-integer"
576version = "0.1.44"
577source = "registry+https://github.com/rust-lang/crates.io-index"
578checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
579dependencies = [
580 "autocfg",
581 "num-traits",
582]
583
584[[package]]
585name = "num-traits"
586version = "0.2.14"
587source = "registry+https://github.com/rust-lang/crates.io-index"
588checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
589dependencies = [
590 "autocfg",
591]
592
593[[package]]
594name = "opaque-debug"
595version = "0.3.0"
596source = "registry+https://github.com/rust-lang/crates.io-index"
597checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
598
599[[package]]
600name = "percent-encoding"
601version = "2.1.0"
602source = "registry+https://github.com/rust-lang/crates.io-index"
603checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
604
605[[package]]
606name = "pin-project"
607version = "0.4.28"
608source = "registry+https://github.com/rust-lang/crates.io-index"
609checksum = "918192b5c59119d51e0cd221f4d49dde9112824ba717369e903c97d076083d0f"
610dependencies = [
611 "pin-project-internal 0.4.28",
612]
613
614[[package]]
615name = "pin-project"
616version = "1.0.6"
617source = "registry+https://github.com/rust-lang/crates.io-index"
618checksum = "bc174859768806e91ae575187ada95c91a29e96a98dc5d2cd9a1fed039501ba6"
619dependencies = [
620 "pin-project-internal 1.0.6",
621]
622
623[[package]]
624name = "pin-project-internal"
625version = "0.4.28"
626source = "registry+https://github.com/rust-lang/crates.io-index"
627checksum = "3be26700300be6d9d23264c73211d8190e755b6b5ca7a1b28230025511b52a5e"
628dependencies = [
629 "proc-macro2",
630 "quote",
631 "syn",
632]
633
634[[package]]
635name = "pin-project-internal"
636version = "1.0.6"
637source = "registry+https://github.com/rust-lang/crates.io-index"
638checksum = "a490329918e856ed1b083f244e3bfe2d8c4f336407e4ea9e1a9f479ff09049e5"
639dependencies = [
640 "proc-macro2",
641 "quote",
642 "syn",
643]
644
645[[package]]
646name = "pin-project-lite"
647version = "0.1.12"
648source = "registry+https://github.com/rust-lang/crates.io-index"
649checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777"
650
651[[package]]
652name = "pin-project-lite"
653version = "0.2.6"
654source = "registry+https://github.com/rust-lang/crates.io-index"
655checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
656
657[[package]]
658name = "pin-utils"
659version = "0.1.0"
660source = "registry+https://github.com/rust-lang/crates.io-index"
661checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
662
663[[package]]
664name = "ppv-lite86"
665version = "0.2.10"
666source = "registry+https://github.com/rust-lang/crates.io-index"
667checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
668
669[[package]]
670name = "pretty_env_logger"
671version = "0.3.1"
672source = "registry+https://github.com/rust-lang/crates.io-index"
673checksum = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074"
674dependencies = [
675 "chrono",
676 "env_logger",
677 "log",
678]
679
680[[package]]
681name = "proc-macro2"
682version = "1.0.26"
683source = "registry+https://github.com/rust-lang/crates.io-index"
684checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
685dependencies = [
686 "unicode-xid",
687]
688
689[[package]]
690name = "quick-error"
691version = "1.2.3"
692source = "registry+https://github.com/rust-lang/crates.io-index"
693checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
694
695[[package]]
696name = "quote"
697version = "1.0.9"
698source = "registry+https://github.com/rust-lang/crates.io-index"
699checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
700dependencies = [
701 "proc-macro2",
702]
703
704[[package]]
705name = "rand"
706version = "0.7.3"
707source = "registry+https://github.com/rust-lang/crates.io-index"
708checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
709dependencies = [
710 "getrandom 0.1.16",
711 "libc",
712 "rand_chacha 0.2.2",
713 "rand_core 0.5.1",
714 "rand_hc 0.2.0",
715]
716
717[[package]]
718name = "rand"
719version = "0.8.3"
720source = "registry+https://github.com/rust-lang/crates.io-index"
721checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
722dependencies = [
723 "libc",
724 "rand_chacha 0.3.0",
725 "rand_core 0.6.2",
726 "rand_hc 0.3.0",
727]
728
729[[package]]
730name = "rand_chacha"
731version = "0.2.2"
732source = "registry+https://github.com/rust-lang/crates.io-index"
733checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
734dependencies = [
735 "ppv-lite86",
736 "rand_core 0.5.1",
737]
738
739[[package]]
740name = "rand_chacha"
741version = "0.3.0"
742source = "registry+https://github.com/rust-lang/crates.io-index"
743checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
744dependencies = [
745 "ppv-lite86",
746 "rand_core 0.6.2",
747]
748
749[[package]]
750name = "rand_core"
751version = "0.5.1"
752source = "registry+https://github.com/rust-lang/crates.io-index"
753checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
754dependencies = [
755 "getrandom 0.1.16",
756]
757
758[[package]]
759name = "rand_core"
760version = "0.6.2"
761source = "registry+https://github.com/rust-lang/crates.io-index"
762checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
763dependencies = [
764 "getrandom 0.2.2",
765]
766
767[[package]]
768name = "rand_hc"
769version = "0.2.0"
770source = "registry+https://github.com/rust-lang/crates.io-index"
771checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
772dependencies = [
773 "rand_core 0.5.1",
774]
775
776[[package]]
777name = "rand_hc"
778version = "0.3.0"
779source = "registry+https://github.com/rust-lang/crates.io-index"
780checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
781dependencies = [
782 "rand_core 0.6.2",
783]
784
785[[package]]
786name = "redox_syscall"
787version = "0.2.5"
788source = "registry+https://github.com/rust-lang/crates.io-index"
789checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
790dependencies = [
791 "bitflags",
792]
793
794[[package]]
795name = "regex"
796version = "1.4.5"
797source = "registry+https://github.com/rust-lang/crates.io-index"
798checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
799dependencies = [
800 "aho-corasick",
801 "memchr",
802 "regex-syntax",
803]
804
805[[package]]
806name = "regex-syntax"
807version = "0.6.23"
808source = "registry+https://github.com/rust-lang/crates.io-index"
809checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
810
811[[package]]
812name = "remove_dir_all"
813version = "0.5.3"
814source = "registry+https://github.com/rust-lang/crates.io-index"
815checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
816dependencies = [
817 "winapi 0.3.9",
818]
819
820[[package]]
821name = "ryu"
822version = "1.0.5"
823source = "registry+https://github.com/rust-lang/crates.io-index"
824checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
825
826[[package]]
827name = "safemem"
828version = "0.3.3"
829source = "registry+https://github.com/rust-lang/crates.io-index"
830checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
831
832[[package]]
833name = "scoped-tls"
834version = "1.0.0"
835source = "registry+https://github.com/rust-lang/crates.io-index"
836checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
837
838[[package]]
839name = "serde"
840version = "1.0.125"
841source = "registry+https://github.com/rust-lang/crates.io-index"
842checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
843dependencies = [
844 "serde_derive",
845]
846
847[[package]]
848name = "serde_derive"
849version = "1.0.125"
850source = "registry+https://github.com/rust-lang/crates.io-index"
851checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
852dependencies = [
853 "proc-macro2",
854 "quote",
855 "syn",
856]
857
858[[package]]
859name = "serde_json"
860version = "1.0.64"
861source = "registry+https://github.com/rust-lang/crates.io-index"
862checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
863dependencies = [
864 "itoa",
865 "ryu",
866 "serde",
867]
868
869[[package]]
870name = "serde_test"
871version = "1.0.125"
872source = "registry+https://github.com/rust-lang/crates.io-index"
873checksum = "b4bb5fef7eaf5a97917567183607ac4224c5b451c15023930f23b937cce879fe"
874dependencies = [
875 "serde",
876]
877
878[[package]]
879name = "serde_urlencoded"
880version = "0.6.1"
881source = "registry+https://github.com/rust-lang/crates.io-index"
882checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
883dependencies = [
884 "dtoa",
885 "itoa",
886 "serde",
887 "url",
888]
889
890[[package]]
891name = "sha-1"
892version = "0.9.4"
893source = "registry+https://github.com/rust-lang/crates.io-index"
894checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f"
895dependencies = [
896 "block-buffer",
897 "cfg-if 1.0.0",
898 "cpuid-bool",
899 "digest",
900 "opaque-debug",
901]
902
903[[package]]
904name = "slab"
905version = "0.4.2"
906source = "registry+https://github.com/rust-lang/crates.io-index"
907checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
908
909[[package]]
910name = "socket2"
911version = "0.3.19"
912source = "registry+https://github.com/rust-lang/crates.io-index"
913checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
914dependencies = [
915 "cfg-if 1.0.0",
916 "libc",
917 "winapi 0.3.9",
918]
919
920[[package]]
921name = "syn"
922version = "1.0.68"
923source = "registry+https://github.com/rust-lang/crates.io-index"
924checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87"
925dependencies = [
926 "proc-macro2",
927 "quote",
928 "unicode-xid",
929]
930
931[[package]]
932name = "tempfile"
933version = "3.2.0"
934source = "registry+https://github.com/rust-lang/crates.io-index"
935checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
936dependencies = [
937 "cfg-if 1.0.0",
938 "libc",
939 "rand 0.8.3",
940 "redox_syscall",
941 "remove_dir_all",
942 "winapi 0.3.9",
943]
944
945[[package]]
946name = "termcolor"
947version = "1.1.2"
948source = "registry+https://github.com/rust-lang/crates.io-index"
949checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
950dependencies = [
951 "winapi-util",
952]
953
954[[package]]
955name = "time"
956version = "0.1.44"
957source = "registry+https://github.com/rust-lang/crates.io-index"
958checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
959dependencies = [
960 "libc",
961 "wasi 0.10.0+wasi-snapshot-preview1",
962 "winapi 0.3.9",
963]
964
965[[package]]
966name = "tinyvec"
967version = "1.2.0"
968source = "registry+https://github.com/rust-lang/crates.io-index"
969checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
970dependencies = [
971 "tinyvec_macros",
972]
973
974[[package]]
975name = "tinyvec_macros"
976version = "0.1.0"
977source = "registry+https://github.com/rust-lang/crates.io-index"
978checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
979
980[[package]]
981name = "tokio"
982version = "0.2.25"
983source = "registry+https://github.com/rust-lang/crates.io-index"
984checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092"
985dependencies = [
986 "bytes 0.5.6",
987 "fnv",
988 "futures-core",
989 "iovec",
990 "lazy_static",
991 "memchr",
992 "mio",
993 "pin-project-lite 0.1.12",
994 "slab",
995 "tokio-macros",
996]
997
998[[package]]
999name = "tokio-macros"
1000version = "0.2.6"
1001source = "registry+https://github.com/rust-lang/crates.io-index"
1002checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a"
1003dependencies = [
1004 "proc-macro2",
1005 "quote",
1006 "syn",
1007]
1008
1009[[package]]
1010name = "tokio-tungstenite"
1011version = "0.11.0"
1012source = "registry+https://github.com/rust-lang/crates.io-index"
1013checksum = "6d9e878ad426ca286e4dcae09cbd4e1973a7f8987d97570e2469703dd7f5720c"
1014dependencies = [
1015 "futures-util",
1016 "log",
1017 "pin-project 0.4.28",
1018 "tokio",
1019 "tungstenite",
1020]
1021
1022[[package]]
1023name = "tokio-util"
1024version = "0.3.1"
1025source = "registry+https://github.com/rust-lang/crates.io-index"
1026checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
1027dependencies = [
1028 "bytes 0.5.6",
1029 "futures-core",
1030 "futures-sink",
1031 "log",
1032 "pin-project-lite 0.1.12",
1033 "tokio",
1034]
1035
1036[[package]]
1037name = "tower-service"
1038version = "0.3.1"
1039source = "registry+https://github.com/rust-lang/crates.io-index"
1040checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
1041
1042[[package]]
1043name = "tracing"
1044version = "0.1.25"
1045source = "registry+https://github.com/rust-lang/crates.io-index"
1046checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f"
1047dependencies = [
1048 "cfg-if 1.0.0",
1049 "log",
1050 "pin-project-lite 0.2.6",
1051 "tracing-core",
1052]
1053
1054[[package]]
1055name = "tracing-core"
1056version = "0.1.17"
1057source = "registry+https://github.com/rust-lang/crates.io-index"
1058checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f"
1059dependencies = [
1060 "lazy_static",
1061]
1062
1063[[package]]
1064name = "tracing-futures"
1065version = "0.2.5"
1066source = "registry+https://github.com/rust-lang/crates.io-index"
1067checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
1068dependencies = [
1069 "pin-project 1.0.6",
1070 "tracing",
1071]
1072
1073[[package]]
1074name = "try-lock"
1075version = "0.2.3"
1076source = "registry+https://github.com/rust-lang/crates.io-index"
1077checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
1078
1079[[package]]
1080name = "tungstenite"
1081version = "0.11.1"
1082source = "registry+https://github.com/rust-lang/crates.io-index"
1083checksum = "f0308d80d86700c5878b9ef6321f020f29b1bb9d5ff3cab25e75e23f3a492a23"
1084dependencies = [
1085 "base64 0.12.3",
1086 "byteorder",
1087 "bytes 0.5.6",
1088 "http",
1089 "httparse",
1090 "input_buffer",
1091 "log",
1092 "rand 0.7.3",
1093 "sha-1",
1094 "url",
1095 "utf-8",
1096]
1097
1098[[package]]
1099name = "twoway"
1100version = "0.1.8"
1101source = "registry+https://github.com/rust-lang/crates.io-index"
1102checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1"
1103dependencies = [
1104 "memchr",
1105]
1106
1107[[package]]
1108name = "typenum"
1109version = "1.13.0"
1110source = "registry+https://github.com/rust-lang/crates.io-index"
1111checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
1112
1113[[package]]
1114name = "unicase"
1115version = "2.6.0"
1116source = "registry+https://github.com/rust-lang/crates.io-index"
1117checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
1118dependencies = [
1119 "version_check",
1120]
1121
1122[[package]]
1123name = "unicode-bidi"
1124version = "0.3.5"
1125source = "registry+https://github.com/rust-lang/crates.io-index"
1126checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0"
1127dependencies = [
1128 "matches",
1129]
1130
1131[[package]]
1132name = "unicode-normalization"
1133version = "0.1.17"
1134source = "registry+https://github.com/rust-lang/crates.io-index"
1135checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef"
1136dependencies = [
1137 "tinyvec",
1138]
1139
1140[[package]]
1141name = "unicode-xid"
1142version = "0.2.1"
1143source = "registry+https://github.com/rust-lang/crates.io-index"
1144checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
1145
1146[[package]]
1147name = "url"
1148version = "2.2.1"
1149source = "registry+https://github.com/rust-lang/crates.io-index"
1150checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b"
1151dependencies = [
1152 "form_urlencoded",
1153 "idna",
1154 "matches",
1155 "percent-encoding",
1156]
1157
1158[[package]]
1159name = "urlencoding"
1160version = "1.1.1"
1161source = "registry+https://github.com/rust-lang/crates.io-index"
1162checksum = "c9232eb53352b4442e40d7900465dfc534e8cb2dc8f18656fcb2ac16112b5593"
1163
1164[[package]]
1165name = "utf-8"
1166version = "0.7.5"
1167source = "registry+https://github.com/rust-lang/crates.io-index"
1168checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7"
1169
1170[[package]]
1171name = "version_check"
1172version = "0.9.3"
1173source = "registry+https://github.com/rust-lang/crates.io-index"
1174checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
1175
1176[[package]]
1177name = "want"
1178version = "0.3.0"
1179source = "registry+https://github.com/rust-lang/crates.io-index"
1180checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
1181dependencies = [
1182 "log",
1183 "try-lock",
1184]
1185
1186[[package]]
1187name = "warp"
1188version = "0.2.5"
1189source = "registry+https://github.com/rust-lang/crates.io-index"
1190checksum = "f41be6df54c97904af01aa23e613d4521eed7ab23537cede692d4058f6449407"
1191dependencies = [
1192 "bytes 0.5.6",
1193 "futures",
1194 "headers",
1195 "http",
1196 "hyper",
1197 "log",
1198 "mime",
1199 "mime_guess",
1200 "multipart",
1201 "pin-project 0.4.28",
1202 "scoped-tls",
1203 "serde",
1204 "serde_json",
1205 "serde_urlencoded",
1206 "tokio",
1207 "tokio-tungstenite",
1208 "tower-service",
1209 "tracing",
1210 "tracing-futures",
1211 "urlencoding",
1212]
1213
1214[[package]]
1215name = "wasi"
1216version = "0.9.0+wasi-snapshot-preview1"
1217source = "registry+https://github.com/rust-lang/crates.io-index"
1218checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
1219
1220[[package]]
1221name = "wasi"
1222version = "0.10.0+wasi-snapshot-preview1"
1223source = "registry+https://github.com/rust-lang/crates.io-index"
1224checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
1225
1226[[package]]
1227name = "winapi"
1228version = "0.2.8"
1229source = "registry+https://github.com/rust-lang/crates.io-index"
1230checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
1231
1232[[package]]
1233name = "winapi"
1234version = "0.3.9"
1235source = "registry+https://github.com/rust-lang/crates.io-index"
1236checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1237dependencies = [
1238 "winapi-i686-pc-windows-gnu",
1239 "winapi-x86_64-pc-windows-gnu",
1240]
1241
1242[[package]]
1243name = "winapi-build"
1244version = "0.1.1"
1245source = "registry+https://github.com/rust-lang/crates.io-index"
1246checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
1247
1248[[package]]
1249name = "winapi-i686-pc-windows-gnu"
1250version = "0.4.0"
1251source = "registry+https://github.com/rust-lang/crates.io-index"
1252checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1253
1254[[package]]
1255name = "winapi-util"
1256version = "0.1.5"
1257source = "registry+https://github.com/rust-lang/crates.io-index"
1258checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
1259dependencies = [
1260 "winapi 0.3.9",
1261]
1262
1263[[package]]
1264name = "winapi-x86_64-pc-windows-gnu"
1265version = "0.4.0"
1266source = "registry+https://github.com/rust-lang/crates.io-index"
1267checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1268
1269[[package]]
1270name = "ws2_32-sys"
1271version = "0.2.1"
1272source = "registry+https://github.com/rust-lang/crates.io-index"
1273checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
1274dependencies = [
1275 "winapi 0.2.8",
1276 "winapi-build",
1277]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..3f9c00d
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,19 @@
1[package]
2name = "gradecoin"
3version = "0.1.0"
4authors = ["Yigit Sever <yigit@ceng.metu.edu.tr>"]
5edition = "2018"
6
7# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8
9[dependencies]
10warp = "0.2.0"
11tokio = { version = "0.2.9", features = ["macros"] }
12serde = { version = "1.0.104", features = ["derive"] }
13chrono = { version = "0.4.10", features = ["serde"] }
14log = "0.4.8"
15pretty_env_logger = "0.3.1"
16
17[dev-dependencies]
18serde_json = "1.0.44"
19serde_test = "1.0.104"
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..fcfda11
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
1# Gradecoin
2
3This will sit behind nginx reverse proxy so running at 127.0.0.1:8080 is no problem, or https.
4
5```
6$ cargo run
7
8$ curl --location --request POST 'localhost:8080/transaction' --header 'Content-Type: application/json' --data-raw '{
9 "source": "Myself Truly",
10 "target": "Literally Anybody Else",
11 "amount": 12,
12 "timestamp": "2021-04-07T00:17:00"
13}'
14```
15
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..76292d2
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,10 @@
1# TODO
2## Proof-of-work
3- [ ] pick a block proposal scheme (= pick hash function) [list of hash functions](https://en.bitcoinwiki.org/wiki/List_of_hash_functions)
4- [ ] check the nonce for incoming blocks
5
6## Authentication
7- [ ] pick a user authentication scheme
8 - [ ] implement it
9
10- [ ] Switch to RwLock (parking_lot)
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 0000000..1a076d8
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1 @@
edition="2018"
diff --git a/src/custom_filters.rs b/src/custom_filters.rs
new file mode 100644
index 0000000..86a78d4
--- /dev/null
+++ b/src/custom_filters.rs
@@ -0,0 +1,21 @@
1// Common filters ment to be shared between many endpoints
2
3use std::convert::Infallible;
4use warp::{Filter, Rejection};
5
6use crate::schema::{Db, Transaction}; // `Block` coming later
7
8// Database context for routes
9pub fn with_db(db: Db) -> impl Filter<Extract = (Db,), Error = Infallible> + Clone {
10 warp::any().map(move || db.clone())
11}
12
13// Optional query params to allow pagination
14// pub fn list_options() -> impl Filter<Extract = (ListOptions,), Error = Rejection> + Clone {
15// warp::query::<ListOptions>()
16// }
17
18// Accept only JSON body and reject big payloads
19pub fn json_body() -> impl Filter<Extract = (Transaction,), Error = Rejection> + Clone {
20 warp::body::content_length_limit(1024 * 32).and(warp::body::json())
21}
diff --git a/src/handlers.rs b/src/handlers.rs
new file mode 100644
index 0000000..51c7b63
--- /dev/null
+++ b/src/handlers.rs
@@ -0,0 +1,122 @@
1// API handlers, the ends of each filter chain
2
3use log::debug;
4use std::convert::Infallible;
5use warp::{http::StatusCode, reply};
6
7use crate::schema::{Db, Transaction}; // `Block` coming later
8
9// PROPOSE Transaction
10// POST /transaction
11pub async fn propose_transaction(
12 new_transaction: Transaction,
13 db: Db,
14) -> Result<impl warp::Reply, warp::Rejection> {
15 debug!("new transaction request {:?}", new_transaction);
16
17 let mut transactions = db.lock().await;
18
19 transactions.push(new_transaction);
20
21 Ok(StatusCode::CREATED)
22}
23
24// GET Transaction List
25// GET /transaction
26// Returns JSON array of transactions
27// Cannot fail?
28pub async fn list_transactions(db: Db) -> Result<impl warp::Reply, Infallible> {
29 debug!("list all transactions");
30
31 let transactions = db.lock().await;
32
33 let transactions: Vec<Transaction> = transactions.clone().into_iter().collect();
34
35 Ok(reply::with_status(
36 reply::json(&transactions),
37 StatusCode::OK,
38 ))
39}
40
41// PROPOSE Block
42// POST /block
43
44// `GET /games`
45// Returns JSON array of todos
46// Allows pagination, for example: `GET /games?offset=10&limit=5`
47// pub async fn list_games(options: ListOptions, db: Db) -> Result<impl Reply, Infallible> {
48// debug!("list all games");
49
50// let games = db.lock().await;
51// let games: Vec<Game> = games
52// .clone()
53// .into_iter()
54// .skip(options.offset.unwrap_or(0))
55// .take(options.limit.unwrap_or(std::usize::MAX))
56// .collect();
57
58// Ok(warp::reply::json(&games))
59// }
60
61// `POST /games`
62// Create new game entry with JSON body
63// pub async fn create_game(new_game: Game, db: Db) -> Result<impl Reply, Infallible> {
64// debug!("create new game: {:?}", new_game);
65
66// let mut games = db.lock().await;
67
68// match games.iter().find(|game| game.id == new_game.id) {
69// Some(game) => {
70// debug!("game of given id already exists: {}", game.id);
71
72// Ok(StatusCode::BAD_REQUEST)
73// }
74// None => {
75// games.push(new_game);
76// Ok(StatusCode::CREATED)
77// }
78// }
79// }
80
81// `PUT /games/:id`
82// pub async fn update_game(id: u64, updated_game: Game, db: Db) -> Result<impl Reply, Infallible> {
83// debug!("update existing game: id={}, game={:?}", id, updated_game);
84
85// let mut games = db.lock().await;
86
87// match games.iter_mut().find(|game| game.id == id) {
88// Some(game) => {
89// *game = updated_game;
90
91// Ok(StatusCode::OK)
92// }
93// None => {
94// debug!("game of given id not found");
95
96// Ok(StatusCode::NOT_FOUND)
97// }
98// }
99// }
100
101// `DELETE /games/:id`
102// pub async fn delete_game(id: u64, db: Db) -> Result<impl Reply, Infallible> {
103// debug!("delete game: id={}", id);
104
105// let mut games = db.lock().await;
106
107// let len = games.len();
108
109// // Removes all games with given id
110// games.retain(|game| game.id != id);
111
112// // If games length was smaller that means specyfic game was found and removed
113// let deleted = games.len() != len;
114
115// if deleted {
116// Ok(StatusCode::NO_CONTENT)
117// } else {
118// debug!("game of given id not found");
119
120// Ok(StatusCode::NOT_FOUND)
121// }
122// }
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..bcd4173
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,26 @@
1use std::env;
2use warp::Filter;
3
4mod custom_filters;
5mod handlers;
6mod routes;
7mod schema;
8// mod validators;
9
10#[tokio::main]
11async fn main() {
12 // Show debug logs by default by setting `RUST_LOG=restful_rust=debug`
13 if env::var_os("RUST_LOG").is_none() {
14 env::set_var("RUST_LOG", "restful_rust=debug");
15 }
16 pretty_env_logger::init();
17
18 let db = schema::ledger(); // 1. we need this to return a _simple_ db
19
20 let api = routes::consensus_routes(db);
21
22 let routes = api.with(warp::log("restful_rust"));
23
24 // Start the server
25 warp::serve(routes).run(([127, 0, 0, 1], 8080)).await;
26}
diff --git a/src/routes.rs b/src/routes.rs
new file mode 100644
index 0000000..fc4426a
--- /dev/null
+++ b/src/routes.rs
@@ -0,0 +1,359 @@
1use warp::{Filter, Rejection, Reply};
2
3use crate::custom_filters;
4use crate::handlers;
5use crate::schema::Db;
6
7// Root, all routes combined
8pub fn consensus_routes(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
9 transaction_list(db.clone()).or(transaction_propose(db.clone()))
10}
11
12// GET /transaction
13pub fn transaction_list(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
14 warp::path!("transaction")
15 .and(warp::get())
16 .and(custom_filters::with_db(db))
17 .and_then(handlers::list_transactions)
18}
19
20// POST /transaction
21pub fn transaction_propose(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
22 warp::path!("transaction")
23 .and(warp::post())
24 .and(custom_filters::json_body())
25 .and(custom_filters::with_db(db))
26 .and_then(handlers::propose_transaction)
27}
28
29///////////////////////////
30// below are not mine. //
31///////////////////////////
32
33// Root, all routes combined
34//pub fn games_routes(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
35// games_list(db.clone())
36// .or(games_create(db.clone()))
37// .or(games_update(db.clone()))
38// .or(games_delete(db))
39//}
40
41//// `GET /games?offset=3&limit=5`
42//pub fn games_list(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
43// warp::path!("games")
44// .and(warp::get())
45// .and(custom_filters::list_options())
46// .and(custom_filters::with_db(db))
47// .and_then(handlers::list_games)
48//}
49
50//// `POST /games`
51//pub fn games_create(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
52// warp::path!("games")
53// .and(warp::post())
54// .and(custom_filters::json_body())
55// .and(custom_filters::with_db(db))
56// .and_then(handlers::create_game)
57//}
58
59//// `PUT /games/:id`
60//pub fn games_update(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
61// warp::path!("games" / u64)
62// .and(warp::put())
63// .and(custom_filters::json_body())
64// .and(custom_filters::with_db(db))
65// .and_then(handlers::update_game)
66//}
67
68//// `DELETE /games/:id`
69//pub fn games_delete(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
70// warp::path!("games" / u64)
71// .and(warp::delete())
72// .and(custom_filters::with_db(db))
73// .and_then(handlers::delete_game)
74//}
75
76////////////////////////////////
77//// tests below, it's fine //
78////////////////////////////////
79
80/////////////////////////////////////
81// of course I'll write tests... //
82/////////////////////////////////////
83
84// TODO: write tests <07-04-21, yigit> //
85
86//#[cfg(test)]
87//mod tests {
88// use super::*;
89
90// use chrono::prelude::*;
91// use std::sync::Arc;
92// use tokio::sync::Mutex;
93// use warp::http::StatusCode;
94
95// use crate::schema::{Game, Genre};
96
97// // Mocked dataset for each test
98
99// fn mocked_db() -> Db {
100// Arc::new(Mutex::new(vec![
101// Game {
102// id: 1,
103// title: String::from("Crappy title"),
104// rating: 35,
105// genre: Genre::RolePlaying,
106// description: Some(String::from("Test description...")),
107// release_date: NaiveDate::from_ymd(2011, 9, 22).and_hms(0, 0, 0),
108// },
109// Game {
110// id: 2,
111// title: String::from("Decent game"),
112// rating: 84,
113// genre: Genre::Strategy,
114// description: None,
115// release_date: NaiveDate::from_ymd(2014, 3, 11).and_hms(0, 0, 0),
116// },
117// ]))
118// }
119
120// fn mocked_game() -> Game {
121// Game {
122// id: 3,
123// title: String::from("Another game"),
124// rating: 65,
125// description: None,
126// genre: Genre::Strategy,
127// release_date: NaiveDate::from_ymd(2016, 3, 11).and_hms(0, 0, 0),
128// }
129// }
130
131// #[tokio::test]
132// async fn get_list_of_games_200() {
133// let db = mocked_db();
134// let filter = games_routes(db);
135
136// let res = warp::test::request().method("GET").path("/games").reply(&filter).await;
137
138// assert_eq!(res.status(), StatusCode::OK);
139
140// let expected_json_body = r#"[{"id":1,"title":"Crappy title","rating":35,"genre":"ROLE_PLAYING","description":"Test description...","releaseDate":"2011-09-22T00:00:00"},{"id":2,"title":"Decent game","rating":84,"genre":"STRATEGY","description":null,"releaseDate":"2014-03-11T00:00:00"}]"#;
141// assert_eq!(res.body(), expected_json_body);
142// }
143
144// #[tokio::test]
145// async fn get_list_of_games_with_options_200() {
146// let db = mocked_db();
147// let filter = games_routes(db);
148
149// let res = warp::test::request()
150// .method("GET")
151// .path("/games?offset=1&limit=5")
152// .reply(&filter)
153// .await;
154
155// assert_eq!(res.status(), StatusCode::OK);
156
157// let expected_json_body = r#"[{"id":2,"title":"Decent game","rating":84,"genre":"STRATEGY","description":null,"releaseDate":"2014-03-11T00:00:00"}]"#;
158// assert_eq!(res.body(), expected_json_body);
159// }
160
161// #[tokio::test]
162// async fn get_empty_list_with_offset_overshot_200() {
163// let db = mocked_db();
164// let filter = games_routes(db);
165
166// let res = warp::test::request()
167// .method("GET")
168// .path("/games?offset=5&limit=5")
169// .reply(&filter)
170// .await;
171
172// assert_eq!(res.status(), StatusCode::OK);
173
174// let expected_json_body = r#"[]"#;
175// assert_eq!(res.body(), expected_json_body);
176// }
177
178// #[tokio::test]
179// async fn get_incorrect_options_400() {
180// let db = mocked_db();
181// let filter = games_routes(db);
182
183// let res = warp::test::request()
184// .method("GET")
185// .path("/games?offset=a&limit=b")
186// .reply(&filter)
187// .await;
188
189// assert_eq!(res.status(), StatusCode::BAD_REQUEST);
190// }
191
192// #[tokio::test]
193// async fn get_wrong_path_405() {
194// let db = mocked_db();
195// let filter = games_routes(db);
196
197// let res = warp::test::request()
198// .method("GET")
199// .path("/games/42")
200// .reply(&filter)
201// .await;
202
203// assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
204// }
205
206// #[tokio::test]
207// async fn post_json_201() {
208// let db = mocked_db();
209// let filter = games_routes(db.clone());
210
211// let res = warp::test::request()
212// .method("POST")
213// .json(&mocked_game())
214// .path("/games")
215// .reply(&filter)
216// .await;
217
218// assert_eq!(res.status(), StatusCode::CREATED);
219// assert_eq!(db.lock().await.len(), 3);
220// }
221
222// #[tokio::test]
223// async fn post_too_long_content_413() {
224// let db = mocked_db();
225// let filter = games_routes(db);
226
227// let res = warp::test::request()
228// .method("POST")
229// .header("content-length", 1024 * 36)
230// .path("/games")
231// .reply(&filter)
232// .await;
233
234// assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
235// }
236
237// #[tokio::test]
238// async fn post_wrong_payload_400() {
239// let db = mocked_db();
240// let filter = games_routes(db);
241
242// let res = warp::test::request()
243// .method("POST")
244// .body(&r#"{"id":4}"#)
245// .path("/games")
246// .reply(&filter)
247// .await;
248
249// assert_eq!(res.status(), StatusCode::BAD_REQUEST);
250// }
251
252// #[tokio::test]
253// async fn post_wrong_path_405() {
254// let db = mocked_db();
255// let filter = games_routes(db);
256
257// let res = warp::test::request()
258// .method("POST")
259// .path("/games/42")
260// .reply(&filter)
261// .await;
262
263// assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
264// }
265
266// #[tokio::test]
267// async fn put_json_200() {
268// let db = mocked_db();
269// let filter = games_routes(db.clone());
270
271// let res = warp::test::request()
272// .method("PUT")
273// .json(&mocked_game())
274// .path("/games/2")
275// .reply(&filter)
276// .await;
277
278// assert_eq!(res.status(), StatusCode::OK);
279
280// let db = db.lock().await;
281// let ref title = db[1].title;
282// assert_eq!(title, "Another game");
283// }
284
285// #[tokio::test]
286// async fn put_wrong_id_404() {
287// let db = mocked_db();
288// let filter = games_routes(db);
289
290// let res = warp::test::request()
291// .method("PUT")
292// .json(&mocked_game())
293// .path("/games/42")
294// .reply(&filter)
295// .await;
296
297// assert_eq!(res.status(), StatusCode::NOT_FOUND);
298// }
299
300// #[tokio::test]
301// async fn put_wrong_payload_400() {
302// let db = mocked_db();
303// let filter = games_routes(db);
304
305// let res = warp::test::request()
306// .method("PUT")
307// .header("content-length", 1024 * 16)
308// .body(&r#"{"id":2"#)
309// .path("/games/2")
310// .reply(&filter)
311// .await;
312
313// assert_eq!(res.status(), StatusCode::BAD_REQUEST);
314// }
315
316// #[tokio::test]
317// async fn put_too_long_content_413() {
318// let db = mocked_db();
319// let filter = games_routes(db);
320
321// let res = warp::test::request()
322// .method("PUT")
323// .header("content-length", 1024 * 36)
324// .path("/games/2")
325// .reply(&filter)
326// .await;
327
328// assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
329// }
330
331// #[tokio::test]
332// async fn delete_wrong_id_404() {
333// let db = mocked_db();
334// let filter = games_routes(db);
335
336// let res = warp::test::request()
337// .method("DELETE")
338// .path("/games/42")
339// .reply(&filter)
340// .await;
341
342// assert_eq!(res.status(), StatusCode::NOT_FOUND);
343// }
344
345// #[tokio::test]
346// async fn delete_game_204() {
347// let db = mocked_db();
348// let filter = games_routes(db.clone());
349
350// let res = warp::test::request()
351// .method("DELETE")
352// .path("/games/1")
353// .reply(&filter)
354// .await;
355
356// assert_eq!(res.status(), StatusCode::NO_CONTENT);
357// assert_eq!(db.lock().await.len(), 1);
358// }
359//}
diff --git a/src/schema.rs b/src/schema.rs
new file mode 100644
index 0000000..ea36a70
--- /dev/null
+++ b/src/schema.rs
@@ -0,0 +1,223 @@
1// Common types used across API
2
3use chrono::{NaiveDate, NaiveDateTime};
4use serde::{Deserialize, Serialize};
5use std::sync::Arc;
6use tokio::sync::Mutex;
7
8// use crate::validators;
9
10pub fn ledger() -> Db {
11 // TODO: there was something simpler in one of the other tutorials? <07-04-21, yigit> //
12
13 Arc::new(Mutex::new(vec![
14 Transaction {
15 source: String::from("Myself"),
16 target: String::from("Nobody"),
17 amount: 4,
18 timestamp: NaiveDate::from_ymd(2021, 4, 7).and_hms(00, 17, 00),
19 },
20 ]))
21}
22
23
24// For presentation purposes keep mocked data in in-memory structure
25// In real life scenario connection with regular database would be established
26
27pub type Db = Arc<Mutex<Vec<Transaction>>>;
28
29#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
30pub struct Transaction {
31 pub source: String,
32 pub target: String,
33 pub amount: i32,
34 pub timestamp: NaiveDateTime,
35}
36
37#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
38pub struct Block {
39 pub transaction_list: Vec<Transaction>, // [Transaction; N]
40 pub nonce: i32,
41 pub timestamp: NaiveDateTime,
42 pub hash: String, // future proof'd baby
43}
44
45// #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
46// #[serde(rename_all = "camelCase")]
47// pub struct Game {
48// pub id: u64,
49// pub title: String,
50// #[serde(with = "validators::validate_game_rating")]
51// pub rating: u8,
52// pub genre: Genre,
53// pub description: Option<String>,
54// pub release_date: NaiveDateTime,
55// }
56
57// #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
58// #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
59// pub enum Genre {
60// RolePlaying,
61// Strategy,
62// Shooter,
63// }
64
65// #[derive(Deserialize, Debug, PartialEq)]
66// pub struct ListOptions {
67// pub offset: Option<usize>,
68// pub limit: Option<usize>,
69// }
70
71// pub fn example_db() -> Db {
72// Arc::new(Mutex::new(
73// vec![
74// Game {
75// id: 1,
76// title: String::from("Dark Souls"),
77// rating: 91,
78// genre: Genre::RolePlaying,
79// description: Some(String::from("Takes place in the fictional kingdom of Lordran, where players assume the role of a cursed undead character who begins a pilgrimage to discover the fate of their kind.")),
80// release_date: NaiveDate::from_ymd(2011, 9, 22).and_hms(0, 0, 0),
81// },
82// Game {
83// id: 2,
84// title: String::from("Dark Souls 2"),
85// rating: 87,
86// genre: Genre::RolePlaying,
87// description: None,
88// release_date: NaiveDate::from_ymd(2014, 3, 11).and_hms(0, 0, 0),
89// },
90// Game {
91// id: 3,
92// title: String::from("Dark Souls 3"),
93// rating: 89,
94// genre: Genre::RolePlaying,
95// description: Some(String::from("The latest chapter in the series with its trademark sword and sorcery combat and rewarding action RPG gameplay.")),
96// release_date: NaiveDate::from_ymd(2016, 3, 24).and_hms(0, 0, 0),
97// },
98// ]
99// ))
100// }
101
102// #[cfg(test)]
103// mod tests {
104// use super::*;
105
106// use serde_json::error::Error;
107// use serde_test::{assert_tokens, Token};
108
109// #[test]
110// fn game_serialize_correctly() {
111// let game = Game {
112// id: 1,
113// title: String::from("Test"),
114// rating: 90,
115// genre: Genre::Shooter,
116// description: None,
117// release_date: NaiveDate::from_ymd(2019, 11, 12).and_hms(0, 0, 0),
118// };
119
120// assert_tokens(
121// &game,
122// &[
123// Token::Struct {
124// name: "Game",
125// len: 6,
126// },
127// Token::String("id"),
128// Token::U64(1),
129// Token::String("title"),
130// Token::String("Test"),
131// Token::String("rating"),
132// Token::U8(90),
133// Token::String("genre"),
134// Token::UnitVariant {
135// name: "Genre",
136// variant: "SHOOTER",
137// },
138// Token::String("description"),
139// Token::None,
140// Token::String("releaseDate"),
141// Token::String("2019-11-12T00:00:00"),
142// Token::StructEnd,
143// ],
144// );
145// }
146
147// #[test]
148// fn game_deserialize_correctly() {
149// let data = r#"{"id":3,"title":"Another game","rating":65,"genre":"STRATEGY","description":null,"releaseDate":"2016-03-11T00:00:00"}"#;
150// let game: Game = serde_json::from_str(data).unwrap();
151// let expected_game = Game {
152// id: 3,
153// title: String::from("Another game"),
154// rating: 65,
155// genre: Genre::Strategy,
156// description: None,
157// release_date: NaiveDate::from_ymd(2016, 3, 11).and_hms(0, 0, 0),
158// };
159
160// assert_eq!(game, expected_game);
161// }
162
163// #[test]
164// fn game_error_when_wrong_rating_passed() {
165// let data = r#"{"id":3,"title":"Another game","rating":120,"genre":"STRATEGY","description":null,"releaseDate":"2016-03-11T00:00:00"}"#;
166// let err: Error = serde_json::from_str::<Game>(data).unwrap_err();
167
168// assert_eq!(err.is_data(), true);
169// }
170
171// #[test]
172// fn genre_serialize_correctly() {
173// let genre = Genre::Shooter;
174// assert_tokens(
175// &genre,
176// &[Token::UnitVariant {
177// name: "Genre",
178// variant: "SHOOTER",
179// }],
180// );
181
182// let genre = Genre::RolePlaying;
183// assert_tokens(
184// &genre,
185// &[Token::UnitVariant {
186// name: "Genre",
187// variant: "ROLE_PLAYING",
188// }],
189// );
190
191// let genre = Genre::Strategy;
192// assert_tokens(
193// &genre,
194// &[Token::UnitVariant {
195// name: "Genre",
196// variant: "STRATEGY",
197// }],
198// );
199// }
200
201// #[test]
202// fn genre_deserialize_correctly() {
203// let data = r#""SHOOTER""#;
204// let genre: Genre = serde_json::from_str(data).unwrap();
205// let expected_genre = Genre::Shooter;
206
207// assert_eq!(genre, expected_genre);
208
209// let data = r#""ROLE_PLAYING""#;
210// let genre: Genre = serde_json::from_str(data).unwrap();
211// let expected_genre = Genre::RolePlaying;
212
213// assert_eq!(genre, expected_genre);
214// }
215
216// #[test]
217// fn genre_error_when_wrong_rating_passed() {
218// let data = r#""SPORT""#;
219// let err: Error = serde_json::from_str::<Genre>(data).unwrap_err();
220
221// assert_eq!(err.is_data(), true);
222// }
223// }
diff --git a/src/validators.rs b/src/validators.rs
new file mode 100644
index 0000000..dbebee8
--- /dev/null
+++ b/src/validators.rs
@@ -0,0 +1,44 @@
1// Custom validators incoming data
2
3use log::error;
4use serde::de::{Deserializer, Error as DeserializerError, Unexpected};
5use serde::ser::{Error as SerializerError, Serializer};
6use serde::Deserialize;
7
8pub mod validate_game_rating {
9 use super::*;
10
11 const ERROR_MESSAGE: &str = "rating must be a number between 0 and 100";
12
13 pub fn deserialize<'de, D>(deserializer: D) -> Result<u8, D::Error>
14 where
15 D: Deserializer<'de>,
16 {
17 let value = u8::deserialize(deserializer)?;
18
19 if value > 100 {
20 error!("{}", ERROR_MESSAGE);
21
22 return Err(DeserializerError::invalid_value(
23 Unexpected::Unsigned(u64::from(value)),
24 &ERROR_MESSAGE,
25 ));
26 }
27
28 Ok(value)
29 }
30
31 #[allow(clippy::trivially_copy_pass_by_ref)]
32 pub fn serialize<S>(value: &u8, serializer: S) -> Result<S::Ok, S::Error>
33 where
34 S: Serializer,
35 {
36 if *value > 100 {
37 error!("{}", ERROR_MESSAGE);
38
39 return Err(SerializerError::custom(ERROR_MESSAGE));
40 }
41
42 serializer.serialize_u8(*value)
43 }
44}