init: proxy parsing, formatting & source management
Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
commit
2ba7383f81
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# claude
|
||||||
|
CLAUDE.md
|
||||||
|
|
||||||
|
# python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*.egg-info/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.eggs/
|
||||||
|
|
||||||
|
# env
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
.env
|
||||||
|
.pytest_cache/
|
||||||
105
README.md
Normal file
105
README.md
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
# aioproxies
|
||||||
|
|
||||||
|
Proxy parsing, formatting, and source management. Renders proxies for
|
||||||
|
aiohttp/aioweb, camoufox, and socks5; manages session templates (with
|
||||||
|
caller-supplied fields like country/ttl), rotating lists, or a static proxy.
|
||||||
|
**Credentials are always injected — never hardcoded.**
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```
|
||||||
|
aioproxies @ git+ssh://git@git.rethinkstudios.io/rethink-public/aioproxies.git@v0.1.0
|
||||||
|
# network helpers (current_ip / reset) need the extra:
|
||||||
|
aioproxies[net] @ git+ssh://git@git.rethinkstudios.io/rethink-public/aioproxies.git@v0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
The core has no dependencies. The `net` extra adds `aiohttp` for `current_ip` /
|
||||||
|
`reset`.
|
||||||
|
|
||||||
|
## Formatting
|
||||||
|
|
||||||
|
```python
|
||||||
|
from aioproxies import parse
|
||||||
|
|
||||||
|
p = parse("1.2.3.4:8080:user:pass") # or "host:port"
|
||||||
|
p.aiohttp() # {"http": "...", "https": "..."} -> aioweb ExtendedSession(proxies=)
|
||||||
|
p.camoufox() # {"server": "...", "username": ..., "password": ...}
|
||||||
|
p.socks5() # {"server": "socks5://...", ...}
|
||||||
|
p.url() # "http://user:pass@host:port"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
|
||||||
|
Construct with exactly one source:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from aioproxies import AioProxies
|
||||||
|
|
||||||
|
# rotating list (round-robin, shuffled by default)
|
||||||
|
m = AioProxies(proxies=["h1:1:u:p", "h2:2:u:p"])
|
||||||
|
m.get() # next proxy as an aiohttp dict
|
||||||
|
|
||||||
|
# session template — {session} is filled with a fresh id each call
|
||||||
|
m = AioProxies(template="gw.example.io:9000:user_X,sess_{session}:pw")
|
||||||
|
# a bare {} also works and is treated as the session slot
|
||||||
|
|
||||||
|
# static
|
||||||
|
m = AioProxies(static="1.2.3.4:8080:u:p")
|
||||||
|
|
||||||
|
# from a file (raises FileNotFoundError if missing — never exits the process)
|
||||||
|
m = AioProxies.from_file("proxies.txt")
|
||||||
|
```
|
||||||
|
|
||||||
|
The class is also exported as `ProxyManager` and lowercase `aioproxies` (aliases of
|
||||||
|
`AioProxies`) — use whichever reads best at your call site.
|
||||||
|
|
||||||
|
## Location / per-call fields
|
||||||
|
|
||||||
|
Templates can carry extra named placeholders the caller fills per call; the lib
|
||||||
|
always fills `{session}`. This replaces the old `location_proxy(country, ttl)` /
|
||||||
|
`dynamic_proxy(user)` helpers — one template, fields supplied at call time:
|
||||||
|
|
||||||
|
```python
|
||||||
|
m = AioProxies(template="portal.io:1080:user_X,country_{country},ttl_{ttl},sess_{session}:pw")
|
||||||
|
|
||||||
|
m.next(country="ca", ttl=30) # lib fills {session}; caller fills {country}/{ttl}
|
||||||
|
m.get(country="us", ttl=60) # same, returned as an aiohttp dict
|
||||||
|
```
|
||||||
|
|
||||||
|
Provider-specific values (account, password, the host, country codes, ASN tables,
|
||||||
|
which providers support geo) are **your config** — bake them into the template or
|
||||||
|
pass them as fields. The lib only fills placeholders; it never holds credentials.
|
||||||
|
|
||||||
|
### Provider session strings (e.g. mobile rotation)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# creds come from your config — placeholders shown here
|
||||||
|
template = (
|
||||||
|
"portal.anyip.io:1080:"
|
||||||
|
"user_{ACCOUNT},type_mobile,country_{{country}},asn_{{asn}},session_{{session}}:{PASSWORD}"
|
||||||
|
).format(ACCOUNT=acct, PASSWORD=pw) # double-braced fields survive this .format()
|
||||||
|
m = AioProxies(template=template) # and stay as {country}/{asn}/{session} for the lib
|
||||||
|
m.next(country="us", asn="7922")
|
||||||
|
```
|
||||||
|
|
||||||
|
The credentials are baked in once with `.format()`; the per-call fields and `{session}`
|
||||||
|
are double-braced (`{{country}}`) so they pass through that `.format()` untouched and
|
||||||
|
remain for `next(**fields)` / the lib to fill.
|
||||||
|
|
||||||
|
## Network helpers (optional)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from aioproxies.net import current_ip, reset
|
||||||
|
|
||||||
|
ip = await current_ip("1.2.3.4:8080:u:p") # egress ip through the proxy (ipify by default)
|
||||||
|
await reset("https://provider/reset-url") # rotate upstream ip
|
||||||
|
```
|
||||||
|
|
||||||
|
`current_ip` defaults to ipify and is opt-in; pass `test_url=` to point elsewhere.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- No module-level globals; rotation state is per-instance.
|
||||||
|
- A missing proxy file raises, it does not exit the process.
|
||||||
|
- Country/ASN tables, provider accounts, and reset URLs are project config —
|
||||||
|
inject them; do not hardcode credentials in shared code.
|
||||||
Loading…
Reference in New Issue
Block a user