VEN5WJYRT23IT77JAAZ5CJRSW3GUTTNMAECT3WVTHQA34HI4646AC [[package]]name = "bincode"version = "1.3.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"dependencies = ["byteorder","serde",][[package]]name = "bstr"version = "0.2.13"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931"dependencies = ["lazy_static","memchr","regex-automata","serde",][[package]]name = "byteorder"version = "1.3.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
name = "itoa"version = "0.4.6"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"[[package]]name = "lazy_static"version = "1.4.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"[[package]]
use crate::message::Message;use std::os::unix::net::UnixDatagram;use thiserror::Error;#[derive(Debug)]pub struct Client {}#[derive(Error, Debug)]pub enum Error {}pub fn new() -> Client {Client {}}impl Client {pub fn send(&self, message: Message) -> Result<(), Error> {let xdg_dirs = xdg::BaseDirectories::with_prefix("histdb-rs").unwrap();let socket_path = xdg_dirs.find_runtime_file("socket").unwrap();let socket = UnixDatagram::unbound().unwrap();socket.connect(socket_path).unwrap();socket.send(&bincode::serialize(&message).unwrap()).unwrap();Ok(())}}
#[derive(Error, Debug)]pub enum Error {#[error("can not get current directory: {0}")]GetCurrentDir(std::io::Error),#[error("can not get current user: {0}")]GetUser(env::VarError),#[error("invalid session id in environment variable: {0}")]InvalidSessionIDEnvVar(env::VarError),#[error("invalid session id: {0}")]InvalidSessionID(uuid::Error),#[error("session id is missing")]MissingSessionID,#[error("invalid result: {0}")]InvalidResult(std::num::ParseIntError),}
pub fn from_env() -> Result<Self, Error> {let command = env::args().into_iter().skip(2).next().unwrap_or_default();let pwd = env::current_dir().map_err(Error::GetCurrentDir)?;let time_start = Utc::now();let time_end = None;let user = env::var("USER").map_err(Error::GetUser)?;let result = env::var("HISTDB_RS_RETVAL").ok().map(|s| s.parse().map_err(Error::InvalidResult)).transpose()?;let session_id = match env::var("HISTDB_RS_SESSION_ID") {Err(err) => match err {env::VarError::NotPresent => Err(Error::MissingSessionID),_ => Err(Error::InvalidSessionIDEnvVar(err)),},Ok(s) => Uuid::parse_str(&s).map_err(Error::InvalidSessionID),}?;Ok(Self {command,pwd,result,session_id,time_end,time_start,user,})
pub fn from_messages(start: CommandStart, finish: CommandFinished) -> Self {Self {command: start.command,pwd: start.pwd,result: finish.result,session_id: start.session_id,time_finished: finish.time_stamp,time_start: start.time_stamp,user: start.user,}
eprintln!("zshaddhistory");let entry = Entry::from_env().unwrap();dbg!(&entry);let xdg_dirs = xdg::BaseDirectories::with_prefix("histdb-rs").unwrap();let socket_path = xdg_dirs.find_runtime_file("socket").unwrap();dbg!(&socket_path);
let data = CommandStart::from_env()?;client::new().send(Message::CommandStart(data))?;
use chrono::{DateTime,Utc,};use serde::{Deserialize,Serialize,};use std::{env,path::PathBuf,};use thiserror::Error;use uuid::Uuid;#[derive(Debug, Serialize, Deserialize)]pub enum Message {Stop,CommandStart(CommandStart),CommandFinished(CommandFinished),}#[derive(Error, Debug)]pub enum Error {#[error("can not get current directory: {0}")]GetCurrentDir(std::io::Error),#[error("can not get current user: {0}")]GetUser(env::VarError),#[error("invalid session id in environment variable: {0}")]InvalidSessionIDEnvVar(env::VarError),#[error("invalid session id: {0}")]InvalidSessionID(uuid::Error),#[error("session id is missing")]MissingSessionID,#[error("retval is missing")]MissingRetval(std::env::VarError),#[error("invalid result: {0}")]InvalidResult(std::num::ParseIntError),}#[derive(Debug, Serialize, Deserialize)]pub struct CommandStart {pub command: String,pub pwd: PathBuf,pub session_id: Uuid,pub time_stamp: DateTime<Utc>,pub user: String,}impl CommandStart {pub fn from_env() -> Result<Self, Error> {let command = env::args().into_iter().skip(2).next().unwrap_or_default();let pwd = env::current_dir().map_err(Error::GetCurrentDir)?;let time_stamp = Utc::now();let user = env::var("USER").map_err(Error::GetUser)?;let session_id = match env::var("HISTDB_RS_SESSION_ID") {Err(err) => match err {env::VarError::NotPresent => Err(Error::MissingSessionID),_ => Err(Error::InvalidSessionIDEnvVar(err)),},Ok(s) => Uuid::parse_str(&s).map_err(Error::InvalidSessionID),}?;Ok(Self {command,pwd,session_id,time_stamp,user,})}}#[derive(Debug, Serialize, Deserialize)]pub struct CommandFinished {pub session_id: Uuid,pub time_stamp: DateTime<Utc>,pub result: usize,}impl CommandFinished {pub fn from_env() -> Result<Self, Error> {let time_stamp = Utc::now();let session_id = match env::var("HISTDB_RS_SESSION_ID") {Err(err) => match err {env::VarError::NotPresent => Err(Error::MissingSessionID),_ => Err(Error::InvalidSessionIDEnvVar(err)),},Ok(s) => Uuid::parse_str(&s).map_err(Error::InvalidSessionID),}?;let result = env::var("HISTDB_RS_RETVAL").map_err(Error::MissingRetval)?.parse().map_err(Error::InvalidResult)?;Ok(Self {session_id,time_stamp,result,})}}
pub struct Server {}
#[error("server is stopping")]Stop,#[error("can not add to storeo: {0}")]AddStore(crate::store::Error),}impl Error {fn is_stop(&self) -> bool {match self {Self::Stop => true,_ => false,}}}pub struct Server {entries: HashMap<Uuid, CommandStart>,}
if let Err(err) = Self::receive(&socket) {eprintln!("{}", err)
match Self::receive(&socket) {Err(err) => eprintln!("{}", err),Ok(message) => {if let Err(err) = self.process(message) {if err.is_stop() {break;}eprintln!("error encountered: {}", err)}}
fn receive(socket: &UnixDatagram) -> Result<(), Error> {
fn process(&mut self, message: Message) -> Result<(), Error> {match message {Message::Stop => Err(Error::Stop),Message::CommandStart(data) => self.command_start(data),Message::CommandFinished(data) => self.command_finished(data),}}fn receive(socket: &UnixDatagram) -> Result<Message, Error> {
dbg!(String::from_utf8_lossy(&buffer[0..written]));
let message = bincode::deserialize(&buffer[0..written]).unwrap();Ok(message)}fn command_start(&mut self, start: CommandStart) -> Result<(), Error> {if self.entries.contains_key(&start.session_id) {return Err(Error::SessionCommandAlreadyStarted);}self.entries.insert(start.session_id, start);Ok(())}fn command_finished(&mut self, finish: CommandFinished) -> Result<(), Error> {if !self.entries.contains_key(&finish.session_id) {return Err(Error::SessionCommandNotStarted);}let start = self.entries.remove(&finish.session_id).expect("already tested if exists");let entry = Entry::from_messages(start, finish);
use crate::entry::Entry;use std::{fs,path::PathBuf,};use thiserror::Error;#[derive(Error, Debug)]pub enum Error {#[error("can not get hostname: {0}")]GetHostname(std::io::Error),#[error("can not create log folder: {0}")]CreateLogFolder(PathBuf, std::io::Error),#[error("can not open log file: {0}")]OpenLogFile(PathBuf, std::io::Error),#[error("can not serialize entry: {0}")]SerializeEntry(csv::Error),}pub struct Store {}pub fn new() -> Store {Store {}}impl Store {pub fn add(&self, entry: Entry) -> Result<(), Error> {let xdg_dirs = xdg::BaseDirectories::with_prefix("histdb-rs").unwrap();let datadir_path = xdg_dirs.get_data_home();let hostname = hostname::get().map_err(Error::GetHostname)?;let uuid = entry.session_id.to_string();let mut uuid = uuid.chars();let mut uuid_first_part = String::new();uuid_first_part.push(uuid.next().unwrap());uuid_first_part.push(uuid.next().unwrap());let mut uuid_second_part = String::new();uuid_second_part.push(uuid.next().unwrap());uuid_second_part.push(uuid.next().unwrap());let folder_path = datadir_path.as_path().join(hostname).join(&uuid_first_part).join(&uuid_second_part);let file_path = folder_path.join(entry.session_id.to_string()).with_extension("csv");dbg!(&folder_path);dbg!(&file_path);fs::create_dir_all(&folder_path).map_err(|err| Error::CreateLogFolder(folder_path.to_path_buf(), err))?;let mut builder = csv::WriterBuilder::new();// We only want to write the header if the file does not exist yet so we can// just append new entries to the existing file without having multiple// headers.builder.has_headers(!file_path.exists());let index_file = std::fs::OpenOptions::new().append(true).create(true).open(&file_path).map_err(|err| Error::OpenLogFile(file_path.to_path_buf(), err))?;let mut writer = builder.from_writer(index_file);writer.serialize(&entry).map_err(Error::SerializeEntry)?;Ok(())}}