Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,6 @@ decky_plugin.py
# Ignore decky CLI for building plugins
out
out/*
cli/
cli/*
cli/decky

# Ignore python link
Expand Down
2 changes: 1 addition & 1 deletion defaults/python/lib/cli/cmd/app/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ async def execute(buddy_client: BuddyClient, settings: CliSettings, host_id: str
logger.info(f"Buddy has accepted the request to launch {app_id}")
return 0

wake_on_lan(address=wol_address, mac=wol_mac)
await wake_on_lan(hostname=settings["hosts"][host_id]["hostName"], address=wol_address, mac=wol_mac)
if not await check_connectivity(client=buddy_client,
info_port=settings["hosts"][host_id]["infoPort"],
host_id=host_id,
Expand Down
4 changes: 2 additions & 2 deletions defaults/python/lib/cli/cmd/host/wake.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
@host_pattern_matcher(match_one=True)
@wol_settings
@cmd_entry
async def execute(wol_address: str, wol_mac: str):
wake_on_lan(address=wol_address, mac=wol_mac)
async def execute(hostname: str, wol_address: str, wol_mac: str):
await wake_on_lan(hostname=hostname, address=wol_address, mac=wol_mac)
return 0
3 changes: 2 additions & 1 deletion defaults/python/lib/cli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,14 @@ async def async_wrapper(*args, **kwargs):
settings: CliSettings = cast(CliSettings, kwargs["settings"])
host_id: str = cast(str, kwargs["host_id"])

hostname = settings["hosts"][host_id]["hostName"]
address = settings["hosts"][host_id]["address"]
mac = settings["hosts"][host_id]["mac"]
if mac is None:
logger.error("Host has not been paired yet or the MAC was not synced!")
return 1

return await f(*args, wol_address=address, wol_mac=mac, **kwargs)
return await f(*args, hostname=hostname, wol_address=address, wol_mac=mac, **kwargs)

return async_wrapper

Expand Down
22 changes: 3 additions & 19 deletions defaults/python/lib/moonlightproxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,37 +137,21 @@ async def start(self, hostname: str, host_app: str, cmd_options: Optional[Comman
async def terminate(self):
# Lazy import to improve CLI performance
import asyncio
import psutil
from .utils import ps_signal

if self.process is None:
return

assert self.__proc is not None
def ps_signal(kill: bool):
def do_signal(proc_or_child):
try:
if kill:
proc_or_child.kill()
else:
proc_or_child.terminate()
except psutil.NoSuchProcess:
pass

proc = cast(psutil.Process, self.__proc)
for child in list(proc.children(recursive=True)):
do_signal(child)

do_signal(proc)

try:
logger.info("Trying to gracefully terminate Moonlight...")
ps_signal(kill=False)
ps_signal(self.__proc, kill=False)
try:
await asyncio.wait_for(self.process.wait(), timeout=5.0)
logger.info("Moonlight terminated gracefully.")
except asyncio.TimeoutError:
logger.info("Moonlight did not terminate in time - killing it!")
ps_signal(kill=True)
ps_signal(self.__proc, kill=True)
await self.process.wait()
except ProcessLookupError:
pass
Expand Down
9 changes: 8 additions & 1 deletion defaults/python/lib/plugin/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class HostSettings(TypedDict):
buddy: BuddySettings
gameStreamApps: GameStreamAppsSettings
nonSteamApps: NonSteamAppsSettings
useCustomWolExec: bool
customWolExecPath: str


class GameSessionSettings(TypedDict):
Expand All @@ -114,7 +116,7 @@ class ButtonStyleSettings(TypedDict):


class UserSettings(TypedDict):
version: Literal[36]
version: Literal[37]
clientId: str
currentHostId: Optional[str]
gameSession: GameSessionSettings
Expand Down Expand Up @@ -356,3 +358,8 @@ def _migrate_settings(self, data: dict):
data["version"] = 36
if data["gameSession"]["controllerConfig"] == "Noop":
data["gameSession"]["controllerConfig"] = None
if data["version"] == 36:
data["version"] = 37
for host in data["hostSettings"].keys():
data["hostSettings"][host]["useCustomWolExec"] = False
data["hostSettings"][host]["customWolExecPath"] = ""
5 changes: 3 additions & 2 deletions defaults/python/lib/runner/moondeckapprunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ async def launch(cls, client: BuddyClient, big_picture_mode: bool, app_id: str,

class MoonDeckAppRunner:
@staticmethod
async def check_connectivity(client: BuddyClient, mac: str, host_id: str, hostname: str, host_port: int, wol_timeout: int, server_timeout: int):
async def check_connectivity(client: BuddyClient, mac: str, host_id: str, hostname: str, host_port: int, custom_wol_exec: Optional[str], wol_timeout: int, server_timeout: int):
logger.info("Checking connection to Buddy and GameStream server")

# Lazy import to improve CLI performance
from .wolsplashscreen import WolSplashScreen

async with WolSplashScreen(client.address, mac, wol_timeout, hostname) as splash:
async with WolSplashScreen(client.address, mac, wol_timeout, hostname, custom_wol_exec) as splash:
while True:
try:
await client.say_hello(force=True)
Expand Down Expand Up @@ -256,6 +256,7 @@ async def run(cls, settings: MoonDeckAppRunnerSettings):
host_id=settings["host_id"],
hostname=settings["hostname"],
host_port=settings["host_port"],
custom_wol_exec=settings["custom_wol_exec_path"],
wol_timeout=settings["timeouts"]["wakeOnLan"],
server_timeout=settings["timeouts"]["servicePing"])
await cls.wait_for_initial_conditions(client=client,
Expand Down
6 changes: 4 additions & 2 deletions defaults/python/lib/runner/moonlightonlyrunner.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing import Optional
from .settingsparser import MoonlightOnlyRunnerSettings
from ..runnerresult import Result, RunnerError
from ..gamestreaminfo import get_server_info
Expand All @@ -7,13 +8,13 @@

class MoonlightOnlyRunner:
@staticmethod
async def check_connectivity(address: str, mac: str, host_id: str, hostname: str, host_port: int, wol_timeout: int, server_timeout: int):
async def check_connectivity(address: str, mac: str, host_id: str, hostname: str, host_port: int, custom_wol_exec: Optional[str], wol_timeout: int, server_timeout: int):
logger.info("Checking connection to GameStream server")

# Lazy import to improve CLI performance
from .wolsplashscreen import WolSplashScreen

async with WolSplashScreen(address, mac, wol_timeout, hostname) as splash:
async with WolSplashScreen(address, mac, wol_timeout, hostname, custom_wol_exec) as splash:
while True:
server_info = await get_server_info(address=address,
port=host_port,
Expand Down Expand Up @@ -48,6 +49,7 @@ async def run(cls, settings: MoonlightOnlyRunnerSettings):
host_id=settings["host_id"],
hostname=settings["hostname"],
host_port=settings["host_port"],
custom_wol_exec=settings["custom_wol_exec_path"],
wol_timeout=settings["timeouts"]["wakeOnLan"],
server_timeout=settings["timeouts"]["servicePing"])
await cls.start_moonlight(proxy=proxy,
Expand Down
4 changes: 4 additions & 0 deletions defaults/python/lib/runner/settingsparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class MoonDeckAppRunnerSettings(TypedDict):
close_steam: Optional[CloseSteam]
timeouts: RunnerTimeouts
moonlight_exec_path: Optional[str]
custom_wol_exec_path: Optional[str]
app_id: str
debug_logs: bool
runner_type: Literal[RunnerType.MoonDeck]
Expand All @@ -43,6 +44,7 @@ class MoonlightOnlyRunnerSettings(TypedDict):
host_port: int
timeouts: RunnerTimeouts
moonlight_exec_path: Optional[str]
custom_wol_exec_path: Optional[str]
debug_logs: bool
runner_type: Literal[RunnerType.MoonlightOnly]

Expand Down Expand Up @@ -179,6 +181,7 @@ async def parse_settings() -> MoonDeckAppRunnerSettings | MoonlightOnlyRunnerSet
"close_steam": CloseSteam[host_settings["buddy"]["closeSteam"]] if host_settings["buddy"]["closeSteam"] else None,
"timeouts": host_settings["runnerTimeouts"],
"moonlight_exec_path": user_settings["moonlightExecPath"] if user_settings["useMoonlightExec"] else None,
"custom_wol_exec_path": host_settings["customWolExecPath"] if host_settings["useCustomWolExec"] else None,
"app_id": env_settings["app_id"],
"debug_logs": user_settings["runnerDebugLogs"],
"runner_type": RunnerType.MoonDeck
Expand All @@ -197,6 +200,7 @@ async def parse_settings() -> MoonDeckAppRunnerSettings | MoonlightOnlyRunnerSet
"host_port": host_settings["hostInfoPort"],
"timeouts": host_settings["runnerTimeouts"],
"moonlight_exec_path": user_settings["moonlightExecPath"] if user_settings["useMoonlightExec"] else None,
"custom_wol_exec_path": host_settings["customWolExecPath"] if host_settings["useCustomWolExec"] else None,
"debug_logs": user_settings["runnerDebugLogs"],
"runner_type": RunnerType.MoonlightOnly
})
32 changes: 26 additions & 6 deletions defaults/python/lib/runner/wolsplashscreen.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import pyglet
import asyncio

from typing import Optional
from datetime import datetime, timedelta, timezone
from ..logger import logger
from ..utils import wake_on_lan
Expand Down Expand Up @@ -146,10 +147,12 @@ def handle_resize(self, width, height):


class WolSplashScreen:
def __init__(self, address: str, mac: str, timeout: int, hostname: str):
def __init__(self, address: str, mac: str, timeout: int, hostname: str, custom_wol_exec: Optional[str]):
self.address = address
self.hostname = hostname
self.mac = mac
self.custom_wol_exec = custom_wol_exec
if timeout > 0:
wake_on_lan(address=address, mac=mac)
self.timeout_end = datetime.now(timezone.utc) + timedelta(seconds=timeout)
else:
self.timeout_end = None
Expand All @@ -171,26 +174,43 @@ async def __run_loop(self):

async def __aenter__(self):
self.close_flag = True
self.task = None
self.wol_task = None
self.loop_task = None

if self.timeout_end is None:
return self

self.canvas = Canvas() # Added to pyglet.app.windows
self.canvas.label.set_text(text=f"Checking connection to {self.hostname}...")
self.close_flag = False
self.task = asyncio.create_task(self.__run_loop())
self.wol_task = asyncio.create_task(wake_on_lan(hostname=self.hostname,
address=self.address,
mac=self.mac,
custom_exec=self.custom_wol_exec))
self.loop_task = asyncio.create_task(self.__run_loop())
return self

async def __aexit__(self, exc_type, exc, tb):
self.close_flag = True
if self.task:
await self.task
if self.loop_task:
await self.loop_task

if self.wol_task:
_, pending = await asyncio.wait({self.wol_task}, timeout=1)
if self.wol_task in pending:
self.wol_task.cancel()
await asyncio.wait({self.wol_task})

self.loop_task.result()

def update(self, buddy_status, server_status) -> bool:
logger.info(f"Buddy: {buddy_status}, Server: {server_status}")
if self.close_flag or self.timeout_end is None:
return False

if self.wol_task and self.wol_task.done():
self.wol_task.result()
self.wol_task = None

if ((buddy_status is None or buddy_status) and server_status) or (datetime.now(timezone.utc) > self.timeout_end):
return False
Expand Down
Loading