chore: improve error handling 93144835
Steve · 2026-05-06 21:14 2 file(s) · +58 −23
Cargo.lock +16 −16
1302 1302
1303 1303
[[package]]
1304 1304
name = "js-sys"
1305 -
version = "0.3.97"
1305 +
version = "0.3.98"
1306 1306
source = "registry+https://github.com/rust-lang/crates.io-index"
1307 -
checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf"
1307 +
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
1308 1308
dependencies = [
1309 1309
 "cfg-if",
1310 1310
 "futures-util",
2764 2764
2765 2765
[[package]]
2766 2766
name = "tower-http"
2767 -
version = "0.6.9"
2767 +
version = "0.6.10"
2768 2768
source = "registry+https://github.com/rust-lang/crates.io-index"
2769 -
checksum = "a28f0d049ccfaa566e14e9663d304d8577427b368cb4710a20528690287a738b"
2769 +
checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51"
2770 2770
dependencies = [
2771 2771
 "async-compression",
2772 2772
 "bitflags 2.11.1",
3046 3046
3047 3047
[[package]]
3048 3048
name = "wasm-bindgen"
3049 -
version = "0.2.120"
3049 +
version = "0.2.121"
3050 3050
source = "registry+https://github.com/rust-lang/crates.io-index"
3051 -
checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
3051 +
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
3052 3052
dependencies = [
3053 3053
 "cfg-if",
3054 3054
 "once_cell",
3059 3059
3060 3060
[[package]]
3061 3061
name = "wasm-bindgen-futures"
3062 -
version = "0.4.70"
3062 +
version = "0.4.71"
3063 3063
source = "registry+https://github.com/rust-lang/crates.io-index"
3064 -
checksum = "af934872acec734c2d80e6617bbb5ff4f12b052dd8e6332b0817bce889516084"
3064 +
checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8"
3065 3065
dependencies = [
3066 3066
 "js-sys",
3067 3067
 "wasm-bindgen",
3069 3069
3070 3070
[[package]]
3071 3071
name = "wasm-bindgen-macro"
3072 -
version = "0.2.120"
3072 +
version = "0.2.121"
3073 3073
source = "registry+https://github.com/rust-lang/crates.io-index"
3074 -
checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
3074 +
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
3075 3075
dependencies = [
3076 3076
 "quote",
3077 3077
 "wasm-bindgen-macro-support",
3079 3079
3080 3080
[[package]]
3081 3081
name = "wasm-bindgen-macro-support"
3082 -
version = "0.2.120"
3082 +
version = "0.2.121"
3083 3083
source = "registry+https://github.com/rust-lang/crates.io-index"
3084 -
checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
3084 +
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
3085 3085
dependencies = [
3086 3086
 "bumpalo",
3087 3087
 "proc-macro2",
3092 3092
3093 3093
[[package]]
3094 3094
name = "wasm-bindgen-shared"
3095 -
version = "0.2.120"
3095 +
version = "0.2.121"
3096 3096
source = "registry+https://github.com/rust-lang/crates.io-index"
3097 -
checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
3097 +
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
3098 3098
dependencies = [
3099 3099
 "unicode-ident",
3100 3100
]
3135 3135
3136 3136
[[package]]
3137 3137
name = "web-sys"
3138 -
version = "0.3.97"
3138 +
version = "0.3.98"
3139 3139
source = "registry+https://github.com/rust-lang/crates.io-index"
3140 -
checksum = "2eadbac71025cd7b0834f20d1fe8472e8495821b4e9801eb0a60bd1f19827602"
3140 +
checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
3141 3141
dependencies = [
3142 3142
 "js-sys",
3143 3143
 "wasm-bindgen",
src/main.rs +42 −7
75 75
    if !is_bare_domain(&url) {
76 76
        return Ok(url);
77 77
    }
78 -
    let html = ureq::get(&url).call()?.body_mut().read_to_string()?;
78 +
    let timeout = std::time::Duration::from_secs(10);
79 +
    let agent = ureq::Agent::config_builder()
80 +
        .timeout_global(Some(timeout))
81 +
        .build()
82 +
        .into();
83 +
    let html = ureq::Agent::new_with_config(agent)
84 +
        .get(&url)
85 +
        .call()
86 +
        .map_err(|e| color_eyre::eyre::eyre!("Failed to fetch {url}: {e}"))?
87 +
        .body_mut()
88 +
        .read_to_string()
89 +
        .map_err(|e| color_eyre::eyre::eyre!("Failed to read response from {url}: {e}"))?;
79 90
    if let Some(feed_url) = find_feed_link(&html, &url) {
80 91
        return Ok(feed_url);
81 92
    }
95 106
        let candidate = format!("{base}{path}");
96 107
        if ureq::get(&candidate)
97 108
            .call()
98 -
            .map(|r| r.status() == 200)
109 +
            .map(|r: ureq::http::Response<ureq::Body>| r.status() == 200)
99 110
            .unwrap_or(false)
100 111
        {
101 112
            return Ok(candidate);
127 138
    }
128 139
    let feeds: Vec<ParsedFeed> = urls
129 140
        .iter()
130 -
        .map(|url| -> color_eyre::Result<ParsedFeed> {
131 -
            let resolved = discover_feed(url)?;
132 -
            Ok(parse_url(&resolved, None, None, None)?)
141 +
        .filter_map(|url| {
142 +
            let resolved = match discover_feed(url) {
143 +
                Ok(r) => r,
144 +
                Err(e) => {
145 +
                    eprintln!("warning: skipping {url}: {e}");
146 +
                    return None;
147 +
                }
148 +
            };
149 +
            match parse_url(&resolved, None, None, None) {
150 +
                Ok(feed) => Some(feed),
151 +
                Err(e) => {
152 +
                    eprintln!("warning: failed to parse feed {url}: {e}");
153 +
                    None
154 +
                }
155 +
            }
133 156
        })
134 -
        .collect::<Result<_, _>>()?;
157 +
        .collect();
158 +
159 +
    if feeds.is_empty() {
160 +
        eprintln!("No feeds loaded successfully.");
161 +
        std::process::exit(1);
162 +
    }
135 163
136 164
    let mut entries: Vec<(&Entry, Option<&str>)> = feeds
137 165
        .iter()
146 174
        db.cmp(&da)
147 175
    });
148 176
177 +
    if entries.is_empty() {
178 +
        eprintln!("No entries found in any feed.");
179 +
        std::process::exit(1);
180 +
    }
149 181
    ratatui::run(|t| app(t, &entries))?;
150 182
    Ok(())
151 183
}
162 194
            match code {
163 195
                KeyCode::Char('q') => break,
164 196
                KeyCode::Char('j') | KeyCode::Down => {
165 -
                    let next = state.selected().map(|i| (i + 1).min(len - 1)).unwrap_or(0);
197 +
                    let next = state
198 +
                        .selected()
199 +
                        .map(|i| (i + 1).min(len.saturating_sub(1)))
200 +
                        .unwrap_or(0);
166 201
                    state.select(Some(next));
167 202
                }
168 203
                KeyCode::Char('k') | KeyCode::Up => {