256 lines
11 KiB
Rust
256 lines
11 KiB
Rust
use std::{collections::BTreeMap, os::unix::fs::PermissionsExt, path::Path, time::Duration};
|
|
|
|
use tokio::time::Instant;
|
|
|
|
const SLASHINFO: &str = "/srv/tomatenmhark-slashinfo/";
|
|
const REDIRECT: &str = "/srv/tomatenmhark-redirect/";
|
|
|
|
pub struct Status(
|
|
pub BTreeMap<String, (bool, bool, String, Option<String>, Option<Duration>)>,
|
|
pub BTreeMap<String, (bool, bool, String, Option<String>)>,
|
|
);
|
|
impl Status {
|
|
pub fn empty() -> Self {
|
|
Self(Default::default(), Default::default())
|
|
}
|
|
pub fn query_sync(dbg: bool) -> Self {
|
|
let mut map = BTreeMap::new();
|
|
query_status_sync(
|
|
|k, e, r, v, dur| {
|
|
let (v, add) = v
|
|
.split_once('\n')
|
|
.map(|(v, add)| (v, add.trim()))
|
|
.unwrap_or((v, ""));
|
|
map.insert(
|
|
k.to_owned(),
|
|
(
|
|
e,
|
|
r,
|
|
v.trim().to_owned(),
|
|
if add.is_empty() {
|
|
None
|
|
} else {
|
|
Some(add.to_owned())
|
|
},
|
|
dur,
|
|
),
|
|
);
|
|
},
|
|
dbg,
|
|
);
|
|
let mut rest = BTreeMap::new();
|
|
if let Ok(rd) = std::fs::read_dir(SLASHINFO) {
|
|
for f in rd.filter_map(Result::ok) {
|
|
if let Some(id) = f.file_name().to_str() {
|
|
if !map.contains_key(id) {
|
|
let mut p = f.path();
|
|
p.push("desc");
|
|
if let Ok(desc) = std::fs::read_to_string(&p) {
|
|
let info = Path::new(SLASHINFO).join(id).join("index.html");
|
|
let info =
|
|
info.starts_with(SLASHINFO) && info.try_exists().ok() == Some(true);
|
|
let redirect = Path::new(REDIRECT).join(id);
|
|
let redirect = redirect.starts_with(REDIRECT)
|
|
&& redirect.try_exists().ok() == Some(true);
|
|
let desc = desc.trim();
|
|
if let Some(i) = desc.find('\n') {
|
|
rest.insert(
|
|
id.to_owned(),
|
|
(
|
|
info,
|
|
redirect,
|
|
desc[0..i].trim().to_owned(),
|
|
Some(desc[i + 1..].trim().to_owned()),
|
|
),
|
|
);
|
|
} else {
|
|
rest.insert(id.to_owned(), (info, redirect, desc.to_owned(), None));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Self(map, rest)
|
|
}
|
|
pub async fn query_async(dbg: bool) -> Self {
|
|
let mut map = BTreeMap::new();
|
|
query_status_async(
|
|
|k, e, r, v, dur| {
|
|
let (v, add) = v
|
|
.split_once('\n')
|
|
.map(|(v, add)| (v, add.trim()))
|
|
.unwrap_or((v, ""));
|
|
map.insert(
|
|
k.to_owned(),
|
|
(
|
|
e,
|
|
r,
|
|
v.trim().to_owned(),
|
|
if add.is_empty() {
|
|
None
|
|
} else {
|
|
Some(add.to_owned())
|
|
},
|
|
dur,
|
|
),
|
|
);
|
|
},
|
|
dbg,
|
|
)
|
|
.await;
|
|
let mut rest = BTreeMap::new();
|
|
if let Ok(mut rd) = tokio::fs::read_dir(SLASHINFO).await {
|
|
while let Ok(Some(f)) = rd.next_entry().await {
|
|
if let Some(id) = f.file_name().to_str() {
|
|
if !map.contains_key(id) {
|
|
let mut p = f.path();
|
|
p.push("desc");
|
|
if let Ok(desc) = tokio::fs::read_to_string(&p).await {
|
|
let info = Path::new(SLASHINFO).join(id).join("index.html");
|
|
let info = info.starts_with(SLASHINFO)
|
|
&& tokio::fs::try_exists(info).await.ok() == Some(true);
|
|
let redirect = Path::new(REDIRECT).join(id);
|
|
let redirect = redirect.starts_with(REDIRECT)
|
|
&& tokio::fs::try_exists(redirect).await.ok() == Some(true);
|
|
let desc = desc.trim();
|
|
if let Some(i) = desc.find('\n') {
|
|
rest.insert(
|
|
id.to_owned(),
|
|
(
|
|
info,
|
|
redirect,
|
|
desc[0..i].trim().to_owned(),
|
|
Some(desc[i + 1..].trim().to_owned()),
|
|
),
|
|
);
|
|
} else {
|
|
rest.insert(id.to_owned(), (info, redirect, desc.to_owned(), None));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Self(map, rest)
|
|
}
|
|
}
|
|
|
|
fn query_status_sync(mut func: impl FnMut(&str, bool, bool, &str, Option<Duration>), dbg: bool) {
|
|
if let Ok(rd) = std::fs::read_dir("/tmp/") {
|
|
for f in rd.filter_map(Result::ok) {
|
|
if let Some(name) = f.file_name().to_str() {
|
|
if let Some(id) = name
|
|
.strip_prefix("tomatenmhark-status-")
|
|
.map(|v| v.trim())
|
|
.filter(|v| !v.is_empty())
|
|
{
|
|
if let Ok(status) = std::fs::read_to_string(f.path())
|
|
.as_ref()
|
|
.map(|v| v.trim_end())
|
|
{
|
|
if !status.is_empty() {
|
|
let info = Path::new(SLASHINFO).join(id).join("index.html");
|
|
let info =
|
|
info.starts_with(SLASHINFO) && info.try_exists().ok() == Some(true);
|
|
let redirect = Path::new(REDIRECT).join(id);
|
|
let redirect = redirect.starts_with(REDIRECT)
|
|
&& redirect.try_exists().ok() == Some(true);
|
|
func(id, info, redirect, status, None);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if let Ok(rd) = std::fs::read_dir("/srv/tomatenmhark-dystatus/") {
|
|
for f in rd.filter_map(Result::ok) {
|
|
if let Some(name) = f.file_name().to_str() {
|
|
if f.metadata()
|
|
.is_ok_and(|meta| meta.is_file() && meta.permissions().mode() & 1 == 1)
|
|
{
|
|
let id = name.trim();
|
|
if !id.is_empty() {
|
|
let start = dbg.then(Instant::now);
|
|
if let Ok(output) = std::process::Command::new(f.path()).output() {
|
|
let elapsed = start.map(|v| v.elapsed());
|
|
let out = String::from_utf8_lossy(&output.stdout);
|
|
let out = out.trim_end();
|
|
if dbg || !out.is_empty() {
|
|
let info = Path::new(SLASHINFO).join(id).join("index.html");
|
|
let info = info.starts_with(SLASHINFO)
|
|
&& info.try_exists().ok() == Some(true);
|
|
let redirect = Path::new(REDIRECT).join(id);
|
|
let redirect = redirect.starts_with(REDIRECT)
|
|
&& redirect.try_exists().ok() == Some(true);
|
|
func(id, info, redirect, out, elapsed);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
async fn query_status_async(
|
|
mut func: impl FnMut(&str, bool, bool, &str, Option<Duration>),
|
|
dbg: bool,
|
|
) {
|
|
if let Ok(mut rd) = tokio::fs::read_dir("/tmp/").await {
|
|
while let Ok(Some(f)) = rd.next_entry().await {
|
|
if let Some(name) = f.file_name().to_str() {
|
|
if let Some(id) = name
|
|
.strip_prefix("tomatenmhark-status-")
|
|
.map(|v| v.trim())
|
|
.filter(|v| !v.is_empty())
|
|
{
|
|
if let Ok(status) = tokio::fs::read_to_string(f.path())
|
|
.await
|
|
.as_ref()
|
|
.map(|v| v.trim_end())
|
|
{
|
|
if !status.is_empty() {
|
|
let info = Path::new(SLASHINFO).join(id).join("index.html");
|
|
let info = info.starts_with(SLASHINFO)
|
|
&& tokio::fs::try_exists(info).await.ok() == Some(true);
|
|
let redirect = Path::new(REDIRECT).join(id);
|
|
let redirect = redirect.starts_with(REDIRECT)
|
|
&& tokio::fs::try_exists(redirect).await.ok() == Some(true);
|
|
func(id, info, redirect, status, None);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if let Ok(mut rd) = tokio::fs::read_dir("/srv/tomatenmhark-dystatus/").await {
|
|
while let Ok(Some(f)) = rd.next_entry().await {
|
|
if let Some(name) = f.file_name().to_str() {
|
|
if f.metadata()
|
|
.await
|
|
.is_ok_and(|meta| meta.is_file() && meta.permissions().mode() & 1 == 1)
|
|
{
|
|
let id = name.trim();
|
|
if !id.is_empty() {
|
|
let start = dbg.then(Instant::now);
|
|
if let Ok(output) = tokio::process::Command::new(f.path()).output().await {
|
|
let elapsed = start.map(|v| v.elapsed());
|
|
let out = String::from_utf8_lossy(&output.stdout);
|
|
let out = out.trim_end();
|
|
if dbg || !out.is_empty() {
|
|
let info = Path::new(SLASHINFO).join(id).join("index.html");
|
|
let info = info.starts_with(SLASHINFO)
|
|
&& tokio::fs::try_exists(info).await.ok() == Some(true);
|
|
let redirect = Path::new(REDIRECT).join(id);
|
|
let redirect = redirect.starts_with(REDIRECT)
|
|
&& tokio::fs::try_exists(redirect).await.ok() == Some(true);
|
|
func(id, info, redirect, out, elapsed);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|