Skip to content

Commit

Permalink
Add Vss thin client protobuf generation & build setup
Browse files Browse the repository at this point in the history
  • Loading branch information
G8XSU committed Apr 13, 2023
1 parent 3494efa commit 7b9e187
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[workspace]
members = [
"vss-accessor",
]
16 changes: 16 additions & 0 deletions vss-accessor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "vss-accessor"
version = "0.1.0"
edition = "2021"
build = "build.rs"

[dependencies]
prost = "0.11.3"
reqwest = "0.11.13"

[dev-dependencies]
mockito = "0.31.1"
tokio = { version = "1.22.0"}

[build-dependencies]
prost-build = { version = "0.11.3" }
6 changes: 6 additions & 0 deletions vss-accessor/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extern crate prost_build;

fn main() {
prost_build::compile_protos(&["src/proto/vss.proto"],
&["src/"]).unwrap();
}
226 changes: 226 additions & 0 deletions vss-accessor/src/proto/vss.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
syntax = "proto3";
option java_multiple_files = true;
package org.vss;

message GetObjectRequest {

// store_id is a keyspace identifier.
// Ref: https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store)
// All APIs operate within a single store_id.
// It is up to clients to use single or multiple stores for their use-case.
// This can be used for client-isolation/ rate-limiting / throttling on the server-side.
// Authorization and billing can also be performed at the store_id level.
string store_id = 1;

// Key for which the value is to be fetched.
//
// Consistency Guarantee:
// Get(read) operations against a key are consistent reads and will reflect all previous writes,
// since Put/Write provides read-after-write and read-after-update consistency guarantees.
//
// Read Isolation:
// Get/Read operations against a key are ensured to have read-committed isolation.
// Ref: https://en.wikipedia.org/wiki/Isolation_(database_systems)#Read_committed
string key = 2;
}

message GetObjectResponse {

// Fetched value and version along with the corresponding key in the request.
KeyValue value = 2;
}

message PutObjectRequest {

// store_id is a keyspace identifier.
// Ref: https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store)
// All APIs operate within a single store_id.
// It is up to clients to use single or multiple stores for their use-case.
// This can be used for client-isolation/ rate-limiting / throttling on the server-side.
// Authorization and billing can also be performed at the store_id level.
string store_id = 1;

// global_version is a sequence-number/version of the whole store. This can be used for versioning
// and ensures that multiple updates in case of multiple devices can only be done linearly, even
// if those updates did not directly conflict with each other based on keys/transaction_items.
//
// If present, the write will only succeed if the current server-side global_version against
// the store_id is same as in the request.
// Clients are expected to store (client-side) the global version against store_id.
// The request must contain their client-side value of global_version if global versioning and
// conflict detection is desired.
//
// For the first write of the store, global version should be '0'. If the write succeeds, clients
// must increment their global version (client-side) by 1.
// The server increments global_version (server-side) for every successful write, hence this
// client-side increment is required to ensure matching versions. This updated global version
// should be used in subsequent PutObjectRequests for the store.
//
// Requests with a conflicting version will fail with `CONFLICT_EXCEPTION` as ErrorCode.
optional int64 global_version = 2;

// Items to be written as a result of this PutObjectRequest.
//
// In an item, each key is supplied with its corresponding value and version.
// Clients can choose to encrypt the keys client-side in order to obfuscate their usage patterns.
// If the write is successful, the previous value corresponding to the key will be overwritten.
//
// Multiple items in transaction_items of a single PutObjectRequest are written in
// a database-transaction in an all-or-nothing fashion.
// Items in a single PutObjectRequest must have distinct keys.
//
// Clients are expected to store a version against every key.
// The write will succeed if the current DB version against the key is the same as in the request.
// When initiating a PutObjectRequest, the request should contain their client-side version for
// that key-value.
//
// For the first write of any key, the version should be '0'. If the write succeeds, the client
// must increment their corresponding key versions (client-side) by 1.
// The server increments key versions (server-side) for every successful write, hence this
// client-side increment is required to ensure matching versions. These updated key versions should
// be used in subsequent PutObjectRequests for the keys.
//
// Requests with a conflicting version will fail with `CONFLICT_EXCEPTION` as ErrorCode.
//
// Considerations for transactions:
// Transaction writes of multiple items have a performance overhead, hence it is recommended to use
// them only if required by the client application to ensure logic/code correctness.
// That is, transaction_items are not a substitute for batch-write of multiple unrelated items.
// When a write of multiple unrelated items is desired, it is recommended to use separate
// PutObjectRequests.
//
// Consistency guarantee:
// All PutObjectRequests are strongly consistent i.e. they provide read-after-write and
// read-after-update consistency guarantees.
repeated KeyValue transaction_items = 3;
}

message PutObjectResponse {
}

message ListKeyVersionsRequest {

// store_id is a keyspace identifier.
// Ref: https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store)
// All APIs operate within a single store_id.
// It is up to clients to use single or multiple stores for their use-case.
// This can be used for client-isolation/ rate-limiting / throttling on the server-side.
// Authorization and billing can also be performed at the store_id level.
string store_id = 1;

// A key_prefix is a string of characters at the beginning of the key. Prefixes can be used as
// a way to organize key-values in a similar way to directories.
//
// If key_prefix is specified, the response results will be limited to those keys that begin with
// the specified prefix.
//
// If no key_prefix is specified or it is empty (""), all the keys are eligible to be returned in
// the response.
optional string key_prefix = 2;

// page_size is used by clients to specify the maximum number of results that can be returned by
// the server.
// The server may further constrain the maximum number of results returned in a single page.
// If the page_size is 0 or not set, the server will decide the number of results to be returned.
optional int32 page_size = 3;

// page_token is a pagination token.
//
// To query for the first page of ListKeyVersions, page_token must not be specified.
//
// For subsequent pages, use the value that was returned as `next_page_token` in the previous
// page's ListKeyVersionsResponse.
optional string page_token = 4;
}

message ListKeyVersionsResponse {

// Fetched keys and versions.
// Even though this API reuses KeyValue struct, the value sub-field will not be set by the server.
repeated KeyValue key_versions = 1;

// next_page_token is a pagination token, used to retrieve the next page of results.
// Use this value to query for next_page of paginated ListKeyVersions operation, by specifying
// this value as the `page_token` in the next request.
//
// If next_page_token is empty (""), then the "last page" of results has been processed and
// there is no more data to be retrieved.
//
// If next_page_token is not empty, it does not necessarily mean that there is more data in the
// result set. The only way to know when you have reached the end of the result set is when
// next_page_token is empty.
//
// Caution: Clients must not assume a specific number of key_versions to be present in a page for
// paginated response.
optional string next_page_token = 2;

// global_version is a sequence-number/version of the whole store.
//
// global_version is only returned in response for the first page of the ListKeyVersionsResponse
// and is guaranteed to be read before reading any key-versions.
//
// In case of refreshing the complete key-version view on the client-side, correct usage for
// the returned global_version is as following:
// 1. Read global_version from the first page of paginated response and save it as local variable.
// 2. Update all the key_versions on client-side from all the pages of paginated response.
// 3. Update global_version on client_side from the local variable saved in step-1.
// This ensures that on client-side, all current key_versions were stored at global_version or later.
// This guarantee is helpful for ensuring the versioning correctness if using the global_version
// in PutObject API and can help avoid the race conditions related to it.
optional int64 global_version = 3;
}

// When HttpStatusCode is not ok (200), the response `content` contains a serialized ErrorResponse
// with the relevant ErrorCode and message
message ErrorResponse {

// The error code uniquely identifying an error condition.
// It is meant to be read and understood programmatically by code that detects/handles errors by
// type.
ErrorCode error_code = 1;

// The error message containing a generic description of the error condition in English.
// It is intended for a human audience only and should not be parsed to extract any information
// programmatically. Client-side code may use it for logging only.
string message = 2;
}

// ErrorCodes to be used in ErrorResponse
enum ErrorCode {

// Default protobuf Enum value. Will not be used as ErrorCode by server.
UNKNOWN = 0;

// CONFLICT_EXCEPTION is used when the request contains mismatched version (either key or global)
// in PutObjectRequest. For more info refer PutObjectRequest.
CONFLICT_EXCEPTION= 1;

// INVALID_REQUEST_EXCEPTION is used in the following cases:
// - The request was missing a required argument.
// - The specified argument was invalid, incomplete or in the wrong format.
// - The request body of api cannot be deserialized into corresponding protobuf object.
INVALID_REQUEST_EXCEPTION = 2;

// An internal server error occurred, client is probably at no fault and can safely retry this
// error with exponential backoff.
INTERNAL_SERVER_EXCEPTION = 3;
}

message KeyValue {

// Key against which the value is stored.
string key = 1;

// Version field is used for key-level versioning.
// For first write of key, version should be '0'. If the write succeeds, clients must increment
// their corresponding key version (client-side) by 1.
// The server increments key version (server-side) for every successful write, hence this
// client-side increment is required to ensure matching versions. These updated key versions should
// be used in subsequent PutObjectRequests for the keys.
int64 version = 2;

// Object value in bytes which is stored (in put) and fetched (in get).
// Clients must encrypt this blob client-side before sending it over the wire to server in order
// to preserve privacy and security.
bytes value = 3;
}

0 comments on commit 7b9e187

Please sign in to comment.