From e083420c5cb0c2d5ba078b34e3c4ce01b9b9ce57 Mon Sep 17 00:00:00 2001 From: b1ek Date: Tue, 22 Oct 2024 12:56:35 +1000 Subject: [PATCH] add session boilerplate --- src/api.rs | 8 ++-- src/main.rs | 1 + src/session.rs | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 src/session.rs diff --git a/src/api.rs b/src/api.rs index 2fe680b..b3c61fa 100644 --- a/src/api.rs +++ b/src/api.rs @@ -9,19 +9,19 @@ use crate::{cache::Cache, config::Config}; use crate::{WARN, RED, RESET}; #[derive(Debug, Clone, Serialize, Deserialize)] -struct ChatMessagePayload { +pub struct ChatMessagePayload { pub role: String, pub content: String, } #[derive(Debug, Clone, Serialize, Deserialize)] -struct ChatPayload { +pub struct ChatPayload { pub model: String, pub messages: Vec } #[derive(Debug, Clone, Serialize, Deserialize)] -struct ChatChunk { +pub struct ChatChunk { pub role: Option, pub message: String, pub created: u64, @@ -31,7 +31,7 @@ struct ChatChunk { } #[derive(Debug, Clone, Serialize, Deserialize)] -struct ErrChatChunk { +pub struct ErrChatChunk { pub action: String, pub status: u64, #[serde(rename = "type")] diff --git a/src/main.rs b/src/main.rs index 38f9b81..78a265a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use crate::api::{get_res, get_vqd, simulate_browser_reqs}; mod cache; mod config; mod api; +mod session; pub const GREEN: &str = "\x1b[1;32m"; pub const RED: &str = "\x1b[1;31m"; diff --git a/src/session.rs b/src/session.rs new file mode 100644 index 0000000..b4a25cc --- /dev/null +++ b/src/session.rs @@ -0,0 +1,114 @@ +use std::fs; +use std::path::PathBuf; +use std::process::{Command, Stdio}; +use std::time::Duration; + +use chrono::{DateTime, Local}; +use serde::{Deserialize, Serialize}; + +use crate::api::ChatMessagePayload; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Session { + session_id: String, + ttl: DateTime, + messages: Vec +} + +impl Session { + pub fn terminal_session_id>() -> T { + #[cfg(unix)] + fn inner() -> Result> { + let child = Command::new("tty") + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .spawn()?; + + let child = child.wait_with_output()?; + if ! child.status.success() { + Err("")? // value ignored + } + + Ok(String::from_utf8(child.stdout)?) + } + + #[cfg(not(unix))] + fn inner() -> Result { + Err(()) + } + + inner() + .unwrap_or("default".into()) + .replace(['/', '\\', ':'], "-") + .trim() + .trim_start_matches('-') + .to_string() + .into() + } + + fn path_for_id>(id: T) -> PathBuf { + let id: String = id.into(); + std::env::temp_dir().join(format!("hey-duck-session-{id}")) + } + + fn path(&self) -> PathBuf { + Self::path_for_id(&self.session_id) + } + + fn restore_with_id>(id: T) -> Option { + fn inner(path: PathBuf) -> Result> { + if path.is_file() { + let data = fs::read_to_string(path)?; + Ok(serde_json::from_str(&data)?) + } else { + Err("")? // value ignored + } + } + + match inner(Self::path_for_id(id)) { + Ok(session) => { + if session.is_expired() { + session.destroy().expect("Couldn't destroy expired session"); + None + } else { + Some(session) + } + }, + Err(_) => None + } + } + + fn new>(id: T) -> Self { + Self { + session_id: id.into(), + ttl: Local::now() + Duration::from_secs(60 * 5), + messages: vec![] + } + } + + fn save(&self) -> Result<(), Box> { + println!("{:?}", self.path()); + fs::write(self.path(), serde_json::to_string_pretty(self)?)?; + Ok(()) + } + + fn is_expired(&self) -> bool { + self.ttl < Local::now() + } + + pub fn destroy(&self) -> Result<(), Box> { + Ok(fs::remove_file(self.path())?) + } + + pub fn create_or_restore() -> Self { + let session_id: String = Self::terminal_session_id(); + match Self::restore_with_id(&session_id) { + Some(session) => session, + None => { + let session = Self::new(&session_id); + session.save().expect("Couldn't save new session"); + session + } + } + } +} \ No newline at end of file