""" Windows Service wrapper for the RemoteLink Agent. Installs/uninstalls/runs as a Windows Service via pywin32. Usage: remotelink-agent-service.exe install remotelink-agent-service.exe start remotelink-agent-service.exe stop remotelink-agent-service.exe remove """ import sys import os import asyncio import logging # Only import win32 on Windows if sys.platform == "win32": import win32serviceutil import win32service import win32event import servicemanager class RemoteLinkService(win32serviceutil.ServiceFramework): _svc_name_ = "RemoteLinkAgent" _svc_display_name_ = "RemoteLink Agent" _svc_description_ = "RemoteLink remote support agent service" def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) self.stop_event = win32event.CreateEvent(None, 0, 0, None) self._loop = None self._agent = None def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) if self._agent: self._agent.stop() win32event.SetEvent(self.stop_event) def SvcDoRun(self): servicemanager.LogMsg( servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, ""), ) self._run() def _run(self): # Set up logging to Windows Event Log + file log_path = os.path.join( os.environ.get("PROGRAMDATA", "C:\\ProgramData"), "RemoteLink", "agent.log" ) os.makedirs(os.path.dirname(log_path), exist_ok=True) logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", handlers=[logging.FileHandler(log_path)], ) # Import here to avoid circular issues when this module is imported from agent import Agent, load_config, heartbeat import json config = load_config() if not config: logging.error("No agent config found. Run enrollment first.") return self._loop = asyncio.new_event_loop() asyncio.set_event_loop(self._loop) agent = Agent( config["server_url"], config["machine_id"], config["access_key"], config.get("relay_url", ""), ) self._agent = agent try: self._loop.run_until_complete(agent.run()) finally: self._loop.close() if __name__ == "__main__": if len(sys.argv) == 1: servicemanager.Initialize() servicemanager.PrepareToHostSingle(RemoteLinkService) servicemanager.StartServiceCtrlDispatcher() else: win32serviceutil.HandleCommandLine(RemoteLinkService) else: print("Windows service wrapper — only runs on Windows.") sys.exit(1)