ft_sys_shared/
lib.rs

1//! This crate is part of [ft-sdk](https://docs.rs/ft-sdk/) and provides the
2//! system-level functionality. This crate should not be used directly, and
3//! `ft-sdk` should be used.
4#![deny(unused_extern_crates)]
5#![forbid(unsafe_code)]
6
7#[cfg(feature = "host-only")]
8extern crate self as ft_sys_shared;
9
10mod email;
11mod sqlite;
12
13#[cfg(feature = "host-only")]
14pub use email::EmailBind;
15pub use email::{
16    CancelEmailError, Email, EmailAddress, EmailContent, EmailHandle, RenderedEmail, SendEmailError,
17};
18pub use sqlite::{SqliteRawValue, SqliteType};
19
20pub const SESSION_KEY: &str = "fastn-sid";
21pub const TRACKER_KEY: &str = "fastn-tid";
22
23/// Request acts as both a request and a response, and is only used for the
24/// communication between guest and host. It is not exposed via ft-sdk.
25#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
26pub struct Request {
27    pub uri: String,
28    pub method: String,
29    pub headers: Vec<(String, Vec<u8>)>,
30    pub body: Vec<u8>,
31}
32
33impl Request {
34    pub fn server_error(msg: String) -> Self {
35        Request {
36            uri: "server-error".to_string(),
37            method: "500".to_string(),
38            headers: vec![],
39            body: msg.into_bytes(),
40        }
41    }
42
43    pub fn host(&self) -> Option<&str> {
44        self.headers
45            .iter()
46            .find(|(k, _)| k.eq_ignore_ascii_case("host"))
47            .map(|(_, v)| std::str::from_utf8(v).unwrap())
48    }
49}
50
51impl From<Request> for http::Request<bytes::Bytes> {
52    fn from(r: Request) -> Self {
53        let mut req = http::Request::builder()
54            .method(r.method.as_str())
55            .uri(r.uri.as_str());
56
57        for (k, v) in r.headers {
58            req = req.header(k, v);
59        }
60
61        req.body(r.body.into()).unwrap()
62    }
63}
64
65impl From<Request> for http::Response<bytes::Bytes> {
66    fn from(r: Request) -> Self {
67        let mut req = http::Response::builder().status(r.method.parse::<u16>().unwrap());
68
69        for (k, v) in r.headers {
70            req = req.header(k, v);
71        }
72
73        req.body(r.body.into()).unwrap()
74    }
75}
76
77impl From<http::Request<bytes::Bytes>> for Request {
78    fn from(r: http::Request<bytes::Bytes>) -> Self {
79        let uri = r.uri().to_string();
80        let method = r.method().to_string();
81        let (parts, body) = r.into_parts();
82        let headers = parts
83            .headers
84            .iter()
85            .map(|(k, v)| (k.as_str().to_string(), v.as_bytes().to_vec()))
86            .collect();
87
88        Request {
89            uri,
90            method,
91            headers,
92            body: body.to_vec(),
93        }
94    }
95}
96
97impl From<http::Response<bytes::Bytes>> for Request {
98    fn from(r: http::Response<bytes::Bytes>) -> Self {
99        let (parts, body) = r.into_parts();
100        let headers = parts
101            .headers
102            .iter()
103            .map(|(k, v)| (k.as_str().to_string(), v.as_bytes().to_vec()))
104            .collect();
105
106        Request {
107            uri: "response-has-no-url".to_string(),
108            method: parts.status.as_str().to_string(),
109            headers,
110            body: body.to_vec(),
111        }
112    }
113}
114
115/// `DecryptionError` is returned as error when `ft_sdk::decrypt` fails.
116#[derive(Debug, serde::Deserialize, serde::Serialize, thiserror::Error)]
117pub enum DecryptionError {
118    /// Decryption failed.
119    #[error("Decryption failed: {0}")]
120    Generic(String),
121}
122
123#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
124#[serde(rename_all = "kebab-case")]
125pub struct UserData {
126    pub id: i64,
127    pub identity: String,
128    pub name: String,
129    pub email: String,
130    pub verified_email: bool,
131}
132
133// copy from diesel, keeping only the necessary variants
134#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
135pub enum DatabaseErrorKind {
136    UniqueViolation,
137    ForeignKeyViolation,
138    NotNullViolation,
139    CheckViolation,
140    SerializationFailure,
141    ReadOnlyTransaction,
142    ClosedConnection,
143    Unknown,
144}
145
146#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
147pub enum DbError {
148    DatabaseError {
149        kind: DatabaseErrorKind,
150        message: String,
151        details: Option<String>,
152        hint: Option<String>,
153        table_name: Option<String>,
154        column_name: Option<String>,
155        constraint_name: Option<String>,
156        statement_position: Option<i32>,
157    },
158    UnableToSendCommand(String),
159}