feature: refactor BOS web class into multiple classes.

This commit is contained in:
UpstreamData
2023-09-22 09:32:59 -06:00
parent 53a3bbf531
commit 5c904aced0

View File

@@ -25,8 +25,20 @@ 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 = PyasicSettings().global_bosminer_password
@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,
@@ -35,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
@@ -80,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 = {}
@@ -96,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:
@@ -123,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:
@@ -131,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(
@@ -144,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"}
) )
@@ -163,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 = {
@@ -173,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")