Skip to content

Commit 8fb5f5c

Browse files
committed
Add VSS Http thin client implementation for get/put/listKeyVersions api's
1 parent 0715f27 commit 8fb5f5c

File tree

3 files changed

+172
-0
lines changed

3 files changed

+172
-0
lines changed

vss-accessor/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ edition = "2021"
55
build = "build.rs"
66

77
[dependencies]
8+
prost = "0.11.3"
9+
reqwest = { version = "0.11.13", features = ["rustls-tls"] }
810

911
[dev-dependencies]
1012

vss-accessor/src/lib.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use ::prost::Message;
2+
use reqwest;
3+
use reqwest::Client;
4+
use std::error::Error;
5+
6+
use crate::vss::{
7+
GetObjectRequest, GetObjectResponse, KeyValue, ListKeyVersionsRequest, ListKeyVersionsResponse, PutObjectRequest,
8+
PutObjectResponse,
9+
};
10+
use crate::vss_error::VssError;
11+
12+
mod vss_error;
13+
14+
pub mod vss {
15+
include!(concat!(env!("OUT_DIR"), "/org.vss.rs"));
16+
}
17+
18+
pub struct VssAccessor {
19+
base_url: String,
20+
client: Client,
21+
}
22+
23+
impl VssAccessor {
24+
pub fn new(base_url: &str) -> Result<Self, Box<dyn Error>> {
25+
let client = Client::new();
26+
Ok(Self { base_url: String::from(base_url), client })
27+
}
28+
29+
pub async fn get(&self, store: String, key: String) -> Result<GetObjectResponse, VssError> {
30+
let url = format!("{}/getObject", self.base_url);
31+
32+
let request = GetObjectRequest { store_id: store, key };
33+
34+
let response_raw = self.client.post(url).body(request.encode_to_vec()).send().await?;
35+
let status = response_raw.status();
36+
let payload = response_raw.bytes().await?;
37+
38+
if status.is_success() {
39+
let response = GetObjectResponse::decode(&payload[..])?;
40+
Ok(response)
41+
} else {
42+
Err(VssError::new(status, payload))
43+
}
44+
}
45+
46+
pub async fn put(
47+
&self, store: String, global_version: Option<i64>, key: String, version: i64, value: &[u8],
48+
) -> Result<PutObjectResponse, VssError> {
49+
let kv = KeyValue { key: String::from(key), version, value: value.to_vec() };
50+
return self.put_tx(store, global_version, vec![kv]).await;
51+
}
52+
53+
pub async fn put_tx(
54+
&self, store: String, global_version: Option<i64>, transaction_items: Vec<KeyValue>,
55+
) -> Result<PutObjectResponse, VssError> {
56+
let url = format!("{}/putObjects", self.base_url);
57+
58+
let request = PutObjectRequest { store_id: store, global_version, transaction_items };
59+
60+
let response_raw = self.client.post(url).body(request.encode_to_vec()).send().await?;
61+
let status = response_raw.status();
62+
let payload = response_raw.bytes().await?;
63+
64+
if status.is_success() {
65+
let response = PutObjectResponse::decode(&payload[..])?;
66+
Ok(response)
67+
} else {
68+
Err(VssError::new(status, payload))
69+
}
70+
}
71+
72+
pub async fn list_key_versions(
73+
&self, store: String, key_prefix: String, page_size: Option<i32>, page_token: Option<String>,
74+
) -> Result<ListKeyVersionsResponse, VssError> {
75+
let url = format!("{}/listKeyVersions", self.base_url);
76+
77+
let request = ListKeyVersionsRequest {
78+
store_id: store,
79+
key_prefix: Some(key_prefix),
80+
page_size,
81+
page_token,
82+
};
83+
84+
let response_raw = self.client.post(url).body(request.encode_to_vec()).send().await?;
85+
let status = response_raw.status();
86+
let payload = response_raw.bytes().await?;
87+
88+
if status.is_success() {
89+
let response = ListKeyVersionsResponse::decode(&payload[..])?;
90+
Ok(response)
91+
} else {
92+
Err(VssError::new(status, payload))
93+
}
94+
}
95+
}

vss-accessor/src/vss_error.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use crate::vss::{ErrorCode, ErrorResponse};
2+
use prost::bytes::Bytes;
3+
use prost::{DecodeError, Message};
4+
use reqwest::StatusCode;
5+
use std::error::Error;
6+
use std::fmt::{Display, Formatter};
7+
8+
#[derive(Debug)]
9+
pub enum VssError {
10+
InvalidRequestError(ErrorResponse),
11+
ConflictError(ErrorResponse),
12+
InternalServerError(ErrorResponse),
13+
InternalError(String),
14+
}
15+
16+
impl VssError {
17+
pub fn new(status: StatusCode, payload: Bytes) -> VssError {
18+
match ErrorResponse::decode(&payload[..]) {
19+
Ok(error_response) => VssError::from(error_response),
20+
Err(e) => {
21+
let message =
22+
format!("Unable to decode ErrorResponse from server, HttpStatusCode: {}, DecodeErr: {}", status, e);
23+
VssError::InternalError(message)
24+
}
25+
}
26+
}
27+
}
28+
29+
impl Display for VssError {
30+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
31+
match self {
32+
VssError::InvalidRequestError(error_response) => {
33+
write!(f, "Request sent to VSS Server was invalid : {}", error_response.message)
34+
}
35+
VssError::ConflictError(error_response) => {
36+
write!(f, "Potential version conflict in write operation : {}", error_response.message)
37+
}
38+
VssError::InternalServerError(error_response) => {
39+
write!(f, "InternalServerError : {}", error_response.message)
40+
}
41+
VssError::InternalError(message) => {
42+
write!(f, "InternalError : {}", message)
43+
}
44+
}
45+
}
46+
}
47+
48+
impl Error for VssError {}
49+
50+
impl From<ErrorResponse> for VssError {
51+
fn from(error_response: ErrorResponse) -> Self {
52+
return match error_response.error_code() {
53+
ErrorCode::InvalidRequestException => VssError::InvalidRequestError(error_response),
54+
ErrorCode::ConflictException => VssError::ConflictError(error_response),
55+
ErrorCode::InternalServerException => VssError::InternalServerError(error_response),
56+
_ => VssError::InternalError(format!(
57+
"Server responded with an unknown error code: {}, \
58+
message: {}",
59+
error_response.error_code, error_response.message
60+
)),
61+
};
62+
}
63+
}
64+
65+
impl From<DecodeError> for VssError {
66+
fn from(err: DecodeError) -> Self {
67+
VssError::InternalError(err.to_string())
68+
}
69+
}
70+
71+
impl From<reqwest::Error> for VssError {
72+
fn from(err: reqwest::Error) -> Self {
73+
VssError::InternalError(err.to_string())
74+
}
75+
}

0 commit comments

Comments
 (0)