kothok_edge_tts/error.rs
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 Nayeem Bin Ahsan
3//! Crate-level error type for Edge-TTS synthesis failures.
4
5use thiserror::Error;
6
7/// All ways a synthesis request can fail.
8///
9/// Callers typically propagate this with `?` or match on a variant to
10/// decide whether to retry (e.g. [`TtsError::Connect`] after a network blip).
11#[derive(Debug, Error)]
12pub enum TtsError {
13 /// The WebSocket handshake or DRM-token auth failed after all retry
14 /// attempts. The inner string is the last underlying error message.
15 #[error("ws connect failed after retries: {0}")]
16 Connect(String),
17
18 /// The voice-catalogue HTTPS fetch failed (DNS, transport, HTTP framing).
19 /// The inner string is the underlying error message.
20 #[error("voice fetch failed: {0}")]
21 VoiceFetch(String),
22
23 /// A voice-list JSON body could not be deserialized. The inner string is
24 /// the underlying serde error message.
25 #[error("parse failed: {0}")]
26 Parse(String),
27
28 /// Transport-level WebSocket error (handshake, frame decode, TLS).
29 ///
30 /// The `tungstenite::Error` is boxed to keep `TtsError` small: it is the
31 /// largest variant and threads through every `Result<_, TtsError>` on the
32 /// stack. Boxing it allocates only on the rare error path.
33 #[error("ws: {0}")]
34 Ws(#[source] Box<tokio_tungstenite::tungstenite::Error>),
35
36 /// I/O error on the underlying TCP stream, including receive idle timeout.
37 #[error("io: {0}")]
38 Io(#[from] std::io::Error),
39
40 /// The turn completed (or the stream closed) without any audio frames.
41 #[error("no audio received")]
42 NoAudio,
43}
44
45impl From<tokio_tungstenite::tungstenite::Error> for TtsError {
46 fn from(e: tokio_tungstenite::tungstenite::Error) -> Self {
47 TtsError::Ws(Box::new(e))
48 }
49}