diff --git a/pyfactorybridge/__init__.py b/pyfactorybridge/__init__.py index b653d4d..7fcc594 100644 --- a/pyfactorybridge/__init__.py +++ b/pyfactorybridge/__init__.py @@ -1,5 +1,7 @@ import requests import logging +from json import dumps +from pathlib import Path from pyfactorybridge.exceptions import ServerExceptions, ServerError from pyfactorybridge.authentication import BearerAuth @@ -34,19 +36,47 @@ def __init__(self, address, password=None, token=None): else: logging.error("No password provided, some functions may not work.") - def __request(self, function, properties={}) -> dict[Any]: + def __build_request_data( + self, function: str, properties: dict | None = None + ) -> dict: request_data = {"data": {"clientCustomData": ""}, "function": function} - - for property_name, property_value in properties.items(): - request_data["data"][property_name] = property_value + if isinstance(properties, dict): + for property_name, property_value in properties.items(): + request_data["data"][property_name] = property_value + return request_data + + def __request( + self, + function: str, + properties: dict | None = None, + multiparts: dict | None = None, + ) -> dict[Any]: + request_data = self.__build_request_data(function, properties) + + http_method_kwargs = {} + if multiparts is None: + # Simple application/json request + http_method_kwargs = { + "json": request_data, + } + else: + # multipart/form-data request + if "data" not in multiparts: + multiparts["data"] = ( + # Multipart file name + None, + # Multipart content (byte-like) + dumps(request_data), + # Content-Type + "application/json", + ) + http_method_kwargs = { + "files": multiparts, + } try: response_data = requests.post( - self.URL, - verify=False, - json=request_data, - auth=self.auth if self.auth else None, - headers={"Content-Type": "application/json"}, + self.URL, verify=False, auth=self.auth, **http_method_kwargs ) if response_data.text: @@ -167,8 +197,35 @@ def load_game(self, SaveName, EnableAdvancedGameSettings) -> dict[str, str]: }, ) - def upload_save_game(self, data) -> None: - raise NotImplementedError + def upload_save_game( + self, + save_file_path: str, + SaveName: str | None = None, + LoadSaveGame: bool = False, + EnableAdvancedGameSettings: bool = False, + ) -> dict[str, str]: + with open(save_file_path, "rb") as save_file_handle: + save_file_path_obj = Path(save_file_path) + multiparts = { + "saveGameFile": ( + # Save file basename (including .sav) + save_file_path_obj.name, + # Save file content + save_file_handle.read(), + # Content-Type + "application/octet-stream", + ) + } + return self.__request( + function="UploadSaveGame", + properties={ + "SaveName": SaveName + or save_file_path_obj.stem, # Save file name without file extension + "LoadSaveGame": LoadSaveGame, + "EnableAdvancedGameSettings": EnableAdvancedGameSettings, + }, + multiparts=multiparts, + ) def download_save_game(self, SaveName) -> None: raise NotImplementedError