init repo
This commit is contained in:
commit
b0cd77f68a
|
@ -0,0 +1,2 @@
|
|||
target
|
||||
/secret.key
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "blek-heartbeat"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
obfstr = "0.4.3"
|
||||
reqwest = { version = "0.11.23", features = ["blocking", "serde_json"] }
|
||||
serde = "1.0.195"
|
||||
serde_json = "1.0.111"
|
||||
users = "0.11.0"
|
||||
|
||||
[profile.release]
|
||||
strip = "debuginfo"
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
opt-level = "z"
|
|
@ -0,0 +1,58 @@
|
|||
use reqwest::{blocking, Method};
|
||||
use std::{result::Result, error::Error, process::exit, io::{Write, stderr}, fs, path::Path};
|
||||
|
||||
fn write_metrics(add: u32) -> Result<(), Box<dyn Error>> {
|
||||
let user = users::get_user_by_uid(users::get_current_uid());
|
||||
if let Some(user) = user.clone() {
|
||||
let path = format!("/home/{}/.local/share/bHeartbeat", user.name().to_str().unwrap());
|
||||
let file_path = path.clone() + "/data_spent.txt";
|
||||
let _ = fs::create_dir_all(path);
|
||||
if ! Path::new(&file_path).is_file() {
|
||||
fs::write(&file_path, add.to_string())?;
|
||||
} else {
|
||||
let f = fs::File::open(&file_path)?;
|
||||
let meta = f.metadata()?;
|
||||
if meta.permissions().readonly() {
|
||||
return Err("Can't write to the metrics file".into());
|
||||
}
|
||||
|
||||
let mut data = fs::read_to_string(&file_path)?.parse::<u32>().unwrap_or(0);
|
||||
data += add;
|
||||
fs::write(&file_path, data.to_string())?;
|
||||
}
|
||||
} else {
|
||||
return Err("No user data available. Metrics will not be saved.".into())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let key = include_bytes!("key.bin");
|
||||
let cli = blocking::Client::new();
|
||||
let res = cli.request(Method::POST, "https://hb.blek.codes/beat")
|
||||
.body(key.to_vec())
|
||||
.send()?;
|
||||
|
||||
if res.status() != 200 {
|
||||
eprintln!("HTTP heartbeat returned {}", res.status());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let data = write_metrics((1024 * 10) + key.len() as u32);
|
||||
if let Err(data) = data {
|
||||
eprintln!("Can't write metrics:\n{}", data.to_string());
|
||||
}
|
||||
|
||||
let status = res.bytes()?.to_vec();
|
||||
let status = status.as_slice();
|
||||
let ok_status = &status[0..2];
|
||||
|
||||
if ok_status != "OK".as_bytes() {
|
||||
eprintln!("ERR: Server returned this:");
|
||||
eprintln!("-----BEGIN BLOCK-----");
|
||||
stderr().write(status)?;
|
||||
eprintln!("\n-----END BLOCK-----");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
../../secret.key
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "blek-heartbeat-server"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bytes = "1.5.0"
|
||||
chrono = "0.4.31"
|
||||
tokio = { version = "1.35.1", features = ["full"] }
|
||||
warp = "0.3.6"
|
||||
|
||||
[profile.release]
|
||||
strip = "debuginfo"
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
opt-level = "z"
|
|
@ -0,0 +1,100 @@
|
|||
#![forbid(unsafe_code)]
|
||||
|
||||
use std::sync::{Mutex, Arc};
|
||||
use bytes::Bytes;
|
||||
use warp::{Filter, reject::{Rejection, Reject}, reply::{Reply, with_header, with_status}};
|
||||
|
||||
use chrono::{Local, DateTime};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct State {
|
||||
pub last_heartbeat: DateTime<Local>
|
||||
}
|
||||
impl Default for State {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
last_heartbeat: DateTime::UNIX_EPOCH.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum HttpReject {
|
||||
String(String)
|
||||
}
|
||||
|
||||
impl Reject for HttpReject {}
|
||||
|
||||
async fn beat_f(state: Arc<Mutex<State>>, body: Bytes) -> Result<Box<dyn Reply>, Rejection> {
|
||||
|
||||
if body != include_bytes!("secret.key").to_vec() {
|
||||
return Ok(
|
||||
Box::new(
|
||||
with_status("Invalid key", warp::http::StatusCode::FORBIDDEN)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
let mut state = state.lock().map_err(|x| HttpReject::String(x.to_string()))?;
|
||||
state.last_heartbeat = Local::now().into();
|
||||
|
||||
Ok(
|
||||
Box::new("OK")
|
||||
)
|
||||
}
|
||||
|
||||
async fn gif_f(state: Arc<Mutex<State>>) -> Result<Box<dyn Reply>, Rejection> {
|
||||
let state = state.lock().map_err(|x| HttpReject::String(x.to_string()))?;
|
||||
|
||||
let online_gif = include_bytes!("me_online.gif");
|
||||
let offline_gif = include_bytes!("me_offline.gif");
|
||||
|
||||
let duration = (Local::now() - state.last_heartbeat).num_minutes();
|
||||
|
||||
Ok(
|
||||
Box::new(
|
||||
with_header(
|
||||
with_header(
|
||||
{
|
||||
if duration < 2 {
|
||||
online_gif.to_vec()
|
||||
} else {
|
||||
offline_gif.to_vec()
|
||||
}
|
||||
},
|
||||
"Content-Type",
|
||||
"image/gif"
|
||||
),
|
||||
"X-Duration",
|
||||
duration.to_string()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fn beat(state: Arc<Mutex<State>>) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
|
||||
warp::path!("beat")
|
||||
.and(warp::path::end())
|
||||
.and(warp::post())
|
||||
.map(move || state.clone())
|
||||
.and(warp::body::bytes())
|
||||
.and_then(beat_f)
|
||||
}
|
||||
|
||||
fn gif(state: Arc<Mutex<State>>) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
|
||||
warp::path!("gif")
|
||||
.and(warp::path::end())
|
||||
.and(warp::get())
|
||||
.map(move || state.clone())
|
||||
.and_then(gif_f)
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let state = Arc::new(Mutex::new(State::default()));
|
||||
|
||||
warp::serve(
|
||||
beat(state.clone())
|
||||
.or(gif(state))
|
||||
).run(([0, 0, 0, 0], 80)).await;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 575 B |
Binary file not shown.
After Width: | Height: | Size: 630 B |
|
@ -0,0 +1 @@
|
|||
../../secret.key
|
Loading…
Reference in New Issue