ae.sideloading_server

sideloading server

this ae namespace portion provides a simple http server to download a file to another device in the same local network, using any web browser.

by adding this module to your android app you can distribute e.g. the APK file of your app directly to another android device to install it there - without requiring an app store or an internet connection.

The implementation is inspired by the accepted answer to https://stackoverflow.com/questions/18543640/how-would-i-create-a-python-web-server-that-downloads-a-file-on-any-get-request.

Useful debugging tools can be found at https://www.maketecheasier.com/transferring-files-using-python-http-server.

sideloading server lifecycle

The sideloading server provided by this ae namespace portion can be started by first creating an instance of the sideloading app and then call its start_server() method:

from ae.sideloading_server import server_factory

sideloading_server_app = server_factory()
sideloading_server_app.start_server()

By calling start_server() without arguments a default file mask (DEFAULT_FILE_MASK) will be used, which specifies the APK file of the main app situated in the Downloads folder of the device.

The web address that has to be entered in the web browser of the receiving device can be determined with the server_url() method:

client_url = sideloading_server_app.server_url()

While the server is running the client_progress() method is providing the progress state of any currently running sideloading task. More detailed info of the running sideloading process can be gathered by calling the fetch_log_entries() method.

to temporarily stop the sideloading server simple call the stop_server() method. On app exit additionally call the method shutdown().

Hint

The ae namespace portion kivy_sideloading is providing a package for an easy integration of this sideloading server into your kivy app.

An example usage of this sideloading server and the ae.kivy_sideloading package is integrated into the demo apps GlslTester, Lisz and ComPartY.

Module Attributes

DEFAULT_FILE_MASK

default glob file mask to sideloading file

FILE_COUNT_MISMATCH

err msg part of SideloadingServerApp.start_server()

SERVER_BIND

setting BIND to '' or None to allow connections for all local devices

SERVER_PORT

http server listening port (a port number under 1024 requires root privileges)

SOCKET_BUF_LEN

buf length for socket sends in response_to_request()

SHUTDOWN_TIMEOUT

timeout(in seconds) to shut down/stop the console app and http sideloading server

SideloadingKwargs

command/log format of sideloading requests

Functions

server_factory([task_id_func])

create server app instance.

update_handler_progress([handler, ...])

default progress update callback.

Classes

SideloadingServerApp([app_title, app_name, ...])

server service app class

SimpleHTTPRequestHandler(request, ...)

server request handler.

DEFAULT_FILE_MASK = '{downloads}/{main_app_name}*.apk'

default glob file mask to sideloading file

FILE_COUNT_MISMATCH = ' files found matching '

err msg part of SideloadingServerApp.start_server()

SERVER_BIND = ''

setting BIND to ‘’ or None to allow connections for all local devices

SERVER_PORT = 36996

http server listening port (a port number under 1024 requires root privileges)

SOCKET_BUF_LEN = 16384

buf length for socket sends in response_to_request()

SHUTDOWN_TIMEOUT = 3.9

timeout(in seconds) to shut down/stop the console app and http sideloading server

SideloadingKwargs

command/log format of sideloading requests

alias of Dict[str, Any]

server_factory(task_id_func=None)[source]

create server app instance.

Parameters:

task_id_func (Optional[Callable[[str, str, str], str]]) – callable to return an unique id for a transfer request task.

Return type:

SideloadingServerApp

Returns:

sideloading server app instance.

update_handler_progress(handler=None, transferred_bytes=-3, total_bytes=-3, **_kwargs)[source]

default progress update callback.

Parameters:
  • handler (Optional[SimpleHTTPRequestHandler]) – server request handler - containing the attributes to be updated.

  • transferred_bytes (int) – already transferred bytes or error code.

  • total_bytes (int) – total sideloading bytes.

  • _kwargs – additional/optional kwargs (e.g. client_ip).

class SimpleHTTPRequestHandler(request, client_address, server)[source]

Bases: BaseHTTPRequestHandler

server request handler.

progress_total: int = -1

total file size in bytes to be transferred

progress_transferred: int = -1

transferred bytes in this sideloading progress thread

do_GET()[source]

handler callback for a http GET command request.

log_request(code='-', size='-')[source]

overwrite to prevent console output if not in debug mode.

class SideloadingServerApp(app_title='', app_name='', app_version='', sys_env_id='', debug_level=0, multi_threading=False, suppress_stdout=False, cfg_opt_eval_vars=None, additional_cfg_files=(), cfg_opt_val_stripper=None, formatter_class=None, epilog='', **logging_params)[source]

Bases: ConsoleApp

server service app class

client_handlers: Dict[str, SimpleHTTPRequestHandler]

handler for each active client connection

file_path: str

path to the found sideloading file

load_requests: List[Dict[str, Any]]

sideloading requests and error/debug log

progress_callback(**_kwargs)

progress event callback

server_instance: Optional[ThreadingHTTPServer]

server class instance

server_thread: Optional[Thread]

server thread (main or separate thread)

client_progress(client_ip)[source]

determine sideloading progress (transferred bytes) for the client with the passed ip address.

This method can be used alternatively to the callback progress_callback.

Parameters:

client_ip (str) – client ip address.

Return type:

Tuple[int, int]

Returns:

tuple of two int values: status and file size of the sideloading file. A positive status value signifies the number of already transferred bytes. A negative value in this first int signals an error. Possibles error codes are: * -1 if sideloading task did not start yet * -2 if not exists or sideloading task has already finished * -3 if the default Please note that the file size given in the second int can be 0 if an error has occurred or if the sideloading task is not yet fully created/started.

static id_of_task(action, object_type, object_key)[source]

compile the id of the sideloading request task.

Parameters:
  • action (str) – action or log level string.

  • object_type (str) – task object type (currently only ‘log’ is implemented/supported).

  • object_key (str) – task key (for log entries the timestamp of the log entry is used).

Return type:

str

Returns:

unique key identifying the task/log-entry.

log(log_level, message)[source]

print log message and optionally add it to the requests (to be read by controller app).

Parameters:
  • log_level (str) – ‘print’ always prints, ‘debug’ prints if self.debug is True and ‘verbose’ prints a message to the log if self.verbose is True.

  • message (str) – message to print.

fetch_log_entries()[source]

collect last log entries, return them and remove them from this app instance.

Return type:

Dict[str, Dict[str, Any]]

Returns:

Dict[request_tasks_id, sideloading_request_kwargs] with fetched requests log entries.

response_to_request(handler)[source]

process request to this server and return response string.

Note

this method may run in a separate thread (created by the server to process this request).

Parameters:

handler (SimpleHTTPRequestHandler) – stream request handler instance.

server_url()[source]

determine an url string to put into the address field of any browser to start sideloading.

Return type:

str

Returns:

server url string.

shutdown(exit_code=0, timeout=None)[source]

overwritten to stop any running sideloading server instance/threads on shutdown of this app instance.

Parameters:
start_server(file_mask='', threaded=False, progress=<function update_handler_progress>)[source]

start http file sideloading server to run until stop_server() get called.

Parameters:
  • file_mask (str) – optional glob.glob file mask to specify the sideloading file. If not passed then the DEFAULT_FILE_MASK will be used which specifies an APK file of the main app situated in the Downloads folder of the device. The sideloading server will only be started if the file mask matches exactly one file. The file path of the matched file can be accessed via the file_path attribute.

  • threaded (bool) – optionally pass True to use separate thread to run the server instance.

  • progress (Callable) – optional callback executed for each transferred/side-loaded chunk. If not specified then the default callback method update_handler_progress() will be called to update the progress attributes of the request handler, which can be polled via the client_progress() method.

Return type:

str

Returns:

empty string/”” if server instance/thread got started else the error message string.

Note

if threaded is True then the progress callback get executed in its own thread.

stop_server()[source]

stop/pause sideloading server - callable also if not running to reset/prepare this app instance.