Skip to content

Commit

Permalink
Manifest generation / remote version checking
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexeh committed Nov 27, 2023
1 parent 283cf44 commit efabe5d
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 72 deletions.
25 changes: 7 additions & 18 deletions joystick_diagrams/classes/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,13 @@ class InputTypes(Enum):
BUTTON = auto()
AXIS = auto()

@staticmethod
def validate(identifier):
return "baaa"


class Input:
# Rework input
# Better naming of the entities
# Change input to non conflciting class

def __init__(self, identifier: str, style: InputTypes, command: Command, modifiers: list[Modifier] = []) -> None:
style.validate(identifier)
self.identifier = identifier
self.style = style
self.command = command
Expand Down Expand Up @@ -107,9 +102,7 @@ def add_modifier_to_input(self, input_id, modifier: set, command: Command) -> No
obj = self._get_input(input_id)
_logger.debug(f"Modifier input is: {obj}")
if obj is None:
self.create_input(input_id, InputTypes.BUTTON, "Not Used")
obj = self._get_input(input_id)
_logger.debug(f"Modifier input created now: {obj}")
_logger.warning(f"Modifier added to {input_id} but input does not exist")
else:
obj.add_modifier(modifier, command)

Expand All @@ -132,13 +125,12 @@ def clear_devices():
_devices.clear()


def get_devices(guid=None) -> dict[str:LogicalDevice]:
"""Returns a dictionary of all devices"""
return _get_device(guid) if guid else _devices
def get_device(guid: str) -> LogicalDevice:
return _devices[guid]


def _get_device(guid: str) -> LogicalDevice:
return _devices[guid]
def get_all_devices() -> dict[str, LogicalDevice]:
return _devices


def add_device(guid: str, name: str) -> LogicalDevice:
Expand All @@ -151,14 +143,11 @@ def add_device(guid: str, name: str) -> LogicalDevice:


def add_input_modifier(guid: str, input_id: str, modifier: set, command: Command) -> None:
try:
_get_device(guid).add_modifier_to_input(input_id, modifier, command)
except:
pass
get_device(guid).add_modifier_to_input(input_id, modifier, command)


def add_inputs(guid: str, **kwargs) -> None:
_devices[guid].create_input(**kwargs)


_devices = {}
_devices: dict[str, LogicalDevice] = {}
119 changes: 119 additions & 0 deletions joystick_diagrams/classes/version/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
"""
Versioning for Joystick Diagrams
Author: Robert Cox
"""
from dataclasses import dataclass
import logging
from pathlib import Path
from hashlib import sha256
import json
from typing import Any
import os
import requests

_LOGGER = logging.getLogger(__name__)

VERSION = "1.6"
VERSION_SERVER = "https://www.joystick-diagrams.com/"
TEMPLATE_DIR = "./templates"
MANIFEST_DIR = "./"
MANIFEST_FILE = "version_manifest.json"
ENCODING = "UTF8"


@dataclass
class JoystickDiagramVersion:
version: str
template_hashes: dict


class VersionEncode(json.JSONEncoder):
def default(self, o: JoystickDiagramVersion) -> Any:
return {"version": o.version, "template_hashes": o.template_hashes}


def fetch_remote_manifest() -> str | None:
try:
return requests.get(VERSION_SERVER + MANIFEST_FILE, timeout=3).text
except requests.Timeout as timeout:
_LOGGER.error(f"Unable to reach server for version check: {timeout}")
return None


def fetch_local_manifest() -> str | None:
try:
return open(os.path.join(MANIFEST_DIR, MANIFEST_FILE), "r", encoding=ENCODING).read()
except OSError as error:
_LOGGER.error(f"Unable to find local manifest. {error}")
return None


def performn_version_check() -> bool:
"""Checks the local version against the latest release"""
# GET REMOTE JSON
remote_manifest = fetch_remote_manifest()
local_manifest = fetch_local_manifest()

if not remote_manifest or not local_manifest:
_LOGGER.error("Unable to perform version check")
return True

running_version = __convert_json_to_object(local_manifest)
latest_version = __convert_json_to_object(remote_manifest)

# Check Versions
version_match = compare_versions(latest_version=latest_version, running_version=running_version)

return version_match


def __convert_json_to_object(payload: str) -> JoystickDiagramVersion:
json_dictionary = json.loads(payload)

try:
return JoystickDiagramVersion(**json_dictionary)
except TypeError as e:
_LOGGER.error(e)
raise


def generate_version(version_number: str = VERSION) -> JoystickDiagramVersion:
"""Generate a manifest for package and remote"""
manifest = generate_template_manifest()
ver = JoystickDiagramVersion(version=version_number, template_hashes=manifest)

dump = json.dumps(ver, cls=VersionEncode)

with open(os.path.join(MANIFEST_DIR, MANIFEST_FILE), "w", encoding=ENCODING) as output_file:
output_file.write(dump)

return ver


def generate_template_manifest() -> dict[str, str]:
templates = Path(TEMPLATE_DIR)
manifest: dict[str, str] = {}

# Generate Template Manifest
for template in templates.iterdir():
if template.is_dir():
continue
if template.suffix != ".svg":
continue
with open(template, "rb", buffering=0) as file:
manifest[template.name] = sha256(file.read()).hexdigest()

return manifest


def compare_versions(running_version: JoystickDiagramVersion, latest_version: JoystickDiagramVersion) -> bool:
return running_version.version == latest_version.version


def get_current_version() -> str:
return VERSION


if __name__ == "__main__":
performn_version_check()
46 changes: 0 additions & 46 deletions joystick_diagrams/version.py

This file was deleted.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ python = "^3.11"
PyQt5 = "^5.15.8"
PyQt5-Qt5 = "5.15.2"
ply = "^3.11"
requests = "^2.31.0"

[tool.poetry.dev-dependencies]
pytest = "^7.2.0"
Expand Down
17 changes: 9 additions & 8 deletions tests/input/test_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
Command,
add_inputs,
add_input_modifier,
get_devices,
clear_devices,
get_all_devices,
get_device,
)

LOGGER = logging.getLogger(__name__)
Expand All @@ -26,22 +27,22 @@ def test_add_device():
guid = "test_guid"
name = "test_name"
add_device(guid, name)
devices = get_devices()
devices = get_all_devices()
assert len(devices), 1
assert devices[guid].guid, guid
assert devices[guid].name, name


def test_check_devices_registered():
devices = get_devices()
devices = get_all_devices()
assert "dev-1" in devices
assert "dev-2" in devices


def test_clear_devices():
assert len(get_devices()) > 0
assert len(get_all_devices()) > 0
clear_devices()
assert len(get_devices()) == 0
assert len(get_all_devices()) == 0


def test_check_devices_duplication_name(caplog):
Expand Down Expand Up @@ -78,7 +79,7 @@ def test_add_multiple_inputs_with_modifiers():
add_input_modifier(guid, input_data["id"], modifier_data["input"], modifier_data["command"])

# Retrieve the inputs from the device
device_inputs = get_devices(guid).get_device_inputs()
device_inputs = get_device(guid).get_device_inputs()

# Check that the correct number of inputs were added
assert len(device_inputs), len(inputs)
Expand Down Expand Up @@ -117,7 +118,7 @@ def test_add_modify_existing_modifier():
add_input_modifier(guid, input_data["id"], modifier_data["input"], modifier_data["command"])

# Retrieve the inputs from the device
device_inputs = get_devices(guid).get_device_inputs()
device_inputs = get_device(guid).get_device_inputs()

# Check that each input has the correct properties
for input_data in inputs:
Expand All @@ -133,6 +134,6 @@ def test_add_modify_existing_modifier():
assert modifier.command.name, modifier_data["command"].name

# Change a modifier
device = get_devices(guid)
device = get_device(guid)
add_input_modifier(guid, "input1", {"modifier1"}, "potato")
assert device.inputs[0].modifiers[0].command == "potato"
1 change: 1 addition & 0 deletions version_manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version": "1.6", "template_hashes": {"CH Fighterstick USB.svg": "ecb58ae3850233772d06a97deb09a33585a6311526fd608204a202e9e06a03a4", "CH Pro Throttle USB.svg": "a85b52eb622d5c28c15364ae4882ce8e589364154a486aea94d53c52770ae917", "HOTAS Warthog Joystick.svg": "87a7b91fa093a48533e490096ab34dd441d04bc73aa12a797f057f1fce9d4672", "HOTAS Warthog Throttle.svg": "ec06478e328471c3dd1081ddb9722d15b06f3c7581d4a43ee5b302de108e4f84", "T.16000M Joystick Left.svg": "9fa8059b9cbecc96033522a3e3307590bb425a6f74b2218ad3bc9aacd764b313", "T.16000M Joystick.svg": "0a893b46544d15253838402cb88d91a3513e793cd2ec742e572291b551ae1951", "TotalControls_Device_1.svg": "4493b84ec00e9a3c3d5ed5bb2252ff3d1c0f43062628074c64afb7c61f1f2ea4", "TotalControls_Device_2.svg": "75273c53282b7aeddbdcc604d63a4162fb8484dcbfdda60ac06ad89a28601d2a", "TWCS Throttle.svg": "128e972df307a9a3236253ecd1299925d1faf569c74cc5f1de3304d162b8ba88", "VKB-Sim Gladiator NXT L.svg": "11f07941223e5349015874f89308b0c0cdba93667dec6cf83ee2f0b8cfc676ed", "VKB-Sim Gladiator NXT R.svg": "5a435f2a9d4b2b021c968771e4a1fb44274ebbcc9b56b5e2ca847a72ee49e526", "VPC Constellation ALPHA R.svg": "ad9cdec0ac1b6acda10913ace837e05a7732a46c10d684baafd04a634bba5cba", "VPC Control Panel #1.svg": "6926094d565b60b4e2e9df7a6957d32e5df41854933f9bb5ae2254ad4737d48f", "VPC Stick MT-50CM.svg": "0602a7b529a194545c45881d98ae3feec21f9084ffbe1aee57d650c77a40212e", "VPC Stick VFX.svg": "33e343e77d4ce72e641343def9c8ee3710ab960bc79d0cdf894decb0cfc494ab", "VPC Stick WarBRD.svg": "c16aac95e6140284ca84ef6637c075befa9aadafb1bd034edb1b7f440f779da8", "VPC Throttle MT-50 CM2.svg": "6445aa8a920890674d8ab9dc0367277afcbb93e9f2b2bb7b31118390c45d6149", "X52_H.O.T.A.S..svg": "a8f9b5efd10942e0cd8354bf0c3b085fdf8532c11b691021906513df305bb4d6", "X56 H.O.T.A.S. Stick.svg": "6a1398ffbd02b51396286967fb8c8ddb795fbb2e9600060214b72af2d2ef6eb5", "X56 H.O.T.A.S. Throttle.svg": "b0d43840a9d8392d4ddb6f7cb1d80c7a4a83a3e3d0d2848d8c4aab7c68ccd70c"}}

0 comments on commit efabe5d

Please sign in to comment.