Skip to content

Colduction/proxykit-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

proxykit-go

Go Reference License

Fast, allocation-aware tools for validating, parsing, and iterating over HTTP and SOCKS proxies.

Note

Parsers and pools are safe for concurrent use. ParseInto, ParseString, ParseBytes, and NextBytes support zero-allocation hot paths when caller-owned storage is reused.

Install

go get github.com/colduction/proxykit-go@latest

Requires Go 1.26 or later.

Packages

Package Purpose
proxykit Proxy model, URL export, and validation
proxyparser Compiled custom-format parser
proxypool Concurrent iteration over newline-delimited proxy files

Proxy

package main

import (
	"fmt"

	"github.com/colduction/proxykit-go"
)

func main() {
	proxy := proxykit.Proxy{
		Scheme:   proxykit.HTTP,
		Host:     "proxy.example.com:8080",
		Username: "user",
		Password: "pass",
	}

	if proxy.IsValid() {
		fmt.Println(proxy.ExportURL())
	}
}

Supported schemes are http, https, socks5, and socks5h. Host values accept ASCII DNS host names, IPv4 addresses, and IPv6 addresses. Host-port values use host:port for DNS and IPv4, and [ipv6]:port for IPv6.

DNS host names follow LDH rules: letters, decimal digits, and interior hyphens inside dot-separated labels. Labels are limited to 63 bytes, full names are limited to DNS presentation length, and absolute names may end with a root dot. IPv6 zone identifiers are accepted in bracketed IPv6 host-port values such as [fe80::1%eth0]:1080.

Validation is available through both Proxy methods and standalone helpers:

proxykit.IsValidScheme(proxykit.SOCKS5)
proxykit.IsValidHost("proxy.example.com")
proxykit.IsValidHost("2001:db8::1")
proxykit.IsValidHostnamePort("proxy.example.com:1080")
proxykit.IsValidHostnamePort("192.0.2.10:1080")
proxykit.IsValidHostnamePort("[2001:db8::1]:1080")
proxykit.IsValidCredentials("user", "pass")

Use SplitHostnamePort when the caller needs to preserve whether the input used IPv6 brackets before validating host and port separately.

Parser

Compile a format once and reuse it across goroutines:

package main

import (
	"fmt"
	"log"

	"github.com/colduction/proxykit-go"
	"github.com/colduction/proxykit-go/proxyparser"
)

func main() {
	parser, err := proxyparser.New("%t://%u:%p@%h:%d", true)
	if err != nil {
		log.Fatal(err)
	}

	var proxy proxykit.Proxy
	if err := parser.ParseInto(
		"socks5://user:pass@proxy.example.com:1080",
		&proxy,
	); err != nil {
		log.Fatal(err)
	}

	fmt.Println(proxy.ExportURL())
}

For stack-friendly parsing, use ParseString:

proxy, err := parser.ParseString("http://proxy.example.com:8080")

For file or network buffers, use ParseBytes. Parsed string fields alias the input bytes, so keep the buffer immutable while the proxy value is in use:

var proxy proxykit.Proxy
buf := []byte("http://proxy.example.com:8080")
err := parser.ParseBytes(buf, &proxy)
Verb Field
%t Scheme
%h Host
%d Port
%u Username
%p Password
%% Literal percent sign

strict=true requires an exact match. Lenient mode tolerates missing optional credentials or ports after a scheme and host are parsed.

Use errors.Is for sentinel errors such as ErrInvalidProxyFormat, and errors.As for typed errors such as ErrInvalidFormatVerb.

Pool

Each input line is returned without its trailing CR or LF:

package main

import (
	"fmt"
	"log"

	"github.com/colduction/proxykit-go/proxypool"
)

func main() {
	pool, err := proxypool.New(
		"proxies.txt",
		proxypool.ModeSequential,
		false,
	)
	if err != nil {
		log.Fatal(err)
	}
	defer pool.Close()

	for proxy, ok := pool.Next(); ok; proxy, ok = pool.Next() {
		fmt.Println(proxy)
	}
}
Mode Behavior
ModeSequential Streams proxies in file order without an index
ModeShuffled Uses a <path>.idx sidecar and returns one permutation per cycle

Set reuse=true to begin another cycle after the final proxy. For an allocation-free read path, reuse a byte slice with NextBytes:

buf := make([]byte, 0, 128)
for {
	var ok bool
	buf, ok = pool.NextBytes(buf[:0])
	if !ok {
		break
	}
	consume(buf)
}

Use Open with Options when the pool needs custom buffers, a custom index path, persistent sidecar indexes, or preloaded shuffled reads:

pool, err := proxypool.Open("proxies.txt", proxypool.Options{
	Mode:      proxypool.ModeShuffled,
	Reuse:     true,
	Preload:   true,
	IndexPath: "proxies.idx",
})

Preload reads the proxy file into memory for shuffled mode. It avoids per-line file I/O and keeps NextBytes allocation-free when the destination buffer has enough capacity.

Stats reports file size, indexed line count, cursor, mode, reuse, preload, and index behavior. Reset rewinds the pool to the start of its current cycle.

Important

Close releases pool resources. Pools created with New remove the shuffled sidecar index on close. Pools created with Open keep it unless Options.RemoveIndexOnClose is true.

License

Licensed under the MIT License.

About

Lightweight Go package for defining, parsing, and iterating proxy endpoints with validation helpers and file-backed pooling for large lists.

Topics

Resources

License

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages