feature: remove ssh references when getting MAC on bosminer.
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from typing import List, Optional, Tuple, Union
|
from typing import List, Optional, Tuple, Union
|
||||||
@@ -29,7 +29,12 @@ from pyasic.miners.base import BaseMiner
|
|||||||
from pyasic.web.bosminer import BOSMinerWebAPI
|
from pyasic.web.bosminer import BOSMinerWebAPI
|
||||||
|
|
||||||
BOSMINER_DATA_LOC = {
|
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": {}},
|
"model": {"cmd": "get_model", "kwargs": {}},
|
||||||
"api_ver": {
|
"api_ver": {
|
||||||
"cmd": "get_api_ver",
|
"cmd": "get_api_ver",
|
||||||
@@ -196,8 +201,8 @@ class BOSMiner(BaseMiner):
|
|||||||
result = None
|
result = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = await self._get_ssh_connection()
|
conn = await asyncio.wait_for(self._get_ssh_connection(), timeout=10)
|
||||||
except ConnectionError:
|
except (ConnectionError, asyncio.TimeoutError):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# open an ssh connection
|
# open an ssh connection
|
||||||
@@ -368,10 +373,30 @@ class BOSMiner(BaseMiner):
|
|||||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
async def get_mac(self) -> Optional[str]:
|
async def get_mac(self, web_net_conf: Union[dict, list] = None) -> Optional[str]:
|
||||||
result = await self.send_ssh_command("cat /sys/class/net/eth0/address")
|
if not web_net_conf:
|
||||||
if result:
|
try:
|
||||||
return result.upper().strip()
|
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]:
|
async def get_model(self) -> Optional[str]:
|
||||||
if self.model is not None:
|
if self.model is not None:
|
||||||
|
|||||||
@@ -625,7 +625,10 @@ class MinerFactory:
|
|||||||
|
|
||||||
data = await self._fix_api_data(data)
|
data = await self._fix_api_data(data)
|
||||||
|
|
||||||
data = json.loads(data)
|
try:
|
||||||
|
data = json.loads(data)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return {}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from typing import Union
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
|
from pyasic import APIError
|
||||||
from pyasic.settings import PyasicSettings
|
from pyasic.settings import PyasicSettings
|
||||||
from pyasic.web import BaseWebAPI
|
from pyasic.web import BaseWebAPI
|
||||||
|
|
||||||
@@ -27,6 +28,18 @@ class BOSMinerWebAPI(BaseWebAPI):
|
|||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.pwd = PyasicSettings().global_bosminer_password
|
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:
|
def parse_command(self, graphql_command: Union[dict, set]) -> str:
|
||||||
if isinstance(graphql_command, dict):
|
if isinstance(graphql_command, dict):
|
||||||
data = []
|
data = []
|
||||||
@@ -40,12 +53,9 @@ class BOSMinerWebAPI(BaseWebAPI):
|
|||||||
data = graphql_command
|
data = graphql_command
|
||||||
return "{" + ",".join(data) + "}"
|
return "{" + ",".join(data) + "}"
|
||||||
|
|
||||||
async def send_command(
|
async def send_gql_command(
|
||||||
self,
|
self,
|
||||||
command: dict,
|
command: dict,
|
||||||
ignore_errors: bool = False,
|
|
||||||
allow_warning: bool = True,
|
|
||||||
**parameters: Union[str, int, bool],
|
|
||||||
) -> dict:
|
) -> dict:
|
||||||
url = f"http://{self.ip}/graphql"
|
url = f"http://{self.ip}/graphql"
|
||||||
query = self.parse_command(command)
|
query = self.parse_command(command)
|
||||||
@@ -63,8 +73,29 @@ class BOSMinerWebAPI(BaseWebAPI):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
async def multicommand(
|
async def multicommand(
|
||||||
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
self, *commands: Union[dict, str], allow_warning: bool = True
|
||||||
) -> dict:
|
):
|
||||||
|
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):
|
def merge(*d: dict):
|
||||||
ret = {}
|
ret = {}
|
||||||
for i in d:
|
for i in d:
|
||||||
@@ -85,8 +116,8 @@ 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_command(command)
|
data = await self.send_gql_command(command)
|
||||||
except LookupError:
|
except (LookupError, ValueError):
|
||||||
pass
|
pass
|
||||||
if not data:
|
if not data:
|
||||||
data = {}
|
data = {}
|
||||||
@@ -105,3 +136,51 @@ class BOSMinerWebAPI(BaseWebAPI):
|
|||||||
+ '"){__typename}}}'
|
+ '"){__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")
|
||||||
|
|||||||
Reference in New Issue
Block a user