Browse Source

Add option for offline usage

Johannes Hofmann 8 years ago
parent
commit
00b904a720
4 changed files with 60 additions and 35 deletions
  1. 4
    0
      src/main.rs
  2. 2
    2
      src/map_view_gl.rs
  3. 7
    4
      src/tile_cache.rs
  4. 47
    29
      src/tile_loader.rs

+ 4
- 0
src/main.rs View File

170
             .value_name("FILE")
170
             .value_name("FILE")
171
             .help("Set a custom config file")
171
             .help("Set a custom config file")
172
             .takes_value(true))
172
             .takes_value(true))
173
+        .arg(Arg::with_name("offline")
174
+            .long("offline")
175
+            .help("Do not use the network"))
173
         .get_matches();
176
         .get_matches();
174
 
177
 
175
     let config = if let Some(config_path) = matches.value_of_os("config") {
178
     let config = if let Some(config_path) = matches.value_of_os("config") {
197
             &cx,
200
             &cx,
198
             window.get_inner_size_pixels().unwrap(),
201
             window.get_inner_size_pixels().unwrap(),
199
             move || { proxy.wakeup_event_loop(); },
202
             move || { proxy.wakeup_event_loop(); },
203
+            !matches.is_present("offline")
200
         )
204
         )
201
     };
205
     };
202
 
206
 

+ 2
- 2
src/map_view_gl.rs View File

24
 }
24
 }
25
 
25
 
26
 impl<'a> MapViewGl<'a> {
26
 impl<'a> MapViewGl<'a> {
27
-    pub fn new<F>(cx: &Context, initial_size: (u32, u32), update_func: F) -> MapViewGl
27
+    pub fn new<F>(cx: &Context, initial_size: (u32, u32), update_func: F, use_network: bool) -> MapViewGl
28
         where F: Fn() + Sync + Send + 'static,
28
         where F: Fn() + Sync + Send + 'static,
29
     {
29
     {
30
         unsafe {
30
         unsafe {
71
                 buf: buf,
71
                 buf: buf,
72
                 viewport_size: initial_size,
72
                 viewport_size: initial_size,
73
                 map_view: map_view,
73
                 map_view: map_view,
74
-                tile_cache: TileCache::new(move |_tile| update_func()),
74
+                tile_cache: TileCache::new(move |_tile| update_func(), use_network),
75
                 tile_cache_gl: TileCacheGl::new(tex, 256),
75
                 tile_cache_gl: TileCacheGl::new(tex, 256),
76
             }
76
             }
77
         }
77
         }

+ 7
- 4
src/tile_cache.rs View File

13
 }
13
 }
14
 
14
 
15
 impl TileCache {
15
 impl TileCache {
16
-    pub fn new<F>(new_tile_func: F) -> Self
16
+    pub fn new<F>(new_tile_func: F, use_network: bool) -> Self
17
         where F: Fn(Tile) + Sync + Send + 'static,
17
         where F: Fn(Tile) + Sync + Send + 'static,
18
     {
18
     {
19
         TileCache {
19
         TileCache {
20
-            loader: TileLoader::new(move |tile| {
21
-                new_tile_func(tile);
22
-            }),
20
+            loader: TileLoader::new(
21
+                move |tile| {
22
+                    new_tile_func(tile);
23
+                },
24
+                use_network,
25
+            ),
23
             map: LinkedHashMap::new(),
26
             map: LinkedHashMap::new(),
24
             max_tiles: 512, //TODO set a reasonable value
27
             max_tiles: 512, //TODO set a reasonable value
25
         }
28
         }

+ 47
- 29
src/tile_loader.rs View File

5
 use std::cmp::Ordering;
5
 use std::cmp::Ordering;
6
 use std::cmp;
6
 use std::cmp;
7
 use std::collections::hash_set::HashSet;
7
 use std::collections::hash_set::HashSet;
8
+use std::error::Error;
8
 use std::fs::File;
9
 use std::fs::File;
9
 use std::io::Write;
10
 use std::io::Write;
10
 use std::path::{Path, PathBuf};
11
 use std::path::{Path, PathBuf};
11
-use std::sync::{Arc, mpsc, Mutex};
12
 use std::sync::mpsc::TryRecvError;
12
 use std::sync::mpsc::TryRecvError;
13
+use std::sync::{Arc, mpsc, Mutex};
13
 use std::thread;
14
 use std::thread;
14
 use tile::Tile;
15
 use tile::Tile;
15
 use tile_source::TileSource;
16
 use tile_source::TileSource;
24
     request_tx: mpsc::Sender<LoaderMessage>,
25
     request_tx: mpsc::Sender<LoaderMessage>,
25
     result_rx: mpsc::Receiver<(Tile, Option<DynamicImage>)>,
26
     result_rx: mpsc::Receiver<(Tile, Option<DynamicImage>)>,
26
     pending: HashSet<Tile>,
27
     pending: HashSet<Tile>,
28
+    use_network: bool,
27
 }
29
 }
28
 
30
 
29
 impl TileLoader {
31
 impl TileLoader {
30
-    pub fn new<F>(notice_func: F) -> Self
32
+    pub fn new<F>(notice_func: F, use_network: bool) -> Self
31
         where F: Fn(Tile) + Sync + Send + 'static,
33
         where F: Fn(Tile) + Sync + Send + 'static,
32
     {
34
     {
33
         let (request_tx, request_rx) = mpsc::channel();
35
         let (request_tx, request_rx) = mpsc::channel();
35
 
37
 
36
         TileLoader {
38
         TileLoader {
37
             client: None,
39
             client: None,
38
-            join_handle: thread::spawn(move || Self::work(&request_rx, &result_tx, notice_func)),
40
+            join_handle: thread::spawn(move || Self::work(&request_rx, &result_tx, notice_func, use_network)),
39
             request_tx: request_tx,
41
             request_tx: request_tx,
40
             result_rx: result_rx,
42
             result_rx: result_rx,
41
             pending: HashSet::new(),
43
             pending: HashSet::new(),
44
+            use_network: use_network,
42
         }
45
         }
43
     }
46
     }
44
 
47
 
46
         request_rx: &mpsc::Receiver<LoaderMessage>,
49
         request_rx: &mpsc::Receiver<LoaderMessage>,
47
         result_tx: &mpsc::Sender<(Tile, Option<DynamicImage>)>,
50
         result_tx: &mpsc::Sender<(Tile, Option<DynamicImage>)>,
48
         notice_func: F,
51
         notice_func: F,
52
+        use_network: bool,
49
     )
53
     )
50
         where F: Fn(Tile) + Sync + Send + 'static,
54
         where F: Fn(Tile) + Sync + Send + 'static,
51
     {
55
     {
125
                                 continue;
129
                                 continue;
126
                             },
130
                             },
127
                             Err(_) => {
131
                             Err(_) => {
128
-                                if let Ok(mut remote_queue) = remote_queue.lock() {
129
-                                    //TODO restrict size of remote_queue
130
-                                    remote_queue.push(request);
131
-                                    if let Some(view) = view_opt {
132
-                                        remote_queue.as_mut_slice().sort_by(|a, b| {
133
-                                            compare_tiles(a.tile, b.tile, view)
134
-                                        });
135
-                                    }
136
-                                    if remote_request_tx.send(RemoteLoaderMessage::PopQueue).is_err() {
137
-                                        //TODO remote worker terminated
132
+                                if use_network {
133
+                                    if let Ok(mut remote_queue) = remote_queue.lock() {
134
+                                        //TODO restrict size of remote_queue
135
+                                        remote_queue.push(request);
136
+                                        if let Some(view) = view_opt {
137
+                                            remote_queue.as_mut_slice().sort_by(|a, b| {
138
+                                                compare_tiles(a.tile, b.tile, view)
139
+                                            });
140
+                                        }
141
+                                        if let Err(e) = remote_request_tx.send(RemoteLoaderMessage::PopQueue) {
142
+                                            //TODO what now? restart worker?
143
+                                            error!("remote worker terminated, {}", e.description());
144
+                                        }
138
                                     }
145
                                     }
146
+                                } else if result_tx.send((request.tile, None)).is_err() {
147
+                                    break 'outer;
139
                                 }
148
                                 }
140
                             },
149
                             },
141
                         }
150
                         }
183
                                     notice_func(request.tile);
192
                                     notice_func(request.tile);
184
 
193
 
185
                                     if request.write_to_file {
194
                                     if request.write_to_file {
186
-                                        //TODO do something on write errors
187
-                                        let _ = Self::write_to_file(&request.path, &buf);
195
+                                        if let Err(e) = Self::write_to_file(&request.path, &buf) {
196
+                                            warn!("could not write file {}, {}", request.path.display(), e.description());
197
+                                        }
188
                                     }
198
                                     }
189
 
199
 
190
                                     continue;
200
                                     continue;
232
             Err(_) => None,
242
             Err(_) => None,
233
             Ok((tile, None)) => {
243
             Ok((tile, None)) => {
234
                 self.pending.remove(&tile);
244
                 self.pending.remove(&tile);
245
+                debug!("async_result none, pending.len: {}, {:?}", self.pending.len(), tile);
235
                 None
246
                 None
236
             },
247
             },
237
             Ok((tile, Some(img))) => {
248
             Ok((tile, Some(img))) => {
238
                 self.pending.remove(&tile);
249
                 self.pending.remove(&tile);
250
+                debug!("async_result some, pending.len: {}, {:?}", self.pending.len(), tile);
239
                 Some((tile, img))
251
                 Some((tile, img))
240
             },
252
             },
241
         }
253
         }
247
                 Some(img)
259
                 Some(img)
248
             },
260
             },
249
             Err(_) => {
261
             Err(_) => {
250
-                //TODO do not try to create a client every time when it failed before
251
-                if self.client.is_none() {
252
-                    self.client = Client::builder().build().ok();
253
-                }
262
+                if self.use_network {
263
+                    //TODO do not try to create a client every time when it failed before
264
+                    if self.client.is_none() {
265
+                        self.client = Client::builder().build().ok();
266
+                    }
254
 
267
 
255
-                if let (Some(client), Some(url)) = (self.client.as_ref(), source.remote_tile_url(tile)) {
256
-                    if let Ok(mut response) = client.get(&url).send() {
257
-                        let mut buf: Vec<u8> = vec![];
258
-                        if response.copy_to(&mut buf).is_ok() {
259
-                            if let Ok(img) = image::load_from_memory(&buf) {
260
-                                if write_to_file {
261
-                                    let path = source.local_tile_path(tile);
262
-                                    let _ = Self::write_to_file(path, &buf);
268
+                    if let (Some(client), Some(url)) = (self.client.as_ref(), source.remote_tile_url(tile)) {
269
+                        if let Ok(mut response) = client.get(&url).send() {
270
+                            let mut buf: Vec<u8> = vec![];
271
+                            if response.copy_to(&mut buf).is_ok() {
272
+                                if let Ok(img) = image::load_from_memory(&buf) {
273
+                                    if write_to_file {
274
+                                        let path = source.local_tile_path(tile);
275
+                                        if let Err(e) = Self::write_to_file(&path, &buf) {
276
+                                            warn!("could not write file {}, {}", &path.display(), e.description());
277
+                                        }
278
+                                    }
279
+                                    return Some(img);
263
                                 }
280
                                 }
264
-                                return Some(img);
265
                             }
281
                             }
266
                         }
282
                         }
267
                     }
283
                     }
284
+                    None
285
+                } else {
286
+                    None
268
                 }
287
                 }
269
-                None
270
             },
288
             },
271
         }
289
         }
272
     }
290
     }