feat: readme, validcount

This commit is contained in:
sajadMRjl
2026-01-28 03:52:25 +03:30
parent 51f7e649a6
commit 644e135464
2 changed files with 130 additions and 13 deletions

107
README.md Normal file
View File

@@ -0,0 +1,107 @@
# Find Me Internet 🌐
**Find Me Internet** is a high-performance, scalable proxy scanner and tester written in Go. It is designed to ingest thousands of proxy links (VLESS, VMess, Trojan, Reality, etc.), filter out dead nodes efficiently using "cheap" network checks, and rigorously test survivors using a real **Sing-box** core.
It uses a "Funnel Architecture" to minimize resource usage, allowing it to scan 100,000+ proxies without crashing your system.
## 🚀 Architecture
The system processes proxies through a multi-stage pipeline:
```mermaid
graph LR
A[Source File/URL] --> B(Parser)
B --> C{Dedup}
C -- New --> D{Cheap Filter}
C -- Duplicate --> X[Discard]
D -- TCP/TLS OK --> E(Sing-box Core)
D -- Fail --> X
E -- Latency OK --> F(GeoIP Enricher)
E -- Fail --> X
F --> G[JSONL Sink]
```
## 🛠️ Prerequisites
1. **Go 1.21+** installed.
2. **Sing-box Binary:** The engine that powers the tests.
3. **GeoLite2 Database (Optional):** For country detection.
## 📦 Installation
### 1. Clone & Dependencies
```bash
git clone https://github.com/sajadMRjl/find-me-internet.git
cd find-me-internet
go mod tidy
```
### 2. Install Sing-box
Download the latest release for your OS from [Sing-box Releases](https://github.com/SagerNet/sing-box/releases).
- Extract the binary.
- Place it in the `./bin/` folder (or anywhere you like).
- _Linux/macOS:_ Ensure it is executable: `chmod +x ./bin/sing-box`
### 3. Setup GeoIP (Optional)
- Register for a free MaxMind account.
- Download the `GeoLite2-Country.mmdb`.
- Place it in `./data/`.
## ⚙️ Configuration
Create a `.env` file in the root directory:
```ini
# --- General ---
LOG_LEVEL=INFO # Options: DEBUG, INFO, WARN, ERROR
MAX_WORKERS=50 # Concurrency limit for Sing-box instances
# --- Timeouts ---
TCP_TIMEOUT=2s # Max time for "Cheap" TCP connect
TEST_TIMEOUT=10s # Max time for "Expensive" HTTP test
TEST_URL=http://cp.cloudflare.com # The target to fetch
# --- Paths ---
SING_BOX_PATH=./bin/sing-box
INPUT_PATH=./data/proxies.txt
OUTPUT_PATH=./data/valid_proxies.jsonl
GEOIP_PATH=./data/GeoLite2-Country.mmdb
```
## 🏃 Usage
1. **Prepare Input:**
Add your raw proxy links (one per line) to `data/proxies.txt`.
2. **Run the Scanner:**
```bash
go run cmd/main.go
```
3. **View Results:**
Valid proxies are streamed to `data/valid_proxies.jsonl`.
```bash
tail -f data/valid_proxies.jsonl
```
### Output Example
```json
{"link":"vless://uuid@1.2.3.4:443...","type":"vless","address":"1.2.3.4","port":443,"latency_ms":145,"country":"DE"}
{"link":"vmess://...","type":"vmess","address":"5.6.7.8","port":80,"latency_ms":210,"country":"US"}
```
## ⚠️ Disclaimer
This tool is for educational purposes and network analysis only. The user is responsible for ensuring they have permission to test the networks and proxies they scan.

View File

@@ -46,21 +46,23 @@ func main() {
netFilter := filter.NewPipeline(cfg.TcpTimeout)
boxRunner := tester.NewRunner(cfg.SingBoxPath, cfg.TestURL, cfg.TestTimeout)
// 3. Input Stream (Example: reading from a local file 'proxies.txt')
// In production, you might loop through a list of URLs here
// 3. Input Stream
linkStream, err := source.LoadFromFile(cfg.InputPath)
if err != nil {
slog.Error("input_source_failed", "error", err)
os.Exit(1)
}
// 4. Worker Pool
// 4. Worker Pool & Counters
var wg sync.WaitGroup
semaphore := make(chan struct{}, cfg.Workers)
slog.Info("pipeline_started", "workers", cfg.Workers)
// Counters for final stats
countProcessed := 0
countValid := 0
var mu sync.Mutex // Protects countValid from race conditions
slog.Info("pipeline_started", "workers", cfg.Workers)
// Main Loop
loop:
@@ -110,22 +112,30 @@ loop:
// --- STAGE 6: SAVE ---
if err := resultsWriter.Write(proxy); err != nil {
slog.Error("write_failed", "error", err)
}
} else {
// Thread-Safe Increment
mu.Lock()
countValid++
mu.Unlock()
slog.Info("proxy_saved",
"country", proxy.Country,
"latency", proxy.Latency.Milliseconds(),
"type", proxy.Type,
)
slog.Info("proxy_saved",
"country", proxy.Country,
"latency", proxy.Latency.Milliseconds(),
"type", proxy.Type,
)
}
}(rawLink)
countProcessed++
if countProcessed % 1000 == 0 {
slog.Info("progress_report", "processed", countProcessed)
slog.Info("progress_report", "processed", countProcessed, "valid_so_far", countValid)
}
}
wg.Wait()
slog.Info("scan_finished", "total_processed", countProcessed)
slog.Info("scan_finished",
"total_processed", countProcessed,
"total_valid", countValid,
)
}