Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package nbping for openSUSE:Factory checked 
in at 2026-03-11 20:57:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/nbping (Old)
 and      /work/SRC/openSUSE:Factory/.nbping.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "nbping"

Wed Mar 11 20:57:16 2026 rev:2 rq:1338293 version:0.6.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/nbping/nbping.changes    2025-11-18 
15:39:34.854799986 +0100
+++ /work/SRC/openSUSE:Factory/.nbping.new.8177/nbping.changes  2026-03-11 
20:59:22.495954823 +0100
@@ -1,0 +2,13 @@
+Sun Jan 25 15:28:10 UTC 2026 - Martin Hauke <[email protected]>
+
+- Update to version 0.6.1:
+  * feat: update version to v0.6.1 and rename project to NBping.
+  * feat: nping rename to nbping (#105).
+
+-------------------------------------------------------------------
+Tue Jan  6 11:02:17 UTC 2026 - Martin Hauke <[email protected]>
+
+- Update to version 0.6.0:
+  * feat: add prometheus exporter mode (#103)
+
+-------------------------------------------------------------------

Old:
----
  Nping-0.5.0.obscpio

New:
----
  Nping-0.6.1.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ nbping.spec ++++++
--- /var/tmp/diff_new_pack.1WjwgP/_old  2026-03-11 20:59:23.567998973 +0100
+++ /var/tmp/diff_new_pack.1WjwgP/_new  2026-03-11 20:59:23.575999303 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           nbping
-Version:        0.5.0
+Version:        0.6.1
 Release:        0
 Summary:        A ping tool with real-time data and visualizations
 License:        MIT
@@ -48,9 +48,6 @@
 
 %install
 %{cargo_install}
-# next version will be named "nbping"
-#  https://github.com/hanshuaikang/Nping/issues/62#issuecomment-3483448009
-mv %{buildroot}%{_bindir}/nping %{buildroot}%{_bindir}/nbping
 
 %check
 #%%{cargo_test}

++++++ Nping-0.5.0.obscpio -> Nping-0.6.1.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/.github/workflows/release.yml 
new/Nping-0.6.1/.github/workflows/release.yml
--- old/Nping-0.5.0/.github/workflows/release.yml       2025-09-10 
17:15:13.000000000 +0200
+++ new/Nping-0.6.1/.github/workflows/release.yml       2026-01-25 
09:48:45.000000000 +0100
@@ -42,7 +42,7 @@
         with:
           # (required) Comma-separated list of binary names (non-extension 
portion of filename) to build and upload.
           # Note that glob pattern is not supported yet.
-          bin: nping
+          bin: nbping
           # (optional) Target triple, default is host triple.
           target: ${{ matrix.target }}
           # (required) GitHub token for uploading assets to GitHub Releases.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/Cargo.lock new/Nping-0.6.1/Cargo.lock
--- old/Nping-0.5.0/Cargo.lock  2025-09-10 17:15:13.000000000 +0200
+++ new/Nping-0.6.1/Cargo.lock  2026-01-25 09:48:45.000000000 +0100
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "addr2line"
@@ -88,6 +88,12 @@
 checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
 
 [[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
 name = "autocfg"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -302,12 +308,52 @@
 checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
 
 [[package]]
+name = "futures-channel"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+
+[[package]]
+name = "futures-sink"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+
+[[package]]
 name = "gimli"
 version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
 
 [[package]]
+name = "h2"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
 name = "hashbrown"
 version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -325,12 +371,106 @@
 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
+name = "http"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+
+[[package]]
+name = "httpdate"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
+
+[[package]]
+name = "hyper"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "pin-utils",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "hyper",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
 name = "ident_case"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 
 [[package]]
+name = "indexmap"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
 name = "indoc"
 version = "2.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -465,12 +605,16 @@
 ]
 
 [[package]]
-name = "nping"
-version = "0.5.0"
+name = "nbping"
+version = "0.6.1"
 dependencies = [
  "anyhow",
  "clap",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
  "pinger",
+ "prometheus",
  "ratatui",
  "tokio",
 ]
@@ -526,13 +670,19 @@
 checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
 
 [[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
 name = "pinger"
 version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "dbc53a927954d81a867bd7e9163a4b5f13babdf1627863d5b0ab52587fdb02ad"
 dependencies = [
  "lazy-regex",
- "thiserror",
+ "thiserror 2.0.9",
  "winping",
 ]
 
@@ -556,6 +706,27 @@
 ]
 
 [[package]]
+name = "prometheus"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1"
+dependencies = [
+ "cfg-if",
+ "fnv",
+ "lazy_static",
+ "memchr",
+ "parking_lot",
+ "protobuf",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "protobuf"
+version = "2.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
+
+[[package]]
 name = "quote"
 version = "1.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -691,6 +862,12 @@
 ]
 
 [[package]]
+name = "slab"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
+
+[[package]]
 name = "smallvec"
 version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -753,11 +930,31 @@
 
 [[package]]
 name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
 version = "2.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
 dependencies = [
- "thiserror-impl",
+ "thiserror-impl 2.0.9",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
@@ -801,6 +998,44 @@
 ]
 
 [[package]]
+name = "tokio-util"
+version = "0.7.16"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+dependencies = [
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
 name = "unicode-ident"
 version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -842,6 +1077,15 @@
 checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/Cargo.toml new/Nping-0.6.1/Cargo.toml
--- old/Nping-0.5.0/Cargo.toml  2025-09-10 17:15:13.000000000 +0200
+++ new/Nping-0.6.1/Cargo.toml  2026-01-25 09:48:45.000000000 +0100
@@ -1,9 +1,9 @@
 [package]
-name = "nping"
-version = "0.5.0"
+name = "nbping"
+version = "0.6.1"
 edition = "2021"
 license = "MIT License"
-description = "Nping is a Ping tool developed in Rust. It supports concurrent 
Ping for multiple addresses, visual chart display, real-time data updates, and 
other features."
+description = "NBping is a Ping tool developed in Rust. It supports concurrent 
Ping for multiple addresses, visual chart display, real-time data updates, and 
other features."
 authors = ["hanshuaikang https://github.com/hanshuaikang";]
 
 [dependencies]
@@ -12,3 +12,7 @@
 tokio = { version = "1.42.0", features = ["full"] }
 pinger="2.0.0"
 anyhow="1.0.89"
+prometheus = "0.13"
+hyper = { version = "1.0", features = ["full"] }
+hyper-util = { version = "0.1", features = ["tokio", "server", "http1", 
"http2"] }
+http-body-util = "0.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/README.md new/Nping-0.6.1/README.md
--- old/Nping-0.5.0/README.md   2025-09-10 17:15:13.000000000 +0200
+++ new/Nping-0.6.1/README.md   2026-01-25 09:48:45.000000000 +0100
@@ -1,10 +1,10 @@
-<h1 align="center"> 🏎 Nping </h1>
+<h1 align="center"> 🏎 NBping </h1>
 <p align="center">
-    <em>Nping is a Ping tool developed in Rust. It supports concurrent Ping 
for multiple addresses, visual chart display, real-time data updates, and other 
features.</em>
+    <em>NBping is a Ping tool developed in Rust. It supports concurrent Ping 
for multiple addresses, visual chart display, real-time data updates, and other 
features.</em>
 </p>
 
 <p align="center">
-    <img src="docs/imgs/nb.gif" alt="Nping demo" width="30%">
+    <img src="docs/imgs/nb.gif" alt="NBping demo" width="30%">
 </p>
 
 <p align="center">
@@ -16,44 +16,77 @@
 
 [中文文档](./README_ZH.md)
 
+📢 **NBPing (formerly Nping)**
+
+> [!IMPORTANT]
+> **Renaming Notice**
+>
+> This project has been officially renamed from **Nping** to **NBPing**.
+>
+> Please update your bookmarks, dependencies, and installation scripts 
accordingly. The old name is now deprecated and will no longer be maintained.
+> ```bash
+> nbping --help
+> ```
+
+
+**[New Feature] 🛰️ NBping Prometheus Exporter Now Supported**
+
+Now, NBping supports exporting ping metrics to Prometheus format. You can use 
the exporter subcommand to start the exporter server. [Learn 
more](#exporter-mode)
+
+```bash
+nbping exporter www.baidu.com www.google.com -i 1 -p 9100
+```
+Then, you can scrape the metrics from `http://localhost:9100/metrics`
+
 **Graph View**
 <p align="center">
-    <img src="docs/imgs/black.gif" alt="Nping demo" width="100%">
+    <img src="docs/imgs/black.gif" alt="NBping demo" width="100%">
 </p>
 
 **Table View**
 <p align="center">
-    <img src="docs/imgs/table.gif" alt="Nping demo" width="100%">
+    <img src="docs/imgs/table.gif" alt="NBping demo" width="100%">
 </p>
 
 **Point View**
 <p align="center">
-    <img src="docs/imgs/point.gif" alt="Nping demo" width="100%">
+    <img src="docs/imgs/point.gif" alt="NBping demo" width="100%">
 </p>
 
 **Sparkline View**
 <p align="center">
-    <img src="docs/imgs/sparkline.gif" alt="Nping demo" width="100%">
+    <img src="docs/imgs/sparkline.gif" alt="NBping demo" width="100%">
+</p>
+
+
+#### Exporter Mode
+Now NBping supports exporting ping metrics to Prometheus format. you can use 
exporter subcommand to start the exporter server.
+
+```bash
+nbping exporter www.baidu.com www.google.com -i 1 -p 9100
+```
+Then, you can scrape the metrics from `http://localhost:9100/metrics`
+
+You can use grafana to visualize the data
+<p align="center">
+    <img src="docs/imgs/grafana.png" alt="NBping demo" width="100%"> 
 </p>
 
 
+
 ## Installation
 
 #### MacOS Homebrew
 ```bash
-brew tap hanshuaikang/nping
-brew install nping
+brew tap hanshuaikang/nbping
+brew install nbping
 
-nping --help
+nbping --help
 ```
 
 ## Feature:
-- Supports concurrent Ping for multiple addresses
-- Supports visual latency display
-- Real-time display of maximum, minimum, average latency, packet loss rate, 
and other metrics
-- Support IpV4 and IpV6
-- Supports concurrent pinging of n ip's under one address.
-- Support output results to files
+- TCP Ping support
+- IP range Ping support
 
 ## Roadmap:
 - Optimize UI interface, add more dynamic effects.
@@ -61,13 +94,13 @@
 ## Usage
 
 ```bash
-nping www.baidu.com www.google.com www.apple.com www.sina.com -c 20 -i 2
+nbping www.baidu.com www.google.com www.apple.com www.sina.com -c 20 -i 2
 
-nping --help
+nbping --help
 
-🏎  Nping mean NB Ping, A Ping Tool in Rust with Real-Time Data and 
Visualizations
+🏎  NBping mean NB Ping, A Ping Tool in Rust with Real-Time Data and 
Visualizations
 
-Usage: nping [OPTIONS] <TARGET>...
+Usage: nbping [OPTIONS] <TARGET>...
 
 Arguments:
   <TARGET>...  target IP address or hostname to ping
@@ -84,13 +117,33 @@
 
 ```
 
+### Exporter Usage
+
+```bash
+nbping exporter www.baidu.com www.google.com -i 1 -p 9100
+
+./nbping exporter --help
+Exporter mode for monitoring
+
+Usage: nbping exporter [OPTIONS] <TARGET>...
+
+Arguments:
+  <TARGET>...  target IP addresses or hostnames to ping
+
+Options:
+  -i, --interval <INTERVAL>  Interval in seconds between pings [default: 1]
+  -p, --port <PORT>          Prometheus metrics HTTP port [default: 9090]
+  -h, --help                 Print help
+```
+
+
 ## Acknowledgements
-Thanks to these people for their feedback and suggestions for 🏎Nping!
+Thanks to these people for their feedback and suggestions for 🏎NBping!
 
 | [ThatFlower](https://github.com/ThatFlower) | 
[zx4i](https://github.com/zx4i) | [snail2sky](https://github.com/snail2sky) | 
[shenshouer](https://github.com/shenshouer) | 
[vnt-dev](https://github.com/vnt-dev) | 
[qingyuan0o0](https://github.com/qingyuan0o0) 
 | [Onlywzr](https://github.com/Onlywzr)
 
-Thanks to these self-media for reposting and paying attention to 🏎Nping!
+Thanks to these self-media for reposting and paying attention to 🏎NBping!
 
 | [阮一峰的网络日志](https://www.ruanyifeng.com/blog/weekly/) |[Rust 
中文社区](https://rustcc.cn/) | 
[公众号:奇妙的linux世界](https://mp.weixin.qq.com/s/lK_OqKp2yY8lDBoyLxtdGA) | 
[公众号:IT运维技术圈](https://mp.weixin.qq.com/s/bDJZ-H02dIKG3R7LQCeyaQ)
 | [X:@geekbb](https://x.com/geekbb/status/1875754541905539510) | 
[公众号:一飞开源](https://mp.weixin.qq.com/s/BZjr54h8dIQgzr8UW3fwOQ) | [公众号: 
开源日记](https://mp.weixin.qq.com/s/uGtkD4x_XOFyKNbIy5pHYA)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/README_ZH.md new/Nping-0.6.1/README_ZH.md
--- old/Nping-0.5.0/README_ZH.md        2025-09-10 17:15:13.000000000 +0200
+++ new/Nping-0.6.1/README_ZH.md        2026-01-25 09:48:45.000000000 +0100
@@ -1,38 +1,73 @@
 
-<h1 align="center"> 🏎 Nping </h1>
+<h1 align="center"> 🏎 NBping </h1>
 <p align="center">
-    <em>Nping 是一个基于 Rust 开发的终端可视化 Ping 工具, 支持多地址并发 Ping, 可视化图表展示, 数据实时更新等特性 
</em>
+    <em>NBping 是一个基于 Rust 开发的终端可视化 Ping 工具, 支持多地址并发 Ping, 可视化图表展示, 数据实时更新等特性 
</em>
 </p>
 <p align="center">
-    <img src="docs/imgs/nb.gif" alt="Nping demo" width="30%">
+    <img src="docs/imgs/nb.gif" alt="NBping demo" width="30%">
 </p>
 
 <p align="center">
     <a 
href="https://hellogithub.com/repository/21f5600774554866a3d686308df2dbf0"; 
target="_blank">
         <img 
src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=21f5600774554866a3d686308df2dbf0&claim_uid=uT2Sc8Xli4PUA76&theme=neutral";
 alt="Featured|HelloGitHub" style="width: 200px; height: 60px;" width="250" 
height="60" />
     </a>
-<a href="https://trendshift.io/repositories/13472"; target="_blank"><img 
src="https://trendshift.io/api/badge/repositories/13472"; 
alt="hanshuaikang%2FNping | Trendshift" style="width: 200px; height: 60px;" 
width="250" height="55"/></a>
+<a href="https://trendshift.io/repositories/13472"; target="_blank"><img 
src="https://trendshift.io/api/badge/repositories/13472"; 
alt="hanshuaikang%2FNBping | Trendshift" style="width: 200px; height: 60px;" 
width="250" height="55"/></a>
 </p>
 
+📢 **Nping 现在已经更名为 NBPing(nbping)**
+
+> [!IMPORTANT]
+> **更名通知**
+>
+> 本项目已从 **Nping** 正式更名为 **NBPing**。
+>
+> 请相应更新您的书签、依赖项和安装脚本。旧名称现已弃用,不再维护。
+> ```bash
+> nbping --help
+> ```
+
+**[新功能] 🛰️Exporter 模式**
+
+现在 NBping 支持通过将 Ping 指标数据通过 Prometheus 格式导出,你可以使用 Grafana 等工具进行可视化展示。
+
+```bash
+nbping exporter www.baidu.com www.google.com -i 1 -p 9100
+```
+Then, you can scrape the metrics from `http://localhost:9100/metrics`
+
+
 **图表视图**
 <p align="center">
-    <img src="docs/imgs/black.gif" alt="Nping demo" width="100%">
+    <img src="docs/imgs/black.gif" alt="NBping demo" width="100%">
 </p>
 
 
 **表格视图**
 <p align="center">
-    <img src="docs/imgs/table.gif" alt="Nping demo" width="100%">
+    <img src="docs/imgs/table.gif" alt="NBping demo" width="100%">
 </p>
 
 **点视图**
 <p align="center">
-    <img src="docs/imgs/point.gif" alt="Nping demo" width="100%">
+    <img src="docs/imgs/point.gif" alt="NBping demo" width="100%">
 </p>
 
 **Sparkline 视图**
 <p align="center">
-    <img src="docs/imgs/sparkline.gif" alt="Nping demo" width="100%">
+    <img src="docs/imgs/sparkline.gif" alt="NBping demo" width="100%">
+</p>
+
+** Exporter 模式 **
+现在 NBping 支持通过将 Ping 指标数据通过 Prometheus 格式导出,你可以使用 Grafana 等工具进行可视化展示。
+
+```bash
+nbping exporter www.baidu.com www.google.com -i 1 -p 9100
+```
+然后你可以访问获取这些数据 `http://localhost:9100/metrics`
+
+你可以通过 Grafana 来可视化这些数据
+<p align="center">
+    <img src="docs/imgs/grafana.png" alt="NBping demo" width="100%"> 
 </p>
 
 
@@ -40,20 +75,15 @@
 
 #### MacOS Homebrew
 ```bash
-brew tap hanshuaikang/nping
-brew install nping
+brew tap hanshuaikang/nbping
+brew install nbping
 
-nping --help
+nbping --help
 ```
 
-
 ## Feature:
-- 支持多地址并发同时 Ping
-- 支持可视化延迟展示
-- 实时最大最小平均延迟丢包率等指标展示
-- 支持 IpV4 和 IpV6
-- 支持一个地址下并发 Ping n 个 ip
-- 支持输出结果到文件
+- TCP Ping 支持
+- IP 段 Ping 支持
 
 ## 后续的计划:
 - UI 界面优化, 增加更多的动态效果
@@ -61,13 +91,13 @@
 ## Usage
 
 ```bash
-nping www.baidu.com www.google.com www.apple.com www.sina.com -c 20 -i 2
+nbping www.baidu.com www.google.com www.apple.com www.sina.com -c 20 -i 2
 
-nping --help
+nbping --help
 
-🏎  Nping mean NB Ping, A Ping Tool in Rust with Real-Time Data and 
Visualizations
+🏎  NBping mean NB Ping, A Ping Tool in Rust with Real-Time Data and 
Visualizations
 
-Usage: nping [OPTIONS] <TARGET>...
+Usage: nbping [OPTIONS] <TARGET>...
 
 Arguments:
   <TARGET>...  target IP address or hostname to ping
@@ -83,13 +113,33 @@
   -V, --version                Print version
 ```
 
+
+### Exporter Usage
+
+```bash
+nbping exporter www.baidu.com www.google.com -i 1 -p 9100
+
+./nbping exporter --help
+Exporter mode for monitoring
+
+Usage: nbping exporter [OPTIONS] <TARGET>...
+
+Arguments:
+  <TARGET>...  target IP addresses or hostnames to ping
+
+Options:
+  -i, --interval <INTERVAL>  Interval in seconds between pings [default: 1]
+  -p, --port <PORT>          Prometheus metrics HTTP port [default: 9090]
+  -h, --help                 Print help
+```
+
 ## 致谢
-感谢这些朋友对 Nping 提出的反馈和建议。
+感谢这些朋友对 NBping 提出的反馈和建议。
 
 | [ThatFlower](https://github.com/ThatFlower) | 
[zx4i](https://github.com/zx4i) | [snail2sky](https://github.com/snail2sky) | 
[shenshouer](https://github.com/shenshouer) | 
[vnt-dev](https://github.com/vnt-dev) | 
[qingyuan0o0](https://github.com/qingyuan0o0)
 | [Onlywzr](https://github.com/Onlywzr)
 
-感谢以下自媒体对 Nping 的关注和转发。
+感谢以下自媒体对 NBping 的关注和转发。
 
 | [阮一峰的网络日志](https://www.ruanyifeng.com/blog/weekly/) |[Rust 
中文社区](https://rustcc.cn/) | 
[公众号:奇妙的linux世界](https://mp.weixin.qq.com/s/lK_OqKp2yY8lDBoyLxtdGA) | 
[公众号:IT运维技术圈](https://mp.weixin.qq.com/s/bDJZ-H02dIKG3R7LQCeyaQ)
 | [X:@geekbb](https://x.com/geekbb/status/1875754541905539510) | 
[公众号:一飞开源](https://mp.weixin.qq.com/s/BZjr54h8dIQgzr8UW3fwOQ) | [公众号: 
开源日记](https://mp.weixin.qq.com/s/uGtkD4x_XOFyKNbIy5pHYA)
Binary files old/Nping-0.5.0/docs/imgs/grafana.png and 
new/Nping-0.6.1/docs/imgs/grafana.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/src/data_processor.rs 
new/Nping-0.6.1/src/data_processor.rs
--- old/Nping-0.5.0/src/data_processor.rs       2025-09-10 17:15:13.000000000 
+0200
+++ new/Nping-0.6.1/src/data_processor.rs       2026-01-25 09:48:45.000000000 
+0100
@@ -120,4 +120,4 @@
             }
         }
     });
-}
\ No newline at end of file
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/src/exporter/metric.rs 
new/Nping-0.6.1/src/exporter/metric.rs
--- old/Nping-0.5.0/src/exporter/metric.rs      1970-01-01 01:00:00.000000000 
+0100
+++ new/Nping-0.6.1/src/exporter/metric.rs      2026-01-25 09:48:45.000000000 
+0100
@@ -0,0 +1,199 @@
+use prometheus::{CounterVec, HistogramVec, HistogramOpts, Opts, Registry, 
TextEncoder};
+use std::sync::Arc;
+
+/// Prometheus 指标收集器
+#[derive(Debug, Clone)]
+pub struct PrometheusMetrics {
+    /// ping 延迟直方图指标
+    ping_duration_histogram: HistogramVec,
+    /// ping 请求总数(按状态分组)
+    ping_requests_total: CounterVec,
+    /// Prometheus 注册表
+    registry: Arc<Registry>,
+}
+
+impl PrometheusMetrics {
+    /// 创建新的 Prometheus 指标收集器
+    pub fn new() -> Result<Self, prometheus::Error> {
+        // 创建注册表
+        let registry = Arc::new(Registry::new());
+
+        // 定义延迟的 buckets (秒): 1ms, 5ms, 10ms, 50ms, 100ms, 500ms, 1s, 5s, 10s, 
+Inf
+        let buckets = vec![
+            0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0,
+        ];
+
+        // 创建直方图指标
+        let ping_duration_histogram = HistogramVec::new(
+            HistogramOpts::new(
+                "nbping_ping_duration_seconds",
+                "Histogram of ping durations in seconds",
+            )
+                .buckets(buckets),
+            &["target", "ip"], // label 名称
+        )?;
+
+        // 创建请求总数计数器
+        let ping_requests_total = CounterVec::new(
+            Opts::new(
+                "nbping_ping_requests_total",
+                "Total number of ping requests",
+            ),
+            &["target", "ip", "status"],
+        )?;
+
+        // 注册指标
+        registry.register(Box::new(ping_duration_histogram.clone()))?;
+        registry.register(Box::new(ping_requests_total.clone()))?;
+
+        Ok(Self {
+            ping_duration_histogram,
+            ping_requests_total,
+            registry,
+        })
+    }
+
+    /// 记录成功的 ping(记录到直方图)
+    pub fn record_ping_success(&self, target: &str, ip: &str, rtt_ms: f64) {
+        let rtt_seconds = rtt_ms / 1000.0;
+
+        self.ping_requests_total
+            .with_label_values(&[target, ip, "success"])
+            .inc();
+
+        // 为直方图添加 labels 并观察值
+        self.ping_duration_histogram
+            .with_label_values(&[target, ip])
+            .observe(rtt_seconds);
+    }
+
+    /// 记录超时的 ping(不记录到直方图,但可以在这里添加其他指标)
+    pub fn record_ping_timeout(&self, target: &str, ip: &str) {
+        self.ping_requests_total
+            .with_label_values(&[target, ip, "timeout"])
+            .inc();
+    }
+
+    /// 记录错误的 ping
+    pub fn record_ping_error(&self, target: &str, ip: &str) {
+        self.ping_requests_total
+            .with_label_values(&[target, ip, "error"])
+            .inc();
+    }
+
+    /// 获取 Prometheus 格式的指标数据
+    pub fn gather(&self) -> String {
+        let encoder = TextEncoder::new();
+        let metric_families = self.registry.gather();
+
+        encoder.encode_to_string(&metric_families).unwrap_or_else(|e| {
+            eprintln!("Error encoding metrics: {}", e);
+            String::new()
+        })
+    }
+
+}
+
+impl Default for PrometheusMetrics {
+    fn default() -> Self {
+        Self::new().expect("Failed to create PrometheusMetrics")
+    }
+}
+
+/// HTTP 服务器,用于暴露 /metrics 端点
+pub mod http_server {
+    use super::*;
+    use hyper::service::service_fn;
+    use hyper::{Method, Request, Response, StatusCode};
+    use hyper_util::rt::TokioIo;
+    use hyper_util::server::conn::auto::Builder;
+    use http_body_util::Full;
+    use hyper::body::Bytes;
+    use std::convert::Infallible;
+    use std::net::SocketAddr;
+    use std::sync::Arc;
+    use tokio::net::TcpListener;
+
+    /// 启动 Prometheus metrics HTTP 服务器,支持优雅关闭
+    pub async fn start_metrics_server(
+        metrics: Arc<PrometheusMetrics>,
+        addr: SocketAddr,
+        mut shutdown_rx: tokio::sync::oneshot::Receiver<()>,
+    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
+        let listener = TcpListener::bind(addr).await?;
+
+        loop {
+            tokio::select! {
+                // 接受新连接
+                accept_result = listener.accept() => {
+                    match accept_result {
+                        Ok((stream, _)) => {
+                            let metrics = metrics.clone();
+                            
+                            tokio::task::spawn(async move {
+                                let io = TokioIo::new(stream);
+                                let service = service_fn(move |req| {
+                                    handle_request(req, metrics.clone())
+                                });
+
+                                if let Err(err) = 
Builder::new(hyper_util::rt::TokioExecutor::new())
+                                    .serve_connection(io, service)
+                                    .await
+                                {
+                                    eprintln!("Error serving connection: 
{:?}", err);
+                                }
+                            });
+                        }
+                        Err(e) => {
+                            eprintln!("Failed to accept connection: {}", e);
+                        }
+                    }
+                }
+                // 接收关闭信号
+                _ = &mut shutdown_rx => {
+                    println!("Metrics server shutting down gracefully");
+                    break;
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    /// 处理 HTTP 请求
+    async fn handle_request(
+        req: Request<hyper::body::Incoming>,
+        metrics: Arc<PrometheusMetrics>,
+    ) -> Result<Response<Full<Bytes>>, Infallible> {
+        match (req.method(), req.uri().path()) {
+            (&Method::GET, "/metrics") => {
+                let metrics_output = metrics.gather();
+                Ok(Response::builder()
+                    .status(StatusCode::OK)
+                    .header("Content-Type", "text/plain; charset=utf-8")
+                    .body(Full::new(Bytes::from(metrics_output)))
+                    .unwrap())
+            }
+            (&Method::GET, "/") => {
+                let body = r#"<html>
+<head><title>NBPing Metrics</title></head>
+<body>
+<h1>NBPing Metrics</h1>
+<p><a href='/metrics'>Metrics</a></p>
+</body>
+</html>"#;
+                Ok(Response::builder()
+                    .status(StatusCode::OK)
+                    .header("Content-Type", "text/html")
+                    .body(Full::new(Bytes::from(body)))
+                    .unwrap())
+            }
+            _ => {
+                Ok(Response::builder()
+                    .status(StatusCode::NOT_FOUND)
+                    .body(Full::new(Bytes::from("Not Found")))
+                    .unwrap())
+            }
+        }
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/src/exporter/mod.rs 
new/Nping-0.6.1/src/exporter/mod.rs
--- old/Nping-0.5.0/src/exporter/mod.rs 1970-01-01 01:00:00.000000000 +0100
+++ new/Nping-0.6.1/src/exporter/mod.rs 2026-01-25 09:48:45.000000000 +0100
@@ -0,0 +1,6 @@
+mod metric;
+mod runner;
+
+pub use metric::PrometheusMetrics;
+pub use metric::http_server;
+pub use runner::spawn_ping_workers;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/src/exporter/runner.rs 
new/Nping-0.6.1/src/exporter/runner.rs
--- old/Nping-0.5.0/src/exporter/runner.rs      1970-01-01 01:00:00.000000000 
+0100
+++ new/Nping-0.6.1/src/exporter/runner.rs      2026-01-25 09:48:45.000000000 
+0100
@@ -0,0 +1,70 @@
+use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
+use std::thread;
+use std::time::Duration;
+
+use pinger::{ping, PingOptions, PingResult};
+
+use crate::exporter::PrometheusMetrics;
+
+pub fn spawn_ping_workers(
+    targets: Vec<(String, String)>,
+    interval: Duration,
+    running: Arc<AtomicBool>,
+    metrics: Arc<PrometheusMetrics>,
+) -> Vec<thread::JoinHandle<()>> {
+    targets
+        .into_iter()
+        .map(|(addr, ip)| {
+            let running = running.clone();
+            let metrics = metrics.clone();
+            let interval = interval;
+            thread::spawn(move || run_ping_loop(addr, ip, interval, running, 
metrics))
+        })
+        .collect()
+}
+
+fn run_ping_loop(
+    addr: String,
+    ip: String,
+    interval: Duration,
+    running: Arc<AtomicBool>,
+    metrics: Arc<PrometheusMetrics>,
+) {
+    let options = PingOptions::new(ip.clone(), interval, None);
+    let stream = match ping(options) {
+        Ok(stream) => stream,
+        Err(err) => {
+            eprintln!("host({}) ping err, reason: ping init failed, err: {}", 
ip, err);
+            return;
+        }
+    };
+
+    while running.load(Ordering::Relaxed) {
+        match stream.recv() {
+            Ok(PingResult::Pong(duration, _size)) => {
+                let rtt_ms = duration.as_secs_f64() * 1000.0;
+                metrics.record_ping_success(&addr, &ip, rtt_ms);
+            }
+            Ok(PingResult::Timeout(_)) => {
+                metrics.record_ping_timeout(&addr, &ip);
+            }
+            Ok(PingResult::PingExited(status, err)) => {
+                if status.code() != Some(0) {
+                    eprintln!(
+                        "host({}) ping err, reason: ping exited, status: {} 
err: {}",
+                        ip, err, status
+                    );
+                    metrics.record_ping_error(&addr, &ip);
+                }
+            }
+            Ok(PingResult::Unknown(msg)) => {
+                eprintln!("host({}) ping err, reason: unknown, err: {}", ip, 
msg);
+                metrics.record_ping_error(&addr, &ip);
+            }
+            Err(err) => {
+                eprintln!("host({}) ping err, reason: recv failed, err: {}", 
ip, err);
+                metrics.record_ping_error(&addr, &ip);
+            }
+        }
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/src/main.rs new/Nping-0.6.1/src/main.rs
--- old/Nping-0.5.0/src/main.rs 2025-09-10 17:15:13.000000000 +0200
+++ new/Nping-0.6.1/src/main.rs 2026-01-25 09:48:45.000000000 +0100
@@ -5,30 +5,51 @@
 mod ui;
 mod ping_event;
 mod data_processor;
+mod exporter;
 
-use clap::Parser;
+use clap::{Parser, Subcommand};
 use std::collections::{HashSet, VecDeque};
+use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::{Arc, Mutex};
-use tokio::{task, runtime::Builder};
+use std::time::Duration;
+use ratatui::crossterm::event::{self, Event, KeyCode, KeyModifiers};
+use ratatui::crossterm::terminal::{disable_raw_mode, enable_raw_mode};
+use tokio::{task, runtime::Builder, signal};
 use crate::ip_data::IpData;
 use crate::ping_event::PingEvent;
 use crate::data_processor::start_data_processor;
 use std::sync::mpsc;
 use crate::network::send_ping;
+use crate::exporter::{PrometheusMetrics, http_server, spawn_ping_workers};
+
+struct RawModeGuard;
+
+impl RawModeGuard {
+    fn new() -> std::io::Result<Self> {
+        enable_raw_mode()?;
+        Ok(Self)
+    }
+}
+
+impl Drop for RawModeGuard {
+    fn drop(&mut self) {
+        let _ = disable_raw_mode();
+    }
+}
 
 #[derive(Parser, Debug)]
 #[command(
-    version = "v0.5.0",
+    version = "v0.6.1",
     author = "hanshuaikang<https://github.com/hanshuaikang>",
-    about = "🏎  Nping mean NB Ping, A Ping Tool in Rust with Real-Time Data 
and Visualizations"
+    about = "🏎  NBping mean NB Ping, A Ping Tool in Rust with Real-Time Data 
and Visualizations"
 )]
 struct Args {
     /// Target IP address or hostname to ping
-    #[arg(help = "target IP address or hostname to ping", required = true)]
+    #[arg(help = "target IP address or hostname to ping", required = false)]
     target: Vec<String>,
 
     /// Number of pings to send, when count is 0, the maximum number of pings 
per address is calculated
-    #[arg(short, long, default_value_t = 65535, help = "Number of pings to 
send")]
+    #[arg(short, long, default_value_t = 0, help = "Number of pings to send")]
     count: usize,
 
     /// Interval in seconds between pings
@@ -51,6 +72,27 @@
 
     #[arg(short = 'o', long = "output", help = "Output file to save ping 
results")]
     output: Option<String>,
+
+    #[command(subcommand)]
+    command: Option<Commands>,
+}
+
+#[derive(Subcommand, Debug)]
+enum Commands {
+    /// Exporter mode for monitoring
+    Exporter {
+        /// Target IP addresses or hostnames to ping
+        #[arg(help = "target IP addresses or hostnames to ping", required = 
true)]
+        target: Vec<String>,
+
+        /// Interval in seconds between pings
+        #[arg(short, long, default_value_t = 1, help = "Interval in seconds 
between pings")]
+        interval: i32,
+
+        /// Prometheus metrics HTTP port
+        #[arg(short, long, default_value_t = 9090, help = "Prometheus metrics 
HTTP port")]
+        port: u16,
+    },
 }
 
 
@@ -58,45 +100,69 @@
     // parse command line arguments
     let args = Args::parse();
 
-    // set Ctrl+C and q and esc to exit
-    let running = Arc::new(Mutex::new(true));
-
-    // check output file
-    if let Some(ref output_path) = args.output {
-        if std::path::Path::new(output_path).exists() {
-            eprintln!("Output file already exists: {}", output_path);
-            std::process::exit(1);
-        }
-    }
-
+    match args.command {
+        Some(Commands::Exporter { target, interval, port }) => {
+            let worker_threads = (target.len() + 1).max(1);
+            // Create tokio runtime for Exporter mode
+            let rt = Builder::new_multi_thread()
+                .worker_threads(worker_threads)
+                .enable_all()
+                .build()?;
+
+            let res = rt.block_on(run_exporter_mode(target, interval, port));
+
+            // if error print error message and exit
+            if let Err(err) = res {
+                eprintln!("{}", err);
+                std::process::exit(1);
+            }
+        },
+        None => {
+            // Default ping mode
+            if args.target.is_empty() {
+                eprintln!("Error: target IP address or hostname is required");
+                std::process::exit(1);
+            }
 
+            // set Ctrl+C and q and esc to exit
+            let running = Arc::new(Mutex::new(true));
 
-    // after de-duplication, the original order is still preserved
-    let mut seen = HashSet::new();
-    let targets: Vec<String> = args.target.into_iter()
-        .filter(|item| seen.insert(item.clone()))
-        .collect();
+            // check output file
+            if let Some(ref output_path) = args.output {
+                if std::path::Path::new(output_path).exists() {
+                    eprintln!("Output file already exists: {}", output_path);
+                    std::process::exit(1);
+                }
+            }
 
-    // Calculate worker threads based on IP count
-    let ip_count = if targets.len() == 1 && args.multiple > 0 {
-        args.multiple as usize
-    } else {
-        targets.len()
-    };
-    let worker_threads = (ip_count +  1).max(1);
-
-    // Create tokio runtime with specific worker thread count
-    let rt = Builder::new_multi_thread()
-        .worker_threads(worker_threads)
-        .enable_all()
-        .build()?;
-
-    let res = rt.block_on(run_app(targets, args.count, args.interval, 
running.clone(), args.force_ipv6, args.multiple, args.view_type, args.output));
-
-    // if error print error message and exit
-    if let Err(err) = res {
-        eprintln!("{}", err);
-        std::process::exit(1);
+            // after de-duplication, the original order is still preserved
+            let mut seen = HashSet::new();
+            let targets: Vec<String> = args.target.into_iter()
+                .filter(|item| seen.insert(item.clone()))
+                .collect();
+
+            // Calculate worker threads based on IP count
+            let ip_count = if targets.len() == 1 && args.multiple > 0 {
+                args.multiple as usize
+            } else {
+                targets.len()
+            };
+            let worker_threads = (ip_count +  1).max(1);
+
+            // Create tokio runtime with specific worker thread count
+            let rt = Builder::new_multi_thread()
+                .worker_threads(worker_threads)
+                .enable_all()
+                .build()?;
+
+            let res = rt.block_on(run_app(targets, args.count, args.interval, 
running.clone(), args.force_ipv6, args.multiple, args.view_type, args.output));
+
+            // if error print error message and exit
+            if let Err(err) = res {
+                eprintln!("{}", err);
+                std::process::exit(1);
+            }
+        }
     }
     Ok(())
 }
@@ -243,4 +309,144 @@
     draw::restore_terminal(&mut 
terminal_guard.lock().unwrap().terminal.as_mut().unwrap())?;
 
     Ok(())
-}
\ No newline at end of file
+}
+
+async fn run_exporter_mode(
+    targets: Vec<String>,
+    interval: i32,
+    port: u16,
+) -> Result<(), Box<dyn std::error::Error>> {
+    // 创建 Prometheus metrics 收集器
+    let prometheus_metrics = Arc::new(PrometheusMetrics::new()?);
+
+    // 创建信号处理通道
+    let running = Arc::new(AtomicBool::new(true));
+    let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel();
+    let shutdown_tx = Arc::new(Mutex::new(Some(shutdown_tx)));
+
+    // 设置信号处理
+    let running_for_signal = running.clone();
+    let shutdown_tx_for_signal = shutdown_tx.clone();
+    tokio::spawn(async move {
+        match signal::ctrl_c().await {
+            Ok(()) => {
+                println!("\nReceived Ctrl+C, shutting down gracefully...");
+                running_for_signal.store(false, Ordering::Relaxed);
+                
+                // 发送关闭信号给 HTTP 服务器
+                if let Some(tx) = 
shutdown_tx_for_signal.lock().unwrap().take() {
+                    let _ = tx.send(());
+                }
+            }
+            Err(err) => {
+                eprintln!("Unable to listen for shutdown signal: {}", err);
+            }
+        }
+    });
+
+    // 去重目标地址,同时保留原始顺序
+    let mut seen = std::collections::HashSet::new();
+    let targets: Vec<String> = targets.into_iter()
+        .filter(|item| seen.insert(item.clone()))
+        .collect();
+
+    if targets.is_empty() {
+        return Err("No valid targets provided".into());
+    }
+
+    // 解析目标地址为 IP 地址
+    let mut target_pairs = Vec::new();
+    for target in &targets {
+        let ip = network::get_host_ipaddr(target, false)?;
+        target_pairs.push((target.clone(), ip));
+    }
+
+    println!("🚀 NBPing Prometheus Exporter Mode Started");
+    println!("┌─────────────────────────────────────────────────────────");
+    println!("│ Targets     : {} host(s)", targets.len());
+    for (i, target) in targets.iter().enumerate() {
+        if i < 5 {
+            println!("│             : {}", target);
+        } else if i == 5 {
+            println!("│             : ... ({} more)", targets.len() - 5);
+            break;
+        }
+    }
+    println!("│ Interval    : {} seconds", interval);
+    println!("│ Metrics port: {}", port);
+    println!("│ Metrics     : http://0.0.0.0:{}/metrics";, port);
+    println!("│ Actions     : Press Ctrl+C or q to stop");
+    println!("└─────────────────────────────────────────────────────────");
+
+    // 启动 HTTP metrics 服务器
+    let metrics_addr = format!("0.0.0.0:{}", port).parse()?;
+    let metrics_for_server = prometheus_metrics.clone();
+    let metrics_task = task::spawn(async move {
+        http_server::start_metrics_server(
+            metrics_for_server,
+            metrics_addr,
+            shutdown_rx,
+        ).await
+    });
+
+    let interval_ms = interval * 1000;
+    let ping_threads = spawn_ping_workers(
+        target_pairs,
+        Duration::from_millis(interval_ms as u64),
+        running.clone(),
+        prometheus_metrics.clone(),
+    );
+
+    // Listen for q/esc to exit (exporter mode only)
+    let running_for_key = running.clone();
+    let shutdown_tx_for_key = shutdown_tx.clone();
+    let key_listener = std::thread::spawn(move || {
+        let _raw_mode = match RawModeGuard::new() {
+            Ok(guard) => guard,
+            Err(_) => return,
+        };
+
+        while running_for_key.load(Ordering::Relaxed) {
+            if let Ok(true) = event::poll(Duration::from_millis(50)) {
+                if let Ok(Event::Key(key)) = event::read() {
+                    match key.code {
+                        KeyCode::Char('q') | KeyCode::Esc => {
+                            running_for_key.store(false, Ordering::Relaxed);
+                            if let Some(tx) = 
shutdown_tx_for_key.lock().unwrap().take() {
+                                let _ = tx.send(());
+                            }
+                            break;
+                        }
+                        KeyCode::Char('c') if key.modifiers == 
KeyModifiers::CONTROL => {
+                            running_for_key.store(false, Ordering::Relaxed);
+                            if let Some(tx) = 
shutdown_tx_for_key.lock().unwrap().take() {
+                                let _ = tx.send(());
+                            }
+                            break;
+                        }
+                        _ => {}
+                    }
+                }
+            }
+        }
+    });
+
+    // Wait for metrics server to shut down
+    let metrics_result = metrics_task.await?;
+    let metrics_error = metrics_result.err();
+
+    running.store(false, Ordering::Relaxed);
+
+    // Wait for ping threads to complete
+    for handle in ping_threads {
+        let _ = handle.join();
+    }
+
+    let _ = key_listener.join();
+
+    if let Some(err) = metrics_error {
+        return Err(err);
+    }
+
+    Ok(())
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/src/network.rs 
new/Nping-0.6.1/src/network.rs
--- old/Nping-0.5.0/src/network.rs      2025-09-10 17:15:13.000000000 +0200
+++ new/Nping-0.6.1/src/network.rs      2026-01-25 09:48:45.000000000 +0100
@@ -95,11 +95,21 @@
         // star ping
         let stream = ping(options)?;
 
-        for _ in 0..self.count {
+        let mut ping_count = 0;
+        loop {
             // if ctrl+c is pressed, break the loop
             if !*self.running.lock().unwrap() {
                 break;
             }
+            
+            // if count is not 0, check if we've reached the limit
+            if self.count > 0 {
+                if ping_count >= self.count {
+                    break;
+                }
+                ping_count += 1;
+            }
+
             match stream.recv() {
                 Ok(result) => {
                     match result {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/src/ui/point.rs 
new/Nping-0.6.1/src/ui/point.rs
--- old/Nping-0.5.0/src/ui/point.rs     2025-09-10 17:15:13.000000000 +0200
+++ new/Nping-0.6.1/src/ui/point.rs     2026-01-25 09:48:45.000000000 +0100
@@ -39,7 +39,7 @@
 
     // draw legend
     let legend = Line::from(vec![
-        Span::styled(" 🏎  Nping Point View ", 
Style::default().fg(Color::Cyan)),
+        Span::styled(" 🏎  NBping Point View ", 
Style::default().fg(Color::Cyan)),
         Span::raw("("),
         Span::styled("•", Style::default().fg(Color::Green)),
         Span::raw(" Healthy, "),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/src/ui/sparkline.rs 
new/Nping-0.6.1/src/ui/sparkline.rs
--- old/Nping-0.5.0/src/ui/sparkline.rs 2025-09-10 17:15:13.000000000 +0200
+++ new/Nping-0.6.1/src/ui/sparkline.rs 2026-01-25 09:48:45.000000000 +0100
@@ -28,7 +28,7 @@
         .split(area);
 
     let legend = Line::from(vec![
-        Span::styled(" 🏎  Nping SparkLine View ", 
Style::default().fg(Color::Cyan)),
+        Span::styled(" 🏎  NBping SparkLine View ", 
Style::default().fg(Color::Cyan)),
         Span::raw("("),
         Span::raw(" Blank area means timeout or error"),
         Span::raw(")"),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Nping-0.5.0/src/ui/table.rs 
new/Nping-0.6.1/src/ui/table.rs
--- old/Nping-0.5.0/src/ui/table.rs     2025-09-10 17:15:13.000000000 +0200
+++ new/Nping-0.6.1/src/ui/table.rs     2026-01-25 09:48:45.000000000 +0100
@@ -113,7 +113,7 @@
     )
         .header(header)
         .block(Block::default()
-            .title("🏎  Nping Table (Sort by: Loss Rate ↑ then Latency ↑)"))
+            .title("🏎  NBping Table (Sort by: Loss Rate ↑ then Latency ↑)"))
         .row_highlight_style(selected_style)
         .highlight_symbol(">> ");
 

++++++ Nping.obsinfo ++++++
--- /var/tmp/diff_new_pack.1WjwgP/_old  2026-03-11 20:59:23.976015776 +0100
+++ /var/tmp/diff_new_pack.1WjwgP/_new  2026-03-11 20:59:23.976015776 +0100
@@ -1,5 +1,5 @@
 name: Nping
-version: 0.5.0
-mtime: 1757517313
-commit: 524f0a65f8265da6054c9a31f1a8a1faa891d049
+version: 0.6.1
+mtime: 1769330925
+commit: a4950480a926dab8a5a6028d8e4e137358c0b92c
 

++++++ _service ++++++
--- /var/tmp/diff_new_pack.1WjwgP/_old  2026-03-11 20:59:24.004016930 +0100
+++ /var/tmp/diff_new_pack.1WjwgP/_new  2026-03-11 20:59:24.008017094 +0100
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/hanshuaikang/Nping</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="scm">git</param>
-    <param name="revision">v0.5.0</param>
+    <param name="revision">v0.6.1</param>
     <param name="versionrewrite-pattern">v(\d+\.\d+\.\d+)</param>
     <param name="changesgenerate">enable</param>
   </service>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.1WjwgP/_old  2026-03-11 20:59:24.032018083 +0100
+++ /var/tmp/diff_new_pack.1WjwgP/_new  2026-03-11 20:59:24.036018247 +0100
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param name="url">https://github.com/hanshuaikang/Nping</param>
-              <param 
name="changesrevision">524f0a65f8265da6054c9a31f1a8a1faa891d049</param></service></servicedata>
+              <param 
name="changesrevision">a4950480a926dab8a5a6028d8e4e137358c0b92c</param></service></servicedata>
 (No newline at EOF)
 

++++++ vendor.tar.zst ++++++
/work/SRC/openSUSE:Factory/nbping/vendor.tar.zst 
/work/SRC/openSUSE:Factory/.nbping.new.8177/vendor.tar.zst differ: char 7, line 
1

Reply via email to