mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-04 22:43:17 +08:00
latest bacloud cleanup
This commit is contained in:
parent
7abe4d8673
commit
1f7f5e49f5
3
.idea/dictionaries/ericf.xml
generated
3
.idea/dictionaries/ericf.xml
generated
@ -459,6 +459,7 @@
|
|||||||
<w>dynload</w>
|
<w>dynload</w>
|
||||||
<w>eachother</w>
|
<w>eachother</w>
|
||||||
<w>easteregghunt</w>
|
<w>easteregghunt</w>
|
||||||
|
<w>edcc</w>
|
||||||
<w>editcontroller</w>
|
<w>editcontroller</w>
|
||||||
<w>editgame</w>
|
<w>editgame</w>
|
||||||
<w>editorconfig</w>
|
<w>editorconfig</w>
|
||||||
@ -481,6 +482,7 @@
|
|||||||
<w>encerr</w>
|
<w>encerr</w>
|
||||||
<w>endcall</w>
|
<w>endcall</w>
|
||||||
<w>endindex</w>
|
<w>endindex</w>
|
||||||
|
<w>endmessage</w>
|
||||||
<w>endparen</w>
|
<w>endparen</w>
|
||||||
<w>endtime</w>
|
<w>endtime</w>
|
||||||
<w>ensurepip</w>
|
<w>ensurepip</w>
|
||||||
@ -1171,6 +1173,7 @@
|
|||||||
<w>passwd</w>
|
<w>passwd</w>
|
||||||
<w>patcomp</w>
|
<w>patcomp</w>
|
||||||
<w>pathlib</w>
|
<w>pathlib</w>
|
||||||
|
<w>pathnames</w>
|
||||||
<w>pathstonames</w>
|
<w>pathstonames</w>
|
||||||
<w>patsubst</w>
|
<w>patsubst</w>
|
||||||
<w>pausable</w>
|
<w>pausable</w>
|
||||||
|
|||||||
@ -69,27 +69,37 @@ class Response:
|
|||||||
"""Response sent from the bacloud server to the client.
|
"""Response sent from the bacloud server to the client.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
message: If present, client should print this message.
|
message: If present, client should print this message before any other
|
||||||
|
response processing (including error handling) occurs.
|
||||||
error: If present, client should abort with this error message.
|
error: If present, client should abort with this error message.
|
||||||
loadpackage: If present, client should load this package from a
|
loadpackage: If present, client should load this package from a
|
||||||
location on disk (arg1) and push its manifest to a server command
|
location on disk (arg1) and push its manifest to a server command
|
||||||
(arg2) with provided args (arg3). The manifest should be added to
|
(arg2) with provided args (arg3). The manifest should be added to
|
||||||
the args as 'manifest'. arg4 is the index file name whose
|
the args as 'manifest'. arg4, if present, is the index file name whose
|
||||||
contents should be included with the manifest.
|
contents should be included with the manifest.
|
||||||
upload: If present, client should upload the requested files (arg1)
|
uploads: If present, client should upload the requested files (arg1)
|
||||||
from the loaded package to a server command (arg2) with provided
|
from the loaded package to a server command (arg2) with provided
|
||||||
args (arg3). Arg4 and arg5 are a server call and args which should
|
args (arg3). Arg4 and arg5 are a server call and args which should
|
||||||
be called once all file uploads finish.
|
be called once all file uploads finish.
|
||||||
login: If present, a token that should be stored client-side and passed
|
login: If present, a token that should be stored client-side and passed
|
||||||
with subsequent commands.
|
with subsequent commands.
|
||||||
logout: If True, any existing client-side token should be discarded.
|
logout: If True, any existing client-side token should be discarded.
|
||||||
|
inline_downloads: If present, pathnames mapped to base64 gzipped data to
|
||||||
|
be written to the client. This should only be used for relatively
|
||||||
|
small files as they are all included inline as part of the response.
|
||||||
|
deletes: If present, file paths that should be deleted on the client.
|
||||||
|
endmessage: If present, a message that should be printed after all other
|
||||||
|
response processing is done.
|
||||||
"""
|
"""
|
||||||
message: Optional[str] = None
|
message: Optional[str] = None
|
||||||
error: Optional[str] = None
|
error: Optional[str] = None
|
||||||
loadpackage: Optional[Tuple[str, str, Dict, str]] = None
|
loadpackage: Optional[Tuple[str, str, Dict, Optional[str]]] = None
|
||||||
upload: Optional[Tuple[List[str], str, Dict, str, Dict]] = None
|
uploads: Optional[Tuple[List[str], str, Dict, str, Dict]] = None
|
||||||
login: Optional[str] = None
|
login: Optional[str] = None
|
||||||
logout: bool = False
|
logout: bool = False
|
||||||
|
inline_downloads: Optional[Dict[str, str]] = None
|
||||||
|
deletes: Optional[List[str]] = None
|
||||||
|
endmessage: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class CleanError(Exception):
|
class CleanError(Exception):
|
||||||
@ -165,7 +175,7 @@ class App:
|
|||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._state = StateData()
|
self._state = StateData()
|
||||||
self._package: Optional[Package] = None
|
# self._package: Optional[Package] = None
|
||||||
self._project_root: Optional[Path] = None
|
self._project_root: Optional[Path] = None
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
@ -243,16 +253,16 @@ class App:
|
|||||||
output = json.loads(response_raw_2.content.decode())
|
output = json.loads(response_raw_2.content.decode())
|
||||||
|
|
||||||
# Create a default Response and fill in only attrs we're aware of.
|
# Create a default Response and fill in only attrs we're aware of.
|
||||||
# (server may send attrs unknown to older clients)
|
# (newer server may send us attrs we're unaware of)
|
||||||
response = Response()
|
response = Response()
|
||||||
for key, val in output.items():
|
for key, val in output.items():
|
||||||
if hasattr(response, key):
|
if hasattr(response, key):
|
||||||
setattr(response, key, val)
|
setattr(response, key, val)
|
||||||
|
|
||||||
# Handle common responses (can move these out of here at some point)
|
# Handle a few things inline.
|
||||||
|
# (so this functionality is available even to recursive commands, etc.)
|
||||||
if response.message is not None:
|
if response.message is not None:
|
||||||
print(response.message)
|
print(response.message, flush=True)
|
||||||
|
|
||||||
if response.error is not None:
|
if response.error is not None:
|
||||||
raise CleanError(response.error)
|
raise CleanError(response.error)
|
||||||
@ -261,9 +271,10 @@ class App:
|
|||||||
|
|
||||||
def _upload_file(self, filename: str, call: str, args: Dict) -> None:
|
def _upload_file(self, filename: str, call: str, args: Dict) -> None:
|
||||||
print(f'{CLRBLU}Uploading {filename}{CLREND}', flush=True)
|
print(f'{CLRBLU}Uploading {filename}{CLREND}', flush=True)
|
||||||
assert self._package is not None
|
# assert self._package is not None
|
||||||
with tempfile.TemporaryDirectory() as tempdir:
|
with tempfile.TemporaryDirectory() as tempdir:
|
||||||
srcpath = Path(self._package.path, filename)
|
# srcpath = Path(self._package.path, filename)
|
||||||
|
srcpath = Path(filename)
|
||||||
gzpath = Path(tempdir, 'file.gz')
|
gzpath = Path(tempdir, 'file.gz')
|
||||||
subprocess.run(f'gzip --stdout "{srcpath}" > "{gzpath}"',
|
subprocess.run(f'gzip --stdout "{srcpath}" > "{gzpath}"',
|
||||||
shell=True,
|
shell=True,
|
||||||
@ -284,30 +295,31 @@ class App:
|
|||||||
assert isinstance(packagepath, str)
|
assert isinstance(packagepath, str)
|
||||||
assert isinstance(callname, str)
|
assert isinstance(callname, str)
|
||||||
assert isinstance(callargs, dict)
|
assert isinstance(callargs, dict)
|
||||||
assert isinstance(indexfile, str)
|
assert indexfile is None or isinstance(indexfile, str)
|
||||||
self._package = Package.load_from_disk(Path(packagepath))
|
package = Package.load_from_disk(Path(packagepath))
|
||||||
|
|
||||||
# Make the remote call they gave us with the package
|
# Make the remote call they gave us with the package
|
||||||
# manifest added in.
|
# manifest added in.
|
||||||
with Path(self._package.path, indexfile).open() as infile:
|
if indexfile is not None:
|
||||||
index = infile.read()
|
with Path(package.path, indexfile).open() as infile:
|
||||||
|
index = infile.read()
|
||||||
|
else:
|
||||||
|
index = ''
|
||||||
callargs['manifest'] = {
|
callargs['manifest'] = {
|
||||||
'index': index,
|
'index': index,
|
||||||
'files': {
|
'files': {key: asdict(val)
|
||||||
key: asdict(val)
|
for key, val in package.files.items()}
|
||||||
for key, val in self._package.files.items()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return callname, callargs
|
return callname, callargs
|
||||||
|
|
||||||
def _handle_upload_response(
|
def _handle_uploads(self,
|
||||||
self, response: Response) -> Optional[Tuple[str, Dict]]:
|
response: Response) -> Optional[Tuple[str, Dict]]:
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
assert response.upload is not None
|
assert response.uploads is not None
|
||||||
assert self._package is not None
|
# assert self._package is not None
|
||||||
assert len(response.upload) == 5
|
assert len(response.uploads) == 5
|
||||||
(filenames, uploadcmd, uploadargs, completecmd,
|
(filenames, uploadcmd, uploadargs, completecmd,
|
||||||
completeargs) = response.upload
|
completeargs) = response.uploads
|
||||||
assert isinstance(filenames, list)
|
assert isinstance(filenames, list)
|
||||||
assert isinstance(uploadcmd, str)
|
assert isinstance(uploadcmd, str)
|
||||||
assert isinstance(uploadargs, dict)
|
assert isinstance(uploadargs, dict)
|
||||||
@ -328,6 +340,23 @@ class App:
|
|||||||
# Lastly, run the 'upload complete' command we were passed.
|
# Lastly, run the 'upload complete' command we were passed.
|
||||||
return completecmd, completeargs
|
return completecmd, completeargs
|
||||||
|
|
||||||
|
def _handle_inline_downloads(self, response: Response) -> None:
|
||||||
|
"""Handle inline file data to be saved to the client."""
|
||||||
|
import base64
|
||||||
|
import zlib
|
||||||
|
assert response.inline_downloads is not None
|
||||||
|
for fname, fdata in response.inline_downloads.items():
|
||||||
|
data_zipped = base64.b64decode(fdata)
|
||||||
|
data = zlib.decompress(data_zipped)
|
||||||
|
with open(fname, 'wb') as outfile:
|
||||||
|
outfile.write(data)
|
||||||
|
|
||||||
|
def _handle_deletes(self, response: Response) -> None:
|
||||||
|
"""Handle file deletes."""
|
||||||
|
assert response.deletes is not None
|
||||||
|
for fname in response.deletes:
|
||||||
|
os.unlink(fname)
|
||||||
|
|
||||||
def run_user_command(self, args: List[str]) -> None:
|
def run_user_command(self, args: List[str]) -> None:
|
||||||
"""Run a single user command to completion."""
|
"""Run a single user command to completion."""
|
||||||
|
|
||||||
@ -339,12 +368,20 @@ class App:
|
|||||||
nextcall = None
|
nextcall = None
|
||||||
if response.loadpackage is not None:
|
if response.loadpackage is not None:
|
||||||
nextcall = self._handle_loadpackage_response(response)
|
nextcall = self._handle_loadpackage_response(response)
|
||||||
if response.upload is not None:
|
if response.uploads is not None:
|
||||||
nextcall = self._handle_upload_response(response)
|
nextcall = self._handle_uploads(response)
|
||||||
if response.login is not None:
|
if response.login is not None:
|
||||||
self._state.login_token = response.login
|
self._state.login_token = response.login
|
||||||
if response.logout:
|
if response.logout:
|
||||||
self._state.login_token = None
|
self._state.login_token = None
|
||||||
|
if response.inline_downloads:
|
||||||
|
self._handle_inline_downloads(response)
|
||||||
|
if response.deletes:
|
||||||
|
self._handle_deletes(response)
|
||||||
|
|
||||||
|
# This should always be printed last.
|
||||||
|
if response.endmessage is not None:
|
||||||
|
print(response.endmessage, flush=True)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user