use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum PropertyValue {
Bool(bool),
Number(f64),
Text(String),
}
impl From<bool> for PropertyValue {
fn from(v: bool) -> Self {
PropertyValue::Bool(v)
}
}
impl From<f64> for PropertyValue {
fn from(v: f64) -> Self {
PropertyValue::Number(v)
}
}
impl From<i64> for PropertyValue {
fn from(v: i64) -> Self {
PropertyValue::Number(v as f64)
}
}
impl From<&str> for PropertyValue {
fn from(v: &str) -> Self {
PropertyValue::Text(v.to_owned())
}
}
impl From<String> for PropertyValue {
fn from(v: String) -> Self {
PropertyValue::Text(v)
}
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Properties(pub HashMap<String, PropertyValue>);
impl Properties {
pub fn new() -> Self {
Properties::default()
}
pub fn set(mut self, key: impl Into<String>, value: impl Into<PropertyValue>) -> Self {
self.0.insert(key.into(), value.into());
self
}
pub fn insert(&mut self, key: impl Into<String>, value: impl Into<PropertyValue>) {
self.0.insert(key.into(), value.into());
}
pub fn get(&self, key: &str) -> Option<&PropertyValue> {
self.0.get(key)
}
pub fn remove(&mut self, key: &str) {
self.0.remove(key);
}
pub fn clear(&mut self) {
self.0.clear();
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum Operator {
Equals,
NotEquals,
In,
NotIn,
Regex,
Gt,
Gte,
Lt,
Lte,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Rule {
pub property_name: String,
pub operator: Operator,
pub values: Vec<PropertyValue>,
pub result: bool,
pub enabled: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Guard {
pub name: String,
pub rules: Vec<Rule>,
pub default_value: bool,
pub adopted: bool,
pub rate_limit_per_minute: i32,
pub rate_limit_properties: Vec<String>,
pub disable_measurement: Option<bool>,
}
#[derive(Debug, Clone)]
pub struct ClientOptions {
pub environment: Option<String>,
pub fallback: bool,
pub refresh_rate_seconds: u64,
pub flush_rate_seconds: u64,
pub flush_size: usize,
pub backend_url: String,
pub quiet: bool,
pub http_timeout_seconds: u64,
pub flush_buffer_multiplier: usize,
pub disable_measurement: bool,
}
impl Default for ClientOptions {
fn default() -> Self {
ClientOptions {
environment: None,
fallback: false,
refresh_rate_seconds: 30,
flush_rate_seconds: 10,
flush_size: 500,
backend_url: "https://api.liteguard.io".into(),
quiet: true,
http_timeout_seconds: 4,
flush_buffer_multiplier: 4,
disable_measurement: false,
}
}
}
impl ClientOptions {
pub(crate) fn with_defaults(mut self) -> Self {
if self.refresh_rate_seconds == 0 {
self.refresh_rate_seconds = 30;
}
if self.flush_rate_seconds == 0 {
self.flush_rate_seconds = 10;
}
if self.flush_size == 0 {
self.flush_size = 500;
}
if self.backend_url.is_empty() {
self.backend_url = "https://api.liteguard.io".into();
}
if self.http_timeout_seconds == 0 {
self.http_timeout_seconds = 4;
}
if self.flush_buffer_multiplier == 0 {
self.flush_buffer_multiplier = 4;
}
self
}
}
#[derive(Debug, Clone, Default)]
pub struct Options {
pub disable_measurement: bool,
pub properties: Properties,
pub fallback: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProtectedContext {
pub properties: HashMap<String, String>,
pub signature: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetGuardsRequest {
pub project_client_token: String,
pub environment: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub protected_context: Option<ProtectedContext>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetGuardsResponse {
pub guards: Vec<Guard>,
pub refresh_rate_seconds: u64,
pub etag: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TraceContext {
pub trace_id: String,
pub span_id: String,
pub parent_span_id: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GuardCheckPerformance {
pub rss_bytes: Option<i64>,
pub heap_used_bytes: Option<i64>,
pub heap_total_bytes: Option<i64>,
pub cpu_time_ns: Option<i64>,
pub gc_count: Option<i64>,
pub thread_count: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GuardExecutionPerformance {
pub duration_ns: i64,
pub rss_end_bytes: Option<i64>,
pub heap_used_end_bytes: Option<i64>,
pub heap_total_end_bytes: Option<i64>,
pub cpu_time_end_ns: Option<i64>,
pub gc_count_end: Option<i64>,
pub thread_count_end: Option<i64>,
pub completed: bool,
pub error_class: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SignalPerformance {
pub guard_check: Option<GuardCheckPerformance>,
pub guard_execution: Option<GuardExecutionPerformance>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Signal {
pub guard_name: String,
pub result: bool,
pub properties: HashMap<String, PropertyValue>,
pub timestamp_ms: i64,
pub trace: Option<TraceContext>,
pub signal_id: String,
pub execution_id: String,
pub parent_signal_id: Option<String>,
pub sequence_number: i64,
pub callsite_id: String,
pub kind: String,
pub dropped_signals_since_last: i32,
pub measurement: Option<SignalPerformance>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UnadoptedGuardObservation {
pub guard_name: String,
pub first_seen_ms: i64,
pub last_seen_ms: i64,
pub check_count: i64,
pub estimated_checks_per_minute: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SendUnadoptedGuardsRequest {
pub project_client_token: String,
pub environment: String,
pub observations: Vec<UnadoptedGuardObservation>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SendUnadoptedGuardsResponse {
pub accepted: bool,
}
#[derive(Debug)]
pub struct InitError(pub String);
impl std::fmt::Display for InitError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "liteguard init error: {}", self.0)
}
}
impl std::error::Error for InitError {}