package main import ( "fmt" "log" "os" "sync" "time" ) func main() { if len(os.Args) < 2 { fmt.Fprintf(os.Stderr, "Usage: %s \n", os.Args[0]) fmt.Fprintf(os.Stderr, "\nGenerates a RouterOS address list (.rsc) from GeoIP data.\n") fmt.Fprintf(os.Stderr, "\nExample:\n %s blocklist.json\n", os.Args[0]) os.Exit(1) } configFile := os.Args[1] // Load configuration cfg, err := LoadConfig(configFile) if err != nil { log.Fatalf("Error loading config: %v", err) } // Initialize provider provider, err := NewProvider(cfg.Provider) if err != nil { log.Fatalf("Error initializing provider: %v", err) } fmt.Printf("╔══════════════════════════════════════════╗\n") fmt.Printf("║ routeros-geoip generator ║\n") fmt.Printf("╚══════════════════════════════════════════╝\n") fmt.Printf(" Provider: %s\n", provider.Name()) fmt.Printf(" List name: %s\n", cfg.ListName) fmt.Printf(" Countries: %d\n\n", len(cfg.Countries)) // Download CIDR data for all countries concurrently type result struct { data CountryData err error } results := make([]result, len(cfg.Countries)) var wg sync.WaitGroup start := time.Now() for i, code := range cfg.Countries { wg.Add(1) go func(idx int, countryCode string) { defer wg.Done() name := CountryName(countryCode) fmt.Printf(" ↓ downloading %s (%s)...\n", name, countryCode) cidrs, err := provider.FetchCIDRs(countryCode) if err != nil { results[idx] = result{err: fmt.Errorf("%s (%s): %v", name, countryCode, err)} return } results[idx] = result{ data: CountryData{ Code: countryCode, Name: name, CIDRs: cidrs, }, } fmt.Printf(" ✓ %s: %d CIDRs\n", name, len(cidrs)) }(i, code) } wg.Wait() elapsed := time.Since(start) // Collect results and check for errors var countries []CountryData var errors []error for _, r := range results { if r.err != nil { errors = append(errors, r.err) continue } countries = append(countries, r.data) } if len(errors) > 0 { fmt.Printf("\n⚠ Errors occurred:\n") for _, err := range errors { fmt.Printf(" ✗ %v\n", err) } if len(countries) == 0 { log.Fatalf("All downloads failed, cannot generate output") } fmt.Printf("\nContinuing with %d/%d countries...\n", len(countries), len(cfg.Countries)) } // Generate output fmt.Printf("\n Generating output...\n") outputFile, err := GenerateRSC(countries, cfg.ListName) if err != nil { log.Fatalf("Error generating output: %v", err) } totalCIDRs := 0 for _, c := range countries { totalCIDRs += len(c.CIDRs) } fmt.Printf("\n╔══════════════════════════════════════════════════════╗\n") fmt.Printf("║ Done! %-46s║\n", fmt.Sprintf("(%s)", elapsed.Round(time.Millisecond))) fmt.Printf("╠══════════════════════════════════════════════════════╣\n") fmt.Printf("║ Output: %-43s║\n", outputFile) fmt.Printf("║ Entries: %-43s║\n", fmt.Sprintf("%d CIDRs across %d countries", totalCIDRs, len(countries))) fmt.Printf("╚══════════════════════════════════════════════════════╝\n") fmt.Printf("\nImport on your MikroTik router:\n") fmt.Printf(" /import %s\n\n", outputFile) }