veza/veza-common/src/traits.rs
senke 670282989b chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 19:39:18 +01:00

379 lines
12 KiB
Rust

//! Common traits for Veza Rust services
//!
//! This module defines shared traits that can be implemented by different
//! services to provide a consistent interface and enable easy testing.
use async_trait::async_trait;
use std::collections::HashMap;
use uuid::Uuid;
use crate::VezaResult;
/// Authentication provider trait
#[async_trait]
pub trait AuthProvider: Send + Sync {
/// Validate a JWT token
async fn validate_token(&self, token: &str) -> VezaResult<AuthClaims>;
/// Generate a new JWT token
async fn generate_token(&self, claims: &AuthClaims) -> VezaResult<String>;
/// Refresh a token
async fn refresh_token(&self, refresh_token: &str) -> VezaResult<AuthResult>;
/// Revoke a token
async fn revoke_token(&self, token: &str) -> VezaResult<()>;
/// Check if a user has permission for a resource
async fn check_permission(&self, user_id: Uuid, resource: &str, action: &str) -> VezaResult<bool>;
}
/// Message store trait for chat functionality
#[async_trait]
pub trait MessageStore: Send + Sync {
/// Store a message
async fn store_message(&self, message: &Message) -> VezaResult<()>;
/// Get messages for a conversation
async fn get_messages(&self, conversation_id: Uuid, limit: u32, offset: u32) -> VezaResult<Vec<Message>>;
/// Get a specific message
async fn get_message(&self, message_id: Uuid) -> VezaResult<Option<Message>>;
/// Update a message
async fn update_message(&self, message_id: Uuid, content: &str) -> VezaResult<()>;
/// Delete a message
async fn delete_message(&self, message_id: Uuid) -> VezaResult<()>;
/// Mark messages as read
async fn mark_as_read(&self, user_id: Uuid, conversation_id: Uuid, message_id: Uuid) -> VezaResult<()>;
/// Get unread count for a user
async fn get_unread_count(&self, user_id: Uuid) -> VezaResult<u32>;
}
/// Stream provider trait for audio streaming
#[async_trait]
pub trait StreamProvider: Send + Sync {
/// Get stream URL for a track
async fn get_stream_url(&self, track_id: Uuid, user_id: Uuid) -> VezaResult<String>;
/// Validate stream access
async fn validate_access(&self, track_id: Uuid, user_id: Uuid) -> VezaResult<bool>;
/// Get track metadata
async fn get_track_metadata(&self, track_id: Uuid) -> VezaResult<TrackMetadata>;
/// Get audio chunk
async fn get_audio_chunk(&self, track_id: Uuid, chunk_index: u32) -> VezaResult<Vec<u8>>;
/// Get playlist
async fn get_playlist(&self, playlist_id: Uuid, user_id: Uuid) -> VezaResult<Playlist>;
/// Create playlist
async fn create_playlist(&self, user_id: Uuid, name: &str, tracks: Vec<Uuid>) -> VezaResult<Playlist>;
}
/// Cache provider trait
#[async_trait]
pub trait CacheProvider: Send + Sync {
/// Get a value from cache
async fn get<T>(&self, key: &str) -> VezaResult<Option<T>>
where
T: serde::de::DeserializeOwned;
/// Set a value in cache
async fn set<T>(&self, key: &str, value: &T, ttl: Option<u64>) -> VezaResult<()>
where
T: serde::Serialize;
/// Delete a value from cache
async fn delete(&self, key: &str) -> VezaResult<()>;
/// Check if a key exists
async fn exists(&self, key: &str) -> VezaResult<bool>;
/// Get multiple values
async fn get_many<T>(&self, keys: &[String]) -> VezaResult<HashMap<String, T>>
where
T: serde::de::DeserializeOwned;
/// Set multiple values
async fn set_many<T>(&self, values: HashMap<String, T>, ttl: Option<u64>) -> VezaResult<()>
where
T: serde::Serialize;
/// Clear cache
async fn clear(&self) -> VezaResult<()>;
/// Get cache statistics
async fn stats(&self) -> VezaResult<CacheStats>;
}
/// Database provider trait
#[async_trait]
pub trait DatabaseProvider: Send + Sync {
/// Execute a query
async fn execute(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<u64>;
/// Query a single row
async fn query_one<T>(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<Option<T>>
where
T: serde::de::DeserializeOwned;
/// Query multiple rows
async fn query_many<T>(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<Vec<T>>
where
T: serde::de::DeserializeOwned;
/// Begin a transaction
/// Note: This returns a type-erased transaction provider
/// Implementations should return their concrete transaction type
async fn begin_transaction(&self) -> VezaResult<()>;
/// Health check
async fn health_check(&self) -> VezaResult<()>;
}
/// Transaction provider trait
#[async_trait]
pub trait TransactionProvider: Send + Sync {
/// Execute a query in transaction
async fn execute(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<u64>;
/// Query a single row in transaction
async fn query_one<T>(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<Option<T>>
where
T: serde::de::DeserializeOwned;
/// Query multiple rows in transaction
async fn query_many<T>(&self, query: &str, params: &[serde_json::Value]) -> VezaResult<Vec<T>>
where
T: serde::de::DeserializeOwned;
/// Commit transaction
async fn commit(self: Box<Self>) -> VezaResult<()>;
/// Rollback transaction
async fn rollback(self: Box<Self>) -> VezaResult<()>;
}
/// Rate limiter trait
#[async_trait]
pub trait RateLimiter: Send + Sync {
/// Check if a request is allowed
async fn is_allowed(&self, key: &str, limit: u32, window: u64) -> VezaResult<bool>;
/// Get remaining requests
async fn get_remaining(&self, key: &str, limit: u32, window: u64) -> VezaResult<u32>;
/// Reset rate limit for a key
async fn reset(&self, key: &str) -> VezaResult<()>;
/// Get rate limit info
async fn get_info(&self, key: &str, limit: u32, window: u64) -> VezaResult<RateLimitInfo>;
}
/// Metrics provider trait
#[async_trait]
pub trait MetricsProvider: Send + Sync {
/// Increment a counter
async fn increment_counter(&self, name: &str, labels: &[(&str, &str)]) -> VezaResult<()>;
/// Increment a counter by a value
async fn increment_counter_by(&self, name: &str, value: f64, labels: &[(&str, &str)]) -> VezaResult<()>;
/// Set a gauge value
async fn set_gauge(&self, name: &str, value: f64, labels: &[(&str, &str)]) -> VezaResult<()>;
/// Observe a histogram value
async fn observe_histogram(&self, name: &str, value: f64, labels: &[(&str, &str)]) -> VezaResult<()>;
/// Observe a summary value
async fn observe_summary(&self, name: &str, value: f64, labels: &[(&str, &str)]) -> VezaResult<()>;
/// Get metrics as string
async fn get_metrics(&self) -> VezaResult<String>;
}
/// Logger trait
pub trait Logger: Send + Sync {
/// Log a trace message
fn trace(&self, message: &str, fields: &[(&str, String)]);
/// Log a debug message
fn debug(&self, message: &str, fields: &[(&str, String)]);
/// Log an info message
fn info(&self, message: &str, fields: &[(&str, String)]);
/// Log a warning message
fn warn(&self, message: &str, fields: &[(&str, String)]);
/// Log an error message
fn error(&self, message: &str, fields: &[(&str, String)]);
/// Create a child logger with additional fields
fn child(&self, fields: &[(&str, String)]) -> Box<dyn Logger>;
}
/// WebSocket handler trait
#[async_trait]
pub trait WebSocketHandler: Send + Sync {
/// Handle a new connection
async fn handle_connect(&self, user_id: Uuid, connection_id: Uuid) -> VezaResult<()>;
/// Handle a message
async fn handle_message(&self, user_id: Uuid, connection_id: Uuid, message: &str) -> VezaResult<()>;
/// Handle a disconnection
async fn handle_disconnect(&self, user_id: Uuid, connection_id: Uuid) -> VezaResult<()>;
/// Broadcast a message to all users in a conversation
async fn broadcast_to_conversation(&self, conversation_id: Uuid, message: &str, exclude_user: Option<Uuid>) -> VezaResult<()>;
/// Send a message to a specific user
async fn send_to_user(&self, user_id: Uuid, message: &str) -> VezaResult<()>;
}
/// File storage trait
#[async_trait]
pub trait FileStorage: Send + Sync {
/// Store a file
async fn store_file(&self, path: &str, content: &[u8]) -> VezaResult<String>;
/// Get a file
async fn get_file(&self, path: &str) -> VezaResult<Vec<u8>>;
/// Delete a file
async fn delete_file(&self, path: &str) -> VezaResult<()>;
/// Check if a file exists
async fn file_exists(&self, path: &str) -> VezaResult<bool>;
/// Get file metadata
async fn get_file_metadata(&self, path: &str) -> VezaResult<FileMetadata>;
/// List files in a directory
async fn list_files(&self, path: &str) -> VezaResult<Vec<String>>;
}
/// Notification service trait
#[async_trait]
pub trait NotificationService: Send + Sync {
/// Send a push notification
async fn send_push_notification(&self, user_id: Uuid, title: &str, body: &str, data: &HashMap<String, String>) -> VezaResult<()>;
/// Send an in-app notification
async fn send_in_app_notification(&self, user_id: Uuid, message: &str, data: &HashMap<String, serde_json::Value>) -> VezaResult<()>;
/// Send an email
async fn send_email(&self, to: &str, subject: &str, body: &str) -> VezaResult<()>;
/// Send an SMS
async fn send_sms(&self, to: &str, message: &str) -> VezaResult<()>;
}
/// Health check trait
#[async_trait]
pub trait HealthCheck: Send + Sync {
/// Check if the service is healthy
async fn is_healthy(&self) -> VezaResult<bool>;
/// Get detailed health information
async fn get_health_info(&self) -> VezaResult<HealthInfo>;
/// Get service name
fn service_name(&self) -> &str;
/// Get service version
fn service_version(&self) -> &str;
}
// Data types used by traits
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AuthClaims {
pub user_id: Uuid,
pub username: String,
pub email: String,
pub roles: Vec<String>,
pub exp: u64,
pub iat: u64,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AuthResult {
pub access_token: String,
pub refresh_token: String,
pub expires_in: u64,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Message {
pub id: Uuid,
pub conversation_id: Uuid,
pub user_id: Uuid,
pub content: String,
pub message_type: String,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TrackMetadata {
pub id: Uuid,
pub title: String,
pub artist: String,
pub album: String,
pub duration: u32,
pub file_size: u64,
pub format: String,
pub bitrate: u32,
pub sample_rate: u32,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Playlist {
pub id: Uuid,
pub name: String,
pub user_id: Uuid,
pub tracks: Vec<Uuid>,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct CacheStats {
pub hits: u64,
pub misses: u64,
pub keys: u64,
pub memory_usage: u64,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RateLimitInfo {
pub limit: u32,
pub remaining: u32,
pub reset_time: u64,
pub retry_after: Option<u64>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct FileMetadata {
pub path: String,
pub size: u64,
pub mime_type: String,
pub created_at: chrono::DateTime<chrono::Utc>,
pub modified_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct HealthInfo {
pub status: String,
pub version: String,
pub uptime: u64,
pub dependencies: HashMap<String, String>,
pub metrics: HashMap<String, serde_json::Value>,
}