clan-core/pkgs/moonlight-sunshine-accept/moonlight_sunshine_accept/moonlight/state.py
a-kenji 32d0f1ccd4
All checks were successful
checks / check-links (pull_request) Successful in 21s
checks / checks (pull_request) Successful in 33s
checks / checks-impure (pull_request) Successful in 1m48s
init: sunshine-moonlight-accept module
2024-03-19 12:11:09 +01:00

149 lines
4.9 KiB
Python

import os
import random
import string
from configparser import ConfigParser, DuplicateSectionError, NoOptionError
def moonlight_config_dir() -> str:
return os.path.join(
os.path.expanduser("~"), ".config", "Moonlight Game Streaming Project"
)
def moonlight_state_file() -> str:
return os.path.join(moonlight_config_dir(), "Moonlight.conf")
def load_state() -> ConfigParser | None:
try:
with open(moonlight_state_file()) as file:
config = ConfigParser()
config.read_file(file)
print(config.sections())
return config
except FileNotFoundError:
print("Sunshine state file not found.")
return None
# prepare the string for the config file
# this is how qt handles byte arrays
def convert_string_to_bytearray(data: str) -> str:
byte_array = '"@ByteArray('
byte_array += data.replace("\n", "\\n")
byte_array += ')"'
return byte_array
def convert_bytearray_to_string(byte_array: str) -> str:
if byte_array.startswith('"@ByteArray(') and byte_array.endswith(')"'):
byte_array = byte_array[12:-2]
return byte_array.replace("\\n", "\n")
# this must be created before moonlight is first run
def init_state(certificate: str, key: str) -> None:
print("Initializing moonlight state.")
os.makedirs(moonlight_config_dir(), exist_ok=True)
print("Initialized moonlight config directory.")
print("Writing moonlight state file.")
# write the initial bootstrap config file
with open(moonlight_state_file(), "w") as file:
config = ConfigParser()
# bytearray ojbects are not supported by ConfigParser,
# so we need to adjust them ourselves
config.add_section("General")
config.set("General", "certificate", convert_string_to_bytearray(certificate))
config.set("General", "key", convert_string_to_bytearray(key))
config.set("General", "latestsupportedversion-v1", "99.99.99.99")
config.add_section("gcmapping")
config.set("gcmapping", "size", "0")
config.write(file)
def write_state(data: ConfigParser) -> bool:
with open(moonlight_state_file(), "w") as file:
data.write(file)
def add_sunshine_host_to_parser(
config: ConfigParser, hostname: str, manual_host: str, certificate: str, uuid: str
) -> bool:
try:
config.add_section("hosts")
except DuplicateSectionError:
pass
# amount of hosts
try:
no_hosts = int(config.get("hosts", "size"))
except NoOptionError:
no_hosts = 0
new_host = no_hosts + 1
config.set("hosts", f"{new_host}\srvcert", convert_string_to_bytearray(certificate))
config.set("hosts", "size", str(new_host))
config.set("hosts", f"{new_host}\\uuid", uuid)
config.set("hosts", f"{new_host}\hostname", hostname)
config.set("hosts", f"{new_host}\\nvidiasv", "false")
config.set("hosts", f"{new_host}\customname", "false")
config.set("hosts", f"{new_host}\manualaddress", manual_host)
config.set("hosts", f"{new_host}\manualport", "47989")
config.set("hosts", f"{new_host}\\remoteport", "0")
config.set("hosts", f"{new_host}\\remoteaddress", "")
config.set("hosts", f"{new_host}\localaddress", "")
config.set("hosts", f"{new_host}\localport", "0")
config.set("hosts", f"{new_host}\ipv6port", "0")
config.set("hosts", f"{new_host}\ipv6address", "")
config.set(
"hosts", f"{new_host}\mac", convert_string_to_bytearray("\\xceop\\x8d\\xfc{")
)
add_app(config, "Desktop", new_host, 1, 881448767)
add_app(config, "Low Res Desktop", new_host, 2, 303580669)
add_app(config, "Steam Big Picture", new_host, 3, 1093255277)
print(config.items("hosts"))
return True
# set default apps for the host for now
# TODO: do this dynamically
def add_app(
config: ConfigParser, name: str, host_id: int, app_id: int, app_no: int
) -> None:
identifier = f"{host_id}\\apps\{app_id}\\"
config.set("hosts", f"{identifier}appcollector", "false")
config.set("hosts", f"{identifier}directlaunch", "false")
config.set("hosts", f"{identifier}hdr", "false")
config.set("hosts", f"{identifier}hidden", "false")
config.set("hosts", f"{identifier}id", f"{app_no}")
config.set("hosts", f"{identifier}name", f"{name}")
def get_moonlight_certificate() -> str:
config = load_state()
if config is None:
raise FileNotFoundError("Moonlight state file not found.")
certificate = config.get("General", "certificate")
certificate = convert_bytearray_to_string(certificate)
return certificate
def gen_pin() -> str:
return "".join(random.choice(string.digits) for _ in range(4))
def add_sunshine_host(
hostname: str, manual_host: str, certificate: str, uuid: str
) -> bool:
config = load_state()
if config is None:
return False
hostname = "test"
add_sunshine_host_to_parser(config, hostname, manual_host, certificate, uuid)
write_state(config)
return True