generated from PlexSheep/baserepo
Compare commits
No commits in common. "4e486fde800372702f8e79f5a64c6d4e89a1e788" and "d8fd70aae4750eebbe1dc53ec0b0343822719141" have entirely different histories.
4e486fde80
...
d8fd70aae4
38 changed files with 1255 additions and 562 deletions
|
@ -16,11 +16,9 @@ jobs:
|
||||||
- name: get repo
|
- name: get repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: install rust
|
- name: install rust
|
||||||
uses: https://github.com/dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
- name: install additional rust things
|
- name: install additional rust things
|
||||||
run: |
|
run: rustup component add rustfmt
|
||||||
rustup component add rustfmt
|
|
||||||
rustup component add clippy
|
|
||||||
- name: config custom registry
|
- name: config custom registry
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ~/.cargo/
|
mkdir -p ~/.cargo/
|
||||||
|
@ -30,16 +28,16 @@ jobs:
|
||||||
echo '[registries.cscherr]' >> ~/.cargo/config.toml
|
echo '[registries.cscherr]' >> ~/.cargo/config.toml
|
||||||
echo 'index = "https://git.cscherr.de/PlexSheep/_cargo-index.git"' >> ~/.cargo/config.toml
|
echo 'index = "https://git.cscherr.de/PlexSheep/_cargo-index.git"' >> ~/.cargo/config.toml
|
||||||
cat ~/.cargo/config.toml
|
cat ~/.cargo/config.toml
|
||||||
- name: cargo clippy check
|
- name: cargo check
|
||||||
run: cargo clippy --all-features --all-targets
|
run: cargo check --all-features --all-targets
|
||||||
- name: cargo clippy fix
|
- name: cargo fix
|
||||||
run: cargo clippy --fix --all-features --all-targets
|
run: cargo fix --all-features --all-targets
|
||||||
- name: cargo fmt
|
- name: cargo fmt
|
||||||
run: cargo fmt --all
|
run: cargo fmt --all
|
||||||
- name: cargo test
|
- name: cargo test
|
||||||
run: cargo test --all-features --all-targets
|
run: cargo test --all-features --all-targets
|
||||||
- name: commit back to repository
|
- name: commit back to repository
|
||||||
uses: https://github.com/stefanzweifel/git-auto-commit-action@v5
|
uses: stefanzweifel/git-auto-commit-action@v5
|
||||||
with:
|
with:
|
||||||
# Optional. Commit message for the created commit.
|
# Optional. Commit message for the created commit.
|
||||||
# Defaults to "Apply automatic changes"
|
# Defaults to "Apply automatic changes"
|
||||||
|
|
47
.github/workflows/cargo.yaml
vendored
47
.github/workflows/cargo.yaml
vendored
|
@ -1,47 +0,0 @@
|
||||||
name: cargo devel CI
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
# - '!master'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
CI:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: cargo CI
|
|
||||||
permissions:
|
|
||||||
# Give the default GITHUB_TOKEN write permission to commit and push the
|
|
||||||
# added or changed files to the repository.
|
|
||||||
contents: write
|
|
||||||
steps:
|
|
||||||
- name: get repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: install rust
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
- name: install additional rust things
|
|
||||||
run: |
|
|
||||||
rustup component add rustfmt
|
|
||||||
rustup component add clippy
|
|
||||||
- name: config custom registry
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.cargo/
|
|
||||||
echo "" > ~/.cargo/config.toml
|
|
||||||
echo "[registry]" >> ~/.cargo/config.toml
|
|
||||||
echo 'cscherr = "cscherr"' >> ~/.cargo/config.toml
|
|
||||||
echo '[registries.cscherr]' >> ~/.cargo/config.toml
|
|
||||||
echo 'index = "https://git.cscherr.de/PlexSheep/_cargo-index.git"' >> ~/.cargo/config.toml
|
|
||||||
cat ~/.cargo/config.toml
|
|
||||||
- name: cargo clippy check
|
|
||||||
run: cargo clippy --all-features --all-targets
|
|
||||||
- name: cargo clippy fix
|
|
||||||
run: cargo clippy --fix --all-features --all-targets
|
|
||||||
- name: cargo fmt
|
|
||||||
run: cargo fmt --all
|
|
||||||
- name: cargo test
|
|
||||||
run: cargo test --all-features --all-targets
|
|
||||||
- name: commit back to repository
|
|
||||||
uses: stefanzweifel/git-auto-commit-action@v5
|
|
||||||
with:
|
|
||||||
# Optional. Commit message for the created commit.
|
|
||||||
# Defaults to "Apply automatic changes"
|
|
||||||
commit_message: automatic cargo CI changes
|
|
120
.github/workflows/maturin.yml
vendored
120
.github/workflows/maturin.yml
vendored
|
@ -1,120 +0,0 @@
|
||||||
# This file is autogenerated by maturin v1.4.0
|
|
||||||
# To update, run
|
|
||||||
#
|
|
||||||
# maturin generate-ci github
|
|
||||||
#
|
|
||||||
name: CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- master
|
|
||||||
tags:
|
|
||||||
- '*'
|
|
||||||
pull_request:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
linux:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
target: [x86_64, x86, aarch64, armv7, s390x, ppc64le]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: '3.10'
|
|
||||||
- name: Build wheels
|
|
||||||
uses: PyO3/maturin-action@v1
|
|
||||||
with:
|
|
||||||
target: ${{ matrix.target }}
|
|
||||||
args: --release --out dist --find-interpreter
|
|
||||||
sccache: 'true'
|
|
||||||
manylinux: auto
|
|
||||||
- name: Upload wheels
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: wheels
|
|
||||||
path: dist
|
|
||||||
|
|
||||||
windows:
|
|
||||||
runs-on: windows-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
target: [x64, x86]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: '3.10'
|
|
||||||
architecture: ${{ matrix.target }}
|
|
||||||
- name: Build wheels
|
|
||||||
uses: PyO3/maturin-action@v1
|
|
||||||
with:
|
|
||||||
target: ${{ matrix.target }}
|
|
||||||
args: --release --out dist --find-interpreter
|
|
||||||
sccache: 'true'
|
|
||||||
- name: Upload wheels
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: wheels
|
|
||||||
path: dist
|
|
||||||
|
|
||||||
macos:
|
|
||||||
runs-on: macos-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
target: [x86_64, aarch64]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: '3.10'
|
|
||||||
- name: Build wheels
|
|
||||||
uses: PyO3/maturin-action@v1
|
|
||||||
with:
|
|
||||||
target: ${{ matrix.target }}
|
|
||||||
args: --release --out dist --find-interpreter
|
|
||||||
sccache: 'true'
|
|
||||||
- name: Upload wheels
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: wheels
|
|
||||||
path: dist
|
|
||||||
|
|
||||||
sdist:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Build sdist
|
|
||||||
uses: PyO3/maturin-action@v1
|
|
||||||
with:
|
|
||||||
command: sdist
|
|
||||||
args: --out dist
|
|
||||||
- name: Upload sdist
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: wheels
|
|
||||||
path: dist
|
|
||||||
|
|
||||||
release:
|
|
||||||
name: Release
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: "startsWith(github.ref, 'refs/tags/')"
|
|
||||||
needs: [linux, windows, macos, sdist]
|
|
||||||
steps:
|
|
||||||
- uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: wheels
|
|
||||||
- name: Publish to PyPI
|
|
||||||
uses: PyO3/maturin-action@v1
|
|
||||||
env:
|
|
||||||
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
||||||
with:
|
|
||||||
command: upload
|
|
||||||
args: --non-interactive --skip-existing *
|
|
|
@ -1 +0,0 @@
|
||||||
rust
|
|
48
Cargo.toml
48
Cargo.toml
|
@ -3,14 +3,14 @@ resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
".",
|
".",
|
||||||
"members/libpt-core",
|
"members/libpt-core",
|
||||||
|
"members/libpt-math",
|
||||||
"members/libpt-log",
|
"members/libpt-log",
|
||||||
"members/libpt-py",
|
"members/libpt-net",
|
||||||
]
|
]
|
||||||
default-members = [".", "members/libpt-core"]
|
default-members = [".", "members/libpt-core"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
publish = true
|
publish = true
|
||||||
version = "0.4.0-alpha.1"
|
version = "0.3.11"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Christoph J. Scherr <software@cscherr.de>"]
|
authors = ["Christoph J. Scherr <software@cscherr.de>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -18,7 +18,7 @@ description = "Personal multitool"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
homepage = "https://git.cscherr.de/PlexSheep/pt"
|
homepage = "https://git.cscherr.de/PlexSheep/pt"
|
||||||
repository = "https://git.cscherr.de/PlexSheep/pt"
|
repository = "https://git.cscherr.de/PlexSheep/pt"
|
||||||
keywords = ["library"]
|
keywords = ["cli", "library"]
|
||||||
categories = [
|
categories = [
|
||||||
"command-line-utilities",
|
"command-line-utilities",
|
||||||
"development-tools",
|
"development-tools",
|
||||||
|
@ -28,10 +28,11 @@ categories = [
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
anyhow = "1.0.79"
|
anyhow = "1.0.79"
|
||||||
thiserror = "1.0.56"
|
thiserror = "1.0.56"
|
||||||
libpt-core = { version = "0.3.12", path = "members/libpt-core" }
|
libpt-core = { version = "0.3.11", path = "members/libpt-core" }
|
||||||
libpt-bintols = { version = "0.3.12", path = "members/libpt-bintols" }
|
libpt-bintols = { version = "0.3.11", path = "members/libpt-bintols" }
|
||||||
libpt-log = { version = "0.3.12", path = "members/libpt-log" }
|
libpt-log = { version = "0.3.11", path = "members/libpt-log" }
|
||||||
libpt-py = { version = "0.3.12", path = "members/libpt-py" }
|
libpt-math = { version = "0.3.11", path = "members/libpt-math" }
|
||||||
|
libpt-net = { version = "0.3.11", path = "members/libpt-net" }
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "libpt"
|
name = "libpt"
|
||||||
|
@ -48,12 +49,13 @@ keywords.workspace = true
|
||||||
categories.workspace = true
|
categories.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["log", "core"]
|
default = ["log", "core", "bin"]
|
||||||
core = []
|
core = []
|
||||||
full = ["default", "core", "log", "bintols"]
|
math = []
|
||||||
log = ["dep:libpt-log"]
|
log = []
|
||||||
bintols = ["dep:libpt-bintols", "log"]
|
bintols = []
|
||||||
# py = ["dep:libpt-py"]
|
net = []
|
||||||
|
bin = ["dep:clap", "dep:clap-num", "dep:clap-verbosity-flag", "math", "bintols"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "libpt"
|
name = "libpt"
|
||||||
|
@ -63,7 +65,23 @@ crate-type = [
|
||||||
"rlib",
|
"rlib",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "ccc"
|
||||||
|
path = "src/ccc/mod.rs"
|
||||||
|
required-features = ["bin", "math"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "hedu"
|
||||||
|
path = "src/hedu/mod.rs"
|
||||||
|
required-features = ["bin", "bintols"]
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libpt-core = { workspace = true }
|
libpt-core = { workspace = true }
|
||||||
libpt-bintols = { workspace = true, optional = true }
|
libpt-bintols = { workspace = true }
|
||||||
libpt-log = { workspace = true, optional = true }
|
libpt-log = { workspace = true }
|
||||||
|
libpt-math = { workspace = true }
|
||||||
|
libpt-net = { workspace = true }
|
||||||
|
clap = { version = "4.4.4", features = ["derive"], optional = true }
|
||||||
|
clap-num = { version = "1.0.2", optional = true }
|
||||||
|
clap-verbosity-flag = { version = "2.0.1", optional = true }
|
||||||
|
|
20
README.md
20
README.md
|
@ -1,11 +1,5 @@
|
||||||
# pt / libpt
|
# pt / libpt
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
[](https://github.com/PlexSheep/pt/actions/workflows/cargo.yaml)
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
`pt` stands for either one of "personal tool", "plex tool", "pete" or something among those lines.
|
`pt` stands for either one of "personal tool", "plex tool", "pete" or something among those lines.
|
||||||
|
@ -15,12 +9,6 @@ crate, python module or executable.
|
||||||
|
|
||||||
Let's see if I make it a bloated mess or stop committing after 30 hello worlds.
|
Let's see if I make it a bloated mess or stop committing after 30 hello worlds.
|
||||||
|
|
||||||
* [Original Repository](https://git.cscherr.de/PlexSheep/pt)
|
|
||||||
* [GitHub Mirror](https://github.com/PlexSheep/pt)
|
|
||||||
* [Codeberg Mirror](https://codeberg.org/PlexSheep/pt)
|
|
||||||
* [crates.io](https://crates.io/crates/libpt)
|
|
||||||
* [docs.rs](https://docs.rs/crate/libpt/)
|
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
- See `cargo.toml`
|
- See `cargo.toml`
|
||||||
|
@ -71,6 +59,14 @@ The documentation can be automatically generated with `cargo doc --open`.
|
||||||
|
|
||||||
An up to date version of the Documentation can be found [here](https://docs.rs/libpt/)
|
An up to date version of the Documentation can be found [here](https://docs.rs/libpt/)
|
||||||
|
|
||||||
|
## Mirrored
|
||||||
|
|
||||||
|
The origin of this repository is [git.cscherr.de](https://git.cscherr.de/PlexSheep/pt)
|
||||||
|
|
||||||
|
It is mirrored to:
|
||||||
|
- [Codeberg](https://codeberg.org/PlexSheep/pt)
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
**Pt is MIT Licensed**
|
**Pt is MIT Licensed**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "libpt-bintols"
|
name = "libpt-bintols"
|
||||||
publish.workspace = true
|
publish.workspace = true
|
||||||
version = "0.3.12"
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
|
@ -9,13 +9,13 @@ pub use num_traits::{PrimInt, ToPrimitive};
|
||||||
/// * `data` - The data you are trying to dump
|
/// * `data` - The data you are trying to dump
|
||||||
pub fn bytes_to_bin(data: &[u8]) -> String {
|
pub fn bytes_to_bin(data: &[u8]) -> String {
|
||||||
let mut s = format!("0b{:08b}", data.first().unwrap());
|
let mut s = format!("0b{:08b}", data.first().unwrap());
|
||||||
for dat in data {
|
for i in 1..data.len() {
|
||||||
s.push_str(&format!("_{:08b}", dat));
|
s.push_str(&format!("_{:08b}", data[i]));
|
||||||
if dat % 8 == 0 {
|
if i % 8 == 0 {
|
||||||
s.push('\n')
|
s.push_str("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Quickly format a number of Bytes [`usize`] with the corresponding
|
/// Quickly format a number of Bytes [`usize`] with the corresponding
|
||||||
|
@ -34,17 +34,17 @@ where
|
||||||
T: std::fmt::Debug,
|
T: std::fmt::Debug,
|
||||||
{
|
{
|
||||||
if total < T::from(KIBI).unwrap() {
|
if total < T::from(KIBI).unwrap() {
|
||||||
format!("{total} B")
|
return format!("{total} B");
|
||||||
} else if T::from(KIBI).unwrap() <= total && total < T::from(MEBI).unwrap() {
|
} else if T::from(KIBI).unwrap() <= total && total < T::from(MEBI).unwrap() {
|
||||||
format!("{:.2} K", total.to_f64().unwrap() / KIBI as f64)
|
return format!("{:.2} K", total.to_f64().unwrap() / KIBI as f64);
|
||||||
} else if T::from(MEBI).unwrap() <= total && total < T::from(GIBI).unwrap() {
|
} else if T::from(MEBI).unwrap() <= total && total < T::from(GIBI).unwrap() {
|
||||||
format!("{:.2} M", total.to_f64().unwrap() / MEBI as f64)
|
return format!("{:.2} M", total.to_f64().unwrap() / MEBI as f64);
|
||||||
} else if T::from(GIBI).unwrap() <= total && total < T::from(TEBI).unwrap() {
|
} else if T::from(GIBI).unwrap() <= total && total < T::from(TEBI).unwrap() {
|
||||||
format!("{:.2} G", total.to_f64().unwrap() / GIBI as f64)
|
return format!("{:.2} G", total.to_f64().unwrap() / GIBI as f64);
|
||||||
} else if T::from(TEBI).unwrap() <= total && total < T::from(PEBI).unwrap() {
|
} else if T::from(TEBI).unwrap() <= total && total < T::from(PEBI).unwrap() {
|
||||||
format!("{:.2} T", total.to_f64().unwrap() / TEBI as f64)
|
return format!("{:.2} T", total.to_f64().unwrap() / TEBI as f64);
|
||||||
} else if T::from(PEBI).unwrap() <= total && total < T::from(EXBI).unwrap() {
|
} else if T::from(PEBI).unwrap() <= total && total < T::from(EXBI).unwrap() {
|
||||||
format!("{:.2} P", total.to_f64().unwrap() / PEBI as f64)
|
return format!("{:.2} P", total.to_f64().unwrap() / PEBI as f64);
|
||||||
}
|
}
|
||||||
// now we are starting to reach the sizes that are pretty unrealistic
|
// now we are starting to reach the sizes that are pretty unrealistic
|
||||||
// (as of 2023 that is, hello future)
|
// (as of 2023 that is, hello future)
|
||||||
|
@ -53,9 +53,9 @@ where
|
||||||
// to work with a fixed, larger sized datatype
|
// to work with a fixed, larger sized datatype
|
||||||
else {
|
else {
|
||||||
let total: u128 = total.to_u128().unwrap();
|
let total: u128 = total.to_u128().unwrap();
|
||||||
if (EXBI..ZEBI).contains(&total) {
|
if EXBI <= total && total < ZEBI {
|
||||||
return format!("{:.2} E", total.to_f64().unwrap() / EXBI as f64);
|
return format!("{:.2} E", total.to_f64().unwrap() / EXBI as f64);
|
||||||
} else if (ZEBI..YOBI).contains(&total) {
|
} else if ZEBI <= total && total < YOBI {
|
||||||
return format!("{:.2} Z", total.to_f64().unwrap() / ZEBI as f64);
|
return format!("{:.2} Z", total.to_f64().unwrap() / ZEBI as f64);
|
||||||
} else if YOBI <= total {
|
} else if YOBI <= total {
|
||||||
return format!("{:.2} Y", total.to_f64().unwrap() / YOBI as f64);
|
return format!("{:.2} Y", total.to_f64().unwrap() / YOBI as f64);
|
||||||
|
|
239
members/libpt-bintols/src/hedu/mod.rs
Normal file
239
members/libpt-bintols/src/hedu/mod.rs
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
//! # Dump data
|
||||||
|
//!
|
||||||
|
//! This crate is part of [`pt`](../libpt/index.html), but can also be used as a standalone
|
||||||
|
//! module.
|
||||||
|
//!
|
||||||
|
//! Hedu is made for hexdumping data. `libpt` offers a cli application using this module.
|
||||||
|
|
||||||
|
use crate::display::humanbytes;
|
||||||
|
use anyhow::{bail, Result};
|
||||||
|
use libpt_log::{debug, error, trace, warn};
|
||||||
|
use std::io::{prelude::*, Read, SeekFrom};
|
||||||
|
|
||||||
|
pub const BYTES_PER_LINE: usize = 16;
|
||||||
|
pub const LINE_SEP_HORIZ: char = '─';
|
||||||
|
pub const LINE_SEP_VERT: char = '│';
|
||||||
|
pub const CHAR_BORDER: &'static str = "|";
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Hedu {
|
||||||
|
pub chars: bool,
|
||||||
|
pub skip: usize,
|
||||||
|
pub show_identical: bool,
|
||||||
|
pub limit: usize,
|
||||||
|
stop: bool,
|
||||||
|
len: usize,
|
||||||
|
data_idx: usize,
|
||||||
|
rd_counter: usize,
|
||||||
|
buf: [[u8; BYTES_PER_LINE]; 2],
|
||||||
|
alt_buf: usize,
|
||||||
|
pub display_buf: String,
|
||||||
|
first_iter: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hedu {
|
||||||
|
pub fn new(chars: bool, skip: usize, show_identical: bool, limit: usize) -> Self {
|
||||||
|
Hedu {
|
||||||
|
chars,
|
||||||
|
skip,
|
||||||
|
show_identical,
|
||||||
|
limit,
|
||||||
|
stop: false,
|
||||||
|
len: 0,
|
||||||
|
data_idx: 0,
|
||||||
|
rd_counter: 0,
|
||||||
|
buf: [[0; BYTES_PER_LINE]; 2],
|
||||||
|
alt_buf: 0,
|
||||||
|
display_buf: String::new(),
|
||||||
|
first_iter: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn display(&mut self) {
|
||||||
|
println!("{}", self.display_buf);
|
||||||
|
self.display_buf = String::new();
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn sep(&mut self) {
|
||||||
|
if self.chars {
|
||||||
|
self.display_buf += &format!("{LINE_SEP_HORIZ}").repeat(80);
|
||||||
|
} else {
|
||||||
|
self.display_buf += &format!("{LINE_SEP_HORIZ}").repeat(59);
|
||||||
|
}
|
||||||
|
self.display();
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn newline(&mut self) {
|
||||||
|
self.display_buf += "\n";
|
||||||
|
self.display();
|
||||||
|
}
|
||||||
|
fn dump_a_line(&mut self) {
|
||||||
|
self.display_buf += &format!("{:08X} {LINE_SEP_VERT} ", self.data_idx);
|
||||||
|
if self.len != 0 {
|
||||||
|
for i in 0..self.len {
|
||||||
|
if i as usize % BYTES_PER_LINE == BYTES_PER_LINE / 2 {
|
||||||
|
self.display_buf += " ";
|
||||||
|
}
|
||||||
|
self.display_buf += &format!("{:02X} ", self.buf[self.alt_buf][i]);
|
||||||
|
}
|
||||||
|
if self.len == BYTES_PER_LINE / 2 {
|
||||||
|
self.display_buf += " "
|
||||||
|
}
|
||||||
|
for i in 0..(BYTES_PER_LINE - self.len) {
|
||||||
|
if i as usize % BYTES_PER_LINE == BYTES_PER_LINE / 2 {
|
||||||
|
self.display_buf += " ";
|
||||||
|
}
|
||||||
|
self.display_buf += " ";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.display_buf += &format!("{:49}", "");
|
||||||
|
}
|
||||||
|
if self.chars {
|
||||||
|
self.display_buf += &format!("{LINE_SEP_VERT} ");
|
||||||
|
if self.len != 0 {
|
||||||
|
self.display_buf += CHAR_BORDER;
|
||||||
|
for i in 0..self.len {
|
||||||
|
self.display_buf +=
|
||||||
|
&format!("{}", mask_chars(self.buf[self.alt_buf][i] as char));
|
||||||
|
}
|
||||||
|
self.display_buf += CHAR_BORDER;
|
||||||
|
} else {
|
||||||
|
self.display_buf += &format!("{:^8}", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_lines(&mut self, data: &mut dyn DataSource) -> Result<()> {
|
||||||
|
trace!(buf = format!("{:?}", self.buf), "found a duplicating line");
|
||||||
|
let start_line = self.data_idx;
|
||||||
|
while self.buf[0] == self.buf[1] && self.len == BYTES_PER_LINE {
|
||||||
|
self.rd_data(data)?;
|
||||||
|
}
|
||||||
|
self.display_buf += &format!(
|
||||||
|
"******** {LINE_SEP_VERT} {:<49}",
|
||||||
|
format!(
|
||||||
|
"(repeats {} lines)",
|
||||||
|
self.data_idx - start_line / (BYTES_PER_LINE) + 1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if self.chars {
|
||||||
|
self.display_buf += &format!("{LINE_SEP_VERT}");
|
||||||
|
}
|
||||||
|
trace!(
|
||||||
|
buf = format!("{:X?}", self.buf),
|
||||||
|
"dumping buf after line skip"
|
||||||
|
);
|
||||||
|
self.alt_buf ^= 1; // read into the other buf, so we can check for sameness
|
||||||
|
self.display();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn dump(&mut self, data: &mut dyn DataSource) -> Result<()> {
|
||||||
|
// skip a given number of bytes
|
||||||
|
if self.skip > 0 {
|
||||||
|
data.skip(self.skip)?;
|
||||||
|
self.rd_counter += self.skip;
|
||||||
|
debug!(
|
||||||
|
data_idx = self.data_idx,
|
||||||
|
"Skipped {}",
|
||||||
|
humanbytes(self.skip)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the head
|
||||||
|
self.display_buf += &format!("DATA IDX {LINE_SEP_VERT} DATA AS HEX");
|
||||||
|
if self.chars {
|
||||||
|
self.display_buf += &format!("{:width$} {LINE_SEP_VERT} DATA AS CHAR", "", width = 37);
|
||||||
|
}
|
||||||
|
self.display();
|
||||||
|
self.sep();
|
||||||
|
|
||||||
|
// data dump loop
|
||||||
|
self.rd_data(data)?;
|
||||||
|
self.data_idx = 0;
|
||||||
|
while self.len > 0 || self.first_iter {
|
||||||
|
self.first_iter = false;
|
||||||
|
|
||||||
|
self.dump_a_line();
|
||||||
|
|
||||||
|
// loop breaker logic
|
||||||
|
if self.stop || self.len < BYTES_PER_LINE {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.rd_data(data)?;
|
||||||
|
|
||||||
|
// after line logic
|
||||||
|
if self.buf[0] == self.buf[1] && self.len == BYTES_PER_LINE && !self.show_identical {
|
||||||
|
self.skip_lines(data)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.data_idx += BYTES_PER_LINE;
|
||||||
|
|
||||||
|
self.sep();
|
||||||
|
self.display_buf += &format!(
|
||||||
|
"{:08X} {LINE_SEP_VERT} read total:\t\t {:<8} {:<15}",
|
||||||
|
self.rd_counter,
|
||||||
|
humanbytes(self.rd_counter),
|
||||||
|
format!("({} B)", self.rd_counter)
|
||||||
|
);
|
||||||
|
if self.chars {
|
||||||
|
self.display_buf += &format!("{LINE_SEP_VERT}");
|
||||||
|
}
|
||||||
|
self.display();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn adjust_counters(&mut self) {
|
||||||
|
self.rd_counter += self.len;
|
||||||
|
self.data_idx += self.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rd_data(&mut self, data: &mut dyn DataSource) -> Result<()> {
|
||||||
|
match data.read(&mut self.buf[self.alt_buf]) {
|
||||||
|
Ok(mut len) => {
|
||||||
|
if self.limit != 0 && self.rd_counter + (BYTES_PER_LINE - 1) >= self.limit {
|
||||||
|
len = self.limit % BYTES_PER_LINE;
|
||||||
|
self.stop = true;
|
||||||
|
}
|
||||||
|
self.len = len;
|
||||||
|
self.adjust_counters();
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("error while reading data: {err}");
|
||||||
|
bail!(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DataSource: Read {
|
||||||
|
fn skip(&mut self, length: usize) -> std::io::Result<()>;
|
||||||
|
}
|
||||||
|
impl DataSource for std::io::Stdin {
|
||||||
|
fn skip(&mut self, _length: usize) -> std::io::Result<()> {
|
||||||
|
warn!("can't skip bytes for the stdin!");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl DataSource for std::fs::File {
|
||||||
|
fn skip(&mut self, length: usize) -> std::io::Result<()> {
|
||||||
|
self.seek(SeekFrom::Current(length as i64))?;
|
||||||
|
// returns the new position from the start, we don't need it here.
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mask_chars(c: char) -> char {
|
||||||
|
if c.is_ascii_graphic() {
|
||||||
|
return c;
|
||||||
|
} else if c == '\n' {
|
||||||
|
return '↩';
|
||||||
|
} else if c == ' ' {
|
||||||
|
return '␣';
|
||||||
|
} else if c == '\t' {
|
||||||
|
return '⭾';
|
||||||
|
} else {
|
||||||
|
return '<27>';
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,3 +25,4 @@ pub const YOBI: u128 = 2u128.pow(80);
|
||||||
// use libpt_core;
|
// use libpt_core;
|
||||||
pub mod datalayout;
|
pub mod datalayout;
|
||||||
pub mod display;
|
pub mod display;
|
||||||
|
pub mod hedu;
|
||||||
|
|
|
@ -2,6 +2,6 @@ use libpt_bintols::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mkdmp() {
|
fn mkdmp() {
|
||||||
let v = [true, true, false];
|
let v = vec![true, true, false];
|
||||||
investigate_memory_layout!(bool, v);
|
investigate_memory_layout!(bool, v);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "libpt-core"
|
name = "libpt-core"
|
||||||
publish.workspace = true
|
publish.workspace = true
|
||||||
version = "0.3.12"
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
|
@ -6,7 +6,33 @@
|
||||||
//! This crate implements core functionality useful for many use cases, such as macros,
|
//! This crate implements core functionality useful for many use cases, such as macros,
|
||||||
//! formatting functions and more.
|
//! formatting functions and more.
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// macros to make things faster in your code
|
/// macros to make things faster in your code
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
/// some general use printing to stdout tools
|
/// some general use printing to stdout tools
|
||||||
pub mod printing;
|
pub mod printing;
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -2,14 +2,33 @@
|
||||||
//!
|
//!
|
||||||
//! This module implements macros for use with `libpt`.
|
//! This module implements macros for use with `libpt`.
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
pub use crate::get_stdout_for;
|
pub use crate::get_stdout_for;
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// ## catches what the expression would write to the `stdout`
|
/// ## catches what the expression would write to the `stdout`
|
||||||
///
|
///
|
||||||
/// This macro takes an expression, executes it, and catches what it would write to the stdout.
|
/// This macro takes an expression, executes it, and catches what it would write to the stdout.
|
||||||
/// The buffer of the stdout will then be returned for further use.
|
/// The buffer of the stdout will then be returned for further use.
|
||||||
///
|
///
|
||||||
/// This is especially useful when testing loggers or other frontend CLI functions.
|
/// This is especially useful when testing loggers or other frontend CLI functions.
|
||||||
|
///
|
||||||
|
/// Inspiration: [users.rust-lang.org](https://users.rust-lang.org/t/how-to-test-functions-that-use-println/67188/5)
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! get_stdout_for {
|
macro_rules! get_stdout_for {
|
||||||
($test:expr) => {{
|
($test:expr) => {{
|
||||||
|
@ -27,3 +46,13 @@ macro_rules! get_stdout_for {
|
||||||
output
|
output
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1,11 +1,49 @@
|
||||||
//! # tools that make printing stuff better
|
//! # tools that make printing stuff better
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// reimport our macros to this module, so the user does not get confused when importing the macros
|
||||||
|
pub use crate::divider;
|
||||||
|
pub use crate::print_divider;
|
||||||
|
|
||||||
|
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// Quickly get a one line visual divider
|
/// Quickly get a one line visual divider
|
||||||
pub fn divider() -> String {
|
#[macro_export]
|
||||||
format!("{:=^80}", "=")
|
macro_rules! divider {
|
||||||
|
() => {{
|
||||||
|
format!("{:=^80}", "=")
|
||||||
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// Quickly print a one line visual divider
|
/// Quickly print a one line visual divider
|
||||||
pub fn print_divider() {
|
#[macro_export]
|
||||||
println!("{:=^80}", "=")
|
macro_rules! print_divider {
|
||||||
|
() => {{
|
||||||
|
println!("{}", divider!())
|
||||||
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "libpt-log"
|
name = "libpt-log"
|
||||||
publish.workspace = true
|
publish.workspace = true
|
||||||
version = "0.3.12"
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
|
@ -2,22 +2,70 @@
|
||||||
//!
|
//!
|
||||||
//! This module handles errors in logging contexts.
|
//! This module handles errors in logging contexts.
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
use anyhow;
|
use anyhow;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tracing::subscriber::SetGlobalDefaultError;
|
use tracing::subscriber::SetGlobalDefaultError;
|
||||||
|
|
||||||
|
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// ## Errors for the [Logger](super::Logger)
|
/// ## Errors for the [Logger](super::Logger)
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Bad IO operation
|
/// Bad IO operation
|
||||||
#[error("Bad IO operation")]
|
#[error("Bad IO operation")]
|
||||||
IO(#[from] std::io::Error),
|
IO(std::io::Error),
|
||||||
/// Various errors raised when the messenger is used in a wrong way
|
/// Various errors raised when the messenger is used in a wrong way
|
||||||
#[error("Bad usage")]
|
#[error("Bad usage")]
|
||||||
Usage(String),
|
Usage(String),
|
||||||
/// Could not assign logger as the global default
|
/// Could not assign logger as the global default
|
||||||
#[error("Could not assign logger as global default")]
|
#[error("Could not assign as global default")] // TODO: make this more clear
|
||||||
SetGlobalDefaultFail(#[from] SetGlobalDefaultError),
|
SetGlobalDefaultFail(SetGlobalDefaultError),
|
||||||
/// any other error type, wrapped in [anyhow::Error](anyhow::Error)
|
|
||||||
#[error(transparent)]
|
|
||||||
Other(#[from] anyhow::Error),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl From<std::io::Error> for Error {
|
||||||
|
fn from(value: std::io::Error) -> Self {
|
||||||
|
Error::IO(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl From<SetGlobalDefaultError> for Error {
|
||||||
|
fn from(value: SetGlobalDefaultError) -> Self {
|
||||||
|
Error::SetGlobalDefaultFail(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl std::fmt::Debug for Error {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Error::IO(e) => write!(f, "<IO Error {e:?}>"),
|
||||||
|
Error::Usage(e) => write!(f, "<Usage Error {e:?}>"),
|
||||||
|
Error::SetGlobalDefaultFail(e) => write!(f, "<SetGlobalDefaultFail {e:?}>"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -14,8 +14,12 @@
|
||||||
//! - [`tracing_appender`]: Used to log to files
|
//! - [`tracing_appender`]: Used to log to files
|
||||||
//! - [`tracing_subscriber`]: Used to do actual logging, formatting, to stdout
|
//! - [`tracing_subscriber`]: Used to do actual logging, formatting, to stdout
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
|
ops::Deref,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
};
|
};
|
||||||
|
@ -24,34 +28,55 @@ pub mod error;
|
||||||
use error::*;
|
use error::*;
|
||||||
|
|
||||||
pub use tracing::{debug, error, info, trace, warn, Level};
|
pub use tracing::{debug, error, info, trace, warn, Level};
|
||||||
use tracing_appender::{self, non_blocking::NonBlocking};
|
use tracing_appender::{
|
||||||
use tracing_subscriber::fmt::{format::FmtSpan, time};
|
self,
|
||||||
|
non_blocking::{NonBlocking, WorkerGuard},
|
||||||
|
};
|
||||||
|
use tracing_subscriber::{
|
||||||
|
fmt::{
|
||||||
|
format::FmtSpan,
|
||||||
|
time::{self, FormatTime},
|
||||||
|
},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// The log level used when none is specified
|
/// The log level used when none is specified
|
||||||
pub const DEFAULT_LOG_LEVEL: Level = Level::INFO;
|
pub const DEFAULT_LOG_LEVEL: Level = Level::INFO;
|
||||||
/// The path where logs are stored when no path is given.
|
/// The path where logs are stored when no path is given.
|
||||||
///
|
///
|
||||||
/// Currently, this is `/dev/null`, meaning they will be written to the void = discarded.
|
/// Currently, this is `/dev/null`, meaning they will be written to the void = discarded.
|
||||||
pub const DEFAULT_LOG_DIR: &str = "/dev/null";
|
pub const DEFAULT_LOG_DIR: &'static str = "/dev/null";
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
static INITIALIZED: AtomicBool = AtomicBool::new(false);
|
static INITIALIZED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// ## Logger for [`pt`](../libpt/index.html)
|
/// ## Logger for [`pt`](../libpt/index.html)
|
||||||
///
|
///
|
||||||
/// This struct exists mainly for the python module, so that we can use the same logger with both
|
/// This struct exists mainly for the python module, so that we can use the same logger with both
|
||||||
/// python and rust.
|
/// python and rust.
|
||||||
pub struct Logger;
|
pub struct Logger;
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
/// ## Main implementation
|
/// ## Main implementation
|
||||||
impl Logger {
|
impl Logger {
|
||||||
|
/// ## create a `Logger`
|
||||||
|
///
|
||||||
|
/// Creates a new uninitialized [`Logger`] object.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let l = Logger {};
|
||||||
|
l
|
||||||
|
}
|
||||||
/// ## initializes the logger
|
/// ## initializes the logger
|
||||||
///
|
///
|
||||||
/// Will enable the logger to be used.
|
/// Will enable the logger to be used.
|
||||||
///
|
///
|
||||||
/// Assumes some defaults, use [`init_customized`](Self::init_customized) for more control
|
/// Assumes some defaults, use [`init_customized`](Self::init_customized) for more control
|
||||||
pub fn build(log_dir: Option<PathBuf>, max_level: Option<Level>, uptime: bool) -> Result<Self> {
|
pub fn init(log_dir: Option<PathBuf>, max_level: Option<Level>, uptime: bool) -> Result<()> {
|
||||||
Self::build_customized(
|
Self::init_customized(
|
||||||
log_dir.is_some(),
|
log_dir.is_some(),
|
||||||
log_dir.unwrap_or(PathBuf::from(DEFAULT_LOG_DIR)),
|
log_dir.unwrap_or(PathBuf::from(DEFAULT_LOG_DIR)),
|
||||||
true,
|
true,
|
||||||
|
@ -74,8 +99,8 @@ impl Logger {
|
||||||
/// useful in cases with only one sender to the logging framework.
|
/// useful in cases with only one sender to the logging framework.
|
||||||
///
|
///
|
||||||
/// Assumes some defaults, use [`init_customized`](Self::init_customized) for more control
|
/// Assumes some defaults, use [`init_customized`](Self::init_customized) for more control
|
||||||
pub fn build_mini(max_level: Option<Level>) -> Result<Self> {
|
pub fn init_mini(max_level: Option<Level>) -> Result<()> {
|
||||||
Self::build_customized(
|
Self::init_customized(
|
||||||
false,
|
false,
|
||||||
PathBuf::from(DEFAULT_LOG_DIR),
|
PathBuf::from(DEFAULT_LOG_DIR),
|
||||||
true,
|
true,
|
||||||
|
@ -92,12 +117,10 @@ impl Logger {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make the args a struct for easy access
|
|
||||||
//
|
|
||||||
/// ## initializes the logger
|
/// ## initializes the logger
|
||||||
///
|
///
|
||||||
/// Will enable the logger to be used.
|
/// Will enable the logger to be used.
|
||||||
pub fn build_customized(
|
pub fn init_customized(
|
||||||
log_to_file: bool,
|
log_to_file: bool,
|
||||||
log_dir: PathBuf,
|
log_dir: PathBuf,
|
||||||
ansi: bool,
|
ansi: bool,
|
||||||
|
@ -111,11 +134,11 @@ impl Logger {
|
||||||
pretty: bool,
|
pretty: bool,
|
||||||
show_time: bool,
|
show_time: bool,
|
||||||
uptime: bool, // uptime instead of system time
|
uptime: bool, // uptime instead of system time
|
||||||
) -> Result<Self> {
|
) -> Result<()> {
|
||||||
// only init if no init has been performed yet
|
// only init if no init has been performed yet
|
||||||
if INITIALIZED.load(Ordering::Relaxed) {
|
if INITIALIZED.load(Ordering::Relaxed) {
|
||||||
warn!("trying to reinitialize the logger, ignoring");
|
warn!("trying to reinitialize the logger, ignoring");
|
||||||
bail!(Error::Usage("logging is already initialized".to_string()));
|
bail!(Error::Usage(format!("logging is already initialized")));
|
||||||
}
|
}
|
||||||
let subscriber = tracing_subscriber::fmt::Subscriber::builder()
|
let subscriber = tracing_subscriber::fmt::Subscriber::builder()
|
||||||
.with_level(display_level)
|
.with_level(display_level)
|
||||||
|
@ -199,7 +222,7 @@ impl Logger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
INITIALIZED.store(true, Ordering::Relaxed);
|
INITIALIZED.store(true, Ordering::Relaxed);
|
||||||
Ok(Logger {})
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## logging at [`Level::ERROR`]
|
/// ## logging at [`Level::ERROR`]
|
||||||
|
@ -239,6 +262,7 @@ impl Logger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
impl fmt::Debug for Logger {
|
impl fmt::Debug for Logger {
|
||||||
/// ## DEBUG representation for [`Logger`]
|
/// ## DEBUG representation for [`Logger`]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
@ -250,7 +274,10 @@ impl fmt::Debug for Logger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
fn new_file_appender(log_dir: PathBuf) -> NonBlocking {
|
fn new_file_appender(log_dir: PathBuf) -> NonBlocking {
|
||||||
let file_appender = tracing_appender::rolling::daily(log_dir.clone(), "log");
|
let file_appender = tracing_appender::rolling::daily(log_dir.clone(), "log");
|
||||||
tracing_appender::non_blocking(file_appender).0
|
return tracing_appender::non_blocking(file_appender).0;
|
||||||
}
|
}
|
||||||
|
|
21
members/libpt-math/Cargo.toml
Normal file
21
members/libpt-math/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "libpt-math"
|
||||||
|
publish.workspace = true
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
description.workspace = true
|
||||||
|
readme.workspace = true
|
||||||
|
homepage.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
keywords.workspace = true
|
||||||
|
categories.workspace = true
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
num = "0.4.1"
|
||||||
|
num-traits = "0.2.16"
|
||||||
|
libpt-core = { workspace = true }
|
||||||
|
libpt-log = { workspace = true }
|
41
members/libpt-math/src/ccc/mod.rs
Normal file
41
members/libpt-math/src/ccc/mod.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
//! # Calculate expressions
|
||||||
|
//!
|
||||||
|
//! This crate is part of [`pt`](../libpt/index.html), but can also be used as a standalone
|
||||||
|
//! module.
|
||||||
|
//!
|
||||||
|
//! Calculate Calculations with your Calculator (`ccc`)
|
||||||
|
//!
|
||||||
|
//! This modules aim is to take a term of any kind ([String]) and calculate it's value, be it
|
||||||
|
//! variable based or a concrete numerical value. It implements different operators and
|
||||||
|
//! (mathematical) functions.
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
38
members/libpt-math/src/lib.rs
Normal file
38
members/libpt-math/src/lib.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//! # General Mathmatics functionalities
|
||||||
|
//!
|
||||||
|
//! This crate is part of [`pt`](../libpt/index.html), but can also be used as a standalone
|
||||||
|
//! module.
|
||||||
|
//!
|
||||||
|
//! This module is currently empty, but will contain many math functionalities in a future version.
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
pub mod ccc;
|
||||||
|
|
||||||
|
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
24
members/libpt-net/Cargo.toml
Normal file
24
members/libpt-net/Cargo.toml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
[package]
|
||||||
|
name = "libpt-net"
|
||||||
|
publish.workspace = true
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
description.workspace = true
|
||||||
|
readme.workspace = true
|
||||||
|
homepage.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
keywords.workspace = true
|
||||||
|
categories.workspace = true
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
humantime = "2.1.0"
|
||||||
|
libpt-core = { workspace = true }
|
||||||
|
libpt-log = { workspace = true }
|
||||||
|
libpt-math = { workspace = true }
|
||||||
|
reqwest = { version = "0.11.20", features = ["blocking"] }
|
||||||
|
serde = { version = "1.0.188", features = ["serde_derive"] }
|
||||||
|
serde_json = "1.0.107"
|
40
members/libpt-net/src/lib.rs
Normal file
40
members/libpt-net/src/lib.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//! # various networking tools
|
||||||
|
//!
|
||||||
|
//! This crate is part of [`pt`](../libpt/index.html), but can also be used as a standalone
|
||||||
|
//! module.
|
||||||
|
//!
|
||||||
|
//! The networking module contains various tools related to connections. For example, it contains a
|
||||||
|
//! tool that has the purpose to check if your connection is consistently available.
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// monitor your connection
|
||||||
|
pub mod monitoring;
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// how long to wait for a remove server to respond in ms
|
||||||
|
pub const DEFAULT_REQUEST_TIMEOUT: u64 = 2000;
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
33
members/libpt-net/src/monitoring/mod.rs
Normal file
33
members/libpt-net/src/monitoring/mod.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
//! # monitor your network
|
||||||
|
//!
|
||||||
|
//! This module offers functions to monitor your network.
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
pub mod uptime;
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
275
members/libpt-net/src/monitoring/uptime.rs
Normal file
275
members/libpt-net/src/monitoring/uptime.rs
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
//! # monitor your network uptime
|
||||||
|
//!
|
||||||
|
//! This method offers a way to monitor your networks/hosts uptime. This is achieved by making
|
||||||
|
//! HTTPS requests to a given list of
|
||||||
|
//!
|
||||||
|
//! Warning: This module is not unit tested.
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
use std::{fmt, time::Duration};
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
use libpt_log::*;
|
||||||
|
|
||||||
|
use reqwest;
|
||||||
|
|
||||||
|
use humantime::{format_duration, format_rfc3339};
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
|
use libpt_core::divider;
|
||||||
|
|
||||||
|
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// urls used for checking by default
|
||||||
|
pub const DEFAULT_CHECK_URLS: &'static [&'static str] =
|
||||||
|
&["https://www.cscherr.de", "https://www.cloudflare.com"];
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// ## Describes an uptime status
|
||||||
|
///
|
||||||
|
/// [`UptimeStatus`] describes the result of an uptime check.
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct UptimeStatus {
|
||||||
|
/// true if the [`UptimeStatus`] is considered successful
|
||||||
|
pub success: bool,
|
||||||
|
/// the percentage of reachable urls out of the total urls
|
||||||
|
pub success_ratio: u8,
|
||||||
|
/// the percentage of reachable urls out of the total urls that need to be reachable in order
|
||||||
|
/// for this [`UptimeStatus`] to be considered a success.
|
||||||
|
pub success_ratio_target: u8,
|
||||||
|
/// the number of reachable [`urls`](UptimeStatus::urls)
|
||||||
|
pub reachable: usize,
|
||||||
|
/// which urls to check in [`check()`](UptimeStatus::check)
|
||||||
|
pub urls: Vec<String>,
|
||||||
|
/// timeout length for requests (in ms)
|
||||||
|
pub timeout: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Main implementation
|
||||||
|
impl UptimeStatus {
|
||||||
|
/// ## create a new `UptimeStatus` and perform it's check
|
||||||
|
pub fn new(success_ratio_target: u8, urls: Vec<String>, timeout: u64) -> Self {
|
||||||
|
assert!(success_ratio_target <= 100);
|
||||||
|
let mut status = UptimeStatus {
|
||||||
|
success: false,
|
||||||
|
success_ratio: 0,
|
||||||
|
success_ratio_target,
|
||||||
|
reachable: 0,
|
||||||
|
urls,
|
||||||
|
timeout,
|
||||||
|
};
|
||||||
|
status.urls.dedup();
|
||||||
|
|
||||||
|
status.check();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## check for success with the given urls
|
||||||
|
///
|
||||||
|
/// Makes the actual https requests and updates fields accordingly.
|
||||||
|
///
|
||||||
|
/// Note: Blocking execution for all requests, timeout is set to
|
||||||
|
/// [REQUEST_TIMEOUT](crate::networking::REQUEST_TIMEOUT).
|
||||||
|
pub fn check(&mut self) {
|
||||||
|
self.reachable = 0;
|
||||||
|
self.urls.iter().for_each(|url| {
|
||||||
|
let client = reqwest::blocking::Client::builder()
|
||||||
|
.timeout(Duration::from_millis(self.timeout))
|
||||||
|
.build()
|
||||||
|
.expect("could not build a client for https requests");
|
||||||
|
let response = client.get(url.clone()).send();
|
||||||
|
if response.is_ok() {
|
||||||
|
self.reachable += 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.calc_success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## calculate the success based on the `reachable` and `total`
|
||||||
|
///
|
||||||
|
/// Calculates the ratio of [`reachable`](UptimeStatus::reachable) /
|
||||||
|
/// (length of [urls](UptimeStatus::urls)).
|
||||||
|
///
|
||||||
|
/// Calculates a [`success_ratio`](UptimeStatus::success_ratio) (as [u8]) from that,
|
||||||
|
/// by multiplying with 100, then flooring.
|
||||||
|
///
|
||||||
|
/// If the [`success_ratio`](UptimeStatus::success_ratio) is greater than or equal to the
|
||||||
|
/// [`success_ratio_target`](UptimeStatus::success_ratio_target), the [`UptimeStatus`] will be
|
||||||
|
/// considered a success.
|
||||||
|
///
|
||||||
|
/// In the special case that no URLs to check for have been provided, the check will be
|
||||||
|
/// considered a success, but the [`success_ratio`](UptimeStatus::success_ratio) will be `0`.
|
||||||
|
///
|
||||||
|
/// Note: does not check for networking, use [`check()`](UptimeStatus::check) for that.
|
||||||
|
pub fn calc_success(&mut self) {
|
||||||
|
// if no urls need to be checked, success without checking
|
||||||
|
if self.urls.len() == 0 {
|
||||||
|
self.success = true;
|
||||||
|
self.success_ratio = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let ratio: f32 = (self.reachable as f32) / (self.urls.len() as f32) * 100f32;
|
||||||
|
trace!("calculated success_ratio: {}", ratio);
|
||||||
|
self.success_ratio = ratio.floor() as u8;
|
||||||
|
self.success = self.success_ratio >= self.success_ratio_target;
|
||||||
|
trace!("calculated success as: {}", self.success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl fmt::Debug for UptimeStatus {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut urls: Vec<&str> = Vec::new();
|
||||||
|
for url in &self.urls {
|
||||||
|
urls.push(url.as_str());
|
||||||
|
}
|
||||||
|
write!(f, "{}", serde_json::to_string(self).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
impl fmt::Display for UptimeStatus {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut urls: Vec<&str> = Vec::new();
|
||||||
|
for url in &self.urls {
|
||||||
|
urls.push(url.as_str());
|
||||||
|
}
|
||||||
|
write!(f, "{}", serde_json::to_string_pretty(self).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// ## Uptime monitor
|
||||||
|
///
|
||||||
|
/// This function continuously monitors the uptime of your host/network.
|
||||||
|
///
|
||||||
|
/// On change of status, an update will be logged at [INFO Level](log::Level::Info), containing
|
||||||
|
/// information on your current status, including timestamps of the last up/down time and durations
|
||||||
|
/// since.
|
||||||
|
pub fn continuous_uptime_monitor(
|
||||||
|
success_ratio_target: u8,
|
||||||
|
urls: Vec<String>,
|
||||||
|
interval: u64,
|
||||||
|
timeout: u64,
|
||||||
|
) {
|
||||||
|
if urls.len() == 0 {
|
||||||
|
error!("No URLs provided. There is nothing to monitor.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let interval = std::time::Duration::from_millis(interval);
|
||||||
|
let mut last_downtime: Option<SystemTime> = None;
|
||||||
|
let mut last_uptime: Option<SystemTime> = None;
|
||||||
|
let mut status = UptimeStatus::new(success_ratio_target, urls, timeout);
|
||||||
|
// we assume that the last status was up, so the binary shows the first status if its a
|
||||||
|
// failure.
|
||||||
|
let mut last_was_up: bool = true;
|
||||||
|
let mut last_ratio: u8 = status.success_ratio;
|
||||||
|
loop {
|
||||||
|
trace!(
|
||||||
|
?status,
|
||||||
|
?last_was_up,
|
||||||
|
"loop iteration for continuous uptime monitor"
|
||||||
|
);
|
||||||
|
if !status.success {
|
||||||
|
if last_was_up {
|
||||||
|
trace!("displaying status");
|
||||||
|
display_uptime_status("fail", last_uptime, last_downtime, &status)
|
||||||
|
}
|
||||||
|
last_downtime = Some(SystemTime::now());
|
||||||
|
last_was_up = false;
|
||||||
|
} else if status.success_ratio < 100 {
|
||||||
|
if status.success_ratio != last_ratio {
|
||||||
|
let msg = format!(
|
||||||
|
"uptime check: not all urls are reachable ({}%)",
|
||||||
|
status.success_ratio
|
||||||
|
);
|
||||||
|
display_uptime_status(&msg, last_uptime, last_downtime, &status)
|
||||||
|
}
|
||||||
|
last_uptime = Some(SystemTime::now());
|
||||||
|
last_was_up = true;
|
||||||
|
} else {
|
||||||
|
if !last_was_up {
|
||||||
|
display_uptime_status("success", last_uptime, last_downtime, &status)
|
||||||
|
}
|
||||||
|
last_uptime = Some(SystemTime::now());
|
||||||
|
last_was_up = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_ratio = status.success_ratio;
|
||||||
|
std::thread::sleep(interval);
|
||||||
|
status.check();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Displays the current status for the [continuous uptime monitor](continuous_uptime_monitor)
|
||||||
|
fn display_uptime_status(
|
||||||
|
msg: &str,
|
||||||
|
last_uptime: Option<SystemTime>,
|
||||||
|
last_downtime: Option<SystemTime>,
|
||||||
|
status: &UptimeStatus,
|
||||||
|
) {
|
||||||
|
// I know it's weird that this has two spaces too much, but somehow just the tabs is missing
|
||||||
|
// two spaces.
|
||||||
|
info!("uptime check: {}", msg);
|
||||||
|
info!("last uptime: {}", match_format_time(last_uptime));
|
||||||
|
info!("last downtime: {}", match_format_time(last_downtime));
|
||||||
|
info!(
|
||||||
|
"since downtime: {}",
|
||||||
|
match_format_duration_since(last_downtime)
|
||||||
|
);
|
||||||
|
info!(
|
||||||
|
"since uptime: {}",
|
||||||
|
match_format_duration_since(last_uptime)
|
||||||
|
);
|
||||||
|
debug!("\n{}", status);
|
||||||
|
info!("{}", divider!());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Returns "None" if the given [Option] is [None](Option::None). Otherwise, returns the time stamp
|
||||||
|
/// formatted according to rfc3999.
|
||||||
|
fn match_format_time(time: Option<SystemTime>) -> String {
|
||||||
|
match time {
|
||||||
|
Some(time) => format_rfc3339(time).to_string(),
|
||||||
|
None => String::from("None"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Returns "None" if the given [Option] is [None](Option::None). Otherwise, returns duration since
|
||||||
|
/// that time in a human readable format.
|
||||||
|
fn match_format_duration_since(time: Option<SystemTime>) -> String {
|
||||||
|
match time {
|
||||||
|
Some(time) => format_duration(
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(time)
|
||||||
|
.expect("could not calculate elapsed time"),
|
||||||
|
)
|
||||||
|
.to_string(),
|
||||||
|
None => String::from("None"),
|
||||||
|
}
|
||||||
|
}
|
72
members/libpt-py/.gitignore
vendored
72
members/libpt-py/.gitignore
vendored
|
@ -1,72 +0,0 @@
|
||||||
/target
|
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
|
||||||
.pytest_cache/
|
|
||||||
*.py[cod]
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
.venv/
|
|
||||||
env/
|
|
||||||
bin/
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
include/
|
|
||||||
man/
|
|
||||||
venv/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
pip-selfcheck.json
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.coverage
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
|
|
||||||
# Mr Developer
|
|
||||||
.mr.developer.cfg
|
|
||||||
.project
|
|
||||||
.pydevproject
|
|
||||||
|
|
||||||
# Rope
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyCharm
|
|
||||||
.idea/
|
|
||||||
|
|
||||||
# VSCode
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
# Pyenv
|
|
||||||
.python-version
|
|
|
@ -1,23 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "libpt-py"
|
|
||||||
version.workspace = true
|
|
||||||
edition.workspace = true
|
|
||||||
|
|
||||||
[package.metadata.maturin]
|
|
||||||
name = "libpt"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
[lib]
|
|
||||||
crate-type = ["cdylib", "rlib"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
libpt = { version = "0.4.0-alpha.1", path = "../.." }
|
|
||||||
pyo3 = { version = "0.19.0", features = ["full"] }
|
|
||||||
anyhow.workspace = true
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["log", "core", "full"]
|
|
||||||
core = []
|
|
||||||
full = ["default", "core", "log", "bintols"]
|
|
||||||
log = ["libpt/log"]
|
|
||||||
bintols = ["libpt/bintols", "log"]
|
|
|
@ -1,16 +0,0 @@
|
||||||
[build-system]
|
|
||||||
requires = ["maturin>=1.4,<2.0"]
|
|
||||||
build-backend = "maturin"
|
|
||||||
|
|
||||||
[project]
|
|
||||||
name = "libpt"
|
|
||||||
requires-python = ">=3.8"
|
|
||||||
classifiers = [
|
|
||||||
"Programming Language :: Rust",
|
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
|
||||||
]
|
|
||||||
dynamic = ["version"]
|
|
||||||
|
|
||||||
[tool.maturin]
|
|
||||||
features = ["pyo3/extension-module"]
|
|
|
@ -1,56 +0,0 @@
|
||||||
use pyo3::prelude::*;
|
|
||||||
|
|
||||||
use libpt::bintols as origin;
|
|
||||||
|
|
||||||
mod display {
|
|
||||||
use pyo3::prelude::*;
|
|
||||||
|
|
||||||
use libpt::bintols::display as origin;
|
|
||||||
|
|
||||||
#[pyfunction]
|
|
||||||
pub fn bytes_to_bin(data: &[u8]) -> String {
|
|
||||||
origin::bytes_to_bin(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyfunction]
|
|
||||||
pub fn byte_bit_display(data: usize) -> String {
|
|
||||||
origin::byte_bit_display(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyfunction]
|
|
||||||
pub fn humanbytes(total: u128) -> String {
|
|
||||||
origin::humanbytes(total)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// implement a python module in Rust
|
|
||||||
pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> {
|
|
||||||
let module = PyModule::new(py, "display")?;
|
|
||||||
|
|
||||||
module.add_function(wrap_pyfunction!(bytes_to_bin, module)?)?;
|
|
||||||
module.add_function(wrap_pyfunction!(byte_bit_display, module)?)?;
|
|
||||||
module.add_function(wrap_pyfunction!(humanbytes, module)?)?;
|
|
||||||
|
|
||||||
parent.add_submodule(module)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// implement a python module in Rust
|
|
||||||
pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> {
|
|
||||||
let module = PyModule::new(py, "bintols")?;
|
|
||||||
|
|
||||||
// binary constants
|
|
||||||
module.add("KIBI", origin::KIBI)?;
|
|
||||||
module.add("MEBI", origin::MEBI)?;
|
|
||||||
module.add("GIBI", origin::GIBI)?;
|
|
||||||
module.add("TEBI", origin::TEBI)?;
|
|
||||||
module.add("PEBI", origin::PEBI)?;
|
|
||||||
module.add("EXBI", origin::EXBI)?;
|
|
||||||
module.add("ZEBI", origin::ZEBI)?;
|
|
||||||
module.add("YOBI", origin::YOBI)?;
|
|
||||||
|
|
||||||
display::submodule(py, module)?;
|
|
||||||
|
|
||||||
parent.add_submodule(module)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
use pyo3::prelude::*;
|
|
||||||
|
|
||||||
mod printing;
|
|
||||||
|
|
||||||
/// implement a python module in Rust
|
|
||||||
pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> {
|
|
||||||
let module = PyModule::new(py, "core")?;
|
|
||||||
printing::submodule(py, module)?;
|
|
||||||
parent.add_submodule(module)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
use pyo3::prelude::*;
|
|
||||||
|
|
||||||
use libpt::core::printing as origin;
|
|
||||||
|
|
||||||
/// Quickly get a one line visual divider
|
|
||||||
#[pyfunction]
|
|
||||||
pub fn divider() -> String {
|
|
||||||
origin::divider()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Quickly print a one line visual divider
|
|
||||||
#[pyfunction]
|
|
||||||
pub fn print_divider() {
|
|
||||||
origin::print_divider()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// implement a python module in Rust
|
|
||||||
pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> {
|
|
||||||
let module = PyModule::new(py, "printing")?;
|
|
||||||
module.add_function(wrap_pyfunction!(divider, module)?)?;
|
|
||||||
module.add_function(wrap_pyfunction!(print_divider, module)?)?;
|
|
||||||
parent.add_submodule(module)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
//! Python bindings for [`libpt`](libpt)
|
|
||||||
|
|
||||||
#[cfg(feature = "bintols")]
|
|
||||||
mod bintols;
|
|
||||||
#[cfg(feature = "core")]
|
|
||||||
mod core;
|
|
||||||
#[cfg(feature = "log")]
|
|
||||||
mod log;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
|
||||||
|
|
||||||
/// return the version of libpt
|
|
||||||
#[pyfunction]
|
|
||||||
fn version() -> String {
|
|
||||||
env!("CARGO_PKG_VERSION").to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// implement a python module in Rust
|
|
||||||
#[pymodule]
|
|
||||||
#[pyo3(name = "libpt")]
|
|
||||||
fn libpt_py(py: Python, m: &PyModule) -> PyResult<()> {
|
|
||||||
m.add_function(wrap_pyfunction!(version, m)?)?;
|
|
||||||
#[cfg(feature = "core")]
|
|
||||||
core::submodule(py, m)?;
|
|
||||||
#[cfg(feature = "log")]
|
|
||||||
log::submodule(py, m)?;
|
|
||||||
#[cfg(feature = "bintols")]
|
|
||||||
bintols::submodule(py, m)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
|
||||||
|
|
||||||
use libpt::log as origin;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
#[pyclass]
|
|
||||||
pub enum Level {
|
|
||||||
Error,
|
|
||||||
Warn,
|
|
||||||
Info,
|
|
||||||
Debug,
|
|
||||||
Trace,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Level> for origin::Level {
|
|
||||||
fn from(value: Level) -> Self {
|
|
||||||
match value {
|
|
||||||
Level::Error => origin::Level::ERROR,
|
|
||||||
Level::Warn => origin::Level::WARN,
|
|
||||||
Level::Info => origin::Level::INFO,
|
|
||||||
Level::Debug => origin::Level::DEBUG,
|
|
||||||
Level::Trace => origin::Level::TRACE,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyclass]
|
|
||||||
pub struct Logger {
|
|
||||||
inner: origin::Logger,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<origin::Logger> for Logger {
|
|
||||||
fn from(inner: origin::Logger) -> Self {
|
|
||||||
Self { inner }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pymethods]
|
|
||||||
impl Logger {
|
|
||||||
#[new]
|
|
||||||
pub fn build(
|
|
||||||
log_dir: Option<PathBuf>,
|
|
||||||
max_level: Option<Level>,
|
|
||||||
uptime: Option<bool>,
|
|
||||||
) -> anyhow::Result<Self> {
|
|
||||||
// concert our wrapper type
|
|
||||||
let max_level = max_level.map(origin::Level::from);
|
|
||||||
Ok(origin::Logger::build(log_dir, max_level, uptime.unwrap_or(false))?.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ## logging at [`Level::ERROR`]
|
|
||||||
pub fn error(&self, printable: String) {
|
|
||||||
self.inner.error(printable)
|
|
||||||
}
|
|
||||||
/// ## logging at [`Level::WARN`]
|
|
||||||
pub fn warn(&self, printable: String) {
|
|
||||||
self.inner.warn(printable)
|
|
||||||
}
|
|
||||||
/// ## logging at [`Level::INFO`]
|
|
||||||
pub fn info(&self, printable: String) {
|
|
||||||
self.inner.info(printable)
|
|
||||||
}
|
|
||||||
/// ## logging at [`Level::DEBUG`]
|
|
||||||
pub fn debug(&self, printable: String) {
|
|
||||||
self.inner.debug(printable)
|
|
||||||
}
|
|
||||||
/// ## logging at [`Level::StringRACE`]
|
|
||||||
pub fn trace(&self, printable: String) {
|
|
||||||
self.inner.trace(printable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// implement a python module in Rust
|
|
||||||
pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> {
|
|
||||||
let module = PyModule::new(py, "log")?;
|
|
||||||
module.add_class::<Logger>()?;
|
|
||||||
parent.add_submodule(module)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ BODY="
|
||||||
$(git log $(git describe --tags --abbrev=0)..HEAD --pretty="- %s" --oneline --decorate)
|
$(git log $(git describe --tags --abbrev=0)..HEAD --pretty="- %s" --oneline --decorate)
|
||||||
"
|
"
|
||||||
USER=PlexSheep
|
USER=PlexSheep
|
||||||
git tag "v$NEW_VERSION" || echo "could not tag"
|
git tag "v$NEW_VERSION-test" || echo "could not tag"
|
||||||
curl -X 'POST' \
|
curl -X 'POST' \
|
||||||
'https://git.cscherr.de/api/v1/repos/PlexSheep/pt/releases' \
|
'https://git.cscherr.de/api/v1/repos/PlexSheep/pt/releases' \
|
||||||
-H 'accept: application/json' \
|
-H 'accept: application/json' \
|
||||||
|
|
104
src/ccc/mod.rs
Normal file
104
src/ccc/mod.rs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
//! # Executable for the math/compute submodule
|
||||||
|
//!
|
||||||
|
//! Calculate Calculations with your Computer!
|
||||||
|
//!
|
||||||
|
//! This command line tool allows you to input a mathematical expression. It will then process the
|
||||||
|
//! expression.
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
use libpt::log::*;
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use clap_verbosity_flag::{InfoLevel, Verbosity};
|
||||||
|
|
||||||
|
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// short about section displayed in help
|
||||||
|
const ABOUT_ROOT: &'static str = r##"
|
||||||
|
Calculate Calculations with your Computer
|
||||||
|
|
||||||
|
This commandline tool allows you to calculate complex mathematical expressions right in your
|
||||||
|
shell.
|
||||||
|
"##;
|
||||||
|
/// longer about section displayed in help, is combined with [the short help](ABOUT_ROOT)
|
||||||
|
static LONG_ABOUT_ROOT: &'static str = r##"
|
||||||
|
|
||||||
|
libpt is a personal general purpose library, offering this executable, a python module and a
|
||||||
|
dynamic library.
|
||||||
|
"##;
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// defines CLI interface
|
||||||
|
#[derive(Debug, Clone, Parser)]
|
||||||
|
#[command(
|
||||||
|
author,
|
||||||
|
version,
|
||||||
|
about = ABOUT_ROOT,
|
||||||
|
long_about = format!("{}{}", ABOUT_ROOT ,LONG_ABOUT_ROOT),
|
||||||
|
help_template =
|
||||||
|
r#"libpt: {version}{about-section}Author:
|
||||||
|
{author-with-newline}
|
||||||
|
{usage-heading} {usage}{all-args}{tab}"#
|
||||||
|
)]
|
||||||
|
pub struct Cli {
|
||||||
|
// clap_verbosity_flag seems to make this a global option implicitly
|
||||||
|
/// set a verbosity, multiple allowed (f.e. -vvv)
|
||||||
|
#[command(flatten)]
|
||||||
|
pub verbose: Verbosity<InfoLevel>,
|
||||||
|
|
||||||
|
/// show logger meta
|
||||||
|
#[arg(short, long, global = true)]
|
||||||
|
pub log_meta: bool,
|
||||||
|
|
||||||
|
/// your exporession(s)
|
||||||
|
#[clap(trailing_var_arg = true)]
|
||||||
|
pub expression: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
|
fn main() {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
let ll: Level = match cli.verbose.log_level().unwrap().as_str() {
|
||||||
|
"TRACE" => Level::TRACE,
|
||||||
|
"DEBUG" => Level::DEBUG,
|
||||||
|
"INFO" => Level::INFO,
|
||||||
|
"WARN" => Level::WARN,
|
||||||
|
"ERROR" => Level::ERROR,
|
||||||
|
_ => {
|
||||||
|
eprintln!("'{}' is not a valid loglevel", cli.verbose.to_string());
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if cli.log_meta {
|
||||||
|
Logger::init(None, Some(ll), false).expect("could not initialize Logger");
|
||||||
|
} else {
|
||||||
|
// less verbose version
|
||||||
|
Logger::init_mini(Some(ll)).expect("could not initialize Logger");
|
||||||
|
}
|
||||||
|
let mut expr: String = String::new();
|
||||||
|
for part in cli.expression {
|
||||||
|
expr += ∂
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
174
src/hedu/mod.rs
Normal file
174
src/hedu/mod.rs
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
//! # Executable for the hedu submodule
|
||||||
|
//!
|
||||||
|
//! Dump data to a fancy format.
|
||||||
|
|
||||||
|
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we want docs
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
// we want Debug everywhere.
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
// enable clippy's extra lints, the pedantic version
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
use libpt::{bintols::hedu::*, log::*};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use clap_verbosity_flag::{InfoLevel, Verbosity};
|
||||||
|
|
||||||
|
use std::{fs::File, io::IsTerminal, path::PathBuf};
|
||||||
|
|
||||||
|
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// short about section displayed in help
|
||||||
|
const ABOUT_ROOT: &'static str = r##"
|
||||||
|
Dumps data in fancy formats.
|
||||||
|
"##;
|
||||||
|
/// longer about section displayed in help, is combined with [the short help](ABOUT_ROOT)
|
||||||
|
static LONG_ABOUT_ROOT: &'static str = r##"
|
||||||
|
|
||||||
|
libpt is a personal general purpose library, offering this executable, a python module and a
|
||||||
|
dynamic library.
|
||||||
|
"##;
|
||||||
|
|
||||||
|
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// defines CLI interface
|
||||||
|
#[derive(Debug, Clone, Parser)]
|
||||||
|
#[command(
|
||||||
|
author,
|
||||||
|
version,
|
||||||
|
about = ABOUT_ROOT,
|
||||||
|
long_about = format!("{}{}", ABOUT_ROOT ,LONG_ABOUT_ROOT),
|
||||||
|
help_template =
|
||||||
|
r#"{about-section}
|
||||||
|
{usage-heading} {usage}
|
||||||
|
{all-args}{tab}
|
||||||
|
|
||||||
|
libpt: {version}
|
||||||
|
Author: {author-with-newline}
|
||||||
|
"#
|
||||||
|
)]
|
||||||
|
pub struct Cli {
|
||||||
|
// clap_verbosity_flag seems to make this a global option implicitly
|
||||||
|
/// set a verbosity, multiple allowed (f.e. -vvv)
|
||||||
|
#[command(flatten)]
|
||||||
|
pub verbose: Verbosity<InfoLevel>,
|
||||||
|
|
||||||
|
/// show additional logging meta data
|
||||||
|
#[arg(long)]
|
||||||
|
pub meta: bool,
|
||||||
|
|
||||||
|
/// show character representation
|
||||||
|
#[arg(short, long)]
|
||||||
|
pub chars: bool,
|
||||||
|
|
||||||
|
/// skip first N bytes
|
||||||
|
#[arg(short, long, default_value_t = 0)]
|
||||||
|
pub skip: usize,
|
||||||
|
|
||||||
|
/// only interpret N bytes (end after N)
|
||||||
|
#[arg(short, long, default_value_t = 0)]
|
||||||
|
pub limit: usize,
|
||||||
|
|
||||||
|
/// show identical lines
|
||||||
|
#[arg(short = 'i', long)]
|
||||||
|
pub show_identical: bool,
|
||||||
|
|
||||||
|
/// a data source, probably a file.
|
||||||
|
///
|
||||||
|
/// If left empty or set as "-", the program will read from stdin.
|
||||||
|
// TODO: take many sources #60
|
||||||
|
pub data_source: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
|
fn main() {
|
||||||
|
let mut cli = cli_parse();
|
||||||
|
let mut sources: Vec<Box<dyn DataSource>> = Vec::new();
|
||||||
|
if cli.data_source.len() > 0 && cli.data_source[0] != "-" {
|
||||||
|
for data_source in &cli.data_source {
|
||||||
|
let data_source: PathBuf = PathBuf::from(data_source);
|
||||||
|
if data_source.is_dir() {
|
||||||
|
warn!("Not a file {:?}, skipping", data_source);
|
||||||
|
// std::process::exit(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
trace!("Trying to open '{:?}'", data_source);
|
||||||
|
match File::open(&data_source) {
|
||||||
|
Ok(file) => sources.push(Box::new(file)),
|
||||||
|
Err(err) => {
|
||||||
|
error!("Could not open '{:?}': {err}", data_source);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
trace!("Trying to open stdin");
|
||||||
|
let stdin = std::io::stdin();
|
||||||
|
if stdin.is_terminal() {
|
||||||
|
warn!("Refusing to dump from interactive terminal");
|
||||||
|
std::process::exit(2)
|
||||||
|
}
|
||||||
|
// just for the little header
|
||||||
|
cli.data_source = Vec::new();
|
||||||
|
cli.data_source.push(format!("stdin"));
|
||||||
|
sources.push(Box::new(stdin));
|
||||||
|
}
|
||||||
|
for (i, source) in sources.iter_mut().enumerate() {
|
||||||
|
let mut config = Hedu::new(cli.chars, cli.skip, cli.show_identical, cli.limit);
|
||||||
|
// FIXME: find a better way to get the file name
|
||||||
|
// Currently, skipped sources make an extra newline here.
|
||||||
|
match config.chars {
|
||||||
|
false => {
|
||||||
|
println!("{:─^59}", format!(" {} ", cli.data_source[i]));
|
||||||
|
}
|
||||||
|
true => {
|
||||||
|
println!("{:─^80}", format!(" {} ", cli.data_source[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match config.dump(&mut **source) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(err) => {
|
||||||
|
error!("Could not dump data of file: {err}");
|
||||||
|
std::process::exit(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i < cli.data_source.len() - 1 {
|
||||||
|
config.newline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
fn cli_parse() -> Cli {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
let ll: Level = match cli.verbose.log_level().unwrap().as_str() {
|
||||||
|
"TRACE" => Level::TRACE,
|
||||||
|
"DEBUG" => Level::DEBUG,
|
||||||
|
"INFO" => Level::INFO,
|
||||||
|
"WARN" => Level::WARN,
|
||||||
|
"ERROR" => Level::ERROR,
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if cli.meta {
|
||||||
|
Logger::init(None, Some(ll), false).expect("could not initialize Logger");
|
||||||
|
} else {
|
||||||
|
// less verbose version
|
||||||
|
Logger::init_mini(Some(ll)).expect("could not initialize Logger");
|
||||||
|
}
|
||||||
|
return cli;
|
||||||
|
}
|
|
@ -8,9 +8,13 @@
|
||||||
|
|
||||||
#[cfg(feature = "bintols")]
|
#[cfg(feature = "bintols")]
|
||||||
pub use libpt_bintols as bintols;
|
pub use libpt_bintols as bintols;
|
||||||
|
#[cfg(feature = "ccc")]
|
||||||
|
pub use libpt_ccc as ccc;
|
||||||
#[cfg(feature = "core")]
|
#[cfg(feature = "core")]
|
||||||
pub use libpt_core as core;
|
pub use libpt_core as core;
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
pub use libpt_log as log;
|
pub use libpt_log as log;
|
||||||
#[cfg(feature = "py")]
|
#[cfg(feature = "math")]
|
||||||
pub use libpt_py as py;
|
pub use libpt_math as math;
|
||||||
|
#[cfg(feature = "net")]
|
||||||
|
pub use libpt_net as net;
|
||||||
|
|
Reference in a new issue