diff --git a/miners/__init__.py b/miners/__init__.py index ae248053..16f85f93 100644 --- a/miners/__init__.py +++ b/miners/__init__.py @@ -54,8 +54,8 @@ class BaseMiner: raise e async def send_file(self, src, dest): - conn = self._get_ssh_connection() - await asyncssh.scp((conn, src), dest) + async with (await self._get_ssh_connection()) as conn: + await asyncssh.scp(src, (conn, dest)) async def check_light(self): return self.light diff --git a/network/net_range.py b/network/net_range.py index 8e260b5a..d62e997d 100644 --- a/network/net_range.py +++ b/network/net_range.py @@ -19,8 +19,12 @@ class MinerNetworkRange: end_ip = ipaddress.ip_address(end) networks = ipaddress.summarize_address_range(start_ip, end_ip) for network in networks: + self.host_ips.append(network.network_address) for host in network.hosts(): - self.host_ips.append(host) + if host not in self.host_ips: + self.host_ips.append(host) + if network.broadcast_address not in self.host_ips: + self.host_ips.append(network.broadcast_address) def hosts(self): for x in self.host_ips: diff --git a/tools/web_testbench/_miners.py b/tools/web_testbench/_miners.py index 2f666640..aa713027 100644 --- a/tools/web_testbench/_miners.py +++ b/tools/web_testbench/_miners.py @@ -1,18 +1,17 @@ from ipaddress import ip_address import asyncio import os -import datetime from network import ping_miner from miners.miner_factory import MinerFactory from miners.antminer.S9.bosminer import BOSMinerS9 from tools.web_testbench.connections import ConnectionManager +from tools.web_testbench.feeds import get_local_versions REFERRAL_FILE_S9 = os.path.join(os.path.dirname(__file__), "files", "referral.ipk") UPDATE_FILE_S9 = os.path.join(os.path.dirname(__file__), "files", "update.tar") CONFIG_FILE = os.path.join(os.path.dirname(__file__), "files", "config.toml") - # static states (START, UNLOCK, INSTALL, UPDATE, REFERRAL, DONE) = range(6) @@ -21,11 +20,20 @@ class TestbenchMiner: def __init__(self, host: ip_address): self.host = host self.state = START + self.latest_version = None + + async def get_bos_version(self): + miner = await MinerFactory().get_miner(self.host) + result = await miner.send_ssh_command("cat /etc/bos_version") + version_base = result.stdout + version_base = version_base.strip() + version_base = version_base.split("-") + version = version_base[-2] + return version async def add_to_output(self, message): - print(datetime.datetime.now()) await ConnectionManager().broadcast_json( - {"IP": str(self.host), "text": str(message) + "\n"} + {"IP": str(self.host), "text": str(message).replace("\r", "") + "\n"} ) return @@ -39,13 +47,17 @@ class TestbenchMiner: await asyncio.sleep(1) async def install_start(self): - if not await ping_miner(self.host): + if not await ping_miner(self.host, 80): await self.add_to_output("Waiting for miner connection...") return await self.remove_from_cache() miner = await MinerFactory().get_miner(self.host) - await self.add_to_output("Found miner: " + miner) + await self.add_to_output("Found miner: " + str(miner)) if isinstance(miner, BOSMinerS9): + if await self.get_bos_version() == self.latest_version: + await self.add_to_output("Already running the latest version of BraiinsOS, configuring.") + self.state = REFERRAL + return await self.add_to_output("Already running BraiinsOS, updating.") self.state = UPDATE return @@ -84,8 +96,11 @@ class TestbenchMiner: ) # get stdout of the install while True: - stdout = await proc.stderr.readuntil(b"\r") - await self.add_to_output(stdout) + try: + stdout = await proc.stderr.readuntil(b"\r") + except asyncio.exceptions.IncompleteReadError: + break + await self.add_to_output(stdout.decode("utf-8").strip()) if stdout == b"": break await proc.wait() @@ -96,40 +111,38 @@ class TestbenchMiner: self.state = REFERRAL async def install_update(self): + await self.add_to_output("Updating miner...") await self.remove_from_cache() miner = await MinerFactory().get_miner(self.host) try: await miner.send_file(UPDATE_FILE_S9, "/tmp/firmware.tar") await miner.send_ssh_command("sysupgrade /tmp/firmware.tar") - except: + except Exception as e: + print(e) await self.add_to_output("Failed to update, restarting.") self.state = START return + await asyncio.sleep(10) await self.add_to_output("Update complete, configuring.") self.state = REFERRAL async def install_referral(self): + while not await ping_miner(self.host): + await asyncio.sleep(1) miner = await MinerFactory().get_miner(self.host) - if os.path.exists(REFERRAL_FILE_S9): - try: - await miner.send_file(REFERRAL_FILE_S9, "/tmp/referral.ipk") - await miner.send_file(CONFIG_FILE, "/etc/bosminer.toml") - - await miner.send_ssh_command( - "opkg install /tmp/referral.ipk && /etc/init.d/bosminer restart" - ) - except: - await self.add_to_output( - "Failed to add referral and configure, restarting." - ) - self.state = START - return - else: + try: + await miner.send_file(REFERRAL_FILE_S9, "/tmp/referral.ipk") + await miner.send_file(CONFIG_FILE, "/etc/bosminer.toml") + await miner.send_ssh_command( + "opkg install /tmp/referral.ipk && /etc/init.d/bosminer restart" + ) + except Exception as e: await self.add_to_output( "Failed to add referral and configure, restarting." ) self.state = START return + await asyncio.sleep(5) await self.add_to_output("Configuration complete.") self.state = DONE @@ -183,7 +196,7 @@ class TestbenchMiner: # set the miner data miner_data = { - "IP": self.host, + "IP": str(self.host), "Light": "show", "Fans": fans_data, "HR": hr_data, @@ -198,11 +211,13 @@ class TestbenchMiner: async def install_done(self): await self.add_to_output("Waiting for disconnect...") while await ping_miner(self.host) and self.state == DONE: - await ConnectionManager().broadcast_json(await self.get_web_data()) + data = await self.get_web_data() + await ConnectionManager().broadcast_json(data) await asyncio.sleep(1) self.state = START async def install_loop(self): + self.latest_version = sorted(await get_local_versions(), reverse=True)[0] while True: if self.state == START: await self.install_start() diff --git a/tools/web_testbench/_network.py b/tools/web_testbench/_network.py index caa52f9f..d4f59f14 100644 --- a/tools/web_testbench/_network.py +++ b/tools/web_testbench/_network.py @@ -1,3 +1,3 @@ from network import MinerNetwork -miner_network = MinerNetwork("192.168.1.10-192.168.1.33").get_network() +miner_network = MinerNetwork("192.168.1.11-192.168.1.34").get_network() diff --git a/tools/web_testbench/app.py b/tools/web_testbench/app.py index 5a51ada9..73fafabc 100644 --- a/tools/web_testbench/app.py +++ b/tools/web_testbench/app.py @@ -35,9 +35,13 @@ async def ws(websocket: WebSocket): if "IP" in data.keys(): miner = await MinerFactory().get_miner(data["IP"]) if data["Data"] == "unlight": - miner.fault_light_off() + if data["IP"] in ConnectionManager.lit_miners: + ConnectionManager.lit_miners.remove(data["IP"]) + await miner.fault_light_off() if data["Data"] == "light": - miner.fault_light_on() + if data["IP"] not in ConnectionManager().lit_miners: + ConnectionManager.lit_miners.append(data["IP"]) + await miner.fault_light_on() except WebSocketDisconnect: ConnectionManager().disconnect(websocket) except RuntimeError: diff --git a/tools/web_testbench/connections.py b/tools/web_testbench/connections.py index 2ec8173c..a89346a1 100644 --- a/tools/web_testbench/connections.py +++ b/tools/web_testbench/connections.py @@ -7,6 +7,7 @@ from tools.web_testbench._network import miner_network class ConnectionManager: _instance = None _connections = [] + lit_miners = [] def __new__(cls): if not cls._instance: @@ -16,16 +17,17 @@ class ConnectionManager: async def connect(self, websocket: WebSocket): await websocket.accept() miners = [] + print(ConnectionManager.lit_miners) for host in miner_network.hosts(): - if host in MinerFactory().miners.keys(): + if str(host) in ConnectionManager.lit_miners: miners.append( { "IP": str(host), - "Light_On": await MinerFactory().miners[host].get_light(), + "Light_On": True, } ) else: - miners.append({"IP": str(host), "Light_On": None}) + miners.append({"IP": str(host), "Light_On": False}) await websocket.send_json({"miners": miners}) ConnectionManager._connections.append(websocket) diff --git a/tools/web_testbench/feeds.py b/tools/web_testbench/feeds.py index ee532f9a..0427dde3 100644 --- a/tools/web_testbench/feeds.py +++ b/tools/web_testbench/feeds.py @@ -109,6 +109,23 @@ async def get_latest_install_file(session, version, feeds_path, install_file): async def update_installer_files(): + feeds_path = os.path.join( + os.path.dirname(__file__), "files", "bos-toolbox", "feeds" + ) + feeds_versions = await get_local_versions() + async with aiohttp.ClientSession() as session: + version = await get_latest_version(session) + + if version not in feeds_versions: + update_file = await get_update_file(session, version) + install_file = await get_feeds_file(session, version) + await get_latest_update_file(session, update_file) + await get_latest_install_file(session, version, feeds_path, install_file) + else: + logging.info("Feeds are up to date.") + + +async def get_local_versions(): feeds_versions = [] feeds_path = os.path.join( os.path.dirname(__file__), "files", "bos-toolbox", "feeds" @@ -127,16 +144,8 @@ async def update_installer_files(): ver = line.strip().split("\t")[0] feeds_versions.append(ver) - async with aiohttp.ClientSession() as session: - version = await get_latest_version(session) + return feeds_versions - if version not in feeds_versions: - update_file = await get_update_file(session, version) - install_file = await get_feeds_file(session, version) - await get_latest_update_file(session, update_file) - await get_latest_install_file(session, version, feeds_path, install_file) - else: - logging.info("Feeds are up to date.") if __name__ == "__main__": diff --git a/tools/web_testbench/templates/index.html b/tools/web_testbench/templates/index.html index 58451010..7788ec42 100644 --- a/tools/web_testbench/templates/index.html +++ b/tools/web_testbench/templates/index.html @@ -238,7 +238,7 @@ ws.onmessage = function(event) { } light_switch.id = miner["IP"] + "-light" light_switch.className = "form-check-input" - light_switch.addEventListener("click", function(){lightMiner(miner, light_switch);}, false); + light_switch.addEventListener("click", function(){lightMiner(miner["IP"], light_switch);}, false); // add a light label to the button