add simple ui implementation for docker
This commit is contained in:
@@ -147,9 +147,9 @@ jobs:
|
||||
- if: ${{ matrix.cross }}
|
||||
run: cargo +beta install cross --git https://github.com/cross-rs/cross
|
||||
- if: ${{ matrix.cross }}
|
||||
run: cross +beta build --release --target '${{ matrix.target }}' --locked
|
||||
run: cross +beta build --features tui --release --target '${{ matrix.target }}' --locked
|
||||
- if: ${{ !matrix.cross }}
|
||||
run: cargo +beta build --release --target '${{ matrix.target }}' --locked
|
||||
run: cargo +beta build --features tui --release --target '${{ matrix.target }}' --locked
|
||||
- run: mkdir dist
|
||||
- run: echo -n '${{ github.sha }}' > dist/commit-sha.txt
|
||||
shell: bash
|
||||
@@ -178,6 +178,13 @@ jobs:
|
||||
jobs: ${{ toJSON(needs) }}
|
||||
clippy:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
features:
|
||||
- "--features tui"
|
||||
- "--features logger"
|
||||
- ""
|
||||
fail-fast: false
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
@@ -187,7 +194,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
- run: rustup toolchain install beta --profile minimal --component clippy --allow-downgrade
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- run: cargo +beta clippy --all-targets --all-features -- -Dwarnings -Wclippy::pedantic
|
||||
- run: cargo +beta clippy --all-targets ${{ matrix.features }} -- -Dwarnings -Wclippy::pedantic
|
||||
pre-commit:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{ "rust-analyzer.cargo.features": ["tui"] }
|
||||
Generated
+146
-2
@@ -68,6 +68,56 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
version = "0.4.22"
|
||||
@@ -203,9 +253,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.18"
|
||||
version = "1.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@@ -261,6 +311,12 @@ dependencies = [
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "compact_str"
|
||||
version = "0.8.1"
|
||||
@@ -437,6 +493,29 @@ dependencies = [
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"jiff",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
@@ -1054,6 +1133,12 @@ version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf370abdafd54d13e54a620e8c3e1145f28e46cc9d704bc6d94414559df41763"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
@@ -1069,6 +1154,30 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"log",
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
@@ -1291,6 +1400,21 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
@@ -1313,10 +1437,12 @@ dependencies = [
|
||||
name = "proxy-scraper-checker"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"color-eyre",
|
||||
"crossterm",
|
||||
"derivative",
|
||||
"dirs",
|
||||
"env_logger",
|
||||
"fancy-regex",
|
||||
"futures",
|
||||
"log",
|
||||
@@ -1502,6 +1628,18 @@ dependencies = [
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
@@ -2258,6 +2396,12 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.1"
|
||||
|
||||
+12
-3
@@ -6,23 +6,32 @@ license = "MIT"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "=1.0.0"
|
||||
color-eyre = "=0.6.3"
|
||||
crossterm = { version = "=0.28.1", features = ["event-stream"] }
|
||||
crossterm = { version = "=0.28.1", features = [
|
||||
"event-stream",
|
||||
], optional = true }
|
||||
derivative = "=2.2.0"
|
||||
dirs = "=6.0.0"
|
||||
env_logger = { version = "=0.11.8", optional = true }
|
||||
fancy-regex = "=0.14.0"
|
||||
futures = "=0.3.31"
|
||||
log = "=0.4.27"
|
||||
maxminddb = "=0.26.0"
|
||||
ratatui = "=0.29.0"
|
||||
ratatui = { version = "=0.29.0", optional = true }
|
||||
rlimit = "=0.10.2"
|
||||
serde = "=1.0.219"
|
||||
serde_json = "=1.0.140"
|
||||
tokio = { version = "=1.44.2", features = ["full"] }
|
||||
toml = "=0.8.20"
|
||||
tui-logger = "=0.17.0"
|
||||
tui-logger = { version = "=0.17.0", optional = true }
|
||||
url = "=2.5.4"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
logger = ["dep:env_logger"]
|
||||
tui = ["dep:crossterm", "dep:ratatui", "dep:tui-logger"]
|
||||
|
||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||
reqwest = { version = "=0.12.15", default-features = false, features = [
|
||||
"brotli",
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ RUN --mount=source=src,target=src \
|
||||
--mount=source=Cargo.lock,target=Cargo.lock \
|
||||
--mount=type=cache,target=/app/target \
|
||||
--mount=type=cache,target=/usr/local/cargo/registry \
|
||||
cargo build --release --locked \
|
||||
cargo build --features logger --release --locked \
|
||||
&& cp target/release/proxy-scraper-checker .
|
||||
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ You can get proxies obtained using this project in [monosans/proxy-list](https:/
|
||||
|
||||
### Docker
|
||||
|
||||
> [!WARNING]
|
||||
> User interface does not work with Docker.
|
||||
> [!NOTE]
|
||||
> Only a simple user interface in the form of logs is implemented for Docker.
|
||||
|
||||
1. [Install `Docker Compose`](https://docs.docker.com/compose/install/).
|
||||
1. Download [the archive with the program](https://github.com/monosans/proxy-scraper-checker/archive/refs/heads/main.zip).
|
||||
|
||||
@@ -8,7 +8,6 @@ services:
|
||||
init: true
|
||||
logging:
|
||||
driver: local
|
||||
tty: true
|
||||
volumes:
|
||||
- proxy_scraper_checker_cache:/home/app/.cache/proxy_scraper_checker
|
||||
- ./out:/home/app/.local/share/proxy_scraper_checker
|
||||
|
||||
+4
-31
@@ -1,7 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::proxy::ProxyType;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) enum AppEvent {
|
||||
GeoDbTotal(Option<u64>),
|
||||
GeoDbDownloaded(usize),
|
||||
@@ -17,36 +16,10 @@ pub(crate) enum AppEvent {
|
||||
}
|
||||
|
||||
pub(crate) enum Event {
|
||||
#[cfg(feature = "tui")]
|
||||
Tick,
|
||||
#[cfg(feature = "tui")]
|
||||
Crossterm(crossterm::event::Event),
|
||||
#[allow(dead_code)]
|
||||
App(AppEvent),
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) enum AppMode {
|
||||
#[default]
|
||||
Running,
|
||||
Done,
|
||||
Quit,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct AppState {
|
||||
pub(crate) mode: AppMode,
|
||||
|
||||
pub(crate) geodb_total: u64,
|
||||
pub(crate) geodb_downloaded: usize,
|
||||
|
||||
pub(crate) sources_total: HashMap<ProxyType, usize>,
|
||||
pub(crate) sources_scraped: HashMap<ProxyType, usize>,
|
||||
|
||||
pub(crate) proxies_total: HashMap<ProxyType, usize>,
|
||||
pub(crate) proxies_checked: HashMap<ProxyType, usize>,
|
||||
pub(crate) proxies_working: HashMap<ProxyType, usize>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub(crate) fn new() -> Self {
|
||||
AppState::default()
|
||||
}
|
||||
}
|
||||
|
||||
+12
-21
@@ -9,8 +9,9 @@ pub(crate) mod proxy;
|
||||
pub(crate) mod raw_config;
|
||||
pub(crate) mod scraper;
|
||||
pub(crate) mod storage;
|
||||
pub(crate) mod tui;
|
||||
pub(crate) mod ui;
|
||||
pub(crate) mod utils;
|
||||
use ui::UI;
|
||||
|
||||
pub(crate) const APP_DIRECTORY_NAME: &str = "proxy_scraper_checker";
|
||||
pub(crate) const USER_AGENT: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; \
|
||||
@@ -31,9 +32,16 @@ fn create_reqwest_client() -> reqwest::Result<reqwest::Client> {
|
||||
.build()
|
||||
}
|
||||
|
||||
async fn run(terminal: ratatui::DefaultTerminal) -> color_eyre::Result<()> {
|
||||
#[tokio::main]
|
||||
async fn main() -> color_eyre::Result<()> {
|
||||
color_eyre::eyre::Context::wrap_err(
|
||||
color_eyre::install(),
|
||||
"failed to install color_eyre hooks",
|
||||
)?;
|
||||
let ui_impl = ui::UIImpl::new()?;
|
||||
|
||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
let ui_task = tokio::task::spawn(tui::run(terminal, tx.clone(), rx));
|
||||
let ui_task = tokio::task::spawn(ui_impl.run(tx.clone(), rx));
|
||||
|
||||
let http_client = color_eyre::eyre::Context::wrap_err(
|
||||
create_reqwest_client(),
|
||||
@@ -52,7 +60,7 @@ async fn run(terminal: ratatui::DefaultTerminal) -> color_eyre::Result<()> {
|
||||
)?);
|
||||
|
||||
if !config.debug {
|
||||
tui_logger::set_default_level(log::LevelFilter::Info);
|
||||
ui::UIImpl::set_log_level(log::LevelFilter::Info);
|
||||
}
|
||||
|
||||
let maybe_geodb_task = if config.enable_geolocation {
|
||||
@@ -96,20 +104,3 @@ async fn run(terminal: ratatui::DefaultTerminal) -> color_eyre::Result<()> {
|
||||
ui_task.await??;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> color_eyre::Result<()> {
|
||||
color_eyre::eyre::Context::wrap_err(
|
||||
color_eyre::install(),
|
||||
"failed to install color_eyre hooks",
|
||||
)?;
|
||||
color_eyre::eyre::Context::wrap_err(
|
||||
tui_logger::init_logger(log::LevelFilter::Debug),
|
||||
"failed to initialize logger",
|
||||
)?;
|
||||
tui_logger::set_default_level(log::LevelFilter::Debug);
|
||||
let terminal = ratatui::init();
|
||||
let result = run(terminal).await;
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
use crate::event::Event;
|
||||
|
||||
pub(crate) struct DummyUI {}
|
||||
|
||||
impl super::UI for DummyUI {
|
||||
fn new() -> color_eyre::Result<Self> {
|
||||
Ok(Self {})
|
||||
}
|
||||
|
||||
fn set_log_level(_log_level: log::LevelFilter) {}
|
||||
|
||||
async fn run(
|
||||
self,
|
||||
_tx: tokio::sync::mpsc::UnboundedSender<Event>,
|
||||
mut rx: tokio::sync::mpsc::UnboundedReceiver<Event>,
|
||||
) -> color_eyre::Result<()> {
|
||||
while rx.recv().await.is_some() {}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
use crate::event::Event;
|
||||
|
||||
pub(crate) struct LoggerUI {}
|
||||
|
||||
impl super::UI for LoggerUI {
|
||||
fn new() -> color_eyre::Result<Self> {
|
||||
env_logger::Builder::new().filter_level(log::LevelFilter::Debug).init();
|
||||
Ok(Self {})
|
||||
}
|
||||
|
||||
fn set_log_level(log_level: log::LevelFilter) {
|
||||
log::set_max_level(log_level);
|
||||
}
|
||||
|
||||
async fn run(
|
||||
self,
|
||||
_tx: tokio::sync::mpsc::UnboundedSender<Event>,
|
||||
mut rx: tokio::sync::mpsc::UnboundedReceiver<Event>,
|
||||
) -> color_eyre::Result<()> {
|
||||
while rx.recv().await.is_some() {}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
use crate::event::Event;
|
||||
|
||||
pub(crate) trait UI {
|
||||
fn new() -> color_eyre::Result<Self>
|
||||
where
|
||||
Self: std::marker::Sized;
|
||||
|
||||
fn set_log_level(log_level: log::LevelFilter);
|
||||
|
||||
async fn run(
|
||||
self,
|
||||
tx: tokio::sync::mpsc::UnboundedSender<Event>,
|
||||
rx: tokio::sync::mpsc::UnboundedReceiver<Event>,
|
||||
) -> color_eyre::Result<()>;
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(feature="tui", feature="logger"))] {
|
||||
compile_error!("feature \"logger\" and feature \"tui\" cannot be enaled at the same time");
|
||||
} else if #[cfg(feature="tui" )] {
|
||||
mod tui;
|
||||
pub(crate) use self::tui::Tui as UIImpl;
|
||||
} else if #[cfg(feature = "logger")] {
|
||||
mod logger;
|
||||
pub(crate) use self::logger::LoggerUI as UIImpl;
|
||||
} else {
|
||||
mod dummy;
|
||||
pub(crate) use self::dummy::DummyUI as UIImpl;
|
||||
}
|
||||
}
|
||||
+97
-31
@@ -1,10 +1,12 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use color_eyre::eyre::WrapErr;
|
||||
use crossterm::event::{
|
||||
Event as CrosstermEvent, KeyCode, KeyModifiers, MouseEventKind,
|
||||
};
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use ratatui::{
|
||||
Frame,
|
||||
DefaultTerminal, Frame,
|
||||
layout::{Alignment, Constraint, Direction, Flex, Layout},
|
||||
style::{Color, Style},
|
||||
text::{Line, Text},
|
||||
@@ -13,13 +15,96 @@ use ratatui::{
|
||||
use tui_logger::{TuiLoggerWidget, TuiWidgetEvent, TuiWidgetState};
|
||||
|
||||
use crate::{
|
||||
event::{AppEvent, AppMode, AppState, Event},
|
||||
event::{AppEvent, Event},
|
||||
proxy::ProxyType,
|
||||
utils::is_docker,
|
||||
};
|
||||
|
||||
const FPS: f64 = 30.0;
|
||||
|
||||
pub(crate) struct Tui {
|
||||
terminal: DefaultTerminal,
|
||||
}
|
||||
|
||||
impl super::UI for Tui {
|
||||
fn new() -> color_eyre::Result<Self> {
|
||||
tui_logger::init_logger(log::LevelFilter::Debug)
|
||||
.wrap_err("failed to initialize logger")?;
|
||||
tui_logger::set_default_level(log::LevelFilter::Debug);
|
||||
Ok(Self { terminal: ratatui::init() })
|
||||
}
|
||||
|
||||
fn set_log_level(log_level: log::LevelFilter) {
|
||||
log::set_max_level(log_level);
|
||||
tui_logger::set_default_level(log_level);
|
||||
}
|
||||
|
||||
async fn run(
|
||||
mut self,
|
||||
tx: tokio::sync::mpsc::UnboundedSender<Event>,
|
||||
mut rx: tokio::sync::mpsc::UnboundedReceiver<Event>,
|
||||
) -> color_eyre::Result<()> {
|
||||
let tick_task = tokio::spawn(tick_event_listener(tx.clone()));
|
||||
let crossterm_task = tokio::spawn(crossterm_event_listener(tx));
|
||||
let mut app_state = AppState::new();
|
||||
let logger_state = TuiWidgetState::default();
|
||||
while !matches!(app_state.mode, AppMode::Quit) {
|
||||
if let Some(event) = rx.recv().await {
|
||||
if handle_event(event, &mut app_state, &logger_state).await {
|
||||
self.terminal
|
||||
.draw(|frame| draw(frame, &app_state, &logger_state))
|
||||
.wrap_err("failed to draw tui")?;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
drop(rx);
|
||||
tick_task.await.wrap_err("failed to spawn tui tick task")??;
|
||||
crossterm_task
|
||||
.await
|
||||
.wrap_err("failed to spawn tui crossterm task")??;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Tui {
|
||||
fn drop(&mut self) {
|
||||
ratatui::restore();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) enum AppMode {
|
||||
#[default]
|
||||
Running,
|
||||
/// Wait for the user confirmation to close the UI
|
||||
Done,
|
||||
/// Close the UI
|
||||
Quit,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct AppState {
|
||||
pub(crate) mode: AppMode,
|
||||
|
||||
pub(crate) geodb_total: u64,
|
||||
pub(crate) geodb_downloaded: usize,
|
||||
|
||||
pub(crate) sources_total: HashMap<ProxyType, usize>,
|
||||
pub(crate) sources_scraped: HashMap<ProxyType, usize>,
|
||||
|
||||
pub(crate) proxies_total: HashMap<ProxyType, usize>,
|
||||
pub(crate) proxies_checked: HashMap<ProxyType, usize>,
|
||||
pub(crate) proxies_working: HashMap<ProxyType, usize>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub(crate) fn new() -> Self {
|
||||
AppState::default()
|
||||
}
|
||||
}
|
||||
|
||||
async fn tick_event_listener(
|
||||
tx: tokio::sync::mpsc::UnboundedSender<Event>,
|
||||
) -> color_eyre::Result<()> {
|
||||
@@ -55,33 +140,6 @@ async fn crossterm_event_listener(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn run(
|
||||
mut terminal: ratatui::DefaultTerminal,
|
||||
tx: tokio::sync::mpsc::UnboundedSender<Event>,
|
||||
mut rx: tokio::sync::mpsc::UnboundedReceiver<Event>,
|
||||
) -> color_eyre::Result<()> {
|
||||
let tick_task = tokio::spawn(tick_event_listener(tx.clone()));
|
||||
let crossterm_task = tokio::spawn(crossterm_event_listener(tx));
|
||||
let mut app_state = AppState::new();
|
||||
let logger_state = TuiWidgetState::default();
|
||||
let is_docker = is_docker().await;
|
||||
while (is_docker && matches!(app_state.mode, AppMode::Running))
|
||||
|| (!is_docker && !matches!(app_state.mode, AppMode::Quit))
|
||||
{
|
||||
if let Some(event) = rx.recv().await {
|
||||
if handle_event(event, &mut app_state, &logger_state) {
|
||||
terminal
|
||||
.draw(|frame| draw(frame, &app_state, &logger_state))
|
||||
.wrap_err("failed to draw tui")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(rx);
|
||||
tick_task.await.wrap_err("failed to spawn tui tick task")??;
|
||||
crossterm_task.await.wrap_err("failed to spawn tui crossterm task")??;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
#[allow(clippy::too_many_lines)]
|
||||
@@ -250,7 +308,11 @@ fn draw(f: &mut Frame, state: &AppState, logger_state: &TuiWidgetState) {
|
||||
f.render_widget(table, result_layout[1]);
|
||||
}
|
||||
|
||||
fn handle_event(
|
||||
async fn is_interactive() -> bool {
|
||||
is_docker().await
|
||||
}
|
||||
|
||||
async fn handle_event(
|
||||
event: Event,
|
||||
state: &mut AppState,
|
||||
logger_state: &TuiWidgetState,
|
||||
@@ -318,7 +380,11 @@ fn handle_event(
|
||||
*state.proxies_working.entry(proxy_type).or_default() += 1;
|
||||
}
|
||||
AppEvent::Done => {
|
||||
state.mode = AppMode::Done;
|
||||
state.mode = if is_interactive().await {
|
||||
AppMode::Quit
|
||||
} else {
|
||||
AppMode::Done
|
||||
};
|
||||
}
|
||||
}
|
||||
false
|
||||
Reference in New Issue
Block a user