feature: add so_linger option to settings.

This commit is contained in:
UpstreamData
2023-11-27 09:24:28 -07:00
parent 2b443497ea
commit 3f1183a4f9
10 changed files with 68 additions and 46 deletions

View File

@@ -13,8 +13,6 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import asyncio
import enum
import ipaddress
@@ -25,6 +23,7 @@ from typing import AsyncGenerator, Callable, List, Optional, Tuple, Union
import anyio
import httpx
from pyasic import settings
from pyasic.logger import logger
from pyasic.miners.antminer import *
from pyasic.miners.avalonminer import *
@@ -45,8 +44,6 @@ from pyasic.miners.innosilicon import *
from pyasic.miners.unknown import UnknownMiner
from pyasic.miners.whatsminer import *
from pyasic import settings
class MinerTypes(enum.Enum):
ANTMINER = 0
@@ -479,11 +476,15 @@ class MinerFactory:
async def _get_miner_web(self, ip: str):
urls = [f"http://{ip}/", f"https://{ip}/"]
async with httpx.AsyncClient(verify=False) as session:
async with httpx.AsyncClient(
transport=settings.transport(verify=False)
) as session:
tasks = [asyncio.create_task(self._web_ping(session, url)) for url in urls]
text, resp = await concurrent_get_first_result(
tasks, lambda x: x[0] is not None and self._parse_web_type(x[0], x[1]) is not None
tasks,
lambda x: x[0] is not None
and self._parse_web_type(x[0], x[1]) is not None,
)
if text is not None:
return self._parse_web_type(text, resp)
@@ -612,7 +613,7 @@ class MinerFactory:
location: str,
auth: Optional[httpx.DigestAuth] = None,
) -> Optional[dict]:
async with httpx.AsyncClient(verify=settings.ssl_cxt) as session:
async with httpx.AsyncClient(transport=settings.transport()) as session:
try:
data = await session.get(
f"http://{str(ip)}{location}",
@@ -808,7 +809,7 @@ class MinerFactory:
async def get_miner_model_innosilicon(self, ip: str) -> Optional[str]:
try:
async with httpx.AsyncClient(verify=settings.ssl_cxt) as session:
async with httpx.AsyncClient(transport=settings.transport()) as session:
auth_req = await session.post(
f"http://{ip}/api/auth",
data={"username": "admin", "password": "admin"},
@@ -838,7 +839,7 @@ class MinerFactory:
pass
try:
async with httpx.AsyncClient(verify=settings.ssl_cxt) as session:
async with httpx.AsyncClient(transport=settings.transport()) as session:
d = await session.post(
f"http://{ip}/graphql",
json={"query": "{bosminer {info{modelName}}}"},

View File

@@ -45,7 +45,7 @@ class MinerNetwork:
"""
hosts = []
for address in addresses:
hosts = [*hosts, *cls.from_address(address)]
hosts = [*hosts, *cls.from_address(address).hosts]
return cls(sorted(list(set(hosts))))
@classmethod
@@ -63,7 +63,9 @@ class MinerNetwork:
return cls.from_octets(*octets)
@classmethod
def from_octets(cls, oct_1: str, oct_2: str, oct_3: str, oct_4: str) -> "MinerNetwork":
def from_octets(
cls, oct_1: str, oct_2: str, oct_3: str, oct_4: str
) -> "MinerNetwork":
"""Parse 4 octet constructors into a MinerNetwork.
Parameters:
@@ -167,7 +169,9 @@ class MinerNetwork:
try:
return await ping_and_get_miner(ip)
except ConnectionRefusedError:
tasks = [ping_and_get_miner(ip, port=port) for port in [4028, 4029, 8889]]
tasks = [
ping_and_get_miner(ip, port=port) for port in [4028, 4029, 8889]
]
for miner in asyncio.as_completed(tasks):
try:
return await miner

View File

@@ -13,10 +13,13 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from typing import Any
import socket
import struct
from ssl import SSLContext
from typing import Any, Union
import httpx
from httpx import AsyncHTTPTransport
_settings = { # defaults
"network_ping_retries": 1,
@@ -32,14 +35,25 @@ _settings = { # defaults
"default_bosminer_password": "root",
"default_vnish_password": "admin",
"default_goldshell_password": "123456789",
"so_linger_time": 1000,
}
ssl_cxt = httpx.create_ssl_context()
def transport(verify: Union[str, bool, SSLContext] = ssl_cxt):
l_onoff = 1
l_linger = get("so_linger_time", 1000)
opts = [(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", l_onoff, l_linger))]
return AsyncHTTPTransport(socket_options=opts, verify=verify)
def get(key: str, other: Any = None) -> Any:
return _settings.get(key, other)
def update(key: str, val: Any) -> Any:
_settings[key] = val
ssl_cxt = httpx.create_ssl_context()

View File

@@ -38,10 +38,13 @@ class AntminerModernWebAPI(BaseWebAPI):
url = f"http://{self.ip}/cgi-bin/{command}.cgi"
auth = httpx.DigestAuth(self.username, self.pwd)
try:
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
if parameters:
data = await client.post(
url, data=json.dumps(parameters), auth=auth, timeout=settings.get("api_function_timeout", 3) # noqa
url,
data=json.dumps(parameters),
auth=auth,
timeout=settings.get("api_function_timeout", 3), # noqa
)
else:
data = await client.get(url, auth=auth)
@@ -57,7 +60,7 @@ class AntminerModernWebAPI(BaseWebAPI):
async def multicommand(
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
) -> dict:
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
tasks = [
asyncio.create_task(self._handle_multicommand(client, command))
for command in commands
@@ -149,10 +152,13 @@ class AntminerOldWebAPI(BaseWebAPI):
url = f"http://{self.ip}/cgi-bin/{command}.cgi"
auth = httpx.DigestAuth(self.username, self.pwd)
try:
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
if parameters:
data = await client.post(
url, data=parameters, auth=auth, timeout=settings.get("api_function_timeout", 3)
url,
data=parameters,
auth=auth,
timeout=settings.get("api_function_timeout", 3),
)
else:
data = await client.get(url, auth=auth)
@@ -170,7 +176,7 @@ class AntminerOldWebAPI(BaseWebAPI):
) -> dict:
data = {k: None for k in commands}
auth = httpx.DigestAuth(self.username, self.pwd)
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
for command in commands:
try:
url = f"http://{self.ip}/cgi-bin/{command}.cgi"

View File

@@ -186,7 +186,7 @@ class BOSMinerGQLAPI:
if command.get("query") is None:
query = {"query": self.parse_command(command)}
try:
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
await self.auth(client)
data = await client.post(url, json=query)
except httpx.HTTPError:
@@ -239,7 +239,7 @@ class BOSMinerLuCIAPI:
async def send_command(self, path: str, ignore_errors: bool = False) -> dict:
try:
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
await self.auth(client)
data = await client.get(
f"http://{self.ip}{path}", headers={"User-Agent": "BTC Tools v0.1"}

View File

@@ -31,7 +31,7 @@ class GoldshellWebAPI(BaseWebAPI):
self.jwt = None
async def auth(self):
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
try:
await client.get(f"http://{self.ip}/user/logout")
auth = (
@@ -71,7 +71,7 @@ class GoldshellWebAPI(BaseWebAPI):
parameters.pop("pool_pwd")
if not self.jwt:
await self.auth()
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
for i in range(settings.get("get_data_retries", 1)):
try:
if parameters:
@@ -102,7 +102,7 @@ class GoldshellWebAPI(BaseWebAPI):
data = {k: None for k in commands}
data["multicommand"] = True
await self.auth()
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
for command in commands:
try:
response = await client.get(

View File

@@ -32,7 +32,7 @@ class InnosiliconWebAPI(BaseWebAPI):
self.jwt = None
async def auth(self):
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
try:
auth = await client.post(
f"http://{self.ip}/api/auth",
@@ -54,7 +54,7 @@ class InnosiliconWebAPI(BaseWebAPI):
) -> dict:
if not self.jwt:
await self.auth()
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
for i in range(settings.get("get_data_retries", 1)):
try:
response = await client.post(
@@ -90,7 +90,7 @@ class InnosiliconWebAPI(BaseWebAPI):
data = {k: None for k in commands}
data["multicommand"] = True
await self.auth()
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
for command in commands:
try:
response = await client.post(

View File

@@ -31,7 +31,7 @@ class VNishWebAPI(BaseWebAPI):
self.token = None
async def auth(self):
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
try:
auth = await client.post(
f"http://{self.ip}/api/v1/unlock",
@@ -58,7 +58,7 @@ class VNishWebAPI(BaseWebAPI):
) -> dict:
if not self.token:
await self.auth()
async with httpx.AsyncClient(verify=settings.ssl_cxt) as client:
async with httpx.AsyncClient(transport=settings.transport()) as client:
for i in range(settings.get("get_data_retries", 1)):
try:
auth = self.token

View File

@@ -9,9 +9,9 @@ readme = "README.md"
[tool.poetry.dependencies]
python = "^3.8"
httpx = "^0.25.0"
httpx = "^0.25.2"
asyncssh = "^2.14.1"
grpc-requests = "^0.1.11"
grpc-requests = "^0.1.12"
passlib = "^1.7.4"
pyaml = "^23.9.7"
toml = "^0.10.2"

View File

@@ -22,7 +22,7 @@ from pyasic.network import MinerNetwork
class NetworkTest(unittest.TestCase):
def test_net_range(self):
net_range_str = "192.168.1.29, 192.168.1.40-192.168.1.43, 192.168.1.60"
net_range_str = ["192.168.1.29", "192.168.1.40-43", "192.168.1.60"]
net_range_list = [
"192.168.1.29",
"192.168.1.40",
@@ -32,8 +32,8 @@ class NetworkTest(unittest.TestCase):
"192.168.1.60",
]
net_1 = list(MinerNetwork(net_range_str).get_network().hosts())
net_2 = list(MinerNetwork(net_range_list).get_network().hosts())
net_1 = list(MinerNetwork.from_list(net_range_list).hosts)
net_2 = list(MinerNetwork.from_list(net_range_str).hosts)
correct_net = [
ipaddress.IPv4Address("192.168.1.29"),
@@ -51,11 +51,9 @@ class NetworkTest(unittest.TestCase):
net_1_str = "192.168.1.0"
net_1_mask = "/29"
net_1 = list(MinerNetwork(net_1_str, mask=net_1_mask).get_network().hosts())
net_1 = list(MinerNetwork.from_subnet(net_1_str + net_1_mask).hosts)
net_2 = list(
MinerNetwork("192.168.1.1-192.168.1.5, 192.168.1.6").get_network().hosts()
)
net_2 = list(MinerNetwork.from_list(["192.168.1.1-5", "192.168.1.6"]).hosts)
correct_net = [
ipaddress.IPv4Address("192.168.1.1"),
@@ -70,11 +68,10 @@ class NetworkTest(unittest.TestCase):
self.assertTrue(net_2 == correct_net)
def test_net_defaults(self):
net = MinerNetwork()
net_obj = net.get_network()
self.assertEqual(net_obj, MinerNetwork("192.168.1.0", mask=24).get_network())
self.assertEqual(net_obj, net.get_network())
net = MinerNetwork.from_subnet("192.168.1.1/24")
self.assertEqual(
net.hosts, list(ipaddress.ip_network("192.168.1.0/24").hosts())
)
if __name__ == "__main__":