refactor: improve RPC handlers.

This commit is contained in:
UpstreamData
2024-01-16 15:26:32 -07:00
parent 307926afbb
commit 7292af450c
4 changed files with 53 additions and 73 deletions

View File

@@ -597,7 +597,9 @@ class MinerProtocol(Protocol):
ip=str(self.ip),
make=self.make,
model=self.model,
expected_chips=self.expected_chips * self.expected_hashboards,
expected_chips=self.expected_chips
if self.expected_chips is not None
else 0 * self.expected_hashboards,
expected_hashboards=self.expected_hashboards,
hashboards=[
HashBoard(slot=i, expected_chips=self.expected_chips)
@@ -619,7 +621,7 @@ class BaseMiner(MinerProtocol):
def __init__(self, ip: str) -> None:
self.ip = ip
if self.expected_chips is None:
if self.expected_chips is None and self.raw_model is not None:
warnings.warn(
f"Unknown chip count for miner type {self.raw_model}, "
f"please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."

View File

@@ -110,38 +110,41 @@ class BaseMinerRPCAPI:
allow_warning: A boolean to supress APIWarnings.
"""
while True:
# make sure we can actually run each command, otherwise they will fail
commands = self._check_commands(*commands)
# standard multicommand format is "command1+command2"
# standard format doesn't work for X19
command = "+".join(commands)
try:
data = await self.send_command(command, allow_warning=allow_warning)
except APIError as e:
# try to identify the error
if e.message is not None:
if ":" in e.message:
err_command = e.message.split(":")[0]
if err_command in commands:
commands.remove(err_command)
continue
return {command: [{}] for command in commands}
logging.debug(f"{self} - (Multicommand) - Received data")
data["multicommand"] = True
return data
async def _handle_multicommand(self, command: str, allow_warning: bool = True):
# make sure we can actually run each command, otherwise they will fail
commands = self._check_commands(*commands)
# standard multicommand format is "command1+command2"
# doesn't work for S19 which uses the backup _send_split_multicommand
command = "+".join(commands)
try:
data = await self.send_command(command, allow_warning=allow_warning)
if "+" not in command:
return {command: [data]}
return data
except APIError:
if "+" in command:
return {command: [{}] for command in command.split("+")}
return {command: [{}]}
data = await self._send_split_multicommand(*commands)
data["multicommand"] = True
return data
async def _send_split_multicommand(
self, *commands, allow_warning: bool = True
) -> dict:
tasks = {}
# send all commands individually
for cmd in commands:
tasks[cmd] = asyncio.create_task(
self.send_command(cmd, allow_warning=allow_warning)
)
await asyncio.gather(*[tasks[cmd] for cmd in tasks], return_exceptions=True)
data = {}
for cmd in tasks:
try:
result = tasks[cmd].result()
if result is None or result == {}:
result = {}
data[cmd] = [result]
except APIError:
pass
return data
@property
def commands(self) -> list:

View File

@@ -202,28 +202,33 @@ class BTMinerRPCAPI(BaseMinerRPCAPI):
# standard multicommand format is "command1+command2"
# commands starting with "get_" and the "status" command aren't supported, but we can fake that
tasks = []
split_commands = []
for command in list(commands):
if command.startswith("get_") or command == "status":
commands.remove(command)
# send seperately and append later
tasks.append(
asyncio.create_task(
self._handle_multicommand(command, allow_warning=allow_warning)
)
)
split_commands.append(command)
command = "+".join(commands)
tasks.append(
asyncio.create_task(
self._handle_multicommand(command, allow_warning=allow_warning)
tasks = []
if len(split_commands) > 0:
tasks.append(
asyncio.create_task(
self._send_split_multicommand(
*split_commands, allow_warning=allow_warning
)
)
)
tasks.append(
asyncio.create_task(self.send_command(command, allow_warning=allow_warning))
)
all_data = await asyncio.gather(*tasks)
logging.debug(f"{self} - (Multicommand) - Received data")
try:
all_data = await asyncio.gather(*tasks)
except APIError:
return {}
data = {}
for item in all_data:

View File

@@ -36,36 +36,6 @@ class CGMinerRPCAPI(BaseMinerRPCAPI):
ip: The IP of the miner to reference the API on.
"""
async def multicommand(self, *commands: str, allow_warning: bool = True) -> dict:
# make sure we can actually run each command, otherwise they will fail
commands = self._check_commands(*commands)
# standard multicommand format is "command1+command2"
# doesn't work for S19 which uses the backup _x19_multicommand
command = "+".join(commands)
try:
data = await self.send_command(command, allow_warning=allow_warning)
except APIError:
logging.debug(f"{self} - (Multicommand) - Handling X19 multicommand.")
data = await self._x19_multicommand(*command.split("+"))
data["multicommand"] = True
return data
async def _x19_multicommand(self, *commands) -> dict:
tasks = []
# send all commands individually
for cmd in commands:
tasks.append(
asyncio.create_task(self._handle_multicommand(cmd, allow_warning=True))
)
all_data = await asyncio.gather(*tasks)
data = {}
for item in all_data:
data.update(item)
return data
async def version(self) -> dict:
"""Get miner version info.
<details>