Skip to content

Commit 8d00c49

Browse files
committed
Error handling
1 parent 603a8a3 commit 8d00c49

6 files changed

Lines changed: 39 additions & 64 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ repository = "https://github.com/UdHo/mapvas.git"
1111
license = "MIT OR Apache-2.0"
1212

1313
[dependencies]
14-
anyhow = "1.0.102"
1514
axum = "0.8.9"
1615
image = "0.25.10"
1716
itertools = "0.14.0"

src/map/tile_loader.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::config::{TileProvider, TileType};
22
use crate::map::coordinates::{Tile, TilePriority};
3-
use anyhow::Result;
43
use log::{debug, error, trace};
54
use regex::Regex;
65
use std::cmp::Reverse;
@@ -79,15 +78,15 @@ impl Ord for PrioritizedTileRequest {
7978
/// The interface the cached and non-cached tile loader.
8079
pub trait TileLoader {
8180
/// Tries to fetch the tile data asyncroneously.
82-
async fn tile_data(&self, tile: &Tile, source: TileSource) -> Result<TileData>;
81+
async fn tile_data(&self, tile: &Tile, source: TileSource) -> Result<TileData, TileLoaderError>;
8382

8483
/// Tries to fetch the tile data with priority.
8584
async fn tile_data_with_priority(
8685
&self,
8786
tile: &Tile,
8887
source: TileSource,
8988
_priority: TilePriority,
90-
) -> Result<TileData> {
89+
) -> Result<TileData, TileLoaderError> {
9190
// Default implementation ignores priority
9291
self.tile_data(tile, source).await
9392
}
@@ -126,20 +125,20 @@ impl TileCache {
126125
}
127126

128127
impl TileLoader for TileCache {
129-
async fn tile_data(&self, tile: &Tile, tile_source: TileSource) -> Result<TileData> {
128+
async fn tile_data(&self, tile: &Tile, tile_source: TileSource) -> Result<TileData, TileLoaderError> {
130129
if tile_source == TileSource::Download {
131-
return Err(TileLoaderError::TileNotAvailable { tile: *tile }.into());
130+
return Err(TileLoaderError::TileNotAvailable { tile: *tile });
132131
}
133132
match self.path(tile) {
134133
Some(p) => {
135134
if p.exists() {
136135
Ok(tokio::fs::read(p).await?)
137136
} else {
138-
Err(TileLoaderError::TileNotAvailable { tile: *tile }.into())
137+
Err(TileLoaderError::TileNotAvailable { tile: *tile })
139138
}
140139
}
141140

142-
None => Err(TileLoaderError::TileNotAvailable { tile: *tile }.into()),
141+
None => Err(TileLoaderError::TileNotAvailable { tile: *tile }),
143142
}
144143
}
145144
}
@@ -386,7 +385,7 @@ impl TileDownloader {
386385
}
387386

388387
impl TileLoader for TileDownloader {
389-
async fn tile_data(&self, tile: &Tile, tile_source: TileSource) -> Result<TileData> {
388+
async fn tile_data(&self, tile: &Tile, tile_source: TileSource) -> Result<TileData, TileLoaderError> {
390389
self
391390
.tile_data_with_priority(tile, tile_source, TilePriority::Current)
392391
.await
@@ -397,17 +396,17 @@ impl TileLoader for TileDownloader {
397396
tile: &Tile,
398397
tile_source: TileSource,
399398
priority: TilePriority,
400-
) -> Result<TileData> {
399+
) -> Result<TileData, TileLoaderError> {
401400
if tile_source == TileSource::Cache {
402-
return Err(TileLoaderError::TileNotAvailable { tile: *tile }.into());
401+
return Err(TileLoaderError::TileNotAvailable { tile: *tile });
403402
}
404403

405404
let download_token =
406405
DownloadManager::download_with_priority(&self.download_manager, *tile, priority)
407406
.or_else(|| DownloadManager::try_next_from_queue(&self.download_manager));
408407

409408
if download_token.is_none() {
410-
return Err(TileLoaderError::TileDownloadInProgress { tile: *tile }.into());
409+
return Err(TileLoaderError::TileDownloadInProgress { tile: *tile });
411410
}
412411

413412
let url = self.get_path_for_tile(tile);
@@ -442,7 +441,7 @@ impl TileLoader for TileDownloader {
442441
};
443442
debug!("Downloaded {tile:?}.");
444443

445-
Ok(result?)
444+
result
446445
}
447446
}
448447

@@ -520,7 +519,7 @@ impl CachedTileLoader {
520519
}
521520
}
522521

523-
pub async fn get_from_cache(&self, tile: &Tile, tile_source: TileSource) -> Result<TileData> {
522+
pub async fn get_from_cache(&self, tile: &Tile, tile_source: TileSource) -> Result<TileData, TileLoaderError> {
524523
self.cache.tile_data(tile, tile_source).await
525524
}
526525

@@ -539,7 +538,7 @@ impl CachedTileLoader {
539538
tile: &Tile,
540539
tile_source: TileSource,
541540
priority: TilePriority,
542-
) -> Result<TileData> {
541+
) -> Result<TileData, TileLoaderError> {
543542
match self
544543
.loader
545544
.tile_data_with_priority(tile, tile_source, priority)
@@ -548,7 +547,7 @@ impl CachedTileLoader {
548547
Ok(data) => {
549548
self.cache.cache_tile(tile, &data);
550549
match data.len() {
551-
0..=100 => Err(TileLoaderError::TileNotAvailable { tile: *tile }.into()),
550+
0..=100 => Err(TileLoaderError::TileNotAvailable { tile: *tile }),
552551
_ => Ok(data),
553552
}
554553
}
@@ -589,7 +588,7 @@ impl Default for CachedTileLoader {
589588
}
590589

591590
impl TileLoader for CachedTileLoader {
592-
async fn tile_data(&self, tile: &Tile, tile_source: TileSource) -> Result<TileData> {
591+
async fn tile_data(&self, tile: &Tile, tile_source: TileSource) -> Result<TileData, TileLoaderError> {
593592
self
594593
.tile_data_with_priority(tile, tile_source, TilePriority::Current)
595594
.await
@@ -600,7 +599,7 @@ impl TileLoader for CachedTileLoader {
600599
tile: &Tile,
601600
tile_source: TileSource,
602601
priority: TilePriority,
603-
) -> Result<TileData> {
602+
) -> Result<TileData, TileLoaderError> {
604603
trace!("Loading tile from file {:?}", &tile);
605604
if let Ok(data) = self.get_from_cache(tile, tile_source).await {
606605
debug!("cache_hit: {tile:?}");

src/search.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,17 @@ pub mod providers;
22
pub mod ui;
33

44
use crate::map::coordinates::WGS84Coordinate;
5-
use anyhow::Result;
65
use serde::{Deserialize, Serialize};
76
use std::fmt::Display;
7+
use thiserror::Error;
8+
9+
#[derive(Debug, Error)]
10+
pub enum SearchError {
11+
#[error("HTTP request failed: {0}")]
12+
Http(#[from] reqwest::Error),
13+
#[error("Search failed: {0}")]
14+
Other(String),
15+
}
816

917
/// A search result containing location information
1018
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -32,15 +40,15 @@ pub trait SearchProvider: Send + Sync {
3240
fn name(&self) -> &str;
3341

3442
/// Search for locations based on query string
35-
async fn search(&self, query: &str) -> Result<Vec<SearchResult>>;
43+
async fn search(&self, query: &str) -> Result<Vec<SearchResult>, SearchError>;
3644

3745
/// Whether this provider supports reverse geocoding
3846
fn supports_reverse(&self) -> bool {
3947
false
4048
}
4149

4250
/// Reverse geocode a coordinate to get place information
43-
async fn reverse(&self, coord: WGS84Coordinate) -> Result<Option<SearchResult>> {
51+
async fn reverse(&self, coord: WGS84Coordinate) -> Result<Option<SearchResult>, SearchError> {
4452
let _ = coord;
4553
Ok(None)
4654
}
@@ -89,7 +97,7 @@ impl SearchManager {
8997
///
9098
/// Returns an error if any of the search providers fail to initialize,
9199
/// such as invalid URLs or missing required configuration parameters.
92-
pub fn with_config(configs: Vec<SearchProviderConfig>) -> Result<Self> {
100+
pub fn with_config(configs: Vec<SearchProviderConfig>) -> Result<Self, SearchError> {
93101
let mut providers: Vec<Box<dyn SearchProvider>> = Vec::new();
94102

95103
for config in configs {
@@ -131,7 +139,7 @@ impl SearchManager {
131139
///
132140
/// Returns an error if all search providers fail or if there are network
133141
/// connectivity issues preventing any searches from completing.
134-
pub async fn search(&self, query: &str) -> Result<Vec<SearchResult>> {
142+
pub async fn search(&self, query: &str) -> Result<Vec<SearchResult>, SearchError> {
135143
let query = query.trim();
136144
if query.is_empty() {
137145
return Ok(vec![]);

src/search/providers.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
use super::{SearchProvider, SearchResult};
1+
use super::{SearchError, SearchProvider, SearchResult};
22
use crate::map::coordinates::WGS84Coordinate;
3-
use anyhow::{Result, anyhow};
43
use regex::Regex;
54
use reqwest;
65
use serde_json::Value;
@@ -130,7 +129,7 @@ impl SearchProvider for NominatimProvider {
130129
"OpenStreetMap Nominatim"
131130
}
132131

133-
async fn search(&self, query: &str) -> Result<Vec<SearchResult>> {
132+
async fn search(&self, query: &str) -> Result<Vec<SearchResult>, SearchError> {
134133
let url = format!(
135134
"{}/search?format=json&limit=5&addressdetails=1&q={}",
136135
self.base_url,
@@ -143,10 +142,10 @@ impl SearchProvider for NominatimProvider {
143142
.header("User-Agent", "MapVas/0.2.8 (https://github.com/UdHo/mapvas)")
144143
.send()
145144
.await
146-
.map_err(|e| anyhow!("Nominatim API request failed: {e}"))?
145+
.map_err(SearchError::Http)?
147146
.json::<Value>()
148147
.await
149-
.map_err(|e| anyhow!("Nominatim API response parse failed: {e}"))?;
148+
.map_err(SearchError::Http)?;
150149

151150
let mut results = Vec::new();
152151

@@ -187,7 +186,7 @@ impl SearchProvider for NominatimProvider {
187186
true
188187
}
189188

190-
async fn reverse(&self, coord: WGS84Coordinate) -> Result<Option<SearchResult>> {
189+
async fn reverse(&self, coord: WGS84Coordinate) -> Result<Option<SearchResult>, SearchError> {
191190
let url = format!(
192191
"{}/reverse?format=json&lat={}&lon={}&addressdetails=1",
193192
self.base_url, coord.lat, coord.lon
@@ -199,10 +198,10 @@ impl SearchProvider for NominatimProvider {
199198
.header("User-Agent", "MapVas/0.2.8 (https://github.com/UdHo/mapvas)")
200199
.send()
201200
.await
202-
.map_err(|e| anyhow!("Nominatim reverse API request failed: {e}"))?
201+
.map_err(SearchError::Http)?
203202
.json::<Value>()
204203
.await
205-
.map_err(|e| anyhow!("Nominatim reverse API response parse failed: {e}"))?;
204+
.map_err(SearchError::Http)?;
206205

207206
if let Some(display_name) = response["display_name"].as_str() {
208207
let address = response["address"].as_object();
@@ -249,7 +248,7 @@ impl SearchProvider for CustomProvider {
249248
&self.name
250249
}
251250

252-
async fn search(&self, query: &str) -> Result<Vec<SearchResult>> {
251+
async fn search(&self, query: &str) -> Result<Vec<SearchResult>, SearchError> {
253252
let url = self
254253
.url_template
255254
.replace("{query}", &urlencoding::encode(query));
@@ -262,10 +261,10 @@ impl SearchProvider for CustomProvider {
262261
let response = request
263262
.send()
264263
.await
265-
.map_err(|e| anyhow!("Custom API request failed: {e}"))?
264+
.map_err(SearchError::Http)?
266265
.json::<Value>()
267266
.await
268-
.map_err(|e| anyhow!("Custom API response parse failed: {e}"))?;
267+
.map_err(SearchError::Http)?;
269268

270269
// This is a basic implementation - could be extended to support
271270
// different response formats based on configuration

todo/09-error-handling-convention.md

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)