1use crate::{AsBytes, BotnetResult, Bytes, Key};
2use async_std::sync::{Arc, Mutex};
3use async_trait::async_trait;
4use std::collections::HashMap;
5
6#[cfg(feature = "redisdb")]
7use redis::{aio::Connection as RedisConnection, AsyncCommands, Client as RedisClient};
8
9pub trait DatabaseKey:
10 Key + AsBytes + std::cmp::Eq + std::hash::Hash + Send + Sync
11{
12}
13
14#[async_trait]
15pub trait Database {
16 async fn set_key(&mut self, k: impl DatabaseKey, v: Bytes) -> BotnetResult<()>;
17 async fn get_key(&self, k: impl DatabaseKey) -> BotnetResult<Option<Bytes>>;
18 async fn set_bytes(&self, b: Bytes, v: Bytes) -> BotnetResult<()>;
19 async fn get_bytes(&self, k: &Bytes) -> BotnetResult<Option<Bytes>>;
20}
21
22enum DbType {
23 InMemory,
24 #[allow(unused)]
25 Redis,
26}
27
28pub struct InMemory {
29 #[allow(unused)]
30 db_type: DbType,
31 items: Arc<Mutex<HashMap<Bytes, Bytes>>>,
32}
33
34impl InMemory {
35 pub fn new() -> Self {
36 Self {
37 db_type: DbType::InMemory,
38 items: Arc::new(Mutex::new(HashMap::default())),
39 }
40 }
41}
42
43impl Default for InMemory {
44 fn default() -> Self {
45 Self::new()
46 }
47}
48
49#[async_trait]
50impl Database for InMemory {
51 async fn set_key(&mut self, k: impl DatabaseKey, v: Bytes) -> BotnetResult<()> {
52 self.items.lock().await.insert(k.flatten(), v);
53 Ok(())
54 }
55
56 async fn get_key(&self, k: impl DatabaseKey) -> BotnetResult<Option<Bytes>> {
57 Ok(self.items.lock().await.remove(&k.flatten()))
58 }
59
60 async fn set_bytes(&self, k: Bytes, v: Bytes) -> BotnetResult<()> {
61 self.items.lock().await.insert(k, v);
62 Ok(())
63 }
64
65 async fn get_bytes(&self, k: &Bytes) -> BotnetResult<Option<Bytes>> {
66 Ok(self.items.lock().await.remove(k))
67 }
68}
69
70#[cfg(feature = "redisdb")]
71pub struct Redis {
72 conn: Arc<Mutex<RedisConnection>>,
73}
74
75#[cfg(feature = "redisdb")]
76impl Redis {
77 pub async fn new(url: &str) -> BotnetResult<Self> {
78 let client = RedisClient::open(url)?;
79 let conn = client.get_tokio_connection().await?;
80 Ok(Self {
81 conn: Arc::new(Mutex::new(conn)),
82 })
83 }
84}
85
86#[cfg(feature = "redisdb")]
87#[async_trait]
88impl Database for Redis {
89 async fn set_key(&mut self, k: impl DatabaseKey, v: Bytes) -> BotnetResult<()> {
90 unimplemented!()
91 }
92
93 async fn get_key(&self, k: impl DatabaseKey) -> BotnetResult<Option<Bytes>> {
94 unimplemented!()
95 }
96
97 async fn set_bytes(&self, k: Bytes, v: Bytes) -> BotnetResult<()> {
98 unimplemented!()
99 }
100
101 async fn get_bytes(&self, k: &Bytes) -> BotnetResult<Option<Bytes>> {
102 unimplemented!()
103 }
104}