Skip to content

Commit

Permalink
Add transaction log functionality
Browse files Browse the repository at this point in the history
This allows for users to "stick" if they've been manually shown some number of times

I chose to write this logic in the most performant way I could figure out, so it's somewhat compex. I absolutely don't want to be responsible for delaying VRC startup time.
  • Loading branch information
zkxs committed Jun 30, 2024
1 parent 5fcf3c6 commit 5fec60e
Show file tree
Hide file tree
Showing 6 changed files with 475 additions and 68 deletions.
5 changes: 2 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Planned Features

- Users can be whitelisted to exempt them from the auto-clear
- Tracks the number of times you've shown someone's avatar
- Users who have been shown a certain number of times can be exempted from the auto-clear
- Config management UI
- Config management interface
- Think about what happens if someone manages to launch a bunch of hooligan instances simultaneously. Spoiler alert: I'm pretty sure it's file corruption.
71 changes: 71 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// This file is part of hooligan and is licenced under the GNU GPL v3.0.
// See LICENSE file for full text.
// Copyright © 2024 Michael Ripley

use std::fs::File;
use std::io;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::Path;

const AUTO_HIDE_THRESHOLD: &str = "auto_hide_threshold";

pub struct Config {
/// a user that has been manually shown this many times in a row is exempt from auto hide
pub auto_hide_threshold: u32,
}

impl Default for Config {
fn default() -> Self {
Self {
auto_hide_threshold: 3,
}
}
}

impl Config {
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
let file = File::open(path).map_err(Error::Io)?;
let reader = BufReader::new(file);
let mut config = Self::new();
for line in reader.lines() {
let line = line.map_err(Error::Io)?;
config.parse_line(&line)?;
}
Ok(config)
}

const fn new() -> Self {
Self {
auto_hide_threshold: 0,
}
}

fn parse_line(&mut self, line: &str) -> Result<(), Error> {
let (key, value) = line.split_once('=').ok_or(Error::Split)?;
match key {
AUTO_HIDE_THRESHOLD => self.parse_auto_hide_threshold(value),
_ => Err(Error::Key),
}
}

fn parse_auto_hide_threshold(&mut self, value: &str) -> Result<(), Error> {
self.auto_hide_threshold = value.parse().map_err(|_| Error::Int)?;
Ok(())
}

pub fn serialize<P: AsRef<Path>>(&self, path: P) -> Result<(), io::Error> {
let file = File::create_new(path).unwrap();
let mut writer = BufWriter::new(file);
writeln!(writer, "{}={}", AUTO_HIDE_THRESHOLD, self.auto_hide_threshold)?;
writer.flush()
}
}

#[allow(dead_code)] // lint misses usage in debug printing this error
#[derive(Debug)]
pub enum Error {
Split,
Int,
Key,
Io(io::Error),
}
7 changes: 7 additions & 0 deletions src/local_player_moderations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ pub struct Line {
}

impl Line {
pub const fn new(key: String, value: Value) -> Self {
Self {
key,
value,
}
}

pub fn parse(line: &str) -> Result<Self, ParseError> {
let mut split = line.split(' ').filter(|s| !s.is_empty());
let key = split.next().ok_or_else(|| ParseError::BadSplit(line.to_owned()))?;
Expand Down
21 changes: 8 additions & 13 deletions src/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,29 @@ impl LogFile {
}
}

pub fn get_logger() -> io::Result<LogFile> {
pub fn get_logger(project_dirs: &ProjectDirs) -> io::Result<LogFile> {
let file_rotate = FileRotate::new(
get_log_file_prefix()?,
get_log_file_prefix(project_dirs)?,
AppendCount::new(3),
ContentLimit::BytesSurpassed(1024 * 1024 * 10),
);
Ok(LogFile::new(BufWriter::new(file_rotate)))
}

fn get_log_file_prefix() -> io::Result<PathBuf> {
let mut log_file_prefix_path = create_log_dir_path()?;
fn get_log_file_prefix(project_dirs: &ProjectDirs) -> io::Result<PathBuf> {
let mut log_file_prefix_path = create_log_dir_path(project_dirs)?;
log_file_prefix_path.push("hooligan.log");
Ok(log_file_prefix_path)
}

fn create_log_dir_path() -> io::Result<PathBuf> {
let log_dir_path: PathBuf = get_log_dir()?;
fn create_log_dir_path(project_dirs: &ProjectDirs) -> io::Result<PathBuf> {
let log_dir_path: PathBuf = get_log_dir(project_dirs);
fs::create_dir_all(log_dir_path.as_path())?;
Ok(log_dir_path)
}

fn get_log_dir() -> io::Result<PathBuf> {
Ok(
ProjectDirs::from("zkxs.dev", "", "hooligan")
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "failed to find valid project directory"))?
.data_local_dir()
.join("logs")
)
fn get_log_dir(project_dirs: &ProjectDirs) -> PathBuf {
project_dirs.data_local_dir().join("logs")
}

/// Handles displaying the current time in a minimally expensive way
Expand Down
Loading

0 comments on commit 5fec60e

Please sign in to comment.