Author: Jason White [jwhite@esri.com]
Hash: 28dd1852d4ff34832939b11a050490d03fd7abf6
Timestamp: Tue, 02 Apr 2019 21:17:15 +0000 (5 years ago)

+261 -15 +/-8 browse
Add home page
Add home page

Fixes #3.
1diff --git a/.dockerignore b/.dockerignore
2index 8d42d79..a6a6140 100644
3--- a/.dockerignore
4+++ b/.dockerignore
5 @@ -3,5 +3,6 @@
6
7 # Only include these files.
8 !/src/**
9+ !/templates/**
10 !/Cargo.toml
11 !/Cargo.lock
12 diff --git a/Cargo.lock b/Cargo.lock
13index 4db1c72..425a6db 100644
14--- a/Cargo.lock
15+++ b/Cargo.lock
16 @@ -44,6 +44,46 @@ dependencies = [
17 ]
18
19 [[package]]
20+ name = "askama"
21+ version = "0.8.0"
22+ source = "registry+https://github.com/rust-lang/crates.io-index"
23+ dependencies = [
24+ "askama_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
25+ "askama_escape 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
26+ "askama_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
27+ ]
28+
29+ [[package]]
30+ name = "askama_derive"
31+ version = "0.8.0"
32+ source = "registry+https://github.com/rust-lang/crates.io-index"
33+ dependencies = [
34+ "askama_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
35+ "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
36+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
37+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
38+ "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
39+ ]
40+
41+ [[package]]
42+ name = "askama_escape"
43+ version = "0.2.0"
44+ source = "registry+https://github.com/rust-lang/crates.io-index"
45+
46+ [[package]]
47+ name = "askama_shared"
48+ version = "0.8.0"
49+ source = "registry+https://github.com/rust-lang/crates.io-index"
50+ dependencies = [
51+ "askama_escape 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
52+ "humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
53+ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
54+ "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
55+ "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
56+ "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
57+ ]
58+
59+ [[package]]
60 name = "atty"
61 version = "0.2.11"
62 source = "registry+https://github.com/rust-lang/crates.io-index"
63 @@ -464,6 +504,11 @@ version = "0.4.0"
64 source = "registry+https://github.com/rust-lang/crates.io-index"
65
66 [[package]]
67+ name = "humansize"
68+ version = "1.1.0"
69+ source = "registry+https://github.com/rust-lang/crates.io-index"
70+
71+ [[package]]
72 name = "humantime"
73 version = "1.2.0"
74 source = "registry+https://github.com/rust-lang/crates.io-index"
75 @@ -693,6 +738,15 @@ version = "0.1.13"
76 source = "registry+https://github.com/rust-lang/crates.io-index"
77
78 [[package]]
79+ name = "nom"
80+ version = "4.2.3"
81+ source = "registry+https://github.com/rust-lang/crates.io-index"
82+ dependencies = [
83+ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
84+ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
85+ ]
86+
87+ [[package]]
88 name = "num-integer"
89 version = "0.1.39"
90 source = "registry+https://github.com/rust-lang/crates.io-index"
91 @@ -948,6 +1002,7 @@ dependencies = [
92 name = "rudolfs"
93 version = "0.2.2"
94 dependencies = [
95+ "askama 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
96 "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
97 "chacha 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
98 "derive_more 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
99 @@ -1512,6 +1567,14 @@ dependencies = [
100 ]
101
102 [[package]]
103+ name = "toml"
104+ version = "0.4.10"
105+ source = "registry+https://github.com/rust-lang/crates.io-index"
106+ dependencies = [
107+ "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
108+ ]
109+
110+ [[package]]
111 name = "try-lock"
112 version = "0.2.2"
113 source = "registry+https://github.com/rust-lang/crates.io-index"
114 @@ -1591,6 +1654,11 @@ version = "0.8.1"
115 source = "registry+https://github.com/rust-lang/crates.io-index"
116
117 [[package]]
118+ name = "version_check"
119+ version = "0.1.5"
120+ source = "registry+https://github.com/rust-lang/crates.io-index"
121+
122+ [[package]]
123 name = "want"
124 version = "0.0.6"
125 source = "registry+https://github.com/rust-lang/crates.io-index"
126 @@ -1688,6 +1756,10 @@ dependencies = [
127 "checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
128 "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
129 "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
130+ "checksum askama 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc2a4b6d7f812d2b13d251ae792caecebd635d6401761162d4b71d5ebe1a010"
131+ "checksum askama_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ee2fff0f22ad5d215cace1227cd036c28e81e26206763bb837b6d0e766c87d"
132+ "checksum askama_escape 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0de942230b5beedaa9e1d64df5b76fa1c97002e4c7982897be899cccf40621d"
133+ "checksum askama_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6dfa6b6d254fd066a8bbed9a8f913123e3f701db89216ad4f0aff04ad87718c"
134 "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
135 "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
136 "checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
137 @@ -1739,6 +1811,7 @@ dependencies = [
138 "checksum http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fe67e3678f2827030e89cc4b9e7ecd16d52f132c0b940ab5005f88e821500f6a"
139 "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"
140 "checksum human-size 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bec6e801ef7367625bd94ad7e2965e6027189f3e9deef422388d993af2814a0"
141+ "checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e"
142 "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
143 "checksum hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5b6658b016965ae301fa995306db965c93677880ea70765a84235a96eae896"
144 "checksum hyper-rustls 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "15b66d1bd4864ef036adf2363409caa3acd63ebb4725957b66e621c8a36631a3"
145 @@ -1765,6 +1838,7 @@ dependencies = [
146 "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"
147 "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
148 "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
149+ "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
150 "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
151 "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
152 "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
153 @@ -1848,6 +1922,7 @@ dependencies = [
154 "checksum tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "350c9edade9830dc185ae48ba45667a445ab59f6167ef6d0254ec9d2430d9dd3"
155 "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92"
156 "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445"
157+ "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
158 "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
159 "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
160 "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
161 @@ -1861,6 +1936,7 @@ dependencies = [
162 "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
163 "checksum uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0238db0c5b605dd1cf51de0f21766f97fba2645897024461d6a00c036819a768"
164 "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
165+ "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
166 "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3"
167 "checksum webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f7e1cd7900a3a6b65a3e8780c51a3e6b59c0e2c55c6dc69578c288d69f7d082"
168 "checksum webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c10fa4212003ba19a564f25cd8ab572c6791f99a03cc219c13ed35ccab00de0e"
169 diff --git a/Cargo.toml b/Cargo.toml
170index b97a2d5..aea5ecd 100644
171--- a/Cargo.toml
172+++ b/Cargo.toml
173 @@ -15,6 +15,7 @@ categories = ["command-line-utilities"]
174 license = "MIT"
175
176 [dependencies]
177+ askama = "0.8"
178 bytes = "0.4"
179 chacha = "0.3"
180 derive_more = "0.14"
181 diff --git a/src/app.rs b/src/app.rs
182index 08c3ecd..1721486 100644
183--- a/src/app.rs
184+++ b/src/app.rs
185 @@ -20,15 +20,12 @@
186 use std::io;
187 use std::sync::Arc;
188
189+ use askama::Template;
190 use futures::{
191 future::{self, Either},
192 Future, IntoFuture, Stream,
193 };
194- use http::{
195- self, header,
196- uri::{Authority, Scheme},
197- StatusCode, Uri,
198- };
199+ use http::{self, header, StatusCode, Uri};
200 use hyper::{self, service::Service, Chunk, Method, Request, Response};
201
202 use crate::error::Error;
203 @@ -36,6 +33,13 @@ use crate::hyperext::{into_request, Body, IntoResponse, RequestExt};
204 use crate::lfs;
205 use crate::storage::{LFSObject, Namespace, Storage, StorageKey};
206
207+ #[derive(Template)]
208+ #[template(path = "index.html")]
209+ struct IndexTemplate<'a> {
210+ title: &'a str,
211+ api: Uri,
212+ }
213+
214 /// Shared state for all instances of the `App` service.
215 pub struct State<S> {
216 // Storage backend.
217 @@ -63,6 +67,18 @@ where
218 App { state }
219 }
220
221+ /// Handles the index route.
222+ fn index(&mut self, req: Request<Body>) -> Result<Response<Body>, Error> {
223+ let template = IndexTemplate {
224+ title: "Rudolfs",
225+ api: req.base_uri().path_and_query("/api").build().unwrap(),
226+ };
227+
228+ Ok(Response::builder()
229+ .status(StatusCode::OK)
230+ .body(template.render()?.into())?)
231+ }
232+
233 /// Generates a "404 not found" response.
234 fn not_found(
235 &mut self,
236 @@ -253,15 +269,7 @@ where
237 namespace: Namespace,
238 ) -> impl Future<Item = Response<Body>, Error = Error> {
239 // Get the host name and scheme.
240- let uri = Uri::builder()
241- .scheme(req.scheme().unwrap_or(Scheme::HTTP))
242- .authority(
243- req.authority()
244- .unwrap_or_else(|| Authority::from_static("localhost")),
245- )
246- .path_and_query("/")
247- .build()
248- .unwrap();
249+ let uri = req.base_uri().path_and_query("/").build().unwrap();
250
251 let state = self.state.clone();
252
253 @@ -445,6 +453,10 @@ where
254 fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
255 let req = into_request(req);
256
257+ if req.uri().path() == "/" {
258+ return self.index(req).response();
259+ }
260+
261 if req.uri().path().starts_with("/api/") {
262 return self.api(req).response();
263 }
264 diff --git a/src/error.rs b/src/error.rs
265index 419087d..ee5e27d 100644
266--- a/src/error.rs
267+++ b/src/error.rs
268 @@ -19,6 +19,7 @@
269 // SOFTWARE.
270 use std::io;
271
272+ use askama;
273 use derive_more::{Display, From};
274 use http;
275 use hyper;
276 @@ -38,6 +39,7 @@ pub enum Error {
277 Sha256VerifyError(Sha256VerifyError),
278 S3(storage::S3Error),
279 S3DiskCache(<storage::S3DiskCache as Storage>::Error),
280+ Askama(askama::Error),
281 }
282
283 impl std::error::Error for Error {}
284 diff --git a/src/hyperext.rs b/src/hyperext.rs
285index cd25498..c3d3f7c 100644
286--- a/src/hyperext.rs
287+++ b/src/hyperext.rs
288 @@ -21,7 +21,7 @@ use std::ops::Deref;
289
290 use derive_more::From;
291 use futures::{Future, IntoFuture, Poll, Stream};
292- use http::uri::{Authority, Scheme};
293+ use http::uri::{self, Authority, Scheme, Uri};
294 use hyper::{
295 body::{Payload, Sender},
296 Body as HBody, Chunk, HeaderMap, Request, Response,
297 @@ -195,6 +195,16 @@ pub trait RequestExt {
298 /// First checks the HTTP/2 header `:authority` and then falls back to the
299 /// `Host` header.
300 fn authority(&self) -> Option<Authority>;
301+
302+ fn base_uri(&self) -> uri::Builder {
303+ let mut builder = Uri::builder();
304+ builder.scheme(self.scheme().unwrap_or(Scheme::HTTP));
305+ builder.authority(
306+ self.authority()
307+ .unwrap_or_else(|| Authority::from_static("localhost")),
308+ );
309+ builder
310+ }
311 }
312
313 impl<B> RequestExt for Request<B> {
314 diff --git a/templates/base.html b/templates/base.html
315new file mode 100644
316index 0000000..d00a371
317--- /dev/null
318+++ b/templates/base.html
319 @@ -0,0 +1,118 @@
320+ <!doctype html>
321+ <html lang="en">
322+ <head>
323+ <meta charset="utf-8">
324+
325+ <title>{{ title }}</title>
326+ <meta name="description" content="A git lfs server.">
327+ <meta name="author" content="Jason White">
328+
329+ <style>
330+ html {
331+ font-family: Helvetica, Arial, sans-serif;
332+ letter-spacing: 0.01em;
333+ }
334+
335+ body {
336+ line-height: 1.6;
337+ color: #777;
338+ }
339+
340+ h1, h2, h3, h4, h5, h6 {
341+ color: #4b4b4b;
342+ }
343+
344+ a {
345+ color: #3b8bba;
346+ text-decoration: none;
347+ }
348+
349+ a:visited {
350+ color: #265778;
351+ }
352+
353+ pre, code {
354+ font-family: Consolas, Courier, monospace;
355+ color: #333;
356+ background: #fafafa;
357+ }
358+
359+ code {
360+ padding: 0.2em 0.4em;
361+ white-space: nowrap;
362+ }
363+
364+ .header .content {
365+ padding-left: 2em;
366+ padding-right: 2em;
367+ }
368+
369+ .header {
370+ margin: 0 auto;
371+ padding: 1em;
372+ text-align: center;
373+ border-bottom: 1px solid #eee;
374+ letter-spacing: 0.05em;
375+ max-width: 768px;
376+ }
377+
378+ .header h1 {
379+ font-size: 320%;
380+ font-weight: 100;
381+ margin: 0;
382+ }
383+
384+ .header h2 {
385+ font-weight: 100;
386+ margin: 0;
387+ color: #666;
388+ letter-spacing: -0.02em;
389+ }
390+
391+ .content {
392+ margin-left: auto;
393+ margin-right: auto;
394+ max-width: 768px;
395+ }
396+
397+ .content p {
398+ font-size: 1.125em;
399+ }
400+
401+ .code {
402+ margin-left: -1em;
403+ margin-right: -1em;
404+ padding: 1em;
405+ border: 1px solid #eee;
406+ border-left-width: 0;
407+ border-right-width: 0;
408+ overflow-x: auto;
409+ -webkit-overflow-scrolling: touch;
410+ }
411+
412+ @media screen and (min-width: 48em) {
413+ .code {
414+ margin-left: auto;
415+ margin-right: auto;
416+ border-left-width: 1px;
417+ border-right-width: 1px;
418+ }
419+ }
420+
421+ .content p code {
422+ font-size: 90%;
423+ }
424+ </style>
425+ </head>
426+
427+ <body>
428+ <div id="main">
429+ <div class="header">
430+ {% block header %}{% endblock %}
431+ </div>
432+ <div class="content">
433+ {% block content %}{% endblock %}
434+ </div>
435+ </div>
436+ </body>
437+ </html>
438 diff --git a/templates/index.html b/templates/index.html
439new file mode 100644
440index 0000000..8b59f48
441--- /dev/null
442+++ b/templates/index.html
443 @@ -0,0 +1,26 @@
444+ {% extends "base.html" %}
445+
446+ {% block header %}
447+ <h1><a href="https://github.com/jasonwhite/rudolfs">{{ title }}</a></h1>
448+ <h2>A high-performance, caching <a
449+ href="https://git-lfs.github.com">Git LFS</a> server.</h2>
450+ {% endblock header %}
451+
452+ {% block content %}
453+ <p>
454+ To use this Git LFS server in your project, add a file named
455+ <code>.lfsconfig</code> to the root of your repository with the
456+ following contents:</p>
457+ <p>
458+ <pre class="code">[lfs]
459+ url = "{{ api }}/my-org/my-repo"</pre>
460+ </p>
461+ <p>
462+ ...where <code>my-org/my-repo</code> is the name of the Git
463+ repository.
464+ </p>
465+ <p>
466+ Please see <a href="https://git-lfs.github.com/">https://git-lfs.github.com/</a>
467+ for more information about how to use the Git LFS client.
468+ </p>
469+ {% endblock content %}