autopush_common/db/
mod.rs1use std::collections::{HashMap, HashSet};
12use std::result::Result as StdResult;
13
14use derive_builder::Builder;
15use serde::Serializer;
16use serde_derive::{Deserialize, Serialize};
17use uuid::Uuid;
18
19#[cfg(feature = "bigtable")]
20pub mod bigtable;
21pub mod client;
22pub mod error;
23pub mod models;
24pub mod reporter;
25pub mod routing;
26
27pub mod mock;
29
30pub use reporter::spawn_pool_periodic_reporter;
31
32use crate::notification::Notification;
33use crate::util::timing::ms_since_epoch;
34use crate::MAX_ROUTER_TTL;
35use models::RangeKey;
36
37pub const USER_RECORD_VERSION: u64 = 1;
38
39#[derive(Eq, Debug, PartialEq)]
40pub enum StorageType {
41 INVALID,
42 #[cfg(feature = "bigtable")]
43 BigTable,
44}
45
46impl From<&str> for StorageType {
47 fn from(name: &str) -> Self {
48 match name.to_lowercase().as_str() {
49 #[cfg(feature = "bigtable")]
50 "bigtable" => Self::BigTable,
51 _ => Self::INVALID,
52 }
53 }
54}
55
56#[allow(clippy::vec_init_then_push)] impl StorageType {
59 fn available<'a>() -> Vec<&'a str> {
60 #[allow(unused_mut)]
61 let mut result: Vec<&str> = Vec::new();
62 #[cfg(feature = "bigtable")]
63 result.push("Bigtable");
64 result
65 }
66
67 pub fn from_dsn(dsn: &Option<String>) -> Self {
68 debug!("Supported data types: {:?}", StorageType::available());
69 debug!("Checking DSN: {:?}", &dsn);
70 if dsn.is_none() {
71 let default = Self::available()[0];
72 info!("No DSN specified, failing over to old default dsn: {default}");
73 return Self::from(default);
74 }
75 let dsn = dsn.clone().unwrap_or_default();
76 #[cfg(feature = "bigtable")]
77 if dsn.starts_with("grpc") {
78 trace!("Found grpc");
79 if let Ok(cred) = std::env::var("GOOGLE_APPLICATION_CREDENTIALS") {
85 trace!("Env: {:?}", cred);
86 }
87 return Self::BigTable;
88 }
89 Self::INVALID
90 }
91}
92
93#[derive(Clone, Debug, Default, Deserialize)]
96pub struct DbSettings {
97 pub dsn: Option<String>,
99 pub db_settings: String,
104}
105pub fn uuid_serializer<S>(x: &Uuid, s: S) -> StdResult<S::Ok, S::Error>
112where
113 S: Serializer,
114{
115 s.serialize_str(&x.simple().to_string())
116}
117
118#[derive(Clone, Default, Debug)]
119pub struct CheckStorageResponse {
120 pub include_topic: bool,
124 pub messages: Vec<Notification>,
126 pub timestamp: Option<u64>,
128}
129
130#[derive(Deserialize, PartialEq, Debug, Clone, Serialize, Builder)]
132#[builder(default, setter(strip_option))]
133pub struct User {
134 #[serde(serialize_with = "uuid_serializer")]
137 pub uaid: Uuid,
138 pub connected_at: u64,
140 pub router_type: String,
142 pub router_data: Option<HashMap<String, serde_json::Value>>,
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub node_id: Option<String>,
147 #[serde(skip_serializing_if = "Option::is_none")]
149 pub record_version: Option<u64>,
150 #[serde(skip_serializing_if = "Option::is_none")]
154 pub current_timestamp: Option<u64>,
155 #[serde(skip_serializing)]
157 pub version: Option<Uuid>,
158 priv_channels: HashSet<Uuid>,
171}
172
173impl Default for User {
174 fn default() -> Self {
175 let uaid = Uuid::new_v4();
176 Self {
178 uaid,
179 connected_at: ms_since_epoch(),
180 router_type: "webpush".to_string(),
181 router_data: None,
182 node_id: None,
183 record_version: Some(USER_RECORD_VERSION),
184 current_timestamp: None,
185 version: Some(Uuid::new_v4()),
186 priv_channels: HashSet::new(),
187 }
188 }
189}
190
191impl User {
192 pub fn builder() -> UserBuilder {
194 UserBuilder::default()
195 }
196
197 pub fn channel_count(&self) -> usize {
198 self.priv_channels.len()
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::{User, USER_RECORD_VERSION};
205
206 #[test]
207 fn user_defaults() {
208 let user = User::builder().current_timestamp(22).build().unwrap();
209 assert_eq!(user.current_timestamp, Some(22));
210 assert_eq!(user.router_type, "webpush".to_owned());
211 assert_eq!(user.record_version, Some(USER_RECORD_VERSION));
212 }
213}