feature: remove ssh references when getting MAC on bosminer.

This commit is contained in:
UpstreamData
2023-06-26 09:52:30 -06:00
parent 7b1b23016e
commit 2245904740
3 changed files with 124 additions and 17 deletions

View File

@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import asyncio
import logging
from collections import namedtuple
from typing import List, Optional, Tuple, Union
@@ -29,7 +29,12 @@ from pyasic.miners.base import BaseMiner
from pyasic.web.bosminer import BOSMinerWebAPI
BOSMINER_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {}},
"mac": {
"cmd": "get_mac",
"kwargs": {
"web_net_conf": {"web": "/cgi-bin/luci/admin/network/iface_status/lan"}
},
},
"model": {"cmd": "get_model", "kwargs": {}},
"api_ver": {
"cmd": "get_api_ver",
@@ -196,8 +201,8 @@ class BOSMiner(BaseMiner):
result = None
try:
conn = await self._get_ssh_connection()
except ConnectionError:
conn = await asyncio.wait_for(self._get_ssh_connection(), timeout=10)
except (ConnectionError, asyncio.TimeoutError):
return None
# open an ssh connection
@@ -368,10 +373,30 @@ class BOSMiner(BaseMiner):
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
##################################################
async def get_mac(self) -> Optional[str]:
result = await self.send_ssh_command("cat /sys/class/net/eth0/address")
if result:
return result.upper().strip()
async def get_mac(self, web_net_conf: Union[dict, list] = None) -> Optional[str]:
if not web_net_conf:
try:
web_net_conf = await self.web.send_command(
"/cgi-bin/luci/admin/network/iface_status/lan"
)
except APIError:
pass
if isinstance(web_net_conf, dict):
if "/cgi-bin/luci/admin/network/iface_status/lan" in web_net_conf.keys():
web_net_conf = web_net_conf[
"/cgi-bin/luci/admin/network/iface_status/lan"
]
if web_net_conf:
try:
return web_net_conf[0]["macaddr"]
except LookupError:
pass
# could use ssh, but its slow and buggy
# result = await self.send_ssh_command("cat /sys/class/net/eth0/address")
# if result:
# return result.upper().strip()
async def get_model(self) -> Optional[str]:
if self.model is not None:

View File

@@ -625,7 +625,10 @@ class MinerFactory:
data = await self._fix_api_data(data)
data = json.loads(data)
try:
data = json.loads(data)
except json.JSONDecodeError:
return {}
return data

View File

@@ -18,6 +18,7 @@ from typing import Union
import httpx
from pyasic import APIError
from pyasic.settings import PyasicSettings
from pyasic.web import BaseWebAPI
@@ -27,6 +28,18 @@ class BOSMinerWebAPI(BaseWebAPI):
super().__init__(ip)
self.pwd = PyasicSettings().global_bosminer_password
async def send_command(
self,
command: Union[str, dict],
ignore_errors: bool = False,
allow_warning: bool = True,
**parameters: Union[str, int, bool],
) -> dict:
if isinstance(command, str):
return await self.send_luci_command(command)
else:
return await self.send_gql_command(command)
def parse_command(self, graphql_command: Union[dict, set]) -> str:
if isinstance(graphql_command, dict):
data = []
@@ -40,12 +53,9 @@ class BOSMinerWebAPI(BaseWebAPI):
data = graphql_command
return "{" + ",".join(data) + "}"
async def send_command(
async def send_gql_command(
self,
command: dict,
ignore_errors: bool = False,
allow_warning: bool = True,
**parameters: Union[str, int, bool],
) -> dict:
url = f"http://{self.ip}/graphql"
query = self.parse_command(command)
@@ -63,8 +73,29 @@ class BOSMinerWebAPI(BaseWebAPI):
pass
async def multicommand(
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
) -> dict:
self, *commands: Union[dict, str], allow_warning: bool = True
):
luci_commands = []
gql_commands = []
for cmd in commands:
if isinstance(cmd, dict):
gql_commands.append(cmd)
if isinstance(cmd, str):
luci_commands.append(cmd)
luci_data = await self.luci_multicommand(*luci_commands)
gql_data = await self.gql_multicommand(*gql_commands)
data = dict(**luci_data, **gql_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:
def merge(*d: dict):
ret = {}
for i in d:
@@ -85,8 +116,8 @@ class BOSMinerWebAPI(BaseWebAPI):
# noinspection PyTypeChecker
commands.remove({"bos": {"faultLight": None}})
command = merge(*commands)
data = await self.send_command(command)
except LookupError:
data = await self.send_gql_command(command)
except (LookupError, ValueError):
pass
if not data:
data = {}
@@ -105,3 +136,51 @@ class BOSMinerWebAPI(BaseWebAPI):
+ '"){__typename}}}'
},
)
async def send_luci_command(self, path: str, ignore_errors: bool = False) -> dict:
try:
async with httpx.AsyncClient() as client:
await self.luci_auth(client)
data = await client.get(f"http://{self.ip}{path}")
if data.status_code == 200:
return data.json()
if ignore_errors:
return {}
raise APIError(
f"Web command failed: path={path}, code={data.status_code}"
)
except (httpx.HTTPError, json.JSONDecodeError):
if ignore_errors:
return {}
raise APIError(f"Web command failed: path={path}")
async def luci_auth(self, session: httpx.AsyncClient):
login = {"luci_username": self.username, "luci_password": self.pwd}
url = f"http://{self.ip}/cgi-bin/luci"
headers = {
"User-Agent": "BTC Tools v0.1", # only seems to respond if this user-agent is set
"Content-Type": "application/x-www-form-urlencoded",
}
d = await session.post(url, headers=headers, data=login)
async def get_net_conf(self):
return await self.send_luci_command(
"/cgi-bin/luci/admin/network/iface_status/lan"
)
async def get_cfg_metadata(self):
return await self.send_luci_command("/cgi-bin/luci/admin/miner/cfg_metadata")
async def get_cfg_data(self):
return await self.send_luci_command("/cgi-bin/luci/admin/miner/cfg_data")
async def get_bos_info(self):
return await self.send_luci_command("/cgi-bin/luci/bos/info")
async def get_overview(self):
return await self.send_luci_command(
"/cgi-bin/luci/admin/status/overview?status=1"
) # needs status=1 or it fails
async def get_api_status(self):
return await self.send_luci_command("/cgi-bin/luci/admin/miner/api_status")