use std::fmt;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SessionId(String);
impl SessionId {
pub fn new() -> Self {
use rand::Rng;
let nonce: u64 = rand::rng().random();
Self(format!(
"session-{:x}-{:x}",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos(),
nonce
))
}
pub fn from_raw(raw: impl Into<String>) -> Self {
Self(raw.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for SessionId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl FromStr for SessionId {
type Err = std::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(s.to_string()))
}
}
impl Default for SessionId {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum SessionStatus {
#[default]
Created,
Active,
Idle,
Compacting,
Failed(String),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SessionMetadata {
pub id: SessionId,
pub title: String,
pub model: String,
pub status: SessionStatus,
pub turn_count: usize,
pub created_at: u64,
pub updated_at: u64,
}
impl SessionMetadata {
pub fn new(id: SessionId, title: impl Into<String>, model: impl Into<String>) -> Self {
let now = unix_now();
Self {
id,
title: title.into(),
model: model.into(),
status: SessionStatus::Created,
turn_count: 0,
created_at: now,
updated_at: now,
}
}
}
fn unix_now() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs()
}