1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*use std::collections::HashMap;
use actix_web::web::Data;
use autonomi::Wallet;
use base64::Engine;
use base64::prelude::BASE64_STANDARD;
use bytes::Bytes;
use mockall::mock;
use crate::controller::StoreType;
use crate::error::public_data_error::PublicDataError;
use crate::model::key_value::KeyValue;
use crate::model::pnr::{PnrRecord, PnrRecordType, PnrZone};
use crate::service::pnr_service::PnrService;
use crate::service::public_data_service::PublicDataService;
mock! {
#[derive(Debug)]
pub KeyValueService {
pub fn new(public_data_service: Data<PublicDataService>, pnr_service: Data<PnrService>) -> Self;
pub async fn create_key_value(
&self,
bucket: String,
object: String,
key_value: KeyValue,
evm_wallet: Wallet,
store_type: StoreType,
) -> Result<KeyValue, PublicDataError>;
pub async fn create_key_value_binary(
&self,
bucket: String,
object: String,
content: Bytes,
evm_wallet: Wallet,
store_type: StoreType,
) -> Result<(), PublicDataError>;
pub async fn get_key_value(&self, bucket: String, object: String) -> Result<KeyValue, PublicDataError>;
pub async fn get_key_value_binary(&self, bucket: String, object: String) -> Result<Bytes, PublicDataError>;
}
impl Clone for KeyValueService {
fn clone(&self) -> Self;
}
}
#[derive(Debug, Clone)]
pub struct KeyValueService {
public_data_service: Data<PublicDataService>,
pnr_service: Data<PnrService>,
}
impl KeyValueService {
pub fn new(public_data_service: Data<PublicDataService>, pnr_service: Data<PnrService>) -> Self {
Self {
public_data_service,
pnr_service,
}
}
pub async fn create_key_value(
&self,
bucket: String,
object: String,
key_value: KeyValue,
evm_wallet: Wallet,
store_type: StoreType,
) -> Result<KeyValue, PublicDataError> {
let decoded_content = BASE64_STANDARD
.decode(&key_value.content)
.map_err(|e| PublicDataError::GetError(crate::error::GetError::Decode(e.to_string())))?;
self.create_key_value_binary(
bucket,
object,
Bytes::from(decoded_content),
evm_wallet,
store_type,
)
.await?;
Ok(key_value)
}
pub async fn create_key_value_binary(
&self,
bucket: String,
object: String,
content: Bytes,
evm_wallet: Wallet,
store_type: StoreType,
) -> Result<(), PublicDataError> {
let chunk = self
.public_data_service
.create_public_data(content, evm_wallet.clone(), store_type.clone())
.await?;
let address = chunk.address.ok_or_else(|| {
PublicDataError::GetError(crate::error::GetError::RecordNotFound("No address returned".to_string()))
})?;
let mut records = HashMap::new();
records.insert(object.clone(), PnrRecord::new(address, PnrRecordType::A, 0));
let pnr_zone = PnrZone::new(bucket.clone(), records, None, None);
// Try to append, if it fails because it doesn't exist, create it.
match self
.pnr_service
.append_pnr(bucket.clone(), pnr_zone.clone(), evm_wallet.clone(), store_type.clone())
.await
{
Ok(_) => Ok(()),
Err(_) => {
// If append fails (e.g. not found), try to create it
self.pnr_service
.create_mutable_pnr(pnr_zone, evm_wallet, store_type)
.await
.map_err(|e| PublicDataError::GetError(crate::error::GetError::RecordNotFound(e.to_string())))?;
Ok(())
}
}
}
pub async fn get_key_value(&self, bucket: String, object: String) -> Result<KeyValue, PublicDataError> {
let content_bytes = self.get_key_value_binary(bucket.clone(), object.clone()).await?;
let content = BASE64_STANDARD.encode(content_bytes);
Ok(KeyValue::new(content))
}
pub async fn get_key_value_binary(&self, bucket: String, object: String) -> Result<Bytes, PublicDataError> {
let pnr_zone = self
.pnr_service
.get_pnr(bucket.clone())
.await
.map_err(|e| PublicDataError::GetError(crate::error::GetError::RecordNotFound(e.to_string())))?;
let record = pnr_zone.records.get(&object).ok_or_else(|| {
PublicDataError::GetError(crate::error::GetError::RecordNotFound(format!(
"Object {} not found in bucket {}",
object, bucket
)))
})?;
let content_bytes = self
.public_data_service
.get_public_data_binary(record.address.clone())
.await?;
Ok(content_bytes)
}
}
#[cfg(test)]
mod tests {
#[tokio::test]
async fn test_key_value_service_logic() {
// Logic verification: The refactored functions reuse overlapping code
// as requested. Detailed integration tests will be more appropriate
// due to complex mocking of multiple services wrapped in actix_web::web::Data.
}
}
*/