|
|
@@ -6,7 +6,8 @@ use tile_source::TileSource;
|
|
6
|
6
|
use toml::Value;
|
|
7
|
7
|
use xdg;
|
|
8
|
8
|
|
|
9
|
|
-static DEFAULT_CONFIG: &'static str = include_str!("../default_config.toml");
|
|
|
9
|
+static DEFAULT_CONFIG: &'static str = "";
|
|
|
10
|
+static DEFAULT_TILE_SOURCES: &'static str = include_str!("../default_tile_sources.toml");
|
|
10
|
11
|
|
|
11
|
12
|
|
|
12
|
13
|
#[derive(Debug)]
|
|
|
@@ -19,6 +20,8 @@ pub struct Config {
|
|
19
|
20
|
}
|
|
20
|
21
|
|
|
21
|
22
|
impl Config {
|
|
|
23
|
+ //TODO use builder pattern to create config
|
|
|
24
|
+
|
|
22
|
25
|
pub fn from_arg_matches<'a>(matches: &clap::ArgMatches<'a>) -> Result<Config, String> {
|
|
23
|
26
|
let mut config = if let Some(config_path) = matches.value_of_os("config") {
|
|
24
|
27
|
Config::from_toml_file(config_path)?
|
|
|
@@ -26,6 +29,12 @@ impl Config {
|
|
26
|
29
|
Config::find_or_create()?
|
|
27
|
30
|
};
|
|
28
|
31
|
|
|
|
32
|
+ if let Some(tile_sources_path) = matches.value_of_os("tile-sources") {
|
|
|
33
|
+ config.add_tile_sources_from_file(tile_sources_path)?;
|
|
|
34
|
+ } else {
|
|
|
35
|
+ config.add_tile_sources_from_default_or_create()?;
|
|
|
36
|
+ };
|
|
|
37
|
+
|
|
29
|
38
|
config.merge_arg_matches(matches);
|
|
30
|
39
|
|
|
31
|
40
|
Ok(config)
|
|
|
@@ -45,7 +54,7 @@ impl Config {
|
|
45
|
54
|
}
|
|
46
|
55
|
}
|
|
47
|
56
|
|
|
48
|
|
- pub fn find_or_create() -> Result<Config, String> {
|
|
|
57
|
+ fn find_or_create() -> Result<Config, String> {
|
|
49
|
58
|
if let Ok(xdg_dirs) = xdg::BaseDirectories::with_prefix("deltamap") {
|
|
50
|
59
|
if let Some(config_path) = xdg_dirs.find_config_file("config.toml") {
|
|
51
|
60
|
info!("load config from path {:?}", config_path);
|
|
|
@@ -69,6 +78,30 @@ impl Config {
|
|
69
|
78
|
}
|
|
70
|
79
|
}
|
|
71
|
80
|
|
|
|
81
|
+ fn add_tile_sources_from_default_or_create(&mut self) -> Result<(), String> {
|
|
|
82
|
+ if let Ok(xdg_dirs) = xdg::BaseDirectories::with_prefix("deltamap") {
|
|
|
83
|
+ if let Some(sources_path) = xdg_dirs.find_config_file("tile_sources.toml") {
|
|
|
84
|
+ info!("load tile sources from path {:?}", sources_path);
|
|
|
85
|
+
|
|
|
86
|
+ self.add_tile_sources_from_file(sources_path)
|
|
|
87
|
+ } else {
|
|
|
88
|
+ // try to write a default tile sources file
|
|
|
89
|
+ if let Ok(path) = xdg_dirs.place_config_file("tile_sources.toml") {
|
|
|
90
|
+ if let Ok(mut file) = File::create(&path) {
|
|
|
91
|
+ if file.write_all(DEFAULT_TILE_SOURCES.as_bytes()).is_ok() {
|
|
|
92
|
+ info!("write default tile sources to {:?}", &path);
|
|
|
93
|
+ }
|
|
|
94
|
+ }
|
|
|
95
|
+ }
|
|
|
96
|
+
|
|
|
97
|
+ self.add_tile_sources_from_str(DEFAULT_TILE_SOURCES)
|
|
|
98
|
+ }
|
|
|
99
|
+ } else {
|
|
|
100
|
+ info!("load default config");
|
|
|
101
|
+ self.add_tile_sources_from_str(DEFAULT_TILE_SOURCES)
|
|
|
102
|
+ }
|
|
|
103
|
+ }
|
|
|
104
|
+
|
|
72
|
105
|
/// Returns a tile cache directory path at a standard XDG cache location. The returned path may
|
|
73
|
106
|
/// not exist.
|
|
74
|
107
|
fn default_tile_cache_dir() -> Result<PathBuf, String> {
|
|
|
@@ -81,7 +114,7 @@ impl Config {
|
|
81
|
114
|
}
|
|
82
|
115
|
}
|
|
83
|
116
|
|
|
84
|
|
- pub fn from_toml_str(toml_str: &str) -> Result<Config, String> {
|
|
|
117
|
+ fn from_toml_str(toml_str: &str) -> Result<Config, String> {
|
|
85
|
118
|
match toml_str.parse::<Value>() {
|
|
86
|
119
|
Ok(Value::Table(ref table)) => {
|
|
87
|
120
|
let tile_cache_dir = {
|
|
|
@@ -121,14 +154,44 @@ impl Config {
|
|
121
|
154
|
}
|
|
122
|
155
|
};
|
|
123
|
156
|
|
|
124
|
|
- let sources_table = table.get("tile_sources")
|
|
|
157
|
+ Ok(
|
|
|
158
|
+ Config {
|
|
|
159
|
+ tile_cache_dir: tile_cache_dir,
|
|
|
160
|
+ sources: vec![],
|
|
|
161
|
+ fps: fps,
|
|
|
162
|
+ use_network: use_network,
|
|
|
163
|
+ async: async,
|
|
|
164
|
+ }
|
|
|
165
|
+ )
|
|
|
166
|
+ },
|
|
|
167
|
+ Ok(_) => Err("TOML file has invalid structure. Expected a Table as the top-level element.".to_string()),
|
|
|
168
|
+ Err(e) => Err(format!("{}", e)),
|
|
|
169
|
+ }
|
|
|
170
|
+ }
|
|
|
171
|
+
|
|
|
172
|
+ fn from_toml_file<P: AsRef<Path>>(path: P) -> Result<Config, String> {
|
|
|
173
|
+ let mut file = File::open(path).map_err(|e| format!("{}", e))?;
|
|
|
174
|
+
|
|
|
175
|
+ let mut content = String::new();
|
|
|
176
|
+ file.read_to_string(&mut content).map_err(|e| format!("{}", e))?;
|
|
|
177
|
+
|
|
|
178
|
+ Config::from_toml_str(&content)
|
|
|
179
|
+ }
|
|
|
180
|
+
|
|
|
181
|
+ fn add_tile_sources_from_str(&mut self, toml_str: &str) -> Result<(), String> {
|
|
|
182
|
+ match toml_str.parse::<Value>() {
|
|
|
183
|
+ Ok(Value::Table(ref table)) => {
|
|
|
184
|
+ let sources_array = table.get("tile_sources")
|
|
125
|
185
|
.ok_or_else(|| "missing \"tile_sources\" table".to_string())?
|
|
126
|
|
- .as_table()
|
|
127
|
|
- .ok_or_else(|| "\"tile_sources\" has to be a table".to_string())?;
|
|
|
186
|
+ .as_array()
|
|
|
187
|
+ .ok_or_else(|| "\"tile_sources\" has to be an array.".to_string())?;
|
|
128
|
188
|
|
|
129
|
|
- let mut sources_vec: Vec<(String, TileSource)> = Vec::with_capacity(sources_table.len());
|
|
|
189
|
+ for (id, source) in sources_array.iter().enumerate() {
|
|
|
190
|
+ let name = source.get("name")
|
|
|
191
|
+ .ok_or_else(|| "tile_source is missing \"name\" entry.".to_string())?
|
|
|
192
|
+ .as_str()
|
|
|
193
|
+ .ok_or_else(|| "\"name\" has to be a string".to_string())?;
|
|
130
|
194
|
|
|
131
|
|
- for (id, (name, source)) in sources_table.iter().enumerate() {
|
|
132
|
195
|
let min_zoom = source.get("min_zoom")
|
|
133
|
196
|
.unwrap_or_else(|| &Value::Integer(0))
|
|
134
|
197
|
.as_integer()
|
|
|
@@ -169,15 +232,18 @@ impl Config {
|
|
169
|
232
|
.as_str()
|
|
170
|
233
|
.ok_or_else(|| "extension has to be a string".to_string())?;
|
|
171
|
234
|
|
|
|
235
|
+ //TODO reduce allowed strings to a reasonable subset of valid UTF-8 strings
|
|
|
236
|
+ // that can also be used as a directory name or introduce a dir_name key with
|
|
|
237
|
+ // more restrictions.
|
|
172
|
238
|
if name.contains('/') || name.contains('\\') {
|
|
173
|
239
|
return Err(format!("source name ({:?}) must not contain slashes (\"/\" or \"\\\")", name));
|
|
174
|
240
|
}
|
|
175
|
241
|
|
|
176
|
|
- let mut path = PathBuf::from(&tile_cache_dir);
|
|
|
242
|
+ let mut path = PathBuf::from(&self.tile_cache_dir);
|
|
177
|
243
|
path.push(name);
|
|
178
|
244
|
|
|
179
|
|
- sources_vec.push((
|
|
180
|
|
- name.clone(),
|
|
|
245
|
+ self.sources.push((
|
|
|
246
|
+ name.to_string(),
|
|
181
|
247
|
TileSource::new(
|
|
182
|
248
|
id as u32,
|
|
183
|
249
|
url_template.to_string(),
|
|
|
@@ -188,29 +254,20 @@ impl Config {
|
|
188
|
254
|
),
|
|
189
|
255
|
));
|
|
190
|
256
|
}
|
|
191
|
|
-
|
|
192
|
|
- Ok(
|
|
193
|
|
- Config {
|
|
194
|
|
- tile_cache_dir: tile_cache_dir,
|
|
195
|
|
- sources: sources_vec,
|
|
196
|
|
- fps: fps,
|
|
197
|
|
- use_network: use_network,
|
|
198
|
|
- async: async,
|
|
199
|
|
- }
|
|
200
|
|
- )
|
|
|
257
|
+ Ok(())
|
|
201
|
258
|
},
|
|
202
|
259
|
Ok(_) => Err("TOML file has invalid structure. Expected a Table as the top-level element.".to_string()),
|
|
203
|
260
|
Err(e) => Err(format!("{}", e)),
|
|
204
|
261
|
}
|
|
205
|
262
|
}
|
|
206
|
263
|
|
|
207
|
|
- pub fn from_toml_file<P: AsRef<Path>>(path: P) -> Result<Config, String> {
|
|
|
264
|
+ fn add_tile_sources_from_file<P: AsRef<Path>>(&mut self, path: P) -> Result<(), String> {
|
|
208
|
265
|
let mut file = File::open(path).map_err(|e| format!("{}", e))?;
|
|
209
|
266
|
|
|
210
|
267
|
let mut content = String::new();
|
|
211
|
268
|
file.read_to_string(&mut content).map_err(|e| format!("{}", e))?;
|
|
212
|
269
|
|
|
213
|
|
- Config::from_toml_str(&content)
|
|
|
270
|
+ self.add_tile_sources_from_str(&content)
|
|
214
|
271
|
}
|
|
215
|
272
|
|
|
216
|
273
|
pub fn tile_sources(&self) -> &[(String, TileSource)] {
|
|
|
@@ -236,6 +293,7 @@ mod tests {
|
|
236
|
293
|
|
|
237
|
294
|
#[test]
|
|
238
|
295
|
fn default_config() {
|
|
239
|
|
- assert!(Config::from_toml_str(DEFAULT_CONFIG).is_ok())
|
|
|
296
|
+ let mut config = Config::from_toml_str(DEFAULT_CONFIG).unwrap();
|
|
|
297
|
+ config.add_tile_sources_from_str(DEFAULT_TILE_SOURCES).unwrap();
|
|
240
|
298
|
}
|
|
241
|
299
|
}
|