1use std::collections::HashMap;
2use std::future::Future;
3use std::num::NonZeroU32;
4use std::pin::Pin;
5use std::sync::Arc;
6
7use serde_json::Value;
8use uuid::Uuid;
9
10use crate::Provider;
11
12#[derive(Clone)]
13pub struct Storages {
14 pub transit: Arc<dyn TransitStorage>,
15}
16
17pub trait TransitStorage: Send + Sync {
18 fn store_identities(
19 &self,
20 declarations: Vec<IdentityDeclaration>,
21 ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send + '_>>;
22
23 fn store_usages(
24 &self,
25 declarations: Vec<UsageDeclaration>,
26 ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send + '_>>;
27
28 fn list_transits(
29 &self,
30 query: TransitQuery,
31 ) -> Pin<Box<dyn Future<Output = anyhow::Result<TransitPage>> + Send + '_>>;
32
33 fn get_transits(
34 &self,
35 transit_ids: Vec<Uuid>,
36 ) -> Pin<Box<dyn Future<Output = anyhow::Result<Vec<TransitRecord>>> + Send + '_>>;
37
38 fn list_unsent(
39 &self,
40 limit: u32,
41 ) -> Pin<Box<dyn Future<Output = anyhow::Result<Vec<TransitRecord>>> + Send + '_>>;
42
43 fn mark_sent(
44 &self,
45 transit_ids: Vec<Uuid>,
46 ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send + '_>>;
47}
48
49pub struct IdentityDeclaration {
50 pub transit_id: Uuid,
51 pub provider: Provider,
52 pub header_id: Option<String>,
53 pub body_id: Option<String>,
54 pub vh_headers: Option<HashMap<String, String>>,
55}
56
57pub struct UsageDeclaration {
58 pub transit_id: Uuid,
59 pub provider: Provider,
60 pub model: Option<String>,
61 pub usage: Value,
62}
63
64pub struct TransitRecord {
65 pub transit_id: Uuid,
66 pub stored_at: chrono::DateTime<chrono::Utc>,
67 pub provider: Provider,
68 pub header_id: Option<String>, pub body_id: Option<String>, pub vh_headers: Option<HashMap<String, String>>, pub model: Option<String>,
72 pub usage: Option<Value>,
73 pub estimated_cost_usd: Option<f64>,
74}
75
76impl TransitRecord {
77 pub fn estimate_cost(&self) -> Option<f64> {
78 if let Some(cost) = self.estimated_cost_usd {
79 return Some(cost);
80 }
81 let model = self.model.as_deref()?;
82 let usage = self.usage.as_ref()?;
83 crate::cost::estimate_cost(self.provider, model, usage)
84 }
85}
86
87pub struct TransitQuery {
88 pub cursor: Option<chrono::DateTime<chrono::Utc>>,
89 pub direction: Direction,
90 pub limit: NonZeroU32,
91}
92
93pub enum Direction {
94 After, Before, }
97
98pub struct TransitPage {
99 pub records: Vec<TransitRecord>,
100 pub has_more: bool,
101}