src/backend.rs 4.6 K raw
1
use crate::db::{self, Db, Snippet};
2
use std::fmt;
3
4
#[derive(Debug)]
5
pub enum BackendError {
6
    NotFound,
7
    Unauthorized(String),
8
    Network(String),
9
    Database(String),
10
}
11
12
impl fmt::Display for BackendError {
13
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14
        match self {
15
            BackendError::NotFound => write!(f, "Not found"),
16
            BackendError::Unauthorized(msg) => write!(f, "Unauthorized: {}", msg),
17
            BackendError::Network(msg) => write!(f, "Network error: {}", msg),
18
            BackendError::Database(msg) => write!(f, "Database error: {}", msg),
19
        }
20
    }
21
}
22
23
impl std::error::Error for BackendError {}
24
25
impl From<db::DbError> for BackendError {
26
    fn from(e: db::DbError) -> Self {
27
        BackendError::Database(e.to_string())
28
    }
29
}
30
31
pub enum Backend {
32
    Local {
33
        db: Db,
34
    },
35
    Remote {
36
        base_url: String,
37
        api_key: Option<String>,
38
        client: reqwest::blocking::Client,
39
    },
40
}
41
42
impl Backend {
43
    pub fn local() -> Result<Self, BackendError> {
44
        Ok(Backend::Local { db: db::init_db()? })
45
    }
46
47
    pub fn remote(base_url: String, api_key: Option<String>) -> Self {
48
        Backend::Remote {
49
            base_url,
50
            api_key,
51
            client: reqwest::blocking::Client::new(),
52
        }
53
    }
54
55
    pub fn list_snippets(&self) -> Result<Vec<Snippet>, BackendError> {
56
        match self {
57
            Backend::Local { db } => Ok(db::get_all_snippets(db)?),
58
            Backend::Remote {
59
                base_url,
60
                api_key,
61
                client,
62
            } => {
63
                let mut req = client.get(format!("{}/api/snippets", base_url));
64
                if let Some(key) = api_key {
65
                    req = req.header("x-api-key", key);
66
                }
67
                let resp = req.send().map_err(|e| BackendError::Network(e.to_string()))?;
68
                match resp.status().as_u16() {
69
                    200 => resp
70
                        .json::<Vec<Snippet>>()
71
                        .map_err(|e| BackendError::Network(e.to_string())),
72
                    401 => Err(BackendError::Unauthorized("Invalid API key".into())),
73
                    403 => Err(BackendError::Unauthorized("No API key configured on server".into())),
74
                    _ => Err(BackendError::Network(format!("HTTP {}", resp.status()))),
75
                }
76
            }
77
        }
78
    }
79
80
    pub fn create_snippet(&self, name: &str, content: &str) -> Result<Snippet, BackendError> {
81
        match self {
82
            Backend::Local { db } => Ok(db::create_snippet(db, name, content)?),
83
            Backend::Remote {
84
                base_url,
85
                api_key,
86
                client,
87
            } => {
88
                let mut req = client
89
                    .post(format!("{}/api/snippets", base_url))
90
                    .json(&serde_json::json!({"name": name, "content": content}));
91
                if let Some(key) = api_key {
92
                    req = req.header("x-api-key", key);
93
                }
94
                let resp = req.send().map_err(|e| BackendError::Network(e.to_string()))?;
95
                match resp.status().as_u16() {
96
                    201 => resp
97
                        .json::<Snippet>()
98
                        .map_err(|e| BackendError::Network(e.to_string())),
99
                    401 => Err(BackendError::Unauthorized("Invalid API key".into())),
100
                    403 => Err(BackendError::Unauthorized("No API key configured on server".into())),
101
                    _ => Err(BackendError::Network(format!("HTTP {}", resp.status()))),
102
                }
103
            }
104
        }
105
    }
106
107
    pub fn delete_snippet(&self, short_id: &str) -> Result<bool, BackendError> {
108
        match self {
109
            Backend::Local { db } => Ok(db::delete_snippet_by_short_id(db, short_id)?),
110
            Backend::Remote {
111
                base_url,
112
                api_key,
113
                client,
114
            } => {
115
                let mut req =
116
                    client.delete(format!("{}/api/snippets/{}", base_url, short_id));
117
                if let Some(key) = api_key {
118
                    req = req.header("x-api-key", key);
119
                }
120
                let resp = req.send().map_err(|e| BackendError::Network(e.to_string()))?;
121
                match resp.status().as_u16() {
122
                    200 => Ok(true),
123
                    401 => Err(BackendError::Unauthorized("Invalid API key".into())),
124
                    403 => Err(BackendError::Unauthorized("No API key configured on server".into())),
125
                    404 => Ok(false),
126
                    _ => Err(BackendError::Network(format!("HTTP {}", resp.status()))),
127
                }
128
            }
129
        }
130
    }
131
}