From 1108560d4f203aaec553fe75bdb12fc2490a6f25 Mon Sep 17 00:00:00 2001 From: test Date: Sun, 7 Dec 2025 05:22:16 +0600 Subject: [PATCH 1/2] new datastructure includes `version` and `timestamp` --- .../install_handler/long_poll_handler.py | 42 +++---- Framework/install_handler/route.py | 112 +++++++++--------- .../system_info/system_info.py | 80 ++++++------- 3 files changed, 114 insertions(+), 120 deletions(-) diff --git a/Framework/install_handler/long_poll_handler.py b/Framework/install_handler/long_poll_handler.py index 5776bfee..eadf1e3d 100644 --- a/Framework/install_handler/long_poll_handler.py +++ b/Framework/install_handler/long_poll_handler.py @@ -1,17 +1,17 @@ import asyncio -import json +import datetime import traceback import random import platform import httpx import inspect from colorama import Fore -from Framework.install_handler.route import Response, services +from Framework.install_handler.route import Response, services, version from Framework.install_handler.utils import send_response, debug, read_node_id from pydantic import BaseModel from Framework.Utilities import RequestFormatter, ConfigModule from Framework.node_server_state import STATE -from Framework.install_handler.android.emulator import create_avd_from_system_image, get_available_avds +from Framework.install_handler.android.emulator import create_avd_from_system_image from Framework.install_handler.system_info.system_info import get_formatted_system_info if debug: @@ -29,23 +29,12 @@ async def on_message(self, message: Response) -> None: if debug: print(f"[installer] Received message:\n {message.model_dump_json(indent=4)}") if message.value is None: return + now = int(datetime.datetime.now(datetime.timezone.utc).timestamp()) action = message.value.action if action == "services_list": current_os = platform.system().lower() if debug: print(f"[installer] Current OS: {current_os}") - # Populate AndroidEmulator services with available AVDs - try: - avds = await get_available_avds() - for category in services: - if category["category"] == "AndroidEmulator": - category["services"] = avds - if debug: print(f"[installer] Populated AndroidEmulator with {len(avds)} AVDs") - break - except Exception as e: - if debug: print(f"[installer] Error populating AVDs: {e}") - # Continue with empty services list if AVD population fails - filtered_services = [] for category in services: filtered_category = { @@ -70,9 +59,17 @@ async def on_message(self, message: Response) -> None: if filtered_category["services"]: filtered_services.append(filtered_category) + services_list = { + "timestamp": now, + "version": version, + "services": { + "system_info": None, + "categories": filtered_services + } + } await send_response({ "action": "services_list", - "data": filtered_services + "data": services_list }) elif action == "system_info": if debug: print(f"[installer] Received system_info request") @@ -81,7 +78,12 @@ async def on_message(self, message: Response) -> None: print("system info") system_info_response = await get_formatted_system_info() # Send the response to server - await send_response(system_info_response) + await send_response({ + "timestamp": now, + "version": version, + "action": "system_info", + "data": system_info_response + }) if debug: print(f"[installer] System info sent successfully") except Exception as e: print(f"[installer] Error getting/sending system info: {e}") @@ -110,13 +112,13 @@ async def on_message(self, message: Response) -> None: print(f"[installer] No install_function found for AndroidEmulator category") return - # Case 2: Service name is a device installation request (starts with "install device;") - if service_name.startswith("install device;"): + # Case 2: Service name is a system image (starts with "system-images;") + if service_name.startswith("system-images;"): if action == "install": await create_avd_from_system_image(service_name) return else: - print(f"[installer] Status check not supported for device installation") + print(f"[installer] Status check not supported for system images") return # Case 3: Service name is an existing AVD - find it in services list diff --git a/Framework/install_handler/route.py b/Framework/install_handler/route.py index a4cb5936..4eaeea9c 100644 --- a/Framework/install_handler/route.py +++ b/Framework/install_handler/route.py @@ -10,66 +10,11 @@ from .windows import inspector from .android.emulator import android_emulator_install - +version = "2.0.0" services = [ - { - "category": "Web", - - "services": [ - { - "name": "Chrome For Testing", - "status": "none", - "comment": "Chrome for Testing is required to run web automation in Chrome browser.", - "install_text": "install", - "os": ["windows", "linux", "darwin"], - "status_function": chrome_for_testing.check_status, - "install_function": chrome_for_testing.install, - "user_password": "no", - }, - { - "name": "Mozilla", - "status": "none", - "comment": "Mozilla Firefox is required to run web automation in Mozilla Firefox browser.", - "install_text": "install", - "os": ["windows", "linux", "darwin"], - "status_function": mozilla.check_status, - "install_function": mozilla.install, - "user_password": "yes", - }, - { - "name": "Edge", - "status": "none", - "comment": "Microsoft Edge is required to run web automation in Microsoft Edge browser.", - "install_text": "install", - "os": ["windows", "linux", "darwin"], - "status_function": edge.check_status, - "install_function": edge.install, - "user_password": "yes", - } - - ] - }, - { - "category": "AndroidEmulator", - "name" : "System Images", - "install_text": "install", - "install_function": android_emulator_install, - "installables": [], - "services": [], - }, { "category": "Android", "services": [ - { - "name": "ADB", - "status": "none", - "comment": "ADB is a tool for managing Android devices.", - "install_text": "install", - "os": ["windows", "linux", "darwin"], - "status_function": adb.check_status, - "install_function": adb.install, - "user_password": "no", - }, { "name": "Node js 22", "status": "none", @@ -119,7 +64,62 @@ "status_function": android_sdk.check_status, "install_function": android_sdk.install, "user_password": "no" + }, + { + "name": "ADB", + "status": "none", + "comment": "ADB is a tool for managing Android devices.", + "install_text": "install", + "os": ["windows", "linux", "darwin"], + "status_function": adb.check_status, + "install_function": adb.install, + "user_password": "no", + }, + ] + }, + { + "category": "AndroidEmulator", + "name" : "System Images", + "install_text": "install", + "install_function": android_emulator_install, + "installables": [], + "services": [], + }, + { + "category": "Web", + + "services": [ + { + "name": "Chrome For Testing", + "status": "none", + "comment": "Chrome for Testing is required to run web automation in Chrome browser.", + "install_text": "install", + "os": ["windows", "linux", "darwin"], + "status_function": chrome_for_testing.check_status, + "install_function": chrome_for_testing.install, + "user_password": "no", + }, + { + "name": "Mozilla", + "status": "none", + "comment": "Mozilla Firefox is required to run web automation in Mozilla Firefox browser.", + "install_text": "install", + "os": ["windows", "linux", "darwin"], + "status_function": mozilla.check_status, + "install_function": mozilla.install, + "user_password": "yes", + }, + { + "name": "Edge", + "status": "none", + "comment": "Microsoft Edge is required to run web automation in Microsoft Edge browser.", + "install_text": "install", + "os": ["windows", "linux", "darwin"], + "status_function": edge.check_status, + "install_function": edge.install, + "user_password": "yes", } + ] }, { diff --git a/Framework/install_handler/system_info/system_info.py b/Framework/install_handler/system_info/system_info.py index 27017b87..4f62f93f 100644 --- a/Framework/install_handler/system_info/system_info.py +++ b/Framework/install_handler/system_info/system_info.py @@ -1082,37 +1082,34 @@ async def get_formatted_system_info() -> Dict[str, Any]: Returns: { - "action": "system_info", - "data": { - "os": { - "name": "Ubuntu", - "version": "22.04", - "release": "22.04.3 LTS" - }, - "cpu": { - "cores": 8, - "model": "Intel Core i7", - "architecture": "x86_64" - }, - "memory": { - "total_ram": "16 GB", - "swap": { - "total": "4 GB", - "used": "0.5 GB", - "free": "3.5 GB", - "percent": 12.5 - } - }, - "disk": { - "total_space": "500 GB", - "mount_points": [ - { - "path": "/", - "total": "500 GB", - "available": "200 GB" - } - ] + "os": { + "name": "Ubuntu", + "version": "22.04", + "release": "22.04.3 LTS" + }, + "cpu": { + "cores": 8, + "model": "Intel Core i7", + "architecture": "x86_64" + }, + "memory": { + "total_ram": "16 GB", + "swap": { + "total": "4 GB", + "used": "0.5 GB", + "free": "3.5 GB", + "percent": 12.5 } + }, + "disk": { + "total_space": "500 GB", + "mount_points": [ + { + "path": "/", + "total": "500 GB", + "available": "200 GB" + } + ] } } """ @@ -1208,23 +1205,18 @@ async def get_formatted_system_info() -> Dict[str, Any]: # Return formatted response return { - "action": "system_info", - "data": { - "os": os_data, - "cpu": cpu_data, - "memory": memory_data, - "disk": disk_data - } + "os": os_data, + "cpu": cpu_data, + "memory": memory_data, + "disk": disk_data } except Exception as e: print(f"[installer][system-info] Error formatting system info: {e}") # Return minimal error response return { - "action": "system_info", - "data": { - "os": {"name": "Unknown", "version": "Unknown", "release": "Unknown"}, - "cpu": {"cores": None, "model": "Unknown", "architecture": "Unknown"}, - "memory": {"total_ram": "Unknown"}, - "disk": {"total_space": "Unknown", "mount_points": []} - } + "os": {"name": "Unknown", "version": "Unknown", "release": "Unknown"}, + "cpu": {"cores": None, "model": "Unknown", "architecture": "Unknown"}, + "memory": {"total_ram": "Unknown"}, + "disk": {"total_space": "Unknown", "mount_points": []} } + From 6fa90acb99b0f90e08330713cbbb0748cc98d82e Mon Sep 17 00:00:00 2001 From: test Date: Sun, 7 Dec 2025 09:39:01 +0600 Subject: [PATCH 2/2] adjustments for status check --- .../install_handler/long_poll_handler.py | 51 ++------------ Framework/install_handler/route.py | 69 +++---------------- Framework/install_handler/utils.py | 54 +++++++++++++-- 3 files changed, 62 insertions(+), 112 deletions(-) diff --git a/Framework/install_handler/long_poll_handler.py b/Framework/install_handler/long_poll_handler.py index eadf1e3d..efcd61a5 100644 --- a/Framework/install_handler/long_poll_handler.py +++ b/Framework/install_handler/long_poll_handler.py @@ -1,14 +1,11 @@ import asyncio -import datetime import traceback import random -import platform import httpx import inspect from colorama import Fore -from Framework.install_handler.route import Response, services, version -from Framework.install_handler.utils import send_response, debug, read_node_id -from pydantic import BaseModel +from Framework.install_handler.route import Response, services +from Framework.install_handler.utils import debug, send_response, read_node_id, generate_services_list from Framework.Utilities import RequestFormatter, ConfigModule from Framework.node_server_state import STATE from Framework.install_handler.android.emulator import create_avd_from_system_image @@ -29,47 +26,15 @@ async def on_message(self, message: Response) -> None: if debug: print(f"[installer] Received message:\n {message.model_dump_json(indent=4)}") if message.value is None: return - now = int(datetime.datetime.now(datetime.timezone.utc).timestamp()) action = message.value.action if action == "services_list": - current_os = platform.system().lower() - if debug: print(f"[installer] Current OS: {current_os}") - - filtered_services = [] - for category in services: - filtered_category = { - "category": category["category"], - "services": [] - } - for service in category["services"]: - if current_os not in service["os"]: - if debug: print(f"[installer] Skipping {service['name']} - not compatible with {current_os}") - continue - - filtered_service = { - "name": service["name"], - "status": service["status"], - "comment": service["comment"], - "install_text": service["install_text"], - "os": service["os"], - "user_password": service["user_password"] - } - filtered_category["services"].append(filtered_service) - - if filtered_category["services"]: - filtered_services.append(filtered_category) - - services_list = { - "timestamp": now, - "version": version, - "services": { - "system_info": None, - "categories": filtered_services - } - } + services_list = generate_services_list(services) await send_response({ "action": "services_list", - "data": services_list + "data": { + "system_info": None, + "services": services_list + } }) elif action == "system_info": if debug: print(f"[installer] Received system_info request") @@ -79,8 +44,6 @@ async def on_message(self, message: Response) -> None: system_info_response = await get_formatted_system_info() # Send the response to server await send_response({ - "timestamp": now, - "version": version, "action": "system_info", "data": system_info_response }) diff --git a/Framework/install_handler/route.py b/Framework/install_handler/route.py index 4eaeea9c..e73adb86 100644 --- a/Framework/install_handler/route.py +++ b/Framework/install_handler/route.py @@ -1,7 +1,6 @@ from pydantic import BaseModel, ConfigDict from typing import Literal -import asyncio - +import platform from .web import chrome_for_testing, edge, mozilla from .android import adb, node_js_22, appium, java, android_emulator, android_sdk, jdk, emulator @@ -10,6 +9,11 @@ from .windows import inspector from .android.emulator import android_emulator_install +import httpx +from Framework.Utilities import RequestFormatter, ConfigModule, CommonUtil +import datetime +from Framework.install_handler.utils import debug + version = "2.0.0" services = [ { @@ -201,64 +205,6 @@ ] - -# try: -# avds = asyncio.run(emulator.get_available_avds()) -# except RuntimeError: -# # Event loop already running, use a different approach -# try: -# loop = asyncio.get_event_loop() -# if loop.is_running(): -# # If loop is running, initialize empty and populate later -# avds = [] -# else: -# avds = loop.run_until_complete(emulator.get_available_avds()) -# except RuntimeError: -# avds = [] - -# def _populate_avds(): -# """Populate the AndroidEmulator category with available AVDs""" -# try: -# loop = asyncio.get_event_loop() -# if loop.is_running(): -# # If loop is running, we need to schedule it -# async def refresh(): -# avds = await emulator.get_available_avds() -# for category in services: -# if category["category"] == "AndroidEmulator": -# category["services"] = avds -# break -# # Schedule the refresh -# asyncio.create_task(refresh()) -# else: -# avds = loop.run_until_complete(emulator.get_available_avds()) -# for category in services: -# if category["category"] == "AndroidEmulator": -# category["services"] = avds -# break -# except Exception as e: -# print(f"[installer][route] Error refreshing AVD list: {e}") - - -# async def refresh_avd_list(): -# """Refresh the AVD list in the AndroidEmulator category""" -# try: -# avds = await emulator.get_available_avds() -# for category in services: -# if category["category"] == "AndroidEmulator": -# category["services"] = avds -# break -# print(f"[installer][route] Refreshed AVD list: {len(avds)} AVDs found") -# except Exception as e: -# print(f"[installer][route] Error refreshing AVD list: {e}") - - -# for category in services: -# if category["category"] == "AndroidEmulator": -# category["services"] = avds -# break - - class Item(BaseModel): name: str | None = None category: str @@ -275,4 +221,5 @@ class Value(BaseModel): class Response(BaseModel): model_config = ConfigDict(extra='forbid') - value: Value | None \ No newline at end of file + value: Value | None + diff --git a/Framework/install_handler/utils.py b/Framework/install_handler/utils.py index cedafa9f..59025f4d 100644 --- a/Framework/install_handler/utils.py +++ b/Framework/install_handler/utils.py @@ -1,25 +1,66 @@ +import datetime import httpx +import platform from Framework.Utilities import RequestFormatter, ConfigModule, CommonUtil debug = False +version = "2.0.0" + def read_node_id(): return CommonUtil.MachineInfo().getLocalUser().lower() +def generate_services_list(services): + current_os = platform.system().lower() + + filtered_services = [] + for category in services: + filtered_category = { + "category": category["category"], + "services": [] + } + for service in category["services"]: + if current_os not in service["os"]: + continue + + filtered_service = { + "name": service["name"], + "status": service["status"], + "comment": service["comment"], + "install_text": service["install_text"], + "os": service["os"], + "user_password": service["user_password"] + } + filtered_category["services"].append(filtered_service) + + if filtered_category["services"]: + filtered_services.append(filtered_category) + + return filtered_services + + async def send_response(data=None) -> None: try: + from Framework.install_handler.route import services + api_key = ConfigModule.get_config_value("Authentication", "api-key") url = RequestFormatter.form_uri("d/nodes/install/server/push") - payload = { - "node_id": read_node_id(), - "data": data - } + data['last_updated'] = int(datetime.datetime.now(datetime.timezone.utc).timestamp()) + data['version'] = version + data['node_id'] = read_node_id() + + if data['action'] == "status": + data['all_data'] = { + "system_info": None, + "services": generate_services_list(services) + } + if debug: - print(f"[installer] Sending response to server: {payload}") + print(f"[installer] Sending response to server: {data}") async with httpx.AsyncClient(timeout=30.0, verify=False) as client: - resp = await client.post(url, json=payload, headers={"X-API-KEY": api_key}) + resp = await client.post(url, json=data, headers={"X-API-KEY": api_key}) if debug: print(f"[installer] Response status: {resp.status_code}") print(f"[installer] Response content: {resp.content}") @@ -28,4 +69,3 @@ async def send_response(data=None) -> None: print(f"[installer] Failed to send response: {resp.status_code}") except Exception as e: print(f"[installer] Error sending response: {e}") -