generated from PlexSheep/baserepo
Compare commits
33 commits
a63262825e
...
edcec991dc
Author | SHA1 | Date | |
---|---|---|---|
edcec991dc | |||
|
de9ef8d841 | ||
0155465332 | |||
521ae9a193 | |||
|
15687ca0d7 | ||
441669a2c3 | |||
b2435f3963 | |||
b58dc3dc44 | |||
|
747c3e6eac | ||
5b8753c45d | |||
aa560b0e05 | |||
39a21d64e9 | |||
0515e221f9 | |||
a9cf78ee0d | |||
|
66932f70a3 | ||
3f59e99b88 | |||
b7fbef73b4 | |||
|
b3e5a99718 | ||
eaea5ac1d7 | |||
6181f2bff8 | |||
43f27493b4 | |||
c85e785802 | |||
074dcf9c0f | |||
c679bed538 | |||
3e2ecf1189 | |||
50fea61bb0 | |||
9f393f0369 | |||
|
43ac1e3fb8 | ||
6dcc45d722 | |||
6330c3da48 | |||
0de0340f4e | |||
ceb8c98715 | |||
1bdef8c493 |
50 changed files with 650 additions and 1581 deletions
22
.gitea/workflows/cargo-publish.yaml
Normal file
22
.gitea/workflows/cargo-publish.yaml
Normal file
|
@ -0,0 +1,22 @@
|
|||
name: Cargo Check, Format, Fix, Test and publish
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
format:
|
||||
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:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cargo check --all-features --all-targets
|
||||
- run: rustup component add rustfmt
|
||||
- run: cargo fix --all-features --all-targets
|
||||
- run: cargo fmt --all
|
||||
- run: cargo test --all-features --all-targets
|
||||
- run: cargo publish --index "https://git.cscherr.de/PlexSheep/_cargo-index.git --dry-run
|
27
.gitea/workflows/cargo.yaml
Normal file
27
.gitea/workflows/cargo.yaml
Normal file
|
@ -0,0 +1,27 @@
|
|||
name: Cargo Check, Format, Fix and Test
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
format:
|
||||
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:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cargo check --all-features --all-targets
|
||||
- run: rustup component add rustfmt
|
||||
- run: cargo fix --all-features --all-targets
|
||||
- run: cargo fmt --all
|
||||
- run: cargo test --all-features --all-targets
|
||||
- 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
|
||||
commit_user_name: Gitea CI
|
||||
commit_user_email: noreply@cscherr.de
|
||||
commit_author: Gitea CI <noreply@cscherr.de>
|
||||
|
120
.github/workflows/CI.yml
vendored
120
.github/workflows/CI.yml
vendored
|
@ -1,120 +0,0 @@
|
|||
# This file is autogenerated by maturin v0.14.17
|
||||
# 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: --skip-existing *
|
88
Cargo.toml
88
Cargo.toml
|
@ -1,27 +1,19 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
".",
|
||||
"members/libpt-core",
|
||||
"members/libpt-bintols",
|
||||
"members/libpt-math",
|
||||
"members/libpt-bin",
|
||||
"members/libpt-log",
|
||||
"members/libpt-net",
|
||||
"members/libpt-py",
|
||||
"members/libpt-hedu",
|
||||
]
|
||||
default-members = [
|
||||
".",
|
||||
"members/libpt-bin",
|
||||
"members/libpt-core",
|
||||
"members/libpt-py",
|
||||
"members/libpt-log",
|
||||
"members/libpt-math",
|
||||
".",
|
||||
"members/libpt-core",
|
||||
"members/libpt-bintols",
|
||||
"members/libpt-math",
|
||||
"members/libpt-bin",
|
||||
"members/libpt-log",
|
||||
"members/libpt-net",
|
||||
"members/libpt-hedu",
|
||||
]
|
||||
default-members = [".", "members/libpt-bin", "members/libpt-core"]
|
||||
[workspace.package]
|
||||
publish = false
|
||||
version = "0.1.7"
|
||||
publish = true
|
||||
version = "0.2.4"
|
||||
edition = "2021"
|
||||
authors = ["Christoph J. Scherr <software@cscherr.de>"]
|
||||
license = "MIT"
|
||||
|
@ -29,15 +21,20 @@ description = "Personal multitool"
|
|||
readme = "README.md"
|
||||
homepage = "https://git.cscherr.de/PlexSheep/libpt"
|
||||
repository = "https://git.cscherr.de/PlexSheep/libpt"
|
||||
keywords = ["cli", "python", "scriptable", "pyo3", "library"]
|
||||
categories = ["command-line-utilities", "development-tools", "development-tools::ffi"]
|
||||
keywords = ["cli", "library"]
|
||||
categories = [
|
||||
"command-line-utilities",
|
||||
"development-tools",
|
||||
"development-tools::ffi",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
pyo3 = "0.19"
|
||||
anyhow = "1.0.79"
|
||||
thiserror = "1.0.56"
|
||||
|
||||
[package]
|
||||
name = "libpt"
|
||||
publish = true
|
||||
publish.workspace = true
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
|
@ -50,39 +47,32 @@ keywords.workspace = true
|
|||
categories.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["log"]
|
||||
all = [
|
||||
"default",
|
||||
"math",
|
||||
"log",
|
||||
"bintols",
|
||||
"net",
|
||||
"ccc",
|
||||
"hedu"
|
||||
]
|
||||
fw = []
|
||||
math = []
|
||||
log = []
|
||||
default = ["log", "core"]
|
||||
all = ["default", "math", "log", "bintols", "net", "ccc", "hedu", "core"]
|
||||
core = []
|
||||
fw = []
|
||||
math = []
|
||||
log = []
|
||||
bintols = []
|
||||
net = []
|
||||
ccc = ["math"]
|
||||
hedu = ["bintols"]
|
||||
net = []
|
||||
ccc = ["math"]
|
||||
hedu = ["bintols"]
|
||||
|
||||
[lib]
|
||||
name = "libpt"
|
||||
crate-type = [
|
||||
"dylib", # .dll, .so, .dynlib
|
||||
"staticlib", # .lib, .a
|
||||
"rlib"
|
||||
"dylib", # .dll, .so, .dynlib
|
||||
"staticlib", # .lib, .a
|
||||
"rlib",
|
||||
]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
libpt-bintols = { version = "0.1.7", path = "members/libpt-bintols" }
|
||||
libpt-core = { version = "0.1.7", path = "members/libpt-core" }
|
||||
libpt-hedu = { version = "0.1.7", path = "members/libpt-hedu" }
|
||||
libpt-log = { version = "0.1.7", path = "members/libpt-log" }
|
||||
libpt-math = { version = "0.1.7", path = "members/libpt-math" }
|
||||
libpt-net = { version = "0.1.7", path = "members/libpt-net" }
|
||||
libpt-ccc = { version = "0.1.7", path = "members/libpt-ccc" }
|
||||
libpt-bintols = { path = "members/libpt-bintols" }
|
||||
libpt-core = { path = "members/libpt-core" }
|
||||
libpt-hedu = { path = "members/libpt-hedu" }
|
||||
libpt-log = { path = "members/libpt-log" }
|
||||
libpt-math = { path = "members/libpt-math" }
|
||||
libpt-ccc = { path = "members/libpt-ccc" }
|
||||
libpt-net = { path = "members/libpt-net" }
|
||||
|
|
BIN
data/256B-zero-with-trash.img
Normal file
BIN
data/256B-zero-with-trash.img
Normal file
Binary file not shown.
BIN
data/256B-zero.img
Normal file
BIN
data/256B-zero.img
Normal file
Binary file not shown.
|
@ -19,6 +19,10 @@ categories.workspace = true
|
|||
name = "ccc"
|
||||
path = "src/ccc/mod.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "hedu"
|
||||
path = "src/hedu/mod.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "libpt"
|
||||
path = "src/main/mod.rs"
|
||||
|
@ -27,4 +31,4 @@ path = "src/main/mod.rs"
|
|||
clap = { version = "4.4.4", features = ["derive"] }
|
||||
clap-num = "1.0.2"
|
||||
clap-verbosity-flag = "2.0.1"
|
||||
libpt = { version = "0.1.7", path = "../..", features = ["ccc", "math", "hedu", "net"] }
|
||||
libpt = {path = "../..", features = ["default", "ccc", "math", "hedu", "net", "log"] }
|
||||
|
|
|
@ -15,13 +15,11 @@
|
|||
#![warn(clippy::pedantic)]
|
||||
|
||||
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
use libpt::ccc::*;
|
||||
|
||||
use libpt::log::*;
|
||||
|
||||
use clap::Parser;
|
||||
use clap_verbosity_flag::{Verbosity, InfoLevel};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use clap_verbosity_flag::{InfoLevel, Verbosity};
|
||||
|
||||
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -64,7 +62,7 @@ pub struct Cli {
|
|||
pub log_meta: bool,
|
||||
|
||||
/// your exporession(s)
|
||||
#[clap(trailing_var_arg=true)]
|
||||
#[clap(trailing_var_arg = true)]
|
||||
pub expression: Vec<String>,
|
||||
}
|
||||
|
||||
|
@ -93,49 +91,14 @@ fn main() {
|
|||
}
|
||||
};
|
||||
if cli.log_meta {
|
||||
Logger::init_customized(
|
||||
false,
|
||||
PathBuf::from("/dev/null"),
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
ll,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.expect("could not initialize Logger");
|
||||
Logger::init(None, Some(ll)).expect("could not initialize Logger");
|
||||
} else {
|
||||
// less verbose version
|
||||
Logger::init_customized(
|
||||
false,
|
||||
PathBuf::from("/dev/null"),
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
ll,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.expect("could not initialize Logger");
|
||||
Logger::init_mini(Some(ll)).expect("could not initialize Logger");
|
||||
}
|
||||
let mut expr: String = String::new();
|
||||
for part in cli.expression {
|
||||
expr += ∂
|
||||
}
|
||||
|
||||
debug!("exporssion: {}", expr);
|
||||
let r = Calculator::oneshot(expr);
|
||||
match r {
|
||||
Ok(r) => {
|
||||
println!("{r}");
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Could not compute: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
151
members/libpt-bin/src/hedu/mod.rs
Normal file
151
members/libpt-bin/src/hedu/mod.rs
Normal file
|
@ -0,0 +1,151 @@
|
|||
//! # 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::{hedu::*, log::*};
|
||||
|
||||
use clap::Parser;
|
||||
use clap_verbosity_flag::{InfoLevel, Verbosity};
|
||||
|
||||
use std::{fs::File, io::IsTerminal};
|
||||
|
||||
//// 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.
|
||||
pub data_source: Option<String>,
|
||||
}
|
||||
|
||||
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||
fn main() {
|
||||
let cli = cli_parse();
|
||||
let mut source: Box<dyn DataSource>;
|
||||
if cli.data_source.is_some() && cli.data_source.clone().is_some_and(|val| val != "-") {
|
||||
let data_source = cli.data_source.unwrap();
|
||||
trace!("Trying to open '{}'", data_source);
|
||||
source = match File::open(&data_source) {
|
||||
Ok(file) => Box::new(file),
|
||||
Err(err) => {
|
||||
error!("Could not open file '{}': {err}", data_source);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
trace!("Trying to open stdout");
|
||||
let stdin = std::io::stdin();
|
||||
if stdin.is_terminal() {
|
||||
warn!("Refusing to dump from interactive terminal");
|
||||
std::process::exit(2)
|
||||
}
|
||||
source = Box::new(stdin);
|
||||
}
|
||||
|
||||
match dump(
|
||||
&mut *source,
|
||||
HeduConfig::new(cli.chars, cli.skip, cli.show_identical, cli.limit),
|
||||
) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
error!("Could not dump data of file: {err}");
|
||||
std::process::exit(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
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)).expect("could not initialize Logger");
|
||||
} else {
|
||||
// less verbose version
|
||||
Logger::init_mini(Some(ll)).expect("could not initialize Logger");
|
||||
}
|
||||
return cli;
|
||||
}
|
|
@ -19,7 +19,7 @@ use clap::{Parser, Subcommand};
|
|||
|
||||
use clap_num::number_range;
|
||||
|
||||
use clap_verbosity_flag::{Verbosity, InfoLevel};
|
||||
use clap_verbosity_flag::{InfoLevel, Verbosity};
|
||||
|
||||
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||
/// short about section displayed in help
|
||||
|
@ -42,11 +42,11 @@ static LONG_ABOUT_ROOT: &'static str = r##"
|
|||
/// makes use of composition to build a complex system of commands, subcommands, flags and options.
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
#[command(
|
||||
author,
|
||||
version,
|
||||
about = ABOUT_ROOT,
|
||||
author,
|
||||
version,
|
||||
about = ABOUT_ROOT,
|
||||
long_about = format!("{}{}", ABOUT_ROOT ,LONG_ABOUT_ROOT),
|
||||
help_template =
|
||||
help_template =
|
||||
r#"libpt: {version}{about-section}Author:
|
||||
{author-with-newline}
|
||||
{usage-heading} {usage}{all-args}{tab}"#
|
||||
|
@ -103,13 +103,10 @@ pub enum NetCommands {
|
|||
|
||||
/// set a timeout (in ms)
|
||||
#[clap(short, long, default_value_t = 100)]
|
||||
timeout: u64
|
||||
|
||||
timeout: u64,
|
||||
},
|
||||
/// discover hosts in your network
|
||||
Discover {
|
||||
|
||||
}
|
||||
Discover {},
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
// enable clippy's extra lints, the pedantic version
|
||||
#![warn(clippy::pedantic)]
|
||||
|
||||
|
||||
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
use libpt::{log::*, net::monitoring::uptime};
|
||||
|
||||
|
@ -22,11 +21,8 @@ use clap::Parser;
|
|||
pub mod args;
|
||||
use args::*;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||
#[allow(dead_code)]
|
||||
|
||||
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -53,34 +49,10 @@ pub fn main() {
|
|||
}
|
||||
};
|
||||
if cli.log_meta {
|
||||
Logger::init_customized(
|
||||
false,
|
||||
PathBuf::from("/dev/null"),
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
ll,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.expect("could not initialize Logger");
|
||||
Logger::init(None, Some(ll)).expect("could not initialize Logger");
|
||||
} else {
|
||||
// less verbose version
|
||||
Logger::init_customized(
|
||||
false,
|
||||
PathBuf::from("/dev/null"),
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
ll,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.expect("could not initialize Logger");
|
||||
Logger::init_mini(Some(ll)).expect("could not initialize Logger");
|
||||
}
|
||||
|
||||
trace!("started the main function");
|
||||
|
|
|
@ -16,5 +16,5 @@ categories.workspace = true
|
|||
|
||||
[dependencies]
|
||||
num-traits = "0.2.16"
|
||||
libpt-core = { version = "0.1.0", path = "../libpt-core" }
|
||||
libpt-log = { version = "0.1.0", path = "../libpt-log" }
|
||||
libpt-core = { path = "../libpt-core" }
|
||||
libpt-log = { path = "../libpt-log" }
|
||||
|
|
|
@ -20,7 +20,8 @@ macro_rules! investigate_memory_layout {
|
|||
let pointer = item as *const $t;
|
||||
let mut memory: [u8; std::mem::size_of::<$t>()] = std::mem::transmute(item.clone());
|
||||
memory.reverse();
|
||||
println!("\
|
||||
println!(
|
||||
"\
|
||||
\t{index:02x}\titem:\t\t{item:?}\n\
|
||||
\t\tpointer: \t{:X?}\n\
|
||||
\t\talign: \t{}\n\
|
||||
|
|
|
@ -59,8 +59,7 @@ where
|
|||
return format!("{:.2} Z", total.to_f64().unwrap() / ZEBI as f64);
|
||||
} else if YOBI <= total {
|
||||
return format!("{:.2} Y", total.to_f64().unwrap() / YOBI as f64);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use libpt_bintols::*;
|
||||
use libpt_bintols::display::*;
|
||||
use libpt_bintols::*;
|
||||
|
||||
#[test]
|
||||
fn btobin() {
|
||||
|
@ -10,11 +10,16 @@ fn btobin() {
|
|||
|
||||
#[test]
|
||||
fn big_btobin() {
|
||||
let data = [12,31,82,32,123,32,92,23,12,32,12,1,1,1];
|
||||
let data = [12, 31, 82, 32, 123, 32, 92, 23, 12, 32, 12, 1, 1, 1];
|
||||
let r = bytes_to_bin(&data);
|
||||
assert_eq!(r, format!("0b00001100_00011111_01010010_\
|
||||
assert_eq!(
|
||||
r,
|
||||
format!(
|
||||
"0b00001100_00011111_01010010_\
|
||||
00100000_01111011_00100000_01011100_00010111_00001100\n\
|
||||
_00100000_00001100_00000001_00000001_00000001"));
|
||||
_00100000_00001100_00000001_00000001_00000001"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -26,38 +31,38 @@ fn bybit() {
|
|||
|
||||
#[test]
|
||||
fn hmnbytes() {
|
||||
assert_eq!(humanbytes(0), format!("0 B"));
|
||||
assert_eq!(humanbytes(1), format!("1 B"));
|
||||
assert_eq!(humanbytes(0), format!("0 B"));
|
||||
assert_eq!(humanbytes(1), format!("1 B"));
|
||||
|
||||
assert_eq!(humanbytes(KIBI-1), format!("1023 B"));
|
||||
assert_eq!(humanbytes(KIBI), format!("1.00 K"));
|
||||
assert_eq!(humanbytes(KIBI+1), format!("1.00 K"));
|
||||
assert_eq!(humanbytes(KIBI - 1), format!("1023 B"));
|
||||
assert_eq!(humanbytes(KIBI), format!("1.00 K"));
|
||||
assert_eq!(humanbytes(KIBI + 1), format!("1.00 K"));
|
||||
|
||||
assert_eq!(humanbytes(MEBI-1), format!("1024.00 K"));
|
||||
assert_eq!(humanbytes(MEBI), format!("1.00 M"));
|
||||
assert_eq!(humanbytes(MEBI+1), format!("1.00 M"));
|
||||
assert_eq!(humanbytes(MEBI - 1), format!("1024.00 K"));
|
||||
assert_eq!(humanbytes(MEBI), format!("1.00 M"));
|
||||
assert_eq!(humanbytes(MEBI + 1), format!("1.00 M"));
|
||||
|
||||
assert_eq!(humanbytes(GIBI-1), format!("1024.00 M"));
|
||||
assert_eq!(humanbytes(GIBI), format!("1.00 G"));
|
||||
assert_eq!(humanbytes(GIBI+1), format!("1.00 G"));
|
||||
assert_eq!(humanbytes(GIBI - 1), format!("1024.00 M"));
|
||||
assert_eq!(humanbytes(GIBI), format!("1.00 G"));
|
||||
assert_eq!(humanbytes(GIBI + 1), format!("1.00 G"));
|
||||
|
||||
assert_eq!(humanbytes(TEBI-1), format!("1024.00 G"));
|
||||
assert_eq!(humanbytes(TEBI), format!("1.00 T"));
|
||||
assert_eq!(humanbytes(TEBI+1), format!("1.00 T"));
|
||||
assert_eq!(humanbytes(TEBI - 1), format!("1024.00 G"));
|
||||
assert_eq!(humanbytes(TEBI), format!("1.00 T"));
|
||||
assert_eq!(humanbytes(TEBI + 1), format!("1.00 T"));
|
||||
|
||||
assert_eq!(humanbytes(PEBI-1), format!("1024.00 T"));
|
||||
assert_eq!(humanbytes(PEBI), format!("1.00 P"));
|
||||
assert_eq!(humanbytes(PEBI+1), format!("1.00 P"));
|
||||
assert_eq!(humanbytes(PEBI - 1), format!("1024.00 T"));
|
||||
assert_eq!(humanbytes(PEBI), format!("1.00 P"));
|
||||
assert_eq!(humanbytes(PEBI + 1), format!("1.00 P"));
|
||||
|
||||
assert_eq!(humanbytes(EXBI-1), format!("1024.00 P"));
|
||||
assert_eq!(humanbytes(EXBI), format!("1.00 E"));
|
||||
assert_eq!(humanbytes(EXBI+1), format!("1.00 E"));
|
||||
assert_eq!(humanbytes(EXBI - 1), format!("1024.00 P"));
|
||||
assert_eq!(humanbytes(EXBI), format!("1.00 E"));
|
||||
assert_eq!(humanbytes(EXBI + 1), format!("1.00 E"));
|
||||
|
||||
assert_eq!(humanbytes(ZEBI-1), format!("1024.00 E"));
|
||||
assert_eq!(humanbytes(ZEBI), format!("1.00 Z"));
|
||||
assert_eq!(humanbytes(ZEBI+1), format!("1.00 Z"));
|
||||
assert_eq!(humanbytes(ZEBI - 1), format!("1024.00 E"));
|
||||
assert_eq!(humanbytes(ZEBI), format!("1.00 Z"));
|
||||
assert_eq!(humanbytes(ZEBI + 1), format!("1.00 Z"));
|
||||
|
||||
assert_eq!(humanbytes(YOBI-1), format!("1024.00 Z"));
|
||||
assert_eq!(humanbytes(YOBI), format!("1.00 Y"));
|
||||
assert_eq!(humanbytes(YOBI+1), format!("1.00 Y"));
|
||||
assert_eq!(humanbytes(YOBI - 1), format!("1024.00 Z"));
|
||||
assert_eq!(humanbytes(YOBI), format!("1.00 Y"));
|
||||
assert_eq!(humanbytes(YOBI + 1), format!("1.00 Y"));
|
||||
}
|
||||
|
|
|
@ -17,6 +17,6 @@ categories.workspace = true
|
|||
[dependencies]
|
||||
num = "0.4.1"
|
||||
num-traits = "0.2.16"
|
||||
libpt-core = { version = "0.1.7", path = "../libpt-core" }
|
||||
libpt-log = { version = "0.1.7", path = "../libpt-log" }
|
||||
libpt-math = { version = "0.1.7", path = "../libpt-math" }
|
||||
libpt-core = { path = "../libpt-core" }
|
||||
libpt-log = { path = "../libpt-log" }
|
||||
libpt-math = { path = "../libpt-math" }
|
||||
|
|
|
@ -1,225 +0,0 @@
|
|||
//! # Results and Errors for the calculate module
|
||||
//!
|
||||
//! This module defines the errors and results that can be processed from any given term.
|
||||
|
||||
//// 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 std::fmt::Display;
|
||||
pub use num_traits::PrimInt;
|
||||
|
||||
#[allow(unused_imports)] // we possibly want to use all log levels
|
||||
use libpt_log::*;
|
||||
#[allow(unused_imports)] // import more complex math stuff from there
|
||||
use libpt_math;
|
||||
|
||||
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Quick Result with a ccc error
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// ## Supported Operations
|
||||
///
|
||||
/// This `enum` contains all operations supported in this module.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug)]
|
||||
pub enum Operator {
|
||||
/// Mathmatical addition
|
||||
Addition,
|
||||
/// Mathmatical subtraction
|
||||
Subtraction,
|
||||
/// Mathmatical multiplication
|
||||
Multiplication,
|
||||
/// Mathmatical division
|
||||
Division,
|
||||
/// Mathmatical modulo, finite field arithmetic
|
||||
Modulo,
|
||||
/// Any function, seel [`Function`]
|
||||
Function(Function)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// ## Supported Functions
|
||||
///
|
||||
/// This `enum` contains all functions supported in this module.
|
||||
///
|
||||
/// A function has a name followed by braces directly afterwards.
|
||||
/// A function may have 0 to 31 Arguments.
|
||||
///
|
||||
/// Example: `sqrt(19)`, `floor(19.9)`
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug)]
|
||||
pub enum Function {
|
||||
/// Draw the mathmatical root, attribute n is the nth root
|
||||
Root(u16),
|
||||
/// round up
|
||||
Floor,
|
||||
/// round down
|
||||
Ceil,
|
||||
/// round to nearest integer
|
||||
/// (commercial rounding)
|
||||
Round,
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Top Level Error Type
|
||||
///
|
||||
/// Contains many variants of other errors, that can occur when using the crate.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// The term has bad syntax
|
||||
SyntaxError(String)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Represents some kind of computed value
|
||||
#[derive(Debug)]
|
||||
pub enum Value {
|
||||
/// Variable value
|
||||
Variable(VarVal),
|
||||
/// Numerical value
|
||||
Numerical(NumVal),
|
||||
/// Complex number value
|
||||
Complex(ComplVal),
|
||||
}
|
||||
|
||||
/// Represents some kind of numeric value
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug)]
|
||||
pub enum NumVal {
|
||||
/// Value > 0
|
||||
Signed(i128),
|
||||
/// Value can be negative
|
||||
Unsigned(u128),
|
||||
/// Value is not an integer
|
||||
Float(f64)
|
||||
}
|
||||
|
||||
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Represents a Value with at least one variable,
|
||||
///
|
||||
/// currently not implemented
|
||||
#[derive(Debug)]
|
||||
pub struct VarVal {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Represents a Value with a complex number,
|
||||
///
|
||||
/// currently not implemented
|
||||
#[derive(Debug)]
|
||||
pub struct ComplVal {
|
||||
}
|
||||
|
||||
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||
impl<T: num_traits::PrimInt> From<T> for NumVal where
|
||||
u128: TryFrom<T>,
|
||||
u128: TryFrom<T> {
|
||||
fn from(value: T) -> Self {
|
||||
if T::min_value().is_zero() {
|
||||
// unsigned data types
|
||||
// `u128` is the largest unsigned datatype, any other type will fit.
|
||||
NumVal::Unsigned(value.to_u128().unwrap())
|
||||
}
|
||||
else {
|
||||
// signed data types
|
||||
// `i128` is the largest unsigned datatype, any other type will fit.
|
||||
NumVal::Signed(value.to_i128().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Display Errors with a nice little reason
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::SyntaxError(reason) => {
|
||||
write!(f, "Syntax Error: {}", reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl<T: PrimInt> From<T> for Value where
|
||||
u128: TryFrom<T>,
|
||||
u128: TryFrom<T> {
|
||||
fn from(value: T) -> Self {
|
||||
NumVal::from(value).into()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl From<NumVal> for Value {
|
||||
fn from(value: NumVal) -> Self {
|
||||
Value::Numerical(value)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl Display for Value {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Value::Numerical(val) => {
|
||||
write!(f, "{}", val)
|
||||
}
|
||||
Value::Complex(val) => {
|
||||
write!(f, "{}", val)
|
||||
}
|
||||
Value::Variable(val) => {
|
||||
write!(f, "{}", val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl Display for NumVal {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
NumVal::Float(val) => {
|
||||
write!(f, "{val}")
|
||||
}
|
||||
NumVal::Signed(val) => {
|
||||
write!(f, "{val}")
|
||||
}
|
||||
NumVal::Unsigned(val) => {
|
||||
write!(f, "{val}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl Display for ComplVal {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "")
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl Display for VarVal {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "")
|
||||
}
|
||||
}
|
||||
|
||||
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -19,14 +19,7 @@
|
|||
#![warn(clippy::pedantic)]
|
||||
|
||||
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
pub mod base;
|
||||
pub use base::{Error, Result, Value};
|
||||
pub mod term;
|
||||
pub use term::*;
|
||||
|
||||
#[allow(unused_imports)] // we possibly want to use all log levels
|
||||
use libpt_log::*;
|
||||
#[allow(unused_imports)] // import more complex math stuff from there
|
||||
use libpt_log;
|
||||
use libpt_math;
|
||||
|
||||
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -40,44 +33,8 @@ use libpt_math;
|
|||
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
/// ## A Calculator struct
|
||||
///
|
||||
/// This struct does not do anything at the moment, but aims to be the target for high level
|
||||
/// control. Instead of using the [`Calculator`], you could just use the [`Term`] struct for
|
||||
/// lower level control.
|
||||
#[derive(Debug)]
|
||||
pub struct Calculator;
|
||||
|
||||
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||
impl Calculator {
|
||||
/// Do a single calculation without doing anything else
|
||||
pub fn oneshot(t: String) -> Result<Value> {
|
||||
trace!(orig=t, "parsing original string to Term");
|
||||
let t = Term::new(t)?;
|
||||
trace!("term has been parsed, starting Calculation");
|
||||
debug!("parsed term: {t:#?}");
|
||||
Self::calc(t)
|
||||
}
|
||||
|
||||
/// ## Calculate a [`Term`]
|
||||
///
|
||||
/// This method makes use of the
|
||||
/// [shunting yard algorithm](https://en.wikipedia.org/wiki/Shunting_yard_algorithm) to
|
||||
/// Calculate the final value of any term.
|
||||
///
|
||||
/// This method only processes a single term at a time, without caching.
|
||||
pub fn calc(mut t: Term) -> Result<Value> {
|
||||
trace!("Calculating term {t:?}");
|
||||
t.prepare()?;
|
||||
t.process()?;
|
||||
if t.result.is_none() {
|
||||
let reason = format!("Term was processed but no result was assigned.");
|
||||
// FIXME: unfitting error type
|
||||
return Err(Error::SyntaxError(reason))
|
||||
}
|
||||
return t.result.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -1,223 +0,0 @@
|
|||
//! # A term that can be the input for calculation
|
||||
//!
|
||||
//! Short description
|
||||
//!
|
||||
//! Details
|
||||
//!
|
||||
//! ## Section 1
|
||||
//!
|
||||
//! ## Section 2
|
||||
|
||||
//// 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::collections::VecDeque;
|
||||
|
||||
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
pub use super::{Error, Result, Value, base::{self, *}};
|
||||
#[allow(unused_imports)] // we possibly want to use all log levels
|
||||
use libpt_log::*;
|
||||
#[allow(unused_imports)] // import more complex math stuff from there
|
||||
use libpt_math;
|
||||
|
||||
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// ## Parsed value to be calculated
|
||||
///
|
||||
/// This enum represents anything that goes to the output queue of [`Term::prepare()`] and will
|
||||
/// then be used to actually calculate something in [`Term::process()`].
|
||||
#[derive(Debug)]
|
||||
enum Token {
|
||||
/// Some kind of operator
|
||||
#[allow(unused)] // tmp
|
||||
Operator(Operator),
|
||||
/// A concrete value that we can calculate something with. May be a constant, integer, float,
|
||||
/// etc.
|
||||
/// The Token has a value that can be used in calculation
|
||||
Value(super::base::Value),
|
||||
/// A variable of some kind that will be present in the result
|
||||
#[allow(unused)] // tmp
|
||||
Variable(char),
|
||||
}
|
||||
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
/// ## Term that can be calculated
|
||||
///
|
||||
/// Represents a signular term, that can be calculated. Terms will be evaluated by the [`Term::prepare`]
|
||||
/// function, afterwards calculated (as much as possible) in the [`Term::process`] function.
|
||||
///
|
||||
#[derive(Debug)]
|
||||
pub struct Term {
|
||||
/// the original expression to calculate
|
||||
pub original: String,
|
||||
/// the filtered text of the expression, only with relevant information
|
||||
pub text: String,
|
||||
/// the calculated result, may be of diffrent types, see [`crate::math::calculator::result`].
|
||||
pub result: Option<Result<Value>>,
|
||||
/////////////////////////////////////
|
||||
///// internal values following /////
|
||||
/////////////////////////////////////
|
||||
#[allow(unused)] // tmp
|
||||
operator_stack: Vec<Operator>,
|
||||
output_queue: VecDeque<Token>
|
||||
}
|
||||
|
||||
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||
impl Term {
|
||||
/// Build a new term from an expression
|
||||
///
|
||||
/// Invalid terms will result in an [`Err`].
|
||||
pub fn new(orig: String) -> Result<Term> {
|
||||
return Ok(
|
||||
Term {
|
||||
original: orig,
|
||||
text: String::new(), // will be initialized in `prepare()`
|
||||
result: None,
|
||||
operator_stack: Vec::new(),
|
||||
output_queue: VecDeque::new()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Prepare the term for the processing.
|
||||
pub fn prepare(&mut self) -> Result<()> {
|
||||
trace!("preparing term: {:#?}", self);
|
||||
self.text = Self::filter(&self.original)?;
|
||||
|
||||
// Storage for unfinished tokens
|
||||
let _unfinished_chars: Vec<char> = Vec::new();
|
||||
|
||||
for (_index, c) in self.original.chars().enumerate() {
|
||||
// this will be a mess, but it has to be before i can sort the mess.
|
||||
match c {
|
||||
// TODO: make function to check if character is an operator, use it
|
||||
_ => {
|
||||
let reason = format!("The meaning of '{c}' could not be identified.");
|
||||
warn!(reason);
|
||||
return Err(Error::SyntaxError(reason));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Process a prepared term, calculating it's result
|
||||
pub fn process(&mut self) -> Result<()> {
|
||||
debug!("processing term: {:#?}", self);
|
||||
debug!("queue: {:#?}", self.output_queue);
|
||||
// TODO: process RPN and set result
|
||||
self.result = Some(Ok(19.into()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Convert a character into a token
|
||||
///
|
||||
/// Returns: A tuple with a [`Token`] and a [`bool`]. If the bool is false, the [`Token`] is
|
||||
/// marked as "incomplete", meaning that the character cannot be used yet.
|
||||
#[allow(unused)] // tmp
|
||||
fn to_tok(_s: Vec<char>) -> Result<Token> {
|
||||
Ok(19.into())
|
||||
}
|
||||
|
||||
/// only leave relevant chars for calculation
|
||||
// TODO: make function to check if character is an operator, use it
|
||||
fn filter(s: &str) -> Result<String> {
|
||||
// pre checks
|
||||
// NOTE: Apperently, "alphanumeric" in Rust is a pretty broad term.
|
||||
// Even CJK characters or Japanese Kana are allowed:
|
||||
// - 'さ' alphanumeric
|
||||
// - '数' alphanumeric
|
||||
// - '学' alphanumeric
|
||||
// - '+' not alphanumeric
|
||||
for c in s.chars() {
|
||||
#[cfg(debug_assertions)] {
|
||||
debug!("filter checks for '{c}':
|
||||
alphanumeric: {}
|
||||
allowed special: {}
|
||||
EXCEPT IF
|
||||
ascii control: {}
|
||||
",
|
||||
!c.is_alphanumeric(),
|
||||
!Self::is_allowed_special_c(&c),
|
||||
c.is_ascii_control(),
|
||||
)
|
||||
}
|
||||
if
|
||||
(
|
||||
!c.is_alphanumeric() ||
|
||||
!Self::is_allowed_special_c(&c)
|
||||
)
|
||||
&&
|
||||
(
|
||||
c.is_ascii_control()
|
||||
)
|
||||
{
|
||||
// TODO: allow any unicode char to be a variable
|
||||
let reason = format!("'{c}' is not a valid character, only alphanumeric, punctuation, operators are allowed.");
|
||||
warn!(reason);
|
||||
return Err(Error::SyntaxError(reason));
|
||||
}
|
||||
}
|
||||
|
||||
// filter out single chars
|
||||
let mut filtered = String::new();
|
||||
for c in s.chars() {
|
||||
if !Self::is_ignore(&c) {
|
||||
filtered.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(filtered)
|
||||
}
|
||||
|
||||
/// check if we should ignore this character
|
||||
fn is_ignore(c: &char) -> bool {
|
||||
match *c {
|
||||
' ' => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
/// allowed special chars
|
||||
fn is_allowed_special_c(c: &char) -> bool {
|
||||
match *c {
|
||||
'+' | '-' | '*' | '/' | '%' => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Helper methods for Tokens
|
||||
impl Token { }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl<T> From<T> for Token where
|
||||
T: Into<Value>,
|
||||
T: PrimInt,
|
||||
u128: TryFrom<T>
|
||||
{
|
||||
fn from(value: T) -> Self {
|
||||
Token::Value(base::Value::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -13,3 +13,6 @@ keywords.workspace = true
|
|||
categories.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.79"
|
||||
cucumber = "0.20.2"
|
||||
libpt-log = {path = "../libpt-log" }
|
||||
|
|
|
@ -10,11 +10,9 @@
|
|||
// 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)]
|
||||
|
|
|
@ -6,11 +6,9 @@
|
|||
// 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)]
|
||||
|
|
|
@ -15,3 +15,7 @@ categories.workspace = true
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
libpt-log = {path = "../libpt-log" }
|
||||
libpt-bintols = {path = "../libpt-bintols" }
|
||||
|
|
|
@ -4,3 +4,175 @@
|
|||
//! module.
|
||||
//!
|
||||
//! This crate is currently empty.
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use libpt_bintols::display::{bytes_to_bin, humanbytes};
|
||||
use libpt_log::{debug, error, info, trace, warn};
|
||||
use std::io::{prelude::*, BufReader, Read, SeekFrom};
|
||||
|
||||
const BYTES_PER_LINE: usize = 16;
|
||||
const LINE_SEP_HORIZ: char = '─';
|
||||
const LINE_SEP_VERT: char = '│';
|
||||
|
||||
pub struct HeduConfig {
|
||||
pub chars: bool,
|
||||
pub skip: usize,
|
||||
pub show_identical: bool,
|
||||
pub limit: usize,
|
||||
stop: bool,
|
||||
}
|
||||
|
||||
impl HeduConfig {
|
||||
pub fn new(chars: bool, skip: usize, show_identical: bool, limit: usize) -> Self {
|
||||
HeduConfig {
|
||||
chars,
|
||||
skip,
|
||||
show_identical,
|
||||
limit: limit,
|
||||
stop: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dump(data: &mut dyn DataSource, mut config: HeduConfig) -> Result<()> {
|
||||
// prepare some variables
|
||||
let mut buf: [[u8; BYTES_PER_LINE]; 2] = [[0; BYTES_PER_LINE]; 2];
|
||||
let mut alt_buf = 0usize;
|
||||
let mut byte_counter: usize = 0;
|
||||
let mut len: usize;
|
||||
|
||||
// skip a given number of bytes
|
||||
if config.skip > 0 {
|
||||
data.skip(config.skip)?;
|
||||
byte_counter += config.skip;
|
||||
debug!("Skipped {}", humanbytes(config.skip));
|
||||
}
|
||||
|
||||
// print the head
|
||||
print!("DATA IDX {LINE_SEP_VERT} DATA AS HEX");
|
||||
if config.chars {
|
||||
print!("{:width$} {LINE_SEP_VERT} FOO", "", width = 37);
|
||||
}
|
||||
println!();
|
||||
if config.chars {
|
||||
println!("{}", format!("{LINE_SEP_HORIZ}").repeat(80));
|
||||
} else {
|
||||
println!("{}", format!("{LINE_SEP_HORIZ}").repeat(59));
|
||||
}
|
||||
|
||||
// data dump loop
|
||||
len = rd_data(data, &mut buf, &mut alt_buf, &mut byte_counter, &mut config).unwrap();
|
||||
while len > 0 {
|
||||
print!("{:08X} {LINE_SEP_VERT} ", byte_counter);
|
||||
for i in 0..len {
|
||||
if i as usize % BYTES_PER_LINE == BYTES_PER_LINE / 2 {
|
||||
print!(" ");
|
||||
}
|
||||
print!("{:02X} ", buf[alt_buf][i]);
|
||||
}
|
||||
if len == BYTES_PER_LINE / 2 {
|
||||
print!(" ")
|
||||
}
|
||||
for i in 0..(BYTES_PER_LINE - len) {
|
||||
if i as usize % BYTES_PER_LINE == BYTES_PER_LINE / 2 {
|
||||
print!(" ");
|
||||
}
|
||||
print!(" ");
|
||||
}
|
||||
if config.chars {
|
||||
print!("{LINE_SEP_VERT} |");
|
||||
for i in 0..len {
|
||||
print!("{}", mask_chars(buf[alt_buf][i] as char));
|
||||
}
|
||||
print!("|");
|
||||
}
|
||||
println!();
|
||||
|
||||
// loop breaker logic
|
||||
if config.stop {
|
||||
break;
|
||||
}
|
||||
|
||||
// after line logic
|
||||
len = rd_data(data, &mut buf, &mut alt_buf, &mut byte_counter, &mut config).unwrap();
|
||||
alt_buf ^= 1; // toggle the alt buf
|
||||
if buf[0] == buf[1] && len == BYTES_PER_LINE && !config.show_identical {
|
||||
trace!(buf = format!("{:?}", buf), "found a duplicating line");
|
||||
let start_line = byte_counter;
|
||||
while buf[0] == buf[1] && len == BYTES_PER_LINE {
|
||||
len =
|
||||
rd_data(data, &mut buf, &mut alt_buf, &mut byte_counter, &mut config).unwrap();
|
||||
byte_counter += BYTES_PER_LINE;
|
||||
}
|
||||
println!(
|
||||
"^^^^^^^^ {LINE_SEP_VERT} (repeats {} lines)",
|
||||
byte_counter - start_line
|
||||
);
|
||||
}
|
||||
// switch to the second half of the buf, the original half is stored the old buffer
|
||||
// We detect duplicate lines with this
|
||||
alt_buf ^= 1; // toggle the alt buf
|
||||
}
|
||||
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>';
|
||||
}
|
||||
}
|
||||
|
||||
fn rd_data(
|
||||
data: &mut dyn DataSource,
|
||||
buf: &mut [[u8; BYTES_PER_LINE]; 2],
|
||||
alt_buf: &mut usize,
|
||||
byte_counter: &mut usize,
|
||||
config: &mut HeduConfig,
|
||||
) -> Result<usize> {
|
||||
match data.read(&mut buf[*alt_buf]) {
|
||||
Ok(mut len) => {
|
||||
*byte_counter += len; // FIXME: incremented too early! dump always starts at 0x10
|
||||
if config.limit != 0 && *byte_counter >= config.limit {
|
||||
trace!(
|
||||
byte_counter,
|
||||
limit = config.limit,
|
||||
len,
|
||||
nlen = (config.limit % BYTES_PER_LINE),
|
||||
"byte counter is farther than limit"
|
||||
);
|
||||
len = config.limit % BYTES_PER_LINE;
|
||||
config.stop = true;
|
||||
}
|
||||
return Ok(len);
|
||||
}
|
||||
Err(err) => {
|
||||
error!("error while reading data: {err}");
|
||||
bail!(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ categories.workspace = true
|
|||
tracing = "0.1.37"
|
||||
tracing-appender = "0.2.2"
|
||||
tracing-subscriber = "0.3.17"
|
||||
pyo3 = {workspace = true}
|
||||
anyhow = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
gag = "1.0.0"
|
||||
|
|
|
@ -12,12 +12,11 @@
|
|||
#![warn(clippy::pedantic)]
|
||||
|
||||
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
use pyo3::{exceptions::PyException, PyErr};
|
||||
use anyhow;
|
||||
use thiserror::Error;
|
||||
use tracing::subscriber::SetGlobalDefaultError;
|
||||
|
||||
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// a quick alias for a result with a [`Error`]
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -27,12 +26,16 @@ pub type Result<T> = std::result::Result<T, Error>;
|
|||
|
||||
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// ## Errors for the [Logger](super::Logger)
|
||||
#[derive(Error)]
|
||||
pub enum Error {
|
||||
/// Bad IO operation
|
||||
#[error("Bad IO operation")]
|
||||
IO(std::io::Error),
|
||||
/// Various errors raised when the messenger is used in a wrong way
|
||||
#[error("Bad usage")]
|
||||
Usage(String),
|
||||
/// Could not assign logger as the global default
|
||||
#[error("Could not assign as global default")] // TODO: make this more clear
|
||||
SetGlobalDefaultFail(SetGlobalDefaultError),
|
||||
}
|
||||
|
||||
|
@ -52,19 +55,6 @@ impl From<SetGlobalDefaultError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl Into<PyErr> for Error {
|
||||
fn into(self) -> PyErr {
|
||||
match self {
|
||||
Error::IO(err) => PyException::new_err(format!("LoggerError: IO {err:?}")),
|
||||
Error::Usage(err) => PyException::new_err(format!("LoggerError: Usage {err}")),
|
||||
Error::SetGlobalDefaultFail(err) => {
|
||||
PyException::new_err(format!("LoggerError: SetGlobalDefaultFail {err}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl std::fmt::Debug for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
@ -76,18 +66,6 @@ impl std::fmt::Debug for Error {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl std::fmt::Display 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 /////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
use std::{
|
||||
fmt,
|
||||
ops::Deref,
|
||||
path::PathBuf,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
@ -27,10 +28,20 @@ pub mod error;
|
|||
use error::*;
|
||||
|
||||
pub use tracing::{debug, error, info, trace, warn, Level};
|
||||
use tracing_appender;
|
||||
use tracing_subscriber::{prelude::*, fmt::format::FmtSpan};
|
||||
use tracing_appender::{
|
||||
self,
|
||||
non_blocking::{NonBlocking, WorkerGuard},
|
||||
};
|
||||
use tracing_subscriber::{
|
||||
fmt::{
|
||||
format::FmtSpan,
|
||||
time::{self, FormatTime},
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use pyo3::prelude::*;
|
||||
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||
/// The log level used when none is specified
|
||||
pub const DEFAULT_LOG_LEVEL: Level = Level::INFO;
|
||||
|
@ -47,8 +58,7 @@ static INITIALIZED: AtomicBool = AtomicBool::new(false);
|
|||
///
|
||||
/// This struct exists mainly for the python module, so that we can use the same logger with both
|
||||
/// python and rust.
|
||||
#[pyclass]
|
||||
pub struct Logger {}
|
||||
pub struct Logger;
|
||||
|
||||
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||
/// ## Main implementation
|
||||
|
@ -77,6 +87,33 @@ impl Logger {
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
/// ## initializes the logger
|
||||
///
|
||||
/// Will enable the logger to be used. This is a version that shows less information,
|
||||
/// useful in cases with only one sender to the logging framework.
|
||||
///
|
||||
/// Assumes some defaults, use [`init_customized`](Self::init_customized) for more control
|
||||
pub fn init_mini(max_level: Option<Level>) -> Result<()> {
|
||||
Self::init_customized(
|
||||
false,
|
||||
PathBuf::from(DEFAULT_LOG_DIR),
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
max_level.unwrap_or(DEFAULT_LOG_LEVEL),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -94,57 +131,98 @@ impl Logger {
|
|||
display_thread_ids: bool,
|
||||
display_thread_names: bool,
|
||||
display_line_number: bool,
|
||||
pretty: bool,
|
||||
show_time: bool,
|
||||
uptime: bool, // uptime instead of system time
|
||||
) -> Result<()> {
|
||||
// only init if no init has been performed yet
|
||||
if INITIALIZED.load(Ordering::Relaxed) {
|
||||
warn!("trying to reinitialize the logger, ignoring");
|
||||
return Err(Error::Usage(format!("logging is already initialized")));
|
||||
} else {
|
||||
let filter = tracing_subscriber::filter::FilterFn::new(|_metadata| {
|
||||
// let mut filter = false;
|
||||
//
|
||||
// // if it's this lib, continue
|
||||
// filter |= metadata.target().contains(env!("CARGO_PKG_NAME"));
|
||||
// filter |= metadata.target().contains("libpt");
|
||||
//
|
||||
// // if it's another crate, only show above debug
|
||||
// filter |= metadata.level() > &Level::DEBUG;
|
||||
//
|
||||
// filter
|
||||
// FIXME: Make the filter customizable with sane defaults. Don't block the
|
||||
// executing crate.
|
||||
true
|
||||
});
|
||||
|
||||
let basic_subscriber = tracing_subscriber::fmt::Subscriber::builder()
|
||||
// subscriber configuration
|
||||
.with_ansi(ansi)
|
||||
.with_file(display_filename)
|
||||
.with_level(display_level)
|
||||
.with_target(display_target)
|
||||
.with_max_level(max_level)
|
||||
.with_thread_ids(display_thread_ids)
|
||||
.with_line_number(display_line_number)
|
||||
.with_thread_names(display_thread_names)
|
||||
.with_span_events(FmtSpan::FULL)
|
||||
//.pretty // too verbose and over multiple lines, a bit like python tracebacks
|
||||
.finish()
|
||||
// add layers
|
||||
.with(filter);
|
||||
|
||||
if log_to_file {
|
||||
let file_appender = tracing_appender::rolling::daily(log_dir, "log");
|
||||
let (file_writer, _guard) = tracing_appender::non_blocking(file_appender);
|
||||
let layered_subscriber = basic_subscriber
|
||||
.with(tracing_subscriber::fmt::Layer::default().with_writer(file_writer));
|
||||
tracing::subscriber::set_global_default(layered_subscriber)?;
|
||||
} else {
|
||||
tracing::subscriber::set_global_default(basic_subscriber)?;
|
||||
}
|
||||
|
||||
INITIALIZED.store(true, Ordering::Relaxed);
|
||||
Ok(())
|
||||
bail!(Error::Usage(format!("logging is already initialized")));
|
||||
}
|
||||
let subscriber = tracing_subscriber::fmt::Subscriber::builder()
|
||||
.with_level(display_level)
|
||||
.with_max_level(max_level)
|
||||
.with_ansi(ansi)
|
||||
.with_target(display_target)
|
||||
.with_file(display_filename)
|
||||
.with_thread_ids(display_thread_ids)
|
||||
.with_line_number(display_line_number)
|
||||
.with_thread_names(display_thread_names)
|
||||
.with_span_events(FmtSpan::FULL);
|
||||
// I know this is hacky, but I couldn't get it any other way. I couldn't even find a
|
||||
// project that could do it any other way. You can't apply one after another, because the
|
||||
// type is changed every time. When using Box<dyn Whatever>, some methods complain about
|
||||
// not being in trait bounds.
|
||||
// TODO: somehow find a better solution for this
|
||||
match (log_to_file, show_time, pretty, uptime) {
|
||||
(true, true, true, true) => {
|
||||
let subscriber = subscriber
|
||||
.with_writer(new_file_appender(log_dir))
|
||||
.with_timer(time::uptime())
|
||||
.pretty()
|
||||
.finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
(true, true, true, false) => {
|
||||
let subscriber = subscriber
|
||||
.with_writer(new_file_appender(log_dir))
|
||||
.pretty()
|
||||
.finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
(true, false, true, _) => {
|
||||
let subscriber = subscriber
|
||||
.with_writer(new_file_appender(log_dir))
|
||||
.without_time()
|
||||
.pretty()
|
||||
.finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
(true, true, false, true) => {
|
||||
let subscriber = subscriber
|
||||
.with_writer(new_file_appender(log_dir))
|
||||
.with_timer(time::uptime())
|
||||
.finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
(true, true, false, false) => {
|
||||
let subscriber = subscriber.with_writer(new_file_appender(log_dir)).finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
(true, false, false, _) => {
|
||||
let file_appender = tracing_appender::rolling::daily(log_dir.clone(), "log");
|
||||
let (file_writer, _guard) = tracing_appender::non_blocking(file_appender);
|
||||
let subscriber = subscriber.with_writer(file_writer).without_time().finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
(false, true, true, true) => {
|
||||
let subscriber = subscriber.pretty().with_timer(time::uptime()).finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
(false, true, true, false) => {
|
||||
let subscriber = subscriber.pretty().with_timer(time::uptime()).finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
(false, false, true, _) => {
|
||||
let subscriber = subscriber.without_time().pretty().finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
(false, true, false, true) => {
|
||||
let subscriber = subscriber.with_timer(time::uptime()).finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
(false, true, false, false) => {
|
||||
let subscriber = subscriber.finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
(false, false, false, _) => {
|
||||
let subscriber = subscriber.without_time().finish();
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
}
|
||||
}
|
||||
INITIALIZED.store(true, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// ## logging at [`Level::ERROR`]
|
||||
|
@ -184,61 +262,6 @@ impl Logger {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// ## Implementation of the python interface
|
||||
#[pymethods]
|
||||
impl Logger {
|
||||
/// ## Python version of [`new()`](Logger::new)
|
||||
#[new]
|
||||
pub fn py_new() -> PyResult<Self> {
|
||||
Ok(Logger::new())
|
||||
}
|
||||
/// ## Python version of [`init()`](Logger::init)
|
||||
#[pyo3(name = "init")]
|
||||
#[staticmethod]
|
||||
pub fn py_init(log_dir: Option<PathBuf>, max_level: Option<String>) -> Result<()> {
|
||||
Self::init(
|
||||
log_dir,
|
||||
match max_level {
|
||||
Some(s) => match s.to_uppercase().as_str() {
|
||||
"TRACE" => Some(tracing::Level::TRACE),
|
||||
"DEBUG" => Some(tracing::Level::DEBUG),
|
||||
"INFO" => Some(tracing::Level::INFO),
|
||||
"WARN" => Some(tracing::Level::WARN),
|
||||
"ERROR" => Some(tracing::Level::ERROR),
|
||||
_ => return Err(Error::Usage(format!("'{s}' is not a valid log level"))),
|
||||
},
|
||||
None => None,
|
||||
},
|
||||
)
|
||||
}
|
||||
/// ## Python version of [`error()`](Logger::error)
|
||||
#[pyo3(name = "error")]
|
||||
pub fn py_error(&self, printable: String) {
|
||||
self.error(printable)
|
||||
}
|
||||
/// ## Python version of [`warn()`](Logger::warn)
|
||||
#[pyo3(name = "warn")]
|
||||
pub fn py_warn(&self, printable: String) {
|
||||
self.warn(printable)
|
||||
}
|
||||
/// ## Python version of [`info()`](Logger::info)
|
||||
#[pyo3(name = "info")]
|
||||
pub fn py_info(&self, printable: String) {
|
||||
self.info(printable)
|
||||
}
|
||||
/// ## Python version of [`debug()`](Logger::debug)
|
||||
#[pyo3(name = "debug")]
|
||||
pub fn py_debug(&self, printable: String) {
|
||||
self.debug(printable)
|
||||
}
|
||||
/// ## Python version of [`trace()`](Logger::trace)
|
||||
#[pyo3(name = "trace")]
|
||||
pub fn py_trace(&self, printable: String) {
|
||||
self.trace(printable)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
impl fmt::Debug for Logger {
|
||||
/// ## DEBUG representation for [`Logger`]
|
||||
|
@ -254,4 +277,7 @@ impl fmt::Debug for Logger {
|
|||
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn new_file_appender(log_dir: PathBuf) -> NonBlocking {
|
||||
let file_appender = tracing_appender::rolling::daily(log_dir.clone(), "log");
|
||||
return tracing_appender::non_blocking(file_appender).0;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@ categories.workspace = true
|
|||
|
||||
[dependencies]
|
||||
humantime = "2.1.0"
|
||||
libpt-core = { version = "0.1.0", path = "../libpt-core" }
|
||||
libpt-log = { version = "0.1.0", path = "../libpt-log" }
|
||||
libpt-math = { version = "0.1.0", path = "../libpt-math" }
|
||||
libpt-core = { path = "../libpt-core" }
|
||||
libpt-log = { path = "../libpt-log" }
|
||||
libpt-math = { path = "../libpt-math" }
|
||||
reqwest = { version = "0.11.20", features = ["blocking"] }
|
||||
serde = { version = "1.0.188", features = ["serde_derive"] }
|
||||
serde_json = "1.0.107"
|
||||
|
|
|
@ -10,11 +10,9 @@
|
|||
// 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)]
|
||||
|
|
|
@ -6,11 +6,9 @@
|
|||
// 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)]
|
||||
|
|
|
@ -188,7 +188,11 @@ pub fn continuous_uptime_monitor(
|
|||
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");
|
||||
trace!(
|
||||
?status,
|
||||
?last_was_up,
|
||||
"loop iteration for continuous uptime monitor"
|
||||
);
|
||||
if !status.success {
|
||||
if last_was_up {
|
||||
trace!("displaying status");
|
||||
|
|
120
members/libpt-py/.github/workflows/CI.yml
vendored
120
members/libpt-py/.github/workflows/CI.yml
vendored
|
@ -1,120 +0,0 @@
|
|||
# This file is autogenerated by maturin v1.1.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: --skip-existing *
|
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,22 +0,0 @@
|
|||
[package]
|
||||
name = "libpt-py"
|
||||
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
|
||||
[lib]
|
||||
name = "libpt_py"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
libpt = { version = "0.1.7", path = "../..", features = ["all"] }
|
||||
pyo3 = { workspace = true }
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023 Christoph Johannes Scherr
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,76 +0,0 @@
|
|||
# pt / libpt
|
||||
|
||||

|
||||
|
||||
`pt` stands for either one of "personal tool", "plex tool", "pete" or something among those lines.
|
||||
It is a collection of tools that i might or might not use. The intended purpose of this repo is that
|
||||
I program whatever i feel is worth having in a personal thing into it, then use it as either a lib,
|
||||
crate, python module or executable.
|
||||
|
||||
Let's see if I make it a bloated mess or stop committing after 30 hello worlds.
|
||||
|
||||
#### But the name `pt` / `libpt` already exists!
|
||||
|
||||
So what? I don't care. Besides, there is not enough names to name everything unique.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- See `cargo.toml`
|
||||
- [openssl bindings for rust](https://docs.rs/openssl/latest/openssl/)
|
||||
- [Python](https://www.python.org/)
|
||||
- [`maturin`](https://maturin.rs) - `pip install maturin`
|
||||
|
||||
## Compiling & Installing from source
|
||||
|
||||
If you only want the rust library, you can simply build it with `cargo build`. Add it to your
|
||||
project like any other local dependency.
|
||||
|
||||
If you want to use the python variant too, you need to compile with maturing.
|
||||
|
||||
- Install in `venv`: `maturin develop --release`
|
||||
- Install in system: `maturin build --release && pip install target/wheels/libpt-x.x.x-*`
|
||||
|
||||
## Installing from [pypi](https://pypi.org)
|
||||
|
||||
`libpt` has been packaged for [pypi.org](https://pypi.org/project/libpt/).
|
||||
|
||||
You can install it with `pip install libpt`
|
||||
|
||||
## Installing from [crates.io](https://crates.io)
|
||||
|
||||
`libpt` has been packaged for [crates.io](https://crates.io/crates/libpt).
|
||||
|
||||
You can add the library to your project with `cargo add libpt`.
|
||||
|
||||
## Installing from my personal package registry
|
||||
|
||||
`libpt` has been packaged for [git.cscherr.de](https://git.cscherr.de).
|
||||
|
||||
You can add the registry to your `config.toml` and then `cargo add libpt`
|
||||
|
||||
[Package](https://git.cscherr.de/PlexSheep/-/packages/cargo/libpt/)
|
||||
|
||||
## Testing
|
||||
|
||||
Testing needs to be done separately for the rust and python parts:
|
||||
|
||||
- Rust testing with `cargo test`
|
||||
- Python testing with `./scripts/pytests.sh` or `python -m unittest discover -fs tests/python`
|
||||
|
||||
## Documentation
|
||||
|
||||
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/)
|
||||
|
||||
## 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
|
||||
|
||||
**Pt is MIT Licensed**
|
|
@ -1,25 +0,0 @@
|
|||
[build-system]
|
||||
requires = ["maturin>=0.14,<0.15"]
|
||||
build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "libpt"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.7"
|
||||
authors = [{ name = "Christoph J. Scherr", email = "software@cscherr.de" }]
|
||||
license = { file = "LICENSE" }
|
||||
keywords = ["pyo3"]
|
||||
classifiers = [
|
||||
"Programming Language :: Rust",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://git.cscherr.de/PlexSheep/libpt"
|
||||
|
||||
|
||||
[tool.maturin]
|
||||
features = ["pyo3/extension-module"]
|
||||
python-source = "python"
|
||||
module-name = "libpt._libpt"
|
|
@ -1 +0,0 @@
|
|||
from ._libpt import *
|
|
@ -1,14 +0,0 @@
|
|||
"""
|
||||
# libpt python bindings
|
||||
|
||||
`libpt` is originally implemented in rust, but offers a python module too.
|
||||
"""
|
||||
from . import logger
|
||||
from . import networking
|
||||
from . import common
|
||||
|
||||
def is_loaded() -> bool:
|
||||
"""
|
||||
returns true if `libpt` has been loaded
|
||||
"""
|
||||
...
|
|
@ -1,7 +0,0 @@
|
|||
"""
|
||||
common functionalities
|
||||
|
||||
This module implements common functionality useful for many use cases, such as macros,
|
||||
Formatting functions and more.
|
||||
"""
|
||||
from . import printing
|
|
@ -1,14 +0,0 @@
|
|||
"""
|
||||
tools that make printing stuff better
|
||||
"""
|
||||
def divider() -> str:
|
||||
"""
|
||||
Quickly get a one line visual divider
|
||||
"""
|
||||
...
|
||||
|
||||
def print_divider():
|
||||
"""
|
||||
Quickly print a one line visual divider
|
||||
"""
|
||||
...
|
|
@ -1,65 +0,0 @@
|
|||
"""
|
||||
# A specialized Logger for `libpt`
|
||||
"""
|
||||
|
||||
""" the default log level """
|
||||
DEFAULT_LOG_LEVEL = "INFO"
|
||||
""" Set the value of this key as envar to set a loglevel """
|
||||
LOGGER_ENV_KEY = "LIBPT_LOGLEVEL"
|
||||
|
||||
class Logger:
|
||||
"""
|
||||
`libpt` logger
|
||||
|
||||
Call `init` once before usage, else all logging attempts will be ignored.
|
||||
"""
|
||||
def __init__(self):
|
||||
"""
|
||||
get a new logger
|
||||
"""
|
||||
...
|
||||
|
||||
@staticmethod
|
||||
def init():
|
||||
"""
|
||||
initialize the logger before the first usage
|
||||
"""
|
||||
...
|
||||
|
||||
@staticmethod
|
||||
def init_specialized(color: bool):
|
||||
"""
|
||||
initialize the logger before the first usage, but with the ability to tweak things a bit
|
||||
"""
|
||||
...
|
||||
|
||||
def error(self, printable: str):
|
||||
"""
|
||||
log at level `error`
|
||||
"""
|
||||
...
|
||||
|
||||
def warn(self, printable: str):
|
||||
"""
|
||||
log at level `error`
|
||||
"""
|
||||
...
|
||||
|
||||
def info(self, printable: str):
|
||||
"""
|
||||
log at level `error`
|
||||
"""
|
||||
...
|
||||
|
||||
def debug(self, printable: str):
|
||||
"""
|
||||
log at level `error`
|
||||
"""
|
||||
...
|
||||
|
||||
def trace(self, printable: str):
|
||||
"""
|
||||
log at level `error`
|
||||
"""
|
||||
...
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
"""
|
||||
# various networking tools
|
||||
|
||||
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.
|
||||
"""
|
||||
from . import monitoring
|
|
@ -1,7 +0,0 @@
|
|||
"""
|
||||
# monitor your network
|
||||
|
||||
This module offers functions to monitor your network.
|
||||
"""
|
||||
|
||||
from . import uptime
|
|
@ -1,86 +0,0 @@
|
|||
"""
|
||||
# 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
|
||||
"""
|
||||
|
||||
class UptimeStatus:
|
||||
"""
|
||||
Describes an uptime status
|
||||
|
||||
UptimeStatus describes the result of an uptime check.
|
||||
"""
|
||||
""" true if the [`UptimeStatus`] is considered successful"""
|
||||
success: bool
|
||||
""" the percentage of reachable urls out of the total urls"""
|
||||
success_ratio: int
|
||||
""" 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.
|
||||
"""
|
||||
success_ratio_target: int
|
||||
""" the number of reachable [`urls`](UptimeStatus::urls) """
|
||||
reachable: int
|
||||
""" set a timeout (in ms) """
|
||||
timeout: int
|
||||
"""URL list cant be ported to python, use UptimeStatus.urls()"""
|
||||
__urls: ...
|
||||
|
||||
def __init__(self, success_ratio_target: int, url_strs: list[str], timeout: int) -> None:
|
||||
"""
|
||||
create a new UptimeStatus and check it
|
||||
|
||||
`success_ratio_target` should never be more than 100 (it represents a success percentage)
|
||||
"""
|
||||
...
|
||||
|
||||
def check(self) -> None:
|
||||
"""
|
||||
checks if the stored urls
|
||||
|
||||
Makes the actual https requests and updates fields accordingly.
|
||||
|
||||
This method can block some time, as the web requests are implemented as blocking and
|
||||
executed by the shared library (not in python)
|
||||
"""
|
||||
...
|
||||
|
||||
def calc_success(self) -> None:
|
||||
"""
|
||||
calculate the success based on the `reachable` and `total`
|
||||
|
||||
Calculates the ratio of [reachable]/
|
||||
(length of [__urls]).
|
||||
|
||||
Calculates a [`success_ratio`] from that, by multiplying with 100, then flooring.
|
||||
|
||||
If the [`success_ratio`] is greater than or equal to the [`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`] will be `0`.
|
||||
|
||||
Note: does not check for networking, use [`check()`] for that.
|
||||
"""
|
||||
...
|
||||
|
||||
def urls(self) -> list[str]:
|
||||
"""
|
||||
get urls for python
|
||||
|
||||
Since [`__urls`] has no python equivalent, return the urls as a `list[str]` in
|
||||
Python.
|
||||
"""
|
||||
...
|
||||
|
||||
def continuous_uptime_monitor(success_ratio_target: int, urls: list[str], interval: int, timeout: int) -> None:
|
||||
"""
|
||||
Uptime monitor
|
||||
|
||||
This function continuously monitors the uptime of your host/network.
|
||||
|
||||
On change of status, an update will be logged at INFO Level, containing
|
||||
information on your current status, including timestamps of the last up/down time and durations
|
||||
since.
|
||||
"""
|
||||
...
|
|
@ -1 +0,0 @@
|
|||
python -m unittest discover -fs tests/python
|
|
@ -1,101 +0,0 @@
|
|||
// FIXME: Using a local dependency does not work with maturin as it seems?
|
||||
use libpt::{
|
||||
log::*,
|
||||
};
|
||||
|
||||
use pyo3::prelude::*;
|
||||
|
||||
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||
/// ## Check if [`libpt`](crate) has been loaded
|
||||
///
|
||||
/// Always returns `true` if you can execute it.
|
||||
#[pyfunction]
|
||||
pub fn is_loaded() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||
/// ## Python module: logger
|
||||
#[pymodule]
|
||||
fn py_logger(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||
let module = PyModule::new(py, "logger")?;
|
||||
module.add_class::<Logger>()?;
|
||||
|
||||
parent.add_submodule(module)?;
|
||||
Ok(())
|
||||
}
|
||||
//
|
||||
// ////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// /// ## Python module: common
|
||||
// #[pymodule]
|
||||
// fn py_common(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||
// let module = PyModule::new(py, "common")?;
|
||||
// py_common_printing(py, module)?;
|
||||
//
|
||||
// parent.add_submodule(module)?;
|
||||
// Ok(())
|
||||
// }
|
||||
//
|
||||
// ////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// /// ## Python module: common.printing
|
||||
// #[pymodule]
|
||||
// fn py_common_printing(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||
// let module = PyModule::new(py, "printing")?;
|
||||
// module.add_function(wrap_pyfunction!(common::printing::divider, module)?)?;
|
||||
// module.add_function(wrap_pyfunction!(common::printing::print_divider, module)?)?;
|
||||
//
|
||||
// parent.add_submodule(module)?;
|
||||
// Ok(())
|
||||
// }
|
||||
//
|
||||
// ////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// /// ## Python module: networking
|
||||
// #[pymodule]
|
||||
// fn py_networking(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||
// let module = PyModule::new(py, "networking")?;
|
||||
// py_networking_monitoring(py, module)?;
|
||||
//
|
||||
// parent.add_submodule(module)?;
|
||||
// Ok(())
|
||||
// }
|
||||
//
|
||||
// ////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// /// ## Python module: networking.monitoring
|
||||
// #[pymodule]
|
||||
// fn py_networking_monitoring(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||
// let module = PyModule::new(py, "monitoring")?;
|
||||
// py_networking_monitoring_uptime(py, module)?;
|
||||
//
|
||||
// parent.add_submodule(module)?;
|
||||
// Ok(())
|
||||
// }
|
||||
//
|
||||
// ////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// /// ## Python module: networking.monitoring.uptime
|
||||
// #[pymodule]
|
||||
// fn py_networking_monitoring_uptime(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||
// let module = PyModule::new(py, "uptime")?;
|
||||
// module.add_class::<networking::monitoring::uptime::UptimeStatus>()?;
|
||||
// module.add_function(wrap_pyfunction!(
|
||||
// networking::monitoring::uptime::py_continuous_uptime_monitor,
|
||||
// module
|
||||
// )?)?;
|
||||
//
|
||||
// parent.add_submodule(module)?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// ## Python module: root
|
||||
///
|
||||
/// This function is the entry point of [`PyO3`](pyo3). This is where the main module is built.
|
||||
#[pymodule]
|
||||
fn _libpt(py: Python, m: &PyModule) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(is_loaded, m)?)?;
|
||||
|
||||
// load sub modules
|
||||
// py_common(py, m)?;
|
||||
py_logger(py, m)?;
|
||||
// py_networking(py, m)?;
|
||||
Ok(())
|
||||
}
|
8
publish.sh
Executable file
8
publish.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
PKGs=(libpt-{core,math,log,net,bintols,ccc,hedu,bin,py} libpt)
|
||||
for PKG in "${PKGs[@]}"; do
|
||||
echo "Package: $PKG"
|
||||
cargo publish --registry cscherr -p "$PKG"
|
||||
cargo publish -p "$PKG"
|
||||
done
|
24
src/lib.rs
24
src/lib.rs
|
@ -6,17 +6,17 @@
|
|||
//! `pt` is a project consisting of multiple smaller crates, all bundled together in this
|
||||
//! "main crate". Most crates will only show up if you activate their feature.
|
||||
|
||||
#[cfg(feature = "core")]
|
||||
pub use libpt_core as core;
|
||||
#[cfg(feature = "bintols")]
|
||||
pub use libpt_bintols as bintols;
|
||||
#[cfg(feature = "hedu")]
|
||||
pub use libpt_hedu as hedu;
|
||||
#[cfg(feature = "log")]
|
||||
pub use libpt_log as log;
|
||||
#[cfg(feature = "math")]
|
||||
pub use libpt_math as math;
|
||||
#[cfg(feature = "net")]
|
||||
pub use libpt_net as net;
|
||||
pub use libpt_bintols as bintols;
|
||||
#[cfg(feature = "ccc")]
|
||||
pub use libpt_ccc as ccc;
|
||||
pub use libpt_ccc as ccc;
|
||||
#[cfg(feature = "core")]
|
||||
pub use libpt_core as core;
|
||||
#[cfg(feature = "hedu")]
|
||||
pub use libpt_hedu as hedu;
|
||||
#[cfg(feature = "log")]
|
||||
pub use libpt_log as log;
|
||||
#[cfg(feature = "math")]
|
||||
pub use libpt_math as math;
|
||||
#[cfg(feature = "net")]
|
||||
pub use libpt_net as net;
|
||||
|
|
Reference in a new issue