1use anyhow::Result;
2
3use async_trait::async_trait;
4
5use crate::config::SafirConfig;
6use crate::utils::{self, confirm_entry, print_headless};
7use crate::SafirEngine;
8use rubin::net::client::RubinClient;
9
10fn safir_offline() {
11 eprintln!(
12 "Safir Memcache does not appear to be online.\nStart it by running `safir-mem start`."
13 );
14}
15
16pub struct SafirMemcache {
17 is_online: bool,
18 client: RubinClient,
19}
20
21impl SafirMemcache {
22 pub async fn new(cfg: &SafirConfig) -> Result<Self> {
23 Ok(Self {
24 is_online: utils::is_safir_running(cfg.memcache_pid),
25 client: RubinClient::new("127.0.0.1", 9876),
26 })
27 }
28
29 pub async fn dump_store(&self, path: &str) -> Result<()> {
30 if !self.is_online {
31 safir_offline();
32 return Ok(());
33 }
34
35 self.client.dump_store(path).await?;
36 println!("Safir memcache dumped to {}", path);
37
38 Ok(())
39 }
40}
41
42#[async_trait]
43impl SafirEngine for SafirMemcache {
44 async fn add_entry(&mut self, key: String, value: String) -> Result<()> {
45 if !self.is_online {
46 safir_offline();
47 return Ok(());
48 }
49
50 self.client.insert_string(&key, &value).await?;
51 Ok(())
52 }
53
54 async fn get_entry(&self, key: String) -> Result<()> {
55 if !self.is_online {
56 safir_offline();
57 return Ok(());
58 }
59
60 let value = if let Ok(val) = self.client.get_string(&key).await {
61 val
62 } else {
63 String::from("")
64 };
65
66 print_headless("", &key, &value);
67
68 Ok(())
69 }
70
71 async fn remove_entry(&mut self, keys: Vec<String>) -> Result<()> {
72 if !self.is_online {
73 safir_offline();
74 return Ok(());
75 }
76
77 for key in &keys {
78 self.client.remove_string(key).await?;
79 }
80
81 Ok(())
82 }
83
84 async fn set_commands(&mut self, prefix: &str, keys: &Vec<String>) {
85 if !self.is_online {
86 safir_offline();
87 return;
88 }
89
90 for key in keys {
91 if let Ok(value) = self.client.get_string(key).await {
92 print_headless(prefix, key, &value);
93 }
94 }
95 }
96
97 async fn clear_entries(&mut self) -> Result<()> {
98 if !self.is_online {
99 safir_offline();
100 return Ok(());
101 }
102
103 if confirm_entry("Are you sure you want to clear the store?") {
104 self.client.clear_strings().await?;
105 }
106
107 Ok(())
108 }
109
110 fn to_type(&self) -> &dyn std::any::Any {
111 self
112 }
113}