feature: refactor BOS web class into multiple classes.

This commit is contained in:
UpstreamData
2023-09-22 09:32:59 -06:00
parent 683fcb2138
commit aac1be0565

View File

@@ -18,14 +18,27 @@ from typing import Union
import httpx import httpx
from pyasic import APIError, settings from pyasic import APIError
from pyasic.settings import PyasicSettings
from pyasic.web import BaseWebAPI from pyasic.web import BaseWebAPI
class BOSMinerWebAPI(BaseWebAPI): class BOSMinerWebAPI(BaseWebAPI):
def __init__(self, ip: str) -> None: def __init__(self, ip: str) -> None:
self.gql = BOSMinerGQLAPI(ip, PyasicSettings().global_bosminer_password)
self.luci = BOSMinerLuCIAPI(ip, PyasicSettings().global_bosminer_password)
self._pwd = PyasicSettings().global_bosminer_password
super().__init__(ip) super().__init__(ip)
self.pwd = settings.get("default_bosminer_password", "root")
@property
def pwd(self):
return self._pwd
@pwd.setter
def pwd(self, other: str):
self._pwd = other
self.luci.pwd = other
self.gql.pwd = other
async def send_command( async def send_command(
self, self,
@@ -34,44 +47,10 @@ class BOSMinerWebAPI(BaseWebAPI):
allow_warning: bool = True, allow_warning: bool = True,
**parameters: Union[str, int, bool], **parameters: Union[str, int, bool],
) -> dict: ) -> dict:
if isinstance(command, str): if command.startswith("/cgi-bin/luci"):
return await self.send_luci_command(command) return await self.luci.send_command(command)
else: else:
return await self.send_gql_command(command) return await self.gql.send_command(command)
def parse_command(self, graphql_command: Union[dict, set]) -> str:
if isinstance(graphql_command, dict):
data = []
for key in graphql_command:
if graphql_command[key] is not None:
parsed = self.parse_command(graphql_command[key])
data.append(key + parsed)
else:
data.append(key)
else:
data = graphql_command
return "{" + ",".join(data) + "}"
async def send_gql_command(
self,
command: dict,
) -> dict:
url = f"http://{self.ip}/graphql"
query = command
if command.get("query") is None:
query = {"query": self.parse_command(command)}
try:
async with httpx.AsyncClient() as client:
await self.auth(client)
data = await client.post(url, json=query)
except httpx.HTTPError:
pass
else:
if data.status_code == 200:
try:
return data.json()
except json.decoder.JSONDecodeError:
pass
async def multicommand( async def multicommand(
self, *commands: Union[dict, str], allow_warning: bool = True self, *commands: Union[dict, str], allow_warning: bool = True
@@ -79,13 +58,13 @@ class BOSMinerWebAPI(BaseWebAPI):
luci_commands = [] luci_commands = []
gql_commands = [] gql_commands = []
for cmd in commands: for cmd in commands:
if cmd.startswith("/cgi-bin/luci"):
luci_commands.append(cmd)
if isinstance(cmd, dict): if isinstance(cmd, dict):
gql_commands.append(cmd) gql_commands.append(cmd)
if isinstance(cmd, str):
luci_commands.append(cmd)
luci_data = await self.luci_multicommand(*luci_commands) luci_data = await self.luci.multicommand(*luci_commands)
gql_data = await self.gql_multicommand(*gql_commands) gql_data = await self.gql.multicommand(*gql_commands)
if gql_data is None: if gql_data is None:
gql_data = {} gql_data = {}
@@ -95,13 +74,14 @@ class BOSMinerWebAPI(BaseWebAPI):
data = dict(**luci_data, **gql_data) data = dict(**luci_data, **gql_data)
return data return data
async def luci_multicommand(self, *commands: str) -> dict:
data = {}
for command in commands:
data[command] = await self.send_luci_command(command, ignore_errors=True)
return data
async def gql_multicommand(self, *commands: dict) -> dict: class BOSMinerGQLAPI:
def __init__(self, ip: str, pwd: str):
self.ip = ip
self.username = "root"
self.pwd = pwd
async def multicommand(self, *commands: dict) -> dict:
def merge(*d: dict): def merge(*d: dict):
ret = {} ret = {}
for i in d: for i in d:
@@ -122,7 +102,7 @@ class BOSMinerWebAPI(BaseWebAPI):
# noinspection PyTypeChecker # noinspection PyTypeChecker
commands.remove({"bos": {"faultLight": None}}) commands.remove({"bos": {"faultLight": None}})
command = merge(*commands) command = merge(*commands)
data = await self.send_gql_command(command) data = await self.send_command(command)
except (LookupError, ValueError): except (LookupError, ValueError):
pass pass
if not data: if not data:
@@ -130,6 +110,40 @@ class BOSMinerWebAPI(BaseWebAPI):
data["multicommand"] = False data["multicommand"] = False
return data return data
async def send_command(
self,
command: dict,
) -> dict:
url = f"http://{self.ip}/graphql"
query = command
if command.get("query") is None:
query = {"query": self.parse_command(command)}
try:
async with httpx.AsyncClient() as client:
await self.auth(client)
data = await client.post(url, json=query)
except httpx.HTTPError:
pass
else:
if data.status_code == 200:
try:
return data.json()
except json.decoder.JSONDecodeError:
pass
def parse_command(self, graphql_command: Union[dict, set]) -> str:
if isinstance(graphql_command, dict):
data = []
for key in graphql_command:
if graphql_command[key] is not None:
parsed = self.parse_command(graphql_command[key])
data.append(key + parsed)
else:
data.append(key)
else:
data = graphql_command
return "{" + ",".join(data) + "}"
async def auth(self, client: httpx.AsyncClient) -> None: async def auth(self, client: httpx.AsyncClient) -> None:
url = f"http://{self.ip}/graphql" url = f"http://{self.ip}/graphql"
await client.post( await client.post(
@@ -143,10 +157,23 @@ class BOSMinerWebAPI(BaseWebAPI):
}, },
) )
async def send_luci_command(self, path: str, ignore_errors: bool = False) -> dict:
class BOSMinerLuCIAPI:
def __init__(self, ip: str, pwd: str):
self.ip = ip
self.username = "root"
self.pwd = pwd
async def multicommand(self, *commands: str) -> dict:
data = {}
for command in commands:
data[command] = await self.send_command(command, ignore_errors=True)
return data
async def send_command(self, path: str, ignore_errors: bool = False) -> dict:
try: try:
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
await self.luci_auth(client) await self.auth(client)
data = await client.get( data = await client.get(
f"http://{self.ip}{path}", headers={"User-Agent": "BTC Tools v0.1"} f"http://{self.ip}{path}", headers={"User-Agent": "BTC Tools v0.1"}
) )
@@ -162,7 +189,7 @@ class BOSMinerWebAPI(BaseWebAPI):
return {} return {}
raise APIError(f"Web command failed: path={path}") raise APIError(f"Web command failed: path={path}")
async def luci_auth(self, session: httpx.AsyncClient): async def auth(self, session: httpx.AsyncClient):
login = {"luci_username": self.username, "luci_password": self.pwd} login = {"luci_username": self.username, "luci_password": self.pwd}
url = f"http://{self.ip}/cgi-bin/luci" url = f"http://{self.ip}/cgi-bin/luci"
headers = { headers = {
@@ -172,23 +199,21 @@ class BOSMinerWebAPI(BaseWebAPI):
await session.post(url, headers=headers, data=login) await session.post(url, headers=headers, data=login)
async def get_net_conf(self): async def get_net_conf(self):
return await self.send_luci_command( return await self.send_command("/cgi-bin/luci/admin/network/iface_status/lan")
"/cgi-bin/luci/admin/network/iface_status/lan"
)
async def get_cfg_metadata(self): async def get_cfg_metadata(self):
return await self.send_luci_command("/cgi-bin/luci/admin/miner/cfg_metadata") return await self.send_command("/cgi-bin/luci/admin/miner/cfg_metadata")
async def get_cfg_data(self): async def get_cfg_data(self):
return await self.send_luci_command("/cgi-bin/luci/admin/miner/cfg_data") return await self.send_command("/cgi-bin/luci/admin/miner/cfg_data")
async def get_bos_info(self): async def get_bos_info(self):
return await self.send_luci_command("/cgi-bin/luci/bos/info") return await self.send_command("/cgi-bin/luci/bos/info")
async def get_overview(self): async def get_overview(self):
return await self.send_luci_command( return await self.send_command(
"/cgi-bin/luci/admin/status/overview?status=1" "/cgi-bin/luci/admin/status/overview?status=1"
) # needs status=1 or it fails ) # needs status=1 or it fails
async def get_api_status(self): async def get_api_status(self):
return await self.send_luci_command("/cgi-bin/luci/admin/miner/api_status") return await self.send_command("/cgi-bin/luci/admin/miner/api_status")