153: integrate mini dashboard r=MarinPostma a=MarinPostma

This PR integrate the [mini dashboard](https://github.com/meilisearch/mini-dashboard) to transplant.

It adds a build feature `mini-dashboard` to statically add the mini-dashboard to the MeiliSearch binary. The mini-dashboard build feature is enabled by default and can be disabled by building MeiliSearch with `cargo build --no-default-features`.

- [x] Fetch the mini-dashboard from the Github release
- [x] Check that the SHA1 on the downloaded payload matches the one in the metadata
- [x] Unpack the mini dashboard in `meilisearch-http/mini-dashboard`
- [x] serve the mini-dashboard if the `mini-dashboard` feature is enabled
- [x] Update CI to build MeiliSearch with mini-dashboard for releases

close #87

## Shasum check and build optimizations.

In order to make sure that the right bundle for the mini-dashboard is downloaded, its shasum is computed and compared to the one specified in the `Cargo.toml`. If the shasums match, them the shasum is written to the `.mini-dashboard.sha1` file for later comparison. On subsequent builds, the build script will check that both the mini-dashboard assets and the shasum file are found and that the shasum file content matches the one from the toml file. It will only preform a re-generation on the static dashboard files if it finds that either the dashboard is not present where it expects it to be, or if it finds out that it is outdated, by comparing the shasums.

## Notes

I had to rely on a [custom patch](https://github.com/MarinPostma/actix-web-static-files/tree/actix-web-4) of actix-web-static-files, to support actix-web 4 beta6. there is currently a [pr on the official repo](https://github.com/kilork/actix-web-static-files/pull/35) to support actix-web 4, but it most likely won't be merged until actix is stabilized.


Co-authored-by: Marin Postma <postma.marin@protonmail.com>
This commit is contained in:
bors[bot] 2021-04-26 16:22:20 +00:00 committed by GitHub
commit 9e6a7e3aa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 397 additions and 433 deletions

3
.gitignore vendored
View File

@ -1,8 +1,9 @@
/target
meilisearch-core/target
**/*.csv
**/*.json_lines
**/*.rs.bk
/*.mdb
/query-history.txt
/data.ms
/meilisearch-http/mini-dashboard
/meilisearch-http/.mini-dashboard.sha1

311
Cargo.lock generated
View File

@ -2,9 +2,9 @@
# It is not intended for manual editing.
[[package]]
name = "actix-codec"
version = "0.4.0-beta.1"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90673465c6187bd0829116b02be465dc0195a74d7719f76ffff0effef934a92e"
checksum = "1d5dbeb2d9e51344cb83ca7cc170f1217f9fe25bfc50160e6e200b5c31c1019a"
dependencies = [
"bitflags",
"bytes 1.0.1",
@ -19,8 +19,7 @@ dependencies = [
[[package]]
name = "actix-cors"
version = "0.6.0-beta.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa50c395d15e5946cf04bccb1edef583e9fd42aa6710a1f89a725c5e2c4c5503"
source = "git+https://github.com/MarinPostma/actix-extras.git?rev=2dac1a4#2dac1a421619bf7b386dea63d3ae25a3bc4abc43"
dependencies = [
"actix-service",
"actix-web",
@ -33,9 +32,9 @@ dependencies = [
[[package]]
name = "actix-http"
version = "3.0.0-beta.5"
version = "3.0.0-beta.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb9c5d7ceb490d6565156ae1d4d467db17da1759425c65a2e36ac5e182e014e2"
checksum = "59d51c2ba06062e698a5d212d860e9fb2afc931c285ede687aaae896c8150347"
dependencies = [
"actix-codec",
"actix-rt",
@ -48,7 +47,6 @@ dependencies = [
"brotli2",
"bytes 1.0.1",
"bytestring",
"cookie",
"derive_more",
"encoding_rs",
"flate2",
@ -63,14 +61,13 @@ dependencies = [
"log",
"mime",
"once_cell",
"paste",
"percent-encoding",
"pin-project",
"pin-project-lite 0.2.6",
"rand 0.8.3",
"regex",
"serde",
"serde_json",
"serde_urlencoded",
"sha-1 0.9.4",
"smallvec",
"time 0.2.26",
@ -84,7 +81,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbcb2b608f0accc2f5bcf3dd872194ce13d94ee45b571487035864cf966b04ef"
dependencies = [
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -113,9 +110,9 @@ dependencies = [
[[package]]
name = "actix-server"
version = "2.0.0-beta.4"
version = "2.0.0-beta.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0872f02a1871257ef09c5a269dce5dc5fea5ccf502adbf5d39f118913b61411c"
checksum = "26369215fcc3b0176018b3b68756a8bcc275bb000e6212e454944913a1f9bf87"
dependencies = [
"actix-rt",
"actix-service",
@ -130,11 +127,12 @@ dependencies = [
[[package]]
name = "actix-service"
version = "2.0.0-beta.5"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf82340ad9f4e4caf43737fd3bbc999778a268015cdc54675f60af6240bd2b05"
checksum = "77f5f9d66a8730d0fae62c26f3424f5751e5518086628a40b7ab6fca4a705034"
dependencies = [
"futures-core",
"paste",
"pin-project-lite 0.2.6",
]
@ -169,9 +167,9 @@ dependencies = [
[[package]]
name = "actix-web"
version = "4.0.0-beta.5"
version = "4.0.0-beta.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6de19cc341c2e68b1ee126de171e86b610b5bbcecc660d1250ebed73e0257bd6"
checksum = "ff12e933051557d700b0fcad20fe25b9ca38395cc87bbc5aeaddaef17b937a2f"
dependencies = [
"actix-codec",
"actix-http",
@ -185,11 +183,13 @@ dependencies = [
"actix-web-codegen",
"ahash 0.7.2",
"bytes 1.0.1",
"cookie",
"derive_more",
"either",
"encoding_rs",
"futures-core",
"futures-util",
"itoa",
"language-tags",
"log",
"mime",
@ -213,7 +213,21 @@ checksum = "7f138ac357a674c3b480ddb7bbd894b13c1b6e8927d728bc9ea5e17eee2f8fc9"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
name = "actix-web-static-files"
version = "3.0.5"
source = "git+https://github.com/MarinPostma/actix-web-static-files.git?rev=6db8c3e#6db8c3e2940d61659581492b5e9c9b9062567613"
dependencies = [
"actix-service",
"actix-web",
"change-detection",
"derive_more",
"futures",
"mime_guess",
"path-slash",
]
[[package]]
@ -296,9 +310,9 @@ dependencies = [
[[package]]
name = "async-stream"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3670df70cbc01729f901f94c887814b3c68db038aad1329a418bae178bc5295c"
checksum = "0a26cb53174ddd320edfff199a853f93d571f48eeb4dde75e67a9a3dbb7b7e5e"
dependencies = [
"async-stream-impl",
"futures-core",
@ -306,13 +320,13 @@ dependencies = [
[[package]]
name = "async-stream-impl"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3548b8efc9f8e8a5a0a2808c5bd8451a9031b9e5b879a79590304ae928b0a70"
checksum = "db134ba52475c060f3329a8ef0f8786d6b872ed01515d4b79c162e5798da1340"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -323,7 +337,7 @@ checksum = "0b98e84bbb4cbcdd97da190ba0c58a1bb0de2c1fdf67d159e192ed766aeca722"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -475,9 +489,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byte-unit"
version = "4.0.10"
version = "4.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9520900471c3a9bbcfe0fd4c7b6bcfeff41b20a76cf91c59b7474b09be1ee27"
checksum = "26d98e67b09c0321733bef2f3b879832afa6197e9ea58f32e72c316df2ffe743"
dependencies = [
"utf8-width",
]
@ -521,6 +535,38 @@ dependencies = [
"bytes 1.0.1",
]
[[package]]
name = "bzip2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
dependencies = [
"bzip2-sys",
"libc",
]
[[package]]
name = "bzip2-sys"
version = "0.1.10+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17fa3d1ac1ca21c5c4e36a97f3c3eb25084576f6fc47bf0139c1123434216c6c"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "cargo_toml"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d94e66797729c3a52b74980ec7992a9399aace3044bbcde9ce6bb98926abb673"
dependencies = [
"serde",
"serde_derive",
"toml",
]
[[package]]
name = "cc"
version = "1.0.67"
@ -551,6 +597,16 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "change-detection"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "159fa412eae48a1d94d0b9ecdb85c97ce56eb2a347c62394d3fdbf221adabc1a"
dependencies = [
"path-matchers",
"path-slash",
]
[[package]]
name = "character_converter"
version = "1.0.0"
@ -603,9 +659,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]]
name = "cookie"
version = "0.14.4"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951"
checksum = "ffdf8865bac3d9a3bde5bde9088ca431b11f5d37c7a578b8086af77248b76627"
dependencies = [
"percent-encoding",
"time 0.2.26",
@ -748,7 +804,7 @@ dependencies = [
"convert_case",
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -852,7 +908,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
"synstructure",
]
@ -1008,7 +1064,7 @@ dependencies = [
"proc-macro-hack",
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -1236,6 +1292,12 @@ dependencies = [
"libc",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hostname"
version = "0.3.1"
@ -1268,6 +1330,17 @@ dependencies = [
"http",
]
[[package]]
name = "http-body"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfb77c123b4e2f72a2069aeae0b4b4949cc7e966df277813fc16347e7549737"
dependencies = [
"bytes 1.0.1",
"http",
"pin-project-lite 0.2.6",
]
[[package]]
name = "httparse"
version = "1.4.0"
@ -1280,6 +1353,12 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47"
[[package]]
name = "httpdate"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05842d0d43232b23ccb7060ecb0f0626922c21f30012e97b767b30afd4a5d4b9"
[[package]]
name = "human_format"
version = "1.0.3"
@ -1313,9 +1392,9 @@ dependencies = [
"futures-util",
"h2 0.2.7",
"http",
"http-body",
"http-body 0.3.1",
"httparse",
"httpdate",
"httpdate 0.3.2",
"itoa",
"pin-project",
"socket2 0.3.19",
@ -1325,6 +1404,30 @@ dependencies = [
"want",
]
[[package]]
name = "hyper"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f006b8784cfb01fe7aa9c46f5f5cd4cf5c85a8c612a0653ec97642979062665"
dependencies = [
"bytes 1.0.1",
"futures-channel",
"futures-core",
"futures-util",
"h2 0.3.2",
"http",
"http-body 0.4.1",
"httparse",
"httpdate 1.0.0",
"itoa",
"pin-project",
"socket2 0.4.0",
"tokio 1.5.0",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "hyper-rustls"
version = "0.21.0"
@ -1333,7 +1436,7 @@ checksum = "37743cc83e8ee85eacfce90f2f4102030d9ff0a95244098d781e9bee4a90abb6"
dependencies = [
"bytes 0.5.6",
"futures-util",
"hyper",
"hyper 0.13.10",
"log",
"rustls 0.18.1",
"tokio 0.2.25",
@ -1341,6 +1444,21 @@ dependencies = [
"webpki",
]
[[package]]
name = "hyper-rustls"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64"
dependencies = [
"futures-util",
"hyper 0.14.6",
"log",
"rustls 0.19.1",
"tokio 1.5.0",
"tokio-rustls 0.22.0",
"webpki",
]
[[package]]
name = "idna"
version = "0.2.3"
@ -1631,6 +1749,7 @@ dependencies = [
"actix-rt",
"actix-service",
"actix-web",
"actix-web-static-files",
"anyhow",
"assert-json-diff",
"async-compression",
@ -1638,6 +1757,7 @@ dependencies = [
"async-trait",
"byte-unit",
"bytes 0.6.0",
"cargo_toml",
"chrono",
"crossbeam-channel",
"dashmap",
@ -1649,6 +1769,7 @@ dependencies = [
"futures-util",
"grenad",
"heed",
"hex",
"http",
"indexmap",
"itertools 0.10.0",
@ -1669,11 +1790,13 @@ dependencies = [
"rand 0.7.3",
"rayon",
"regex",
"reqwest 0.11.3",
"rustls 0.19.1",
"sentry",
"serde",
"serde_json",
"serde_url_params",
"sha-1 0.9.4",
"sha2",
"siphasher",
"slice-group-by",
@ -1687,6 +1810,7 @@ dependencies = [
"uuid",
"vergen",
"walkdir",
"zip",
]
[[package]]
@ -1877,7 +2001,7 @@ dependencies = [
"cfg-if 1.0.0",
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -2033,6 +2157,21 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58"
[[package]]
name = "path-matchers"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36cd9b72a47679ec193a5f0229d9ab686b7bd45e1fbc59ccf953c9f3d83f7b2b"
dependencies = [
"glob",
]
[[package]]
name = "path-slash"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cacbb3c4ff353b534a67fb8d7524d00229da4cb1dc8c79f4db96e375ab5b619"
[[package]]
name = "percent-encoding"
version = "2.1.0"
@ -2076,7 +2215,7 @@ dependencies = [
"pest_meta",
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -2145,7 +2284,7 @@ checksum = "48c950132583b500556b1efd71d45b319029f2b71518d979fcc208e16b42426f"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -2216,7 +2355,7 @@ dependencies = [
"proc-macro-error-attr",
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
"version_check",
]
@ -2503,9 +2642,9 @@ dependencies = [
"futures-core",
"futures-util",
"http",
"http-body",
"hyper",
"hyper-rustls",
"http-body 0.3.1",
"hyper 0.13.10",
"hyper-rustls 0.21.0",
"ipnet",
"js-sys",
"lazy_static",
@ -2528,6 +2667,41 @@ dependencies = [
"winreg",
]
[[package]]
name = "reqwest"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2296f2fac53979e8ccbc4a1136b25dcefd37be9ed7e4a1f6b05a6029c84ff124"
dependencies = [
"base64 0.13.0",
"bytes 1.0.1",
"encoding_rs",
"futures-core",
"futures-util",
"http",
"http-body 0.4.1",
"hyper 0.14.6",
"hyper-rustls 0.22.1",
"ipnet",
"js-sys",
"lazy_static",
"log",
"mime",
"percent-encoding",
"pin-project-lite 0.2.6",
"rustls 0.19.1",
"serde",
"serde_urlencoded",
"tokio 1.5.0",
"tokio-rustls 0.22.0",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"webpki-roots 0.21.1",
"winreg",
]
[[package]]
name = "retain_mut"
version = "0.1.2"
@ -2551,9 +2725,9 @@ dependencies = [
[[package]]
name = "roaring"
version = "0.6.5"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6744a4a918e91359ad1d356a91e2e943a86d9fb9ae77f715d617032ea2af88f"
checksum = "a4b2e7ab0bbb2d144558ae3f4761a0db06d21463b45756fc64c3393cdba3d447"
dependencies = [
"bytemuck",
"byteorder",
@ -2684,14 +2858,14 @@ dependencies = [
"env_logger 0.7.1",
"failure",
"hostname",
"httpdate",
"httpdate 0.3.2",
"im",
"lazy_static",
"libc",
"log",
"rand 0.7.3",
"regex",
"reqwest",
"reqwest 0.10.10",
"rustc_version 0.2.3",
"sentry-types",
"uname",
@ -2730,7 +2904,7 @@ checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -2930,7 +3104,7 @@ dependencies = [
"quote 1.0.9",
"serde",
"serde_derive",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -2946,7 +3120,7 @@ dependencies = [
"serde_derive",
"serde_json",
"sha1",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -2982,7 +3156,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -2998,9 +3172,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.69"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
@ -3024,7 +3198,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
"unicode-xid 0.2.1",
]
@ -3098,7 +3272,7 @@ checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -3147,7 +3321,7 @@ dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
"standback",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -3221,7 +3395,7 @@ checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
]
[[package]]
@ -3275,6 +3449,15 @@ dependencies = [
"tokio 1.5.0",
]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]]
name = "tower-service"
version = "0.3.1"
@ -3516,7 +3699,7 @@ dependencies = [
"log",
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
"wasm-bindgen-shared",
]
@ -3550,7 +3733,7 @@ checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
"syn 1.0.69",
"syn 1.0.70",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -3696,10 +3879,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc9c39e6d503229ffa00cc2954af4a751e6bbedf2a2c18e856eb3ece93d32495"
dependencies = [
"proc-macro2 1.0.26",
"syn 1.0.69",
"syn 1.0.70",
"synstructure",
]
[[package]]
name = "zip"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c83dc9b784d252127720168abd71ea82bf8c3d96b17dc565b5e2a02854f2b27"
dependencies = [
"byteorder",
"bzip2",
"crc32fast",
"flate2",
"thiserror",
"time 0.1.44",
]
[[package]]
name = "zstd"
version = "0.5.4+zstd.1.4.7"

View File

@ -5,4 +5,4 @@ authors = ["marin <postma.marin@protonmail.com>"]
edition = "2018"
[dependencies]
actix-http = "=3.0.0-beta.5"
actix-http = "=3.0.0-beta.6"

View File

@ -5,18 +5,28 @@ edition = "2018"
license = "MIT"
name = "meilisearch-http"
version = "0.21.0-alpha.3"
[[bin]]
name = "meilisearch"
path = "src/main.rs"
[build-dependencies]
actix-web-static-files = { git = "https://github.com/MarinPostma/actix-web-static-files.git", rev = "6db8c3e", optional = true }
anyhow = { version = "*", optional = true }
cargo_toml = { version = "0.9.0", optional = true }
hex = { version = "0.4.3", optional = true }
reqwest = { version = "0.11.3", features = ["blocking", "rustls-tls"], default-features = false, optional = true }
sha-1 = { version = "0.9.4", optional = true }
tempfile = { version = "3.1.0", optional = true }
vergen = "3.1.0"
zip = { version = "0.5.12", optional = true }
[dependencies]
actix-cors = "0.6.0-beta.1"
actix-http = { version = "=3.0.0-beta.5" }
actix-service = "=2.0.0-beta.5"
actix-web = { version = "=4.0.0-beta.5", features = ["rustls"] }
actix-cors = { git = "https://github.com/MarinPostma/actix-extras.git", rev = "2dac1a4"}
actix-http = { version = "=3.0.0-beta.6" }
actix-service = "2.0.0"
actix-web = { version = "=4.0.0-beta.6", features = ["rustls"] }
actix-web-static-files = { git = "https://github.com/MarinPostma/actix-web-static-files.git", rev = "6db8c3e", optional = true }
anyhow = "1.0.36"
async-compression = { version = "0.3.6", features = ["gzip", "tokio-02"] }
async-stream = "0.3.0"
@ -45,6 +55,7 @@ memmap = "0.7.0"
milli = { git = "https://github.com/meilisearch/milli.git", tag = "v0.1.1" }
mime = "0.3.16"
once_cell = "1.5.2"
oxidized-json-checker = "0.3.2"
parking_lot = "0.11.1"
rand = "0.7.3"
rayon = "1.5.0"
@ -60,8 +71,7 @@ tar = "0.4.29"
tempfile = "3.1.0"
thiserror = "1.0.24"
tokio = { version = "1", features = ["full"] }
uuid = "0.8.2"
oxidized-json-checker = "0.3.2"
uuid = { version = "0.8.2", features = ["serde"] }
walkdir = "2.3.2"
obkv = "0.1.1"
@ -91,7 +101,22 @@ tempdir = "0.3.7"
urlencoding = "1.1.1"
[features]
default = ["sentry"]
mini-dashboard = [
"actix-web-static-files",
"anyhow",
"cargo_toml",
"hex",
"reqwest",
"sha-1",
"tempfile",
"zip",
]
telemetry = ["sentry"]
default = ["telemetry", "mini-dashboard"]
[target.'cfg(target_os = "linux")'.dependencies]
jemallocator = "0.3.2"
[package.metadata.mini-dashboard]
assets-url = "https://github.com/meilisearch/mini-dashboard/releases/download/v0.1.1/build.zip"
sha1 = "f4247f8f534214e2811637e0555347c3f6bf5794"

View File

@ -7,4 +7,78 @@ fn main() {
// Generate the 'cargo:' key output
generate_cargo_keys(ConstantsFlags::all()).expect("Unable to generate the cargo keys!");
#[cfg(feature = "mini-dashboard")]
mini_dashboard::setup_mini_dashboard().expect("Could not load the mini-dashboard assets");
}
#[cfg(feature = "mini-dashboard")]
mod mini_dashboard {
use std::env;
use std::fs::{create_dir_all, File, OpenOptions};
use std::io::{Cursor, Read, Write};
use std::path::PathBuf;
use actix_web_static_files::resource_dir;
use anyhow::Context;
use cargo_toml::Manifest;
use reqwest::blocking::get;
use sha1::{Digest, Sha1};
pub fn setup_mini_dashboard() -> anyhow::Result<()> {
let cargo_manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let cargo_toml = cargo_manifest_dir.join("Cargo.toml");
let sha1_path = cargo_manifest_dir.join(".mini-dashboard.sha1");
let dashboard_dir = cargo_manifest_dir.join("mini-dashboard");
let manifest = Manifest::from_path(cargo_toml).unwrap();
let meta = &manifest
.package
.as_ref()
.context("package not specified in Cargo.toml")?
.metadata
.as_ref()
.context("no metadata specified in Cargo.toml")?["mini-dashboard"];
// Check if there already is a dashboard built, and if it is up to date.
if sha1_path.exists() && dashboard_dir.exists() {
let mut sha1_file = File::open(&sha1_path)?;
let mut sha1 = String::new();
sha1_file.read_to_string(&mut sha1)?;
if sha1 == meta["sha1"].as_str().unwrap() {
// Nothing to do.
return Ok(())
}
}
let url = meta["assets-url"].as_str().unwrap();
let dashboard_assets_bytes = get(url)?.bytes()?;
let mut hasher = Sha1::new();
hasher.update(&dashboard_assets_bytes);
let sha1 = hex::encode(hasher.finalize());
assert_eq!(meta["sha1"].as_str().unwrap(), sha1, "Downloaded mini-dashboard shasum differs from the one specified in the Cargo.toml");
create_dir_all(&dashboard_dir)?;
let cursor = Cursor::new(&dashboard_assets_bytes);
let mut zip = zip::read::ZipArchive::new(cursor)?;
zip.extract(&dashboard_dir)?;
resource_dir(&dashboard_dir).build()?;
// Write the sha1 for the dashboard back to file.
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(sha1_path)?;
file.write_all(sha1.as_bytes())?;
file.flush()?;
Ok(())
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,333 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="bulma.min.css">
<title>MeiliSearch</title>
<style>
em {
color: hsl(204, 86%, 25%);
font-style: inherit;
background-color: hsl(204, 86%, 88%);
}
#results {
max-width: 900px;
margin: 20px auto 0 auto;
padding: 0;
}
.notification {
display: flex;
justify-content: center;
}
.level-left {
margin-right: 50px;
}
.document {
border-radius: 4px;
margin-bottom: 20px;
display: flex;
}
.document ol {
flex: 0 0 75%;
max-width: 75%;
padding: 0;
margin: 0;
list-style-type: none;
}
.document ol li {
list-style: none;
}
.document .image {
max-width: 50%;
margin: 0 auto;
box-sizing: border-box;
}
@media screen and (min-width: 770px) {
.document .image {
max-width: 25%;
flex: 0 0 25%;
margin: 0;
padding-left: 30px;
box-sizing: border-box;
}
}
.document .image img {
width: 100%;
}
.attribute {
text-align: center;
box-sizing: border-box;
text-transform: uppercase;
font-weight: bold;
color: rgba(0,0,0,.7);
}
@media screen and (min-width: 770px) {
.attribute {
flex: 0 0 25%;
max-width: 25%;
text-align: right;
padding-right: 10px;
font-weight: normal;
box-sizing: border-box;
}
}
@media screen and (max-width: 770px) {
.attribute {
padding-bottom: 0;
}
}
.content {
flex: 0 0 75%;
box-sizing: border-box;
color: rgba(0,0,0,.9);
overflow-wrap: anywhere;
}
.hero-foot {
padding-bottom: 3rem;
}
@media screen and (max-width: 770px) {
.align-on-mobile {
text-align: center;
}
}
</style>
</head>
<body>
<section class="hero is-light">
<div class="hero-body">
<div class="container">
<div class="content is-medium align-on-mobile">
<h1 class="title is-1 is-spaced">
Welcome to MeiliSearch
</h1>
<p class="subtitle is-4">
This dashboard will help you check the search results with ease.
</p>
</div>
<div class="columns">
<div class="column is-4">
<div class="field">
<!-- API Key -->
<label class="label" for="apiKey">API Key (optionnal)</label>
<div class="control">
<input id="apiKey" class="input is-small" type="password" placeholder="Enter your API key">
</div>
<p class="help">At least a private API key is required for the dashboard to access the indexes list.</p>
</div>
</div>
</div>
<div class="columns">
<div class="column is-8">
<label class="label" for="search">Search something</label>
<div class="field has-addons">
<div class="control">
<span class="select">
<select role="listbox" id="index" aria-label="Select the index you want to search on">
<!-- indexes names -->
</select>
</span>
</div>
<div class="control is-expanded">
<input id="search" class="input" type="search" autofocus placeholder="e.g. George Clooney" aria-label="Search through your documents">
</div>
</div>
</div>
<div class="column is-4">
<div class="columns">
<div class="column is-6 has-text-centered">
<p class="heading">Documents</p>
<p id="count" class="title">0</p>
</div>
<div class="column is-6 has-text-centered">
<p class="heading">Time Spent</p>
<p id="time" class="title">N/A</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section>
<div class="container">
<ol id="results" class="content">
<!-- documents matching resquests -->
</ol>
</div>
</section>
</body>
<script>
function sanitizeHTMLEntities(str) {
if (str && typeof str === 'string') {
str = str.replace(/</g,"&lt;");
str = str.replace(/>/g,"&gt;");
str = str.replace(/&lt;em&gt;/g,"<em>");
str = str.replace(/&lt;\/em&gt;/g,"<\/em>");
}
return str;
}
function httpGet(theUrl, apiKey) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", theUrl, false); // false for synchronous request
if (apiKey) {
xmlHttp.setRequestHeader("x-Meili-API-Key", apiKey);
}
xmlHttp.send(null);
return xmlHttp.responseText;
}
function refreshIndexList() {
// TODO we must not block here
let result = JSON.parse(httpGet(`${baseUrl}/indexes`, localStorage.getItem('apiKey')));
if (!Array.isArray(result)) { return }
let select = document.getElementById("index");
select.innerHTML = '';
for (index of result) {
const option = document.createElement('option');
option.value = index.uid;
option.innerHTML = index.name;
select.appendChild(option);
}
}
let lastRequest = undefined;
function triggerSearch() {
var e = document.getElementById("index");
if (e.selectedIndex == -1) { return }
var index = e.options[e.selectedIndex].value;
let theUrl = `${baseUrl}/indexes/${index}/search?q=${encodeURIComponent(search.value)}&attributesToHighlight=*`;
if (lastRequest) { lastRequest.abort() }
lastRequest = new XMLHttpRequest();
lastRequest.open("GET", theUrl, true);
if (localStorage.getItem('apiKey')) {
lastRequest.setRequestHeader("x-Meili-API-Key", localStorage.getItem('apiKey'));
}
lastRequest.onload = function (e) {
if (lastRequest.readyState === 4 && lastRequest.status === 200) {
let sanitizedResponseText = sanitizeHTMLEntities(lastRequest.responseText);
let httpResults = JSON.parse(sanitizedResponseText);
results.innerHTML = '';
let processingTimeMs = httpResults.processingTimeMs;
let numberOfDocuments = httpResults.nbHits;
time.innerHTML = `${processingTimeMs}ms`;
count.innerHTML = `${numberOfDocuments}`;
for (result of httpResults.hits) {
const element = {...result, ...result._formatted };
delete element._formatted;
const elem = document.createElement('li');
elem.classList.add("document","box");
const div = document.createElement('div');
div.classList.add("columns","is-desktop","is-tablet");
const info = document.createElement('div');
info.classList.add("column","align-on-mobile");
let image = undefined;
for (const prop in element) {
// Check if property is an image url link.
if (typeof result[prop] === 'string') {
if (image == undefined && result[prop].match(/^(https|http):\/\/.*(jpe?g|png|gif)(\?.*)?$/g)) {
image = result[prop];
}
}
const field = document.createElement('div');
field.classList.add("columns");
const attribute = document.createElement('div');
attribute.classList.add("attribute", "column");
attribute.innerHTML = prop;
const content = document.createElement('div');
content.classList.add("content", "column");
if (typeof (element[prop]) === "object") {
content.innerHTML = JSON.stringify(element[prop]);
} else {
content.innerHTML = element[prop];
}
field.appendChild(attribute);
field.appendChild(content);
info.appendChild(field);
}
div.appendChild(info);
elem.appendChild(div);
if (image != undefined) {
const divImage = document.createElement('div');
divImage.classList.add("image","column","align-on-mobile");
const img = document.createElement('img');
img.src = image;
img.setAttribute("alt","Item illustration");
divImage.appendChild(img);
div.appendChild(divImage);
elem.appendChild(div);
}
results.appendChild(elem)
}
} else {
console.error(lastRequest.statusText);
}
};
lastRequest.send(null);
}
if (!apiKey.value) {
apiKey.value = localStorage.getItem('apiKey');
}
apiKey.addEventListener('input', function(e) {
localStorage.setItem('apiKey', apiKey.value);
refreshIndexList();
}, false);
let baseUrl = window.location.origin;
refreshIndexList();
search.oninput = triggerSearch;
let select = document.getElementById("index");
select.onchange = triggerSearch;
triggerSearch();
</script>
</html>

View File

@ -2,7 +2,8 @@ use std::error;
use std::fmt;
use actix_web as aweb;
use actix_web::dev::HttpResponseBuilder;
use actix_web::body::Body;
use actix_web::dev::BaseHttpResponseBuilder;
use actix_web::error::{JsonPayloadError, QueryPayloadError};
use actix_web::http::Error as HttpError;
use actix_web::http::StatusCode;
@ -71,8 +72,9 @@ impl Serialize for ResponseError {
}
impl aweb::error::ResponseError for ResponseError {
fn error_response(&self) -> aweb::HttpResponse {
HttpResponseBuilder::new(self.status_code()).json(&self)
fn error_response(&self) -> aweb::BaseHttpResponse<Body> {
let json = serde_json::to_vec(self).unwrap();
BaseHttpResponseBuilder::new(self.status_code()).body(json)
}
fn status_code(&self) -> StatusCode {
@ -297,6 +299,7 @@ impl From<JsonPayloadError> for Error {
JsonPayloadError::Payload(err) => {
Error::BadRequest(format!("Problem while decoding the request: {}", err))
}
e => Error::Internal(format!("Unexpected Json error: {}", e))
}
}
}
@ -307,6 +310,7 @@ impl From<QueryPayloadError> for Error {
QueryPayloadError::Deserialize(err) => {
Error::BadRequest(format!("Invalid query parameters: {}", err))
}
e => Error::Internal(format!("Unexpected query payload error: {}", e))
}
}
}

View File

@ -19,6 +19,14 @@ macro_rules! create_app {
use meilisearch_http::error::payload_error_handler;
use meilisearch_http::routes::*;
#[cfg(feature = "mini-dashboard")]
use actix_web_static_files::ResourceFiles;
#[cfg(feature = "mini-dashboard")]
mod dashboard {
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
}
let app = App::new()
.data($data.clone())
.app_data(
@ -40,16 +48,25 @@ macro_rules! create_app {
.configure(stats::services)
.configure(key::services);
//.configure(routes::dump::services);
#[cfg(feature = "mini-dashboard")]
let app = if $enable_frontend {
app.service(load_html).service(load_css)
let generated = dashboard::generate();
let service = ResourceFiles::new("/", generated);
app.service(service)
} else {
app.service(running)
};
#[cfg(not(feature = "mini-dashboard"))]
let app = app.service(running);
app.wrap(
Cors::default()
.send_wildcard()
.allowed_headers(vec!["content-type", "x-meili-api-key"])
.max_age(86_400), // 24h
.allow_any_origin()
.allow_any_method()
.max_age(86_400) // 24h
)
.wrap(middleware::Logger::default())
.wrap(middleware::Compress::default())

View File

@ -72,19 +72,14 @@ async fn main() -> Result<(), MainError> {
print_launch_resume(&opt, &data);
let enable_frontend = opt.env != "production";
run_http(data, opt, enable_frontend).await?;
run_http(data, opt).await?;
Ok(())
}
async fn run_http(
data: Data,
opt: Opt,
enable_frontend: bool,
) -> Result<(), Box<dyn std::error::Error>> {
let http_server = HttpServer::new(move || create_app!(&data, enable_frontend))
async fn run_http(data: Data, opt: Opt) -> Result<(), Box<dyn std::error::Error>> {
let _enable_dashboard = &opt.env == "development";
let http_server = HttpServer::new(move || create_app!(&data, _enable_dashboard))
// Disable signals allows the server to terminate immediately when a user enter CTRL-C
.disable_signals();
@ -102,11 +97,11 @@ async fn run_http(
pub fn print_launch_resume(opt: &Opt, data: &Data) {
let commit_sha = match option_env!("COMMIT_SHA") {
Some("") | None => env!("VERGEN_SHA"),
Some(commit_sha) => commit_sha
Some(commit_sha) => commit_sha,
};
let commit_date = match option_env!("COMMIT_DATE") {
Some("") | None => env!("VERGEN_COMMIT_DATE"),
Some(commit_date) => commit_date
Some(commit_date) => commit_date,
};
let ascii_name = r#"

View File

@ -28,14 +28,6 @@ impl IndexUpdateResponse {
}
}
/// Return the dashboard, should not be used in production. See [running]
#[get("/")]
pub async fn load_html() -> HttpResponse {
HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(include_str!("../../public/interface.html").to_string())
}
/// Always return a 200 with:
/// ```json
/// {
@ -46,10 +38,3 @@ pub async fn load_html() -> HttpResponse {
pub async fn running() -> HttpResponse {
HttpResponse::Ok().json(serde_json::json!({ "status": "MeiliSearch is running" }))
}
#[get("/bulma.min.css")]
pub async fn load_css() -> HttpResponse {
HttpResponse::Ok()
.content_type("text/css; charset=utf-8")
.body(include_str!("../../public/bulma.min.css").to_string())
}