fix: canonical port key, remove()/restore() drift, escape-aware templates
Port keys no longer drift on zero-padding (host:080 vs host:80 collapsed
one canonical key), so a get() -> burn() pairing on a padded port no
longer raises a false "not in pool". Constructor/from_file now dedupe by
canonical key like add(). remove() decrements the rotation cursor when
the removed slot precedes it, fixing a skip/double-serve. restore() on
an unknown key now warns instead of silently no-op, matching remove()'s
contract. A genuine timed burn() under cooldown>0 is now tracked
separately from routine cooldown resting, so it logs WARNING instead of
being buried as DEBUG. Source validation uses is-not-None instead of
truthiness, so a falsy-but-provided source (e.g. template="") is
accepted. Bare "{}" template normalization is now escape-aware, so an
intentional "{{}}" literal survives instead of being corrupted.
Stored-shape change: burn()/cooldown deadlines now write int(time.time())
instead of float; comparisons are unaffected.
Docstrings compressed (module + next()); no behavior change.
Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
@@ -9,15 +9,15 @@ edits. **Credentials are always injected — never hardcoded.**
|
||||
## Install
|
||||
|
||||
```
|
||||
aioproxies @ git+ssh://git@git.rethinkstudios.io/rethink-public/aioproxies.git@v0.2.2
|
||||
aioproxies @ git+ssh://git@git.rethinkstudios.io/rethink-public/aioproxies.git@v0.3.0
|
||||
# network helpers (current_ip / reset) need the extra:
|
||||
aioproxies[net] @ git+ssh://git@git.rethinkstudios.io/rethink-public/aioproxies.git@v0.2.2
|
||||
aioproxies[net] @ git+ssh://git@git.rethinkstudios.io/rethink-public/aioproxies.git@v0.3.0
|
||||
```
|
||||
|
||||
The core has no dependencies. The `net` extra adds `aiohttp` for `current_ip` /
|
||||
`reset`.
|
||||
|
||||
Drop the `@v0.2.2` suffix from the line above to install the latest unpinned.
|
||||
Drop the `@v0.3.0` suffix from the line above to install the latest unpinned.
|
||||
|
||||
## Formatting
|
||||
|
||||
@@ -144,9 +144,11 @@ pm.is_burned(proxy) # current state (expired timed burns read False)
|
||||
|
||||
`burn`/`restore`/`is_burned`/`remove` accept **any proxy shape** — a spec string, a
|
||||
`Proxy`, an aiohttp/camoufox/socks5 dict, or a url — all resolve to the same canonical
|
||||
key (`host:port:user:pass`, or `host:port` auth-less). The password is part of the key,
|
||||
so two proxies differing only by password are distinct slots. `burn` on a proxy not in
|
||||
the pool raises `ValueError`.
|
||||
key (`host:port:user:pass`, or `host:port` auth-less; the port is normalized so
|
||||
`host:080` and `host:80` are one slot). The password is part of the key, so two proxies
|
||||
differing only by password are distinct slots. `burn` on a proxy not in the pool raises
|
||||
`ValueError`; `restore` on a proxy not in the pool logs a warning and no-ops (matching
|
||||
`remove`'s contract, as of v0.3.0 — previously it silently did nothing with no signal).
|
||||
|
||||
### Cooldown
|
||||
|
||||
@@ -178,9 +180,12 @@ pm.remove(proxy) # drop a slot entirely (any shape) —
|
||||
|
||||
`replace` resets the rotation index and honors the manager's `shuffle` setting on the
|
||||
incoming list. `remove` differs from `burn`: burn = unusable but still tracked; remove =
|
||||
gone from the pool. Like the burn family, `add`/`replace` accept **any proxy shape**
|
||||
(spec/`Proxy`/url/aiohttp dict/camoufox/socks5 dict). `canonical_key(shape)` and
|
||||
`to_proxy(shape)` are exported if you need the key or a normalized `Proxy` yourself.
|
||||
gone from the pool — removing a slot that precedes the rotation cursor adjusts the
|
||||
cursor so `next()` doesn't skip a proxy. Like the burn family, `add`/`replace` accept
|
||||
**any proxy shape** (spec/`Proxy`/url/aiohttp dict/camoufox/socks5 dict). The
|
||||
constructor and `from_file` also dedupe by canonical key, same as `add`.
|
||||
`canonical_key(shape)` and `to_proxy(shape)` are exported if you need the key or a
|
||||
normalized `Proxy` yourself.
|
||||
|
||||
## Network helpers (optional)
|
||||
|
||||
@@ -204,6 +209,39 @@ await reset("https://provider/reset-url") # rotate upstream ip
|
||||
|
||||
## Changelog
|
||||
|
||||
### v0.3.0
|
||||
|
||||
- **Stored-shape change: int unix deadlines.** `burn(proxy, seconds)` and the
|
||||
cooldown timeout write `int(time.time()) + n` instead of a `float`. Comparisons
|
||||
(`is_burned`/`stats`/selection) are unaffected — this only tightens what gets
|
||||
persisted into per-proxy state.
|
||||
- **Port key normalization:** `key()` strips leading zeros from the port, so
|
||||
`host:080` and `host:80` are the same canonical slot. Previously a zero-padded
|
||||
port could break a `get()` → `burn()` pairing (the burn would raise "not in
|
||||
pool" against the proxy that was just handed out).
|
||||
- **Constructor / `from_file` dedupe by canonical key**, matching `add()`. A
|
||||
proxy list with repeated entries (e.g. same host:port:user:pass twice) no
|
||||
longer inflates the pool or double-weights rotation.
|
||||
- **`remove()` no longer skews rotation.** Removing a proxy that precedes the
|
||||
rotation cursor now decrements the cursor, so the next `next()` call doesn't
|
||||
skip or double-serve a proxy.
|
||||
- **`restore()` on an unknown proxy now logs a warning and no-ops**, matching
|
||||
`remove()`'s contract (previously it silently did nothing, with `burn()`
|
||||
raising for the same precondition and `remove()` warning — `restore()` was the
|
||||
odd one out).
|
||||
- **Genuine timed burns under `cooldown>0` now log at WARNING**, not DEBUG. A
|
||||
real `burn(proxy, seconds)` is now tracked separately from the manager's own
|
||||
cooldown resting, so it no longer gets buried as routine cooldown noise when
|
||||
every proxy in the pool happens to also be cooling down.
|
||||
- **Source truthiness → presence.** The constructor's exactly-one-source check
|
||||
now uses `is not None` instead of truthiness, so `template=""` (or another
|
||||
falsy-but-explicitly-provided source) is accepted rather than silently
|
||||
rejected as "no source given."
|
||||
- **Escape-aware bare-`{}` template normalization.** A template's bare `{}` is
|
||||
still filled as the session slot, but an escaped `{{}}` (str.format's own
|
||||
convention for a literal `{}` in the output) now survives untouched instead of
|
||||
being corrupted into `{{session}}`.
|
||||
|
||||
### v0.2.1
|
||||
|
||||
- **Legible missing-template-field error:** a `template=` placeholder not supplied to
|
||||
|
||||
Reference in New Issue
Block a user