From 8b881560dd8884e8e54e1e64654f79749d9ff456 Mon Sep 17 00:00:00 2001 From: Matthias Jaros Date: Mon, 13 Apr 2026 17:31:55 +0200 Subject: Renamed package from network_scanner to jscanner --- .../java/com/it_jaros/jscanner/ProgressBar.java | 118 +++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 src/main/java/com/it_jaros/jscanner/ProgressBar.java (limited to 'src/main/java/com/it_jaros/jscanner/ProgressBar.java') diff --git a/src/main/java/com/it_jaros/jscanner/ProgressBar.java b/src/main/java/com/it_jaros/jscanner/ProgressBar.java new file mode 100644 index 0000000..5ea347b --- /dev/null +++ b/src/main/java/com/it_jaros/jscanner/ProgressBar.java @@ -0,0 +1,118 @@ +package com.it_jaros.jscanner; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ProgressBar { + + private final ScheduledExecutorService ui = Executors.newSingleThreadScheduledExecutor(); + private final ReentrantLock lock = new ReentrantLock(); + private final int columnWidth = ProgressBar.getColumnWidth(); + + private List hosts; + + private static int getColumnWidth() { + try { + Process process = new ProcessBuilder("sh", "-c", "stty size < /dev/tty").start(); + + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(process.getInputStream()))) { + String line = reader.readLine(); + if (line != null && !line.isBlank()) { + Matcher matcher = Pattern.compile("^\\d+\\s+(\\d+)").matcher(line.trim()); + if (matcher.matches()) { + return Integer.parseInt(matcher.group(1)); + } + } + } + } catch (Exception ignored) { + // does not matter why it did not work + } + + return 120; + } + + public void start() { + this.hosts = new ArrayList<>(); + System.out.print("Scanning targets...\n\n"); + ui.scheduleAtFixedRate(() -> { + lock.lock(); + drawProgress(false); + lock.unlock(); + }, 1, 200, TimeUnit.MILLISECONDS); + } + + private void drawProgress(boolean last) { + // find and print finished hosts one last time + for (Iterator it = hosts.iterator(); it.hasNext();) { + Progress p = it.next(); + if (p.done().get() == p.total()) { + it.remove(); + drawBar(p); + } + } + + // the more progressed the host the more up it is + hosts.sort(Comparator.comparingInt((Progress p) -> p.done().get()).reversed()); + for (Progress progress : hosts) { + drawBar(progress); + } + + if (!last) { + // move cursor up again + System.out.print("\u001b[" + hosts.size() + "A"); + } + } + + public void submit(Progress progress) { + lock.lock(); + hosts.add(progress); + lock.unlock(); + } + + private void drawBar(Progress progress) { + System.out.print("\u001b[2K\r"); // clear whole line + System.out.println(createBar( + progress.host(), + progress.open().get(), + progress.filtered().get(), + progress.done().get(), + progress.total())); + } + + public String createBar(String label, int open, int filtered, int done, int total) { + int terminalWidth = columnWidth; + int bracketWidth = terminalWidth / 3; + double pct = total == 0 ? 1.0 : (done / (double) total); + int percent = (int) (pct * 100); + + String statsLeft = String.format("open:%d filtered:%d (%d/%d)", open, filtered, done, total); + String statsRight = String.format("%3d%%", percent); + int filled = (int) (pct * bracketWidth); + String brackets = "[" + "#".repeat(filled) + "-".repeat(bracketWidth - filled) + "]"; + + int spacesBetween = terminalWidth - bracketWidth - (label + statsLeft + statsRight).length() - 5; + return String.format("%s%s%s %s %s", label, " ".repeat(spacesBetween),statsLeft, brackets, statsRight); + } + + public void stop() { + ui.shutdown(); + try { + ui.awaitTermination(10, TimeUnit.SECONDS); + // we need to draw one last time for the 100% to appear + drawProgress(true); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } + } +} -- cgit v1.3.1