add setup script to build an msi windows installer

This commit is contained in:
liamcottle
2024-05-24 01:35:30 +12:00
parent e2f62d46c4
commit d42801c135
6 changed files with 72 additions and 2 deletions

5
.gitignore vendored
View File

@@ -1 +1,6 @@
# build files
build/
dist/
# local storage
storage/ storage/

View File

@@ -115,6 +115,14 @@ python web.py --identity-base64 "GCN6mMhVemdNIK/fw97C1zvU17qjQPFTXRBotVckeGmoOwQ
> NOTE: this is a randomly generated identity for example purposes. Do not use it, it has been leaked! > NOTE: this is a randomly generated identity for example purposes. Do not use it, it has been leaked!
# Build from Source
You can build a standalone Windows Installer `.msi` with the following command;
```
python setup.py bdist_msi
```
## TODO ## TODO
- [ ] conversations/contacts list ui with unread indicators - [ ] conversations/contacts list ui with unread indicators

BIN
logo/icon.ico Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

View File

@@ -1,4 +1,5 @@
aiohttp>=3.9.5 aiohttp>=3.9.5
cx_freeze>=7.0.0
lxmf>=0.4.3 lxmf>=0.4.3
peewee>=3.17.3 peewee>=3.17.3
rns>=0.7.5 rns>=0.7.5

44
setup.py Normal file
View File

@@ -0,0 +1,44 @@
from cx_Freeze import setup, Executable
setup(
name='ReticulumWebChat',
version='1.0.0',
description='A simple open-source web based LXMF client for Reticulum.',
executables=[
Executable(
script='web.py', # this script to run
base=None, # we are running a console application, not a gui
target_name='ReticulumWebChat', # creates ReticulumWebChat.exe
shortcut_name='ReticulumWebChat', # name shown in shortcut
shortcut_dir='ProgramMenuFolder', # put the shortcut in windows start menu
icon='logo/icon.ico', # set the icon for the exe
),
],
options={
'build_exe': {
# libs that are required
'packages': [
# required for dynamic import fix
# https://github.com/marcelotduarte/cx_Freeze/discussions/2039
# https://github.com/marcelotduarte/cx_Freeze/issues/2041
'RNS',
],
# files that are required
'include_files': [
'public/', # static files served by web server
],
# slim down the build by excluding these unused libs
'excludes': [
'PIL', # saves ~200MB
],
# this has the same effect as the -O command line option when executing CPython directly.
# it also prevents assert statements from executing, removes docstrings and sets __debug__ to False.
# https://stackoverflow.com/a/57948104
"optimize": 2,
},
'build_msi': {
# use a static upgrade code to allow installer to remove existing files on upgrade
'upgrade_code': '{6c69616d-ae73-460c-88e8-399b3134134e}',
},
},
)

16
web.py
View File

@@ -3,6 +3,7 @@
import argparse import argparse
import json import json
import os import os
import sys
import time import time
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Callable, List from typing import Callable, List
@@ -21,6 +22,17 @@ from lxmf_message_fields import LxmfImageField, LxmfFileAttachmentsField, LxmfFi
from src.audio_call_manager import AudioCall, AudioCallManager from src.audio_call_manager import AudioCall, AudioCallManager
# NOTE: this is required to be able to pack our app with cxfreeze as an exe, otherwise it can't access bundled assets
# this returns a file path based on if we are running web.py directly, or if we have packed it as an exe with cxfreeze
# https://cx-freeze.readthedocs.io/en/latest/faq.html#using-data-files
def get_file_path(filename):
if getattr(sys, "frozen", False):
datadir = os.path.dirname(sys.executable)
else:
datadir = os.path.dirname(__file__)
return os.path.join(datadir, filename)
class ReticulumWebChat: class ReticulumWebChat:
def __init__(self, identity: RNS.Identity, storage_dir, reticulum_config_dir): def __init__(self, identity: RNS.Identity, storage_dir, reticulum_config_dir):
@@ -116,7 +128,7 @@ class ReticulumWebChat:
# serve index.html # serve index.html
@routes.get("/") @routes.get("/")
async def index(request): async def index(request):
return web.FileResponse(path="public/index.html") return web.FileResponse(path=get_file_path("public/index.html"))
# handle websocket clients # handle websocket clients
@routes.get("/ws") @routes.get("/ws")
@@ -562,7 +574,7 @@ class ReticulumWebChat:
# create and run web app # create and run web app
app = web.Application() app = web.Application()
app.add_routes(routes) app.add_routes(routes)
app.add_routes([web.static('/', "public")]) # serve anything in public folder app.add_routes([web.static('/', get_file_path("public/"))]) # serve anything in public folder
app.on_shutdown.append(self.shutdown) # need to force close websockets and stop reticulum now app.on_shutdown.append(self.shutdown) # need to force close websockets and stop reticulum now
app.on_startup.append(on_startup) app.on_startup.append(on_startup)
web.run_app(app, host=host, port=port) web.run_app(app, host=host, port=port)