redact_crypto/storage/
gcs.rs1use crate::{CryptoError, Entry, NonIndexedTypeStorer, StorableType, Storer, TypeStorer};
2use async_trait::async_trait;
3use cloud_storage::Client;
4use cloud_storage::Error::Other;
5use serde::{Deserialize, Serialize};
6use std::{
7 error::Error,
8 fmt::{self, Display, Formatter},
9};
10
11#[derive(Debug)]
12pub enum GoogleCloudStorerError {
13 InternalError {
15 source: Box<dyn Error + Send + Sync>,
16 },
17
18 NotFound,
20}
21
22impl Error for GoogleCloudStorerError {
23 fn source(&self) -> Option<&(dyn Error + 'static)> {
24 match *self {
25 GoogleCloudStorerError::InternalError { ref source } => Some(source.as_ref()),
26 GoogleCloudStorerError::NotFound => None,
27 }
28 }
29}
30
31impl Display for GoogleCloudStorerError {
32 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
33 match *self {
34 GoogleCloudStorerError::InternalError { .. } => {
35 write!(f, "Internal error occurred")
36 }
37 GoogleCloudStorerError::NotFound => {
38 write!(f, "Requested document not found")
39 }
40 }
41 }
42}
43
44impl From<GoogleCloudStorerError> for CryptoError {
45 fn from(gcse: GoogleCloudStorerError) -> Self {
46 match gcse {
47 GoogleCloudStorerError::InternalError { .. } => CryptoError::InternalError {
48 source: Box::new(gcse),
49 },
50 GoogleCloudStorerError::NotFound => CryptoError::NotFound {
51 source: Box::new(gcse),
52 },
53 }
54 }
55}
56
57#[derive(Serialize, Deserialize, Debug, Clone)]
59pub struct GoogleCloudStorer {
60 bucket_name: String,
61}
62
63impl From<GoogleCloudStorer> for NonIndexedTypeStorer {
64 fn from(gcs: GoogleCloudStorer) -> Self {
65 NonIndexedTypeStorer::GoogleCloud(gcs)
66 }
67}
68
69impl From<GoogleCloudStorer> for TypeStorer {
70 fn from(gcs: GoogleCloudStorer) -> Self {
71 TypeStorer::NonIndexed(NonIndexedTypeStorer::GoogleCloud(gcs))
72 }
73}
74
75impl GoogleCloudStorer {
76 pub fn new(bucket_name: String) -> Self {
77 GoogleCloudStorer { bucket_name }
78 }
79}
80
81#[async_trait]
82impl Storer for GoogleCloudStorer {
83 async fn get<T: StorableType>(&self, path: &str) -> Result<Entry<T>, CryptoError> {
84 let client = Client::new();
85 let bytes = client
86 .object()
87 .download(&self.bucket_name, path)
88 .await
89 .map_err(|e| match e {
90 Other(_) => GoogleCloudStorerError::NotFound {},
91 _ => GoogleCloudStorerError::InternalError {
92 source: Box::new(e),
93 },
94 })?;
95
96 let s = String::from_utf8(bytes).map_err(|e| GoogleCloudStorerError::InternalError {
97 source: Box::new(e),
98 })?;
99
100 Ok(
101 serde_json::from_str(&s).map_err(|e| GoogleCloudStorerError::InternalError {
102 source: Box::new(e),
103 })?,
104 )
105 }
106
107 async fn create<T: StorableType>(&self, entry: Entry<T>) -> Result<Entry<T>, CryptoError> {
108 let entry_string =
109 serde_json::to_string(&entry).map_err(|e| GoogleCloudStorerError::InternalError {
110 source: Box::new(e),
111 })?;
112 let client = Client::new();
113
114 match client
115 .object()
116 .create(
117 &self.bucket_name,
118 entry_string.as_bytes().to_vec(),
119 &entry.path.clone(),
120 "application/json",
121 )
122 .await
123 {
124 Ok(_) => Ok(entry),
125 Err(e) => Err(GoogleCloudStorerError::InternalError {
126 source: Box::new(e),
127 }
128 .into()),
129 }
130 }
131}