asockslib 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- asockslib/__init__.py +117 -0
- asockslib/_console.py +18 -0
- asockslib/_port_utils.py +132 -0
- asockslib/benchmark.py +365 -0
- asockslib/cli/__init__.py +72 -0
- asockslib/cli/_helpers.py +162 -0
- asockslib/cli/_output.py +52 -0
- asockslib/cli/api_commands.py +377 -0
- asockslib/cli/commands.py +485 -0
- asockslib/client.py +634 -0
- asockslib/exceptions.py +89 -0
- asockslib/geo.json +649269 -0
- asockslib/geo_picker/__init__.py +30 -0
- asockslib/geo_picker/_completer.py +90 -0
- asockslib/geo_picker/_messages.py +89 -0
- asockslib/geo_picker/_types.py +89 -0
- asockslib/geo_picker/picker.py +667 -0
- asockslib/models/__init__.py +72 -0
- asockslib/models/directory.py +65 -0
- asockslib/models/enums.py +65 -0
- asockslib/models/port.py +187 -0
- asockslib/models/requests.py +89 -0
- asockslib/models/responses.py +20 -0
- asockslib/proxy_pool.py +659 -0
- asockslib/quick.py +174 -0
- asockslib/smart_proxy.py +251 -0
- asockslib-0.1.0.dist-info/METADATA +228 -0
- asockslib-0.1.0.dist-info/RECORD +30 -0
- asockslib-0.1.0.dist-info/WHEEL +4 -0
- asockslib-0.1.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Interactive geo-data selection via fuzzy search.
|
|
2
|
+
|
|
3
|
+
Re-exports all public types and the :class:`GeoPicker` class
|
|
4
|
+
so that ``from asockslib.geo_picker import GeoPicker`` continues
|
|
5
|
+
to work after the module was split into a package.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from asockslib.geo_picker._types import (
|
|
11
|
+
PickedASN,
|
|
12
|
+
PickedCity,
|
|
13
|
+
PickedConnectionType,
|
|
14
|
+
PickedCountry,
|
|
15
|
+
PickedProxyType,
|
|
16
|
+
PickedServerPortType,
|
|
17
|
+
PickedState,
|
|
18
|
+
)
|
|
19
|
+
from asockslib.geo_picker.picker import GeoPicker
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"GeoPicker",
|
|
23
|
+
"PickedASN",
|
|
24
|
+
"PickedCity",
|
|
25
|
+
"PickedConnectionType",
|
|
26
|
+
"PickedCountry",
|
|
27
|
+
"PickedProxyType",
|
|
28
|
+
"PickedServerPortType",
|
|
29
|
+
"PickedState",
|
|
30
|
+
]
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Fuzzy-match completer and validators for prompt_toolkit.
|
|
2
|
+
|
|
3
|
+
Provides the autocompletion and input validation used by
|
|
4
|
+
:class:`~asockslib.geo_picker.GeoPicker` interactive prompts.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from prompt_toolkit.completion import Completer, Completion
|
|
13
|
+
from prompt_toolkit.styles import Style as PTStyle
|
|
14
|
+
from prompt_toolkit.validation import ValidationError, Validator
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from collections.abc import Iterable
|
|
18
|
+
|
|
19
|
+
from prompt_toolkit.completion import CompleteEvent
|
|
20
|
+
from prompt_toolkit.document import Document
|
|
21
|
+
|
|
22
|
+
_RE_GEO_NAME = re.compile(r"^[\w\s\-.'()/]+$", re.UNICODE)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class FuzzyMatchCompleter(Completer):
|
|
26
|
+
"""Completer that shows all choices on empty input.
|
|
27
|
+
|
|
28
|
+
On non-empty input performs case-insensitive substring matching.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, choices: list[str], ignore_case: bool = True) -> None:
|
|
32
|
+
self.choices = choices
|
|
33
|
+
self.ignore_case = ignore_case
|
|
34
|
+
|
|
35
|
+
def get_completions(
|
|
36
|
+
self, document: Document, complete_event: CompleteEvent
|
|
37
|
+
) -> Iterable[Completion]:
|
|
38
|
+
"""Yield completions matching current input."""
|
|
39
|
+
text = document.text_before_cursor
|
|
40
|
+
if self.ignore_case:
|
|
41
|
+
text = text.lower()
|
|
42
|
+
|
|
43
|
+
for choice in self.choices:
|
|
44
|
+
compare = choice.lower() if self.ignore_case else choice
|
|
45
|
+
if text in compare:
|
|
46
|
+
yield Completion(
|
|
47
|
+
choice,
|
|
48
|
+
start_position=-len(document.text_before_cursor),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def make_choice_validator(
|
|
53
|
+
choices: list[str],
|
|
54
|
+
error_msg: str,
|
|
55
|
+
error_chars: str,
|
|
56
|
+
) -> Validator:
|
|
57
|
+
"""Create a choice validator for prompt_toolkit.
|
|
58
|
+
|
|
59
|
+
Only values present in *choices* (case-insensitive) are accepted.
|
|
60
|
+
"""
|
|
61
|
+
lower_lookup: dict[str, str] = {c.strip().lower(): c for c in choices}
|
|
62
|
+
|
|
63
|
+
class _ChoiceValidator(Validator):
|
|
64
|
+
def validate(self, document: Document) -> None:
|
|
65
|
+
t = document.text.strip()
|
|
66
|
+
if t in choices:
|
|
67
|
+
return
|
|
68
|
+
if t.lower() in lower_lookup:
|
|
69
|
+
return
|
|
70
|
+
if t and not _RE_GEO_NAME.match(t):
|
|
71
|
+
raise ValidationError(message=error_chars)
|
|
72
|
+
raise ValidationError(message=error_msg)
|
|
73
|
+
|
|
74
|
+
return _ChoiceValidator()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def pt_style() -> PTStyle:
|
|
78
|
+
"""Color scheme for prompt_toolkit prompts."""
|
|
79
|
+
return PTStyle.from_dict(
|
|
80
|
+
{
|
|
81
|
+
"qmark": "fg:ansicyan bold",
|
|
82
|
+
"question": "fg:ansiwhite bold",
|
|
83
|
+
"answer": "fg:ansigreen bold",
|
|
84
|
+
"completion-menu": "bg:ansiblack fg:ansiwhite",
|
|
85
|
+
"completion-menu.completion": "",
|
|
86
|
+
"completion-menu.completion.current": "bg:ansicyan fg:ansiblack",
|
|
87
|
+
"scrollbar.background": "bg:ansibrightblack",
|
|
88
|
+
"scrollbar.button": "bg:ansicyan",
|
|
89
|
+
}
|
|
90
|
+
)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""UI messages and proxy output templates for the geo-picker."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
# ── Messages ──────────────────────────────────────────────────────────────── #
|
|
6
|
+
|
|
7
|
+
MESSAGES: dict[str, str] = {
|
|
8
|
+
"pick_country": "🌍 Select country",
|
|
9
|
+
"pick_state": "📍 Select state/region",
|
|
10
|
+
"pick_city": "🏙 Select city",
|
|
11
|
+
"pick_asn": "🔗 Select ASN provider",
|
|
12
|
+
"skip": "⏭ (skip)",
|
|
13
|
+
"no_states": "No states available for this country.",
|
|
14
|
+
"no_cities": "No cities available.",
|
|
15
|
+
"no_asns": "No ASN providers available for this country.",
|
|
16
|
+
"cities_suffix": "cities",
|
|
17
|
+
"params": "Parameters",
|
|
18
|
+
"invalid_choice": "⚠ Value not in the list. Use arrows or type to filter.",
|
|
19
|
+
"invalid_country_code": "⚠ Invalid country code (must be 2 letters, e.g. US).",
|
|
20
|
+
"invalid_chars": "⚠ Input contains invalid characters.",
|
|
21
|
+
"pick_connection_type": "🔌 Connection type",
|
|
22
|
+
"pick_proxy_type": "🛡 Proxy type",
|
|
23
|
+
"pick_server_port_type": "🖥 Server port type",
|
|
24
|
+
"pick_traffic_limit": "📊 Traffic limit (GB)",
|
|
25
|
+
"pick_action": "🚀 What do you want to do?",
|
|
26
|
+
"action_create": "Create proxies — get working proxies quickly",
|
|
27
|
+
"action_best": "Find best proxies — create, benchmark, keep the fastest",
|
|
28
|
+
"pick_count": "🔢 How many proxies?",
|
|
29
|
+
"pick_keep": "🏆 How many best to keep?",
|
|
30
|
+
"pick_name": "📝 Port name (optional, Enter to skip)",
|
|
31
|
+
"pick_format": "📄 Export format",
|
|
32
|
+
"pick_output": "💾 Output file (optional, Enter to skip)",
|
|
33
|
+
"pick_timeout": "⏱ Benchmark timeout (seconds)",
|
|
34
|
+
"pick_concurrency": "⚡ Benchmark concurrency",
|
|
35
|
+
"pick_proxy_template": "📋 Output template (proxy format)",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_message(key: str) -> str:
|
|
40
|
+
"""Get a message string by key."""
|
|
41
|
+
return MESSAGES.get(key, key)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ── Proxy output templates ────────────────────────────────────────────────── #
|
|
45
|
+
|
|
46
|
+
PROXY_TEMPLATES: list[tuple[str, str]] = [
|
|
47
|
+
("{protocol}://{login}:{password}@{ip}:{port}", "Standard URL — protocol://login:pass@ip:port"),
|
|
48
|
+
("http://{login}:{password}@{ip}:{port}", "HTTP URL — http://login:pass@ip:port"),
|
|
49
|
+
("socks5://{login}:{password}@{ip}:{port}", "SOCKS5 URL — socks5://login:pass@ip:port"),
|
|
50
|
+
("{ip}:{port}:{login}:{password}", "ip:port:login:password"),
|
|
51
|
+
("{protocol}://{ip}:{port}:{login}:{password}", "protocol://ip:port:login:password"),
|
|
52
|
+
(
|
|
53
|
+
"{protocol}://{login}:{password}@{ip}:{port}[{refresh_link}]",
|
|
54
|
+
"URL with refresh link — protocol://login:pass@ip:port[refresh]",
|
|
55
|
+
),
|
|
56
|
+
(
|
|
57
|
+
"{protocol}://{login}:{password}@{ip}:{port}:{name}[{refresh_link}]",
|
|
58
|
+
"Full URL — login:pass@ip:port:name[refresh]",
|
|
59
|
+
),
|
|
60
|
+
(
|
|
61
|
+
"http://{login}:{password}@{ip}:{port}:{name}[{refresh_link}]",
|
|
62
|
+
"HTTP full — http://login:pass@ip:port:name[refresh]",
|
|
63
|
+
),
|
|
64
|
+
(
|
|
65
|
+
"socks5://{login}:{password}@{ip}:{port}:{name}[{refresh_link}]",
|
|
66
|
+
"SOCKS5 full — socks5://login:pass@ip:port:name[refresh]",
|
|
67
|
+
),
|
|
68
|
+
("{ip}:{port}:{login}:{password}:{refresh_link}", "ip:port:login:password:refresh_link"),
|
|
69
|
+
("{ip}:{port}:{login}:{password}:{name}", "ip:port:login:password:name"),
|
|
70
|
+
("{name}:{ip}:{port}:{login}:{password}", "name:ip:port:login:password"),
|
|
71
|
+
("{ip}:{port}:{login}:{password}|{refresh_link}", "ip:port:login:password|refresh_link"),
|
|
72
|
+
("HTTP|{ip}|{port}|{login}|{password}", "HTTP|ip|port|login|password (pipe separated)"),
|
|
73
|
+
(
|
|
74
|
+
"{protocol}://{ip}:{port}:{login}:{password}:{refresh_link}",
|
|
75
|
+
"protocol://ip:port:login:password:refresh",
|
|
76
|
+
),
|
|
77
|
+
(
|
|
78
|
+
"{protocol}://{ip}:{port}:{login}:{password}[{refresh_link}]{{name}}",
|
|
79
|
+
"protocol://ip:port:login:password[refresh]{name}",
|
|
80
|
+
),
|
|
81
|
+
(
|
|
82
|
+
"{protocol}:{ip}:{port}:{login}:{password}",
|
|
83
|
+
"protocol:ip:port:login:password (no slashes)",
|
|
84
|
+
),
|
|
85
|
+
(
|
|
86
|
+
"curl -x http://{login}:{password}@{ip}:{port} https://i.pn",
|
|
87
|
+
"curl command — ready-to-use curl",
|
|
88
|
+
),
|
|
89
|
+
]
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Data types for the geo-picker module.
|
|
2
|
+
|
|
3
|
+
Frozen dataclasses representing user selections, plus static
|
|
4
|
+
choice data for connection types, proxy types, and server port types.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
# ── Picked result types ───────────────────────────────────────────────────── #
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True, slots=True)
|
|
15
|
+
class PickedCountry:
|
|
16
|
+
"""Selected country."""
|
|
17
|
+
|
|
18
|
+
code: str
|
|
19
|
+
name: str
|
|
20
|
+
id: int
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(frozen=True, slots=True)
|
|
24
|
+
class PickedState:
|
|
25
|
+
"""Selected state/region."""
|
|
26
|
+
|
|
27
|
+
name: str
|
|
28
|
+
id: int
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True, slots=True)
|
|
32
|
+
class PickedCity:
|
|
33
|
+
"""Selected city."""
|
|
34
|
+
|
|
35
|
+
name: str
|
|
36
|
+
id: int
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True, slots=True)
|
|
40
|
+
class PickedASN:
|
|
41
|
+
"""Selected ASN."""
|
|
42
|
+
|
|
43
|
+
number: int
|
|
44
|
+
name: str
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass(frozen=True, slots=True)
|
|
48
|
+
class PickedConnectionType:
|
|
49
|
+
"""Selected connection type."""
|
|
50
|
+
|
|
51
|
+
id: int
|
|
52
|
+
label: str
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass(frozen=True, slots=True)
|
|
56
|
+
class PickedProxyType:
|
|
57
|
+
"""Selected proxy type."""
|
|
58
|
+
|
|
59
|
+
id: int
|
|
60
|
+
label: str
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass(frozen=True, slots=True)
|
|
64
|
+
class PickedServerPortType:
|
|
65
|
+
"""Selected server port type."""
|
|
66
|
+
|
|
67
|
+
id: int
|
|
68
|
+
label: str
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# ── Static choice data ───────────────────────────────────────────────────── #
|
|
72
|
+
|
|
73
|
+
CONNECTION_TYPES: list[tuple[int, str]] = [
|
|
74
|
+
(1, "Keep Proxy — fixed proxy, highest trust"),
|
|
75
|
+
(2, "Keep Connection — fixed connection, high trust"),
|
|
76
|
+
(3, "Rotate Connection — rotation on each request"),
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
PROXY_TYPES: list[tuple[int, str]] = [
|
|
80
|
+
(1, "Residential — home IP addresses"),
|
|
81
|
+
(2, "All — all proxy types"),
|
|
82
|
+
(3, "Mobile — mobile operator IPs"),
|
|
83
|
+
(4, "Corporate — corporate network IPs"),
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
SERVER_PORT_TYPES: list[tuple[int, str]] = [
|
|
87
|
+
(0, "Shared — shared port (free)"),
|
|
88
|
+
(1, "Dedicated — dedicated port (paid, traffic limit)"),
|
|
89
|
+
]
|