This commit is contained in:
jake 2024-03-24 12:08:47 -04:00
commit cf24968725
4 changed files with 134 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/target
Cargo.lock
tmp/*

13
Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "hit-counter-rs"
version = "0.0.1"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-web = "4"
actix-files = "0.6.5"
env_logger = "0.11.3"
log = "0.4"
async-stream = "0.3.5"

1
asset Symbolic link
View file

@ -0,0 +1 @@
../../perl/hit-counter/asset/

117
src/main.rs Normal file
View file

@ -0,0 +1,117 @@
// Due to the slowness of imagemagick (and calling system commands and w/e else)
// the image that the user will see on the page will be -1 behind the actual count
use actix_web::{
get,
App,
HttpServer,
HttpResponse,
HttpRequest,
};
use actix_files::NamedFile;
use std::{
fs,
path::Path,
process::Command,
};
const MONTAGE_PATH: &str = "/bin/montage";
// this kinda dates ImageMagick, oh well (6.9)
//const MONTAGE_ARGS: &str = "-tile 6x1 -geometry +0+0 -background none -scale 50";
const ASSET_DIR: &str = "asset/";
const TMP_OUTPUT: &str = "tmp/counter.png";
const BIND_IP: &str = "127.0.0.1";
const BIND_PORT: u16 = 8080;
static mut COUNTER: u16 = 0;
const NUMBER_LENGTH: u8 = 6;
const COUNTER_FILE : &str = "counter.numb";
#[get("/")]
async fn counter_route(req: HttpRequest ) -> HttpResponse {
let count: String;
unsafe {
COUNTER = &COUNTER + 1;
count = number_to_length(&COUNTER, NUMBER_LENGTH);
write_counter();
}
create_image(count);
let file = NamedFile::open_async(TMP_OUTPUT).await.unwrap(); // streams the file
let res = file.into_response(&req); // NamedFile to HttpResponse
res
}
fn create_image (count: String) {
let mut command = Command::new(MONTAGE_PATH);
for i in 0..NUMBER_LENGTH {
let mut file_name: String = String::new();
file_name.push_str( ASSET_DIR );
file_name.push_str( &(count.as_str()[i as usize..i as usize + 1]) );
file_name.push_str( ".png" );
command.arg(file_name);
}
command.arg("-tile").arg("6x1").arg("-geometry").arg("+0+0").arg("-background").arg("none").arg("-scale").arg("50");
command.arg(TMP_OUTPUT);
// user will refresh the page faster than imagemagick does stuff
// possible dos I guess, idc
command.spawn().expect("`/bin/montage` has an error! (probably, idk)");
}
fn number_to_length(counter: &u16, length: u8) -> String {
let mut string : String = String::from("");
let mut counter_len = (counter.checked_ilog10().unwrap_or(0) + 1) as u8; // like length() in perl
while counter_len < length {
string.push('0');
counter_len = counter_len + 1;
}
string.push_str( counter.to_string().as_str() );
string
}
unsafe fn read_counter() {
match fs::read_to_string(COUNTER_FILE) {
Ok(n) => COUNTER = n.as_str().parse().unwrap(),
Err(e) => log::info!("{e}"),
}
}
unsafe fn write_counter() {
let count = COUNTER.to_string();
fs::write(COUNTER_FILE, &count).expect("I can't write to file");
}
#[actix_web::main] // or #[tokio::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
if ! Path::new(COUNTER_FILE).exists() {
unsafe {
write_counter();
}
}
unsafe {
read_counter();
}
log::info!("starting HTTP server at http://{BIND_IP}:{BIND_PORT}");
HttpServer::new(|| {
App::new()
.service(counter_route)
})
.bind((BIND_IP, BIND_PORT))?
.run()
.await
}