1use lazy_static::lazy_static;
2use rust_embed::RustEmbed;
3use std::sync::Arc;
4use tera::Tera;
5use warp::Filter;
6
7mod filters;
8mod handlers;
9
10#[derive(RustEmbed)]
11#[folder = "src/templates/"]
12struct Templates;
13
14pub fn catalog<T: Catalog + Clone>(
16 root: String,
17 catalog: T,
18) -> Result<impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone, anyhow::Error>
19{
20 lazy_static! {
21 static ref TERA: Arc<Tera> = {
22 let mut tera = Tera::default();
23 for t in &["base.html", "folder.html", "index.html"] {
24 let template = Templates::get(&t).unwrap();
25 let template = std::str::from_utf8(&template).unwrap();
26 tera.add_raw_template(&t, &template).unwrap();
27 }
28 Arc::new(tera)
29 };
30 }
31
32 Ok(filters::catalog(root, Arc::clone(&TERA), catalog))
33}
34
35pub trait Catalog: Send + Sync {
36 fn paths<'a>(&'a self) -> Box<dyn Iterator<Item = &str> + 'a>;
38}
39
40impl<T: Catalog> Catalog for Arc<T> {
41 fn paths<'a>(&'a self) -> Box<dyn Iterator<Item = &str> + 'a> {
42 T::paths(self)
43 }
44}
45
46#[cfg(test)]
47pub(crate) mod tests {
48 use super::*;
49 use futures::executor::block_on;
50
51 #[derive(Debug)]
52 pub struct TestCatalog {
53 paths: Vec<String>,
54 }
55
56 impl TestCatalog {
57 pub fn test() -> Arc<TestCatalog> {
58 Arc::new(TestCatalog {
59 paths: [
60 "coads1.nc",
61 "coads2.nc",
62 "path1/hula.nc",
63 "path1/hula2.nc",
64 "path1/sub/hula3.nc",
65 "path2/bula.nc",
66 ]
67 .iter()
68 .map(|s| s.to_string())
69 .collect(),
70 })
71 }
72 }
73
74 impl Catalog for Arc<TestCatalog> {
75 fn paths<'a>(&'a self) -> Box<dyn Iterator<Item = &str> + 'a> {
76 Box::new(self.paths.iter().map(|s| s.as_str()))
77 }
78 }
79
80 #[test]
81 fn setup_catalog() {
82 catalog("http://localhost:8001".into(), TestCatalog::test()).unwrap();
83 }
84
85 #[test]
86 fn does_not_match_data_source() {
87 let f = catalog("http://localhost:8001".into(), TestCatalog::test()).unwrap();
88
89 assert_eq!(
90 block_on(
91 warp::test::request()
92 .method("GET")
93 .path("/data/coads1.nc")
94 .reply(&f)
95 )
96 .status(),
97 404
98 );
99
100 assert_eq!(
101 block_on(
102 warp::test::request()
103 .method("GET")
104 .path("/data/path1/hula.nc")
105 .reply(&f)
106 )
107 .status(),
108 404
109 );
110
111 assert_eq!(
112 block_on(
113 warp::test::request()
114 .method("GET")
115 .path("/data/path1/non-exist.nc")
116 .reply(&f)
117 )
118 .status(),
119 404
120 );
121 }
122
123 #[test]
124 fn matches_root() {
125 let f = catalog("http://localhost:8001".into(), TestCatalog::test()).unwrap();
126
127 assert_eq!(
128 block_on(warp::test::request().method("GET").path("/data/").reply(&f)).status(),
129 200
130 );
131
132 assert_eq!(
133 block_on(warp::test::request().method("GET").path("/data").reply(&f)).status(),
134 200
135 );
136 }
137
138 #[test]
139 fn matches_subpath() {
140 let f = catalog("http://localhost:8001".into(), TestCatalog::test()).unwrap();
141
142 assert_eq!(
143 block_on(
144 warp::test::request()
145 .method("GET")
146 .path("/data/path1/")
147 .reply(&f)
148 )
149 .status(),
150 200
151 );
152
153 assert_eq!(
154 block_on(
155 warp::test::request()
156 .method("GET")
157 .path("/data/path1")
158 .reply(&f)
159 )
160 .status(),
161 200
162 );
163 }
164
165 #[test]
166 fn does_not_match_missing_subpath() {
167 let f = catalog("http://localhost:8001".into(), TestCatalog::test()).unwrap();
168
169 assert_eq!(
170 block_on(
171 warp::test::request()
172 .method("GET")
173 .path("/data/missing_path1/")
174 .reply(&f)
175 )
176 .status(),
177 404
178 );
179 }
180}