use pdk_core::logger;
use base64::{DecodeError, Engine};
use std::collections::HashMap;
use std::convert::TryFrom;
use serde::{Deserialize, Serialize};
const MAX_TTL_SECONDS: u32 = 2592000;
#[derive(PartialEq, Eq, Debug)]
pub enum StoreMode {
Always,
Absent,
Cas(String),
}
#[allow(dead_code)]
#[doc(hidden)]
#[derive(Deserialize, Debug)]
pub struct Keys {
pub values: Vec<Key>,
next_page_token: Option<String>,
}
#[allow(dead_code)]
#[doc(hidden)]
#[derive(Deserialize, Debug)]
pub struct Key {
#[serde(rename = "keyId")]
pub key_id: String,
}
#[allow(dead_code)]
#[doc(hidden)]
#[derive(Deserialize, Debug)]
pub struct Partitions {
pub values: Vec<String>,
next_page_token: Option<String>,
}
#[allow(dead_code)]
#[doc(hidden)]
#[derive(Deserialize, Debug)]
pub struct Stores {
pub values: Vec<Store>,
next_page_token: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Store {
#[serde(rename = "storeId")]
store_id: String,
#[serde(rename = "defaultTtlSeconds")]
default_ttl_seconds: u32,
#[serde(rename = "maximumEntries")]
#[serde(skip_serializing_if = "Option::is_none")]
max_entries: Option<u32>,
}
#[allow(dead_code)]
impl Store {
pub fn new(store_id: String, ttl_millis: Option<u32>, max_entries: Option<u32>) -> Self {
Self {
store_id,
default_ttl_seconds: convert_to_seconds(ttl_millis),
max_entries,
}
}
pub fn store_id(&self) -> &str {
self.store_id.as_str()
}
pub fn default_ttl_seconds(&self) -> u32 {
self.default_ttl_seconds
}
pub fn max_entries(&self) -> Option<u32> {
self.max_entries
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
enum Types {
Number,
Binary,
String,
}
#[derive(Serialize, Deserialize, Debug)]
#[doc(hidden)]
pub struct Object {
#[serde(rename = "keyId", skip_serializing_if = "Option::is_none")]
key_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
index: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
metadata: Option<HashMap<String, String>>,
#[serde(rename = "valueType")]
value_type: Types,
#[serde(rename = "stringValue", skip_serializing_if = "Option::is_none")]
string_value: Option<String>,
#[serde(rename = "numberValue", skip_serializing_if = "Option::is_none")]
number_value: Option<u64>,
#[serde(rename = "binaryValue", skip_serializing_if = "Option::is_none")]
binary_value: Option<String>,
}
impl TryFrom<&[u8]> for Object {
type Error = serde_json::Error;
fn try_from(value: &[u8]) -> serde_json::Result<Self> {
serde_json::from_slice(value)
}
}
impl Object {
pub fn new_binary(value: &[u8]) -> Self {
let result = base64::engine::general_purpose::STANDARD.encode(value);
Self {
key_id: None,
index: None,
metadata: None,
value_type: Types::Binary,
string_value: None,
number_value: None,
binary_value: Some(result),
}
}
pub fn get_binary(&self) -> Result<Vec<u8>, DecodeError> {
self.binary_value
.as_ref()
.map(|binary| base64::engine::general_purpose::STANDARD.decode(binary))
.unwrap_or(Ok(vec![]))
}
}
fn convert_to_seconds(ttl_millis: Option<u32>) -> u32 {
let mut ttl_seconds = ttl_millis.map_or(MAX_TTL_SECONDS, |m| m / 1000);
if ttl_seconds > MAX_TTL_SECONDS {
logger::warn!("TTL is greater than the maximum allowed value of {MAX_TTL_SECONDS} seconds. Setting TTL to default max value: {MAX_TTL_SECONDS} seconds.");
ttl_seconds = MAX_TTL_SECONDS;
}
ttl_seconds
}
#[cfg(test)]
mod tests {
use super::{convert_to_seconds, MAX_TTL_SECONDS};
#[test]
fn test_convert_to_seconds_normal_ttl_millis() {
let result = convert_to_seconds(Some(60000));
assert_eq!(result, 60);
}
#[test]
fn test_convert_to_seconds_large_ttl_sets_max_ttl_value() {
let large_ttl_millis = (MAX_TTL_SECONDS + 1) * 1000;
let result = convert_to_seconds(Some(large_ttl_millis));
assert_eq!(result, MAX_TTL_SECONDS);
}
#[test]
fn test_convert_to_seconds_none_sets_max_ttl_value() {
let result = convert_to_seconds(None);
assert_eq!(result, MAX_TTL_SECONDS);
}
}