After some research I found a possible solution of how to “mimic” a desktop app with Anvil App Server (AAS). It’s crude, it is written for Windows, and only partially tested. The goal is to have a solution which would on application run:
- start up the AAS with our Anvil App
- after the AAS is up and running, open the default web browser and present the main page to the user.
When the user closes the app (i. e. closes the browser), it would be convenient if the AAS terminates.
I explored various options, and finally decided to do it in Anvil way as much as possible
The most difficult question is how to signal the AAS to close when user closes the browser, so I decided to have a control app MainApp,py, a relatively short program in Python with these responsibilities:
- it starts the AAS
- if successful, it waits for the server to be up and running (it waits for the server to respond “HTTP Server running”)
- after that, it establishes the uplink with the AAS and starts the default web browser
- listens for a signal via uplink to terminate AAS and itself.
The termination signal is implemented via uplink by @anvil.server.callable function in MainApp.py, so the AAS can terminate when it receives the command to do so from our app like
anvil.server.call('shutdown_me')
This can be hooked to an Exit/Quit button, or even better to onbeforeunload javascript event.
Here’s the code. As I said, it is prepared for Windows, and since os, signal and subprocess libraries behave differently on different platforms, this should be revised for Linux and Mac. I still have to re-check if the AAS really closes gracefully. There are a couple of print() statements if you need to test it on console.
import os
import signal
import sys
import subprocess
import webbrowser
import anvil.server
@anvil.server.callable
def shutdown_me():
global process
#print('AAS WILL TERMINATE')
os.kill(process.pid, signal.CTRL_C_EVENT)
sys.exit(0)
@anvil.server.callable
#JUST TO CHECK IF THE UPLINK WORKS
def say_hello(name):
print(f"Hello from your own machine, {name}!")
def main():
global process
app_path = 'C:\\PATH TO YOUR ANVIL APP'
process = subprocess.Popen(['anvil-app-server.exe', '--app' , app_path, '--uplink-key', '12345'], stdout=subprocess.PIPE)
while True:
output = process.stdout.readline().decode()
if output == '' and process.poll() is not None:
break
if output:
message = output.strip()
#print('{}'.format(message))
if message.find("HTTP Server running") != -1:
anvil.server.connect("12345", url="ws://localhost:3030/_/uplink")
webbrowser.open_new('http://localhost:3030')
if __name__ == '__main__':
main()