From d42801c13574dfc9a3f3f7d4db2af43a4bd83f78 Mon Sep 17 00:00:00 2001 From: liamcottle Date: Fri, 24 May 2024 01:35:30 +1200 Subject: [PATCH] add setup script to build an msi windows installer --- .gitignore | 5 +++++ README.md | 8 ++++++++ logo/icon.ico | Bin 0 -> 129792 bytes requirements.txt | 1 + setup.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ web.py | 16 ++++++++++++++-- 6 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 logo/icon.ico create mode 100644 setup.py diff --git a/.gitignore b/.gitignore index 34ff768..39d321f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ +# build files +build/ +dist/ + +# local storage storage/ diff --git a/README.md b/README.md index ad1301c..6a9cfda 100644 --- a/README.md +++ b/README.md @@ -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! +# Build from Source + +You can build a standalone Windows Installer `.msi` with the following command; + +``` +python setup.py bdist_msi +``` + ## TODO - [ ] conversations/contacts list ui with unread indicators diff --git a/logo/icon.ico b/logo/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f00e77e71edee84185418ac8d4c5d45098e9e694 GIT binary patch literal 129792 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

j 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.9.5 +cx_freeze>=7.0.0 lxmf>=0.4.3 peewee>=3.17.3 rns>=0.7.5 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..01ca47f --- /dev/null +++ b/setup.py @@ -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}', + }, + }, +) diff --git a/web.py b/web.py index dcbc34f..23fb349 100644 --- a/web.py +++ b/web.py @@ -3,6 +3,7 @@ import argparse import json import os +import sys import time from datetime import datetime, timezone 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 +# 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: def __init__(self, identity: RNS.Identity, storage_dir, reticulum_config_dir): @@ -116,7 +128,7 @@ class ReticulumWebChat: # serve index.html @routes.get("/") async def index(request): - return web.FileResponse(path="public/index.html") + return web.FileResponse(path=get_file_path("public/index.html")) # handle websocket clients @routes.get("/ws") @@ -562,7 +574,7 @@ class ReticulumWebChat: # create and run web app app = web.Application() 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_startup.append(on_startup) web.run_app(app, host=host, port=port)