Skip to content

Commit

Permalink
Merge pull request #624 from usc-isi-i2/windows-service-git-action
Browse files Browse the repository at this point in the history
Windows service git action
  • Loading branch information
zmbq authored Sep 1, 2021
2 parents 842379f + 7379073 commit 2083726
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 0 deletions.
54 changes: 54 additions & 0 deletions .github/workflows/create-windows-service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Create Windows Service
on:
push:
tags:
- v*

# For Code Signing please make sure the following secrets are defined in the repository:
# WINDOWS_CERTIFICATE_BASE64 - The Windows code signing certificate, base64 encoded
# WINDOWS_CERTIFICATE_PASSWORD - The password for Windows the certificate

jobs:
windows:
name: Create the Windows Service
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
- name: Set backend environment
working-directory: backend
run: |
pip install --upgrade setuptools pip wheel
pip install t2wml-api
pip install -r requirements.txt
pip install pyinstaller pywin32 semver requests
pip uninstall -y typing typing-extensions
pip install waitress
- name: Create installer
working-directory: backend
env: # Replace unicode characters with ?
PYTHONIOENCODING: :replace
PYTHONLEGACYWINDOWSIOENCODING: true
CI: false # Otherwise React stops on warnings
CSC_KEY_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
run: |
pyinstaller --clean --noupx t2wml-service.spec
- name: Get the version
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
shell: bash
- name: Upload to Release
id: upload-release-asset
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: backend/dist/t2wml-service.exe
asset_name: t2wml-service-${{ steps.get_version.outputs.VERSION }}.exe
tag: ${{ github.ref }}
overwrite: true
body: "Windows Setup"

14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,20 @@ You can also open the Chrome Developers Tools from the GUI's `Debug` menu.
#### Backend Development
To develop the backend, you need to launch the `Backend` from the debug menu. You will be able to set breakpoints and debug properly. If you want to run the GUI, start the `Build and Watch GUI` and `t2wml GUI` tasks, as well.

### Windows service
To run the backend as a service on windows:
Download the file windows-service.exe, and run with Administrator privilges:
Install:
`t2wml-service.exe install`
Start:
`t2wml-service.exe start`
Debug:
`t2wml-service.exe debug`
Stop:
`t2wml-service.exe stop`
Uninstall:
`t2wml-service.exe remove`

## Usage with GUI
<span id="usage_with_gui"></span>

Expand Down
9 changes: 9 additions & 0 deletions backend/causx_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,15 @@ def get_mapping(preload=False):
get_layers(response, calc_params)
return response, 200


@app.route('/api/is-alive')
def is_alive1():
return 'Causx Backend is here', 200

@app.route('/api/causx/is-alive')
def is_alive2():
return 'Causx Backend is here', 200

@app.route('/api/causx/token', methods=['GET'])
def get_token():
return {"token": encode_auth_token()}, 200
Expand Down
116 changes: 116 additions & 0 deletions backend/t2wml-service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"""
# Prerequisites:
cd backend
virtualenv env-service
(activate virtual env)
pip install -r requirements.txt
pip install --upgrade pyinstaller
pip install pywin32
pip install waitress
pip install requests
pip install -e ../../t2wml-api
# Build:
pyinstaller --clean --noupx t2wml-service.spec
# With Administrator privilges
# Install:
dist\t2wml-service.exe install
# Start:
dist\t2wml-service.exe start
# Install with autostart:
dist\t2wml-service.exe --startup delayed install
# Debug:
dist\t2wml-service.exe debug
# Stop:
dist\t2wml-service.exe stop
# Uninstall:
dist\t2wml-service.exe remove
"""

import time
import ctypes
import sys
import win32serviceutil # ServiceFramework and commandline helper
import win32service # Events
import servicemanager # Simple setup and logging
import win32event
from waitress import serve
import socket
import threading

from causx_application import app
class WaitressService(threading.Thread):

def __init__(self):
threading.Thread.__init__(self)

def run(self):
print('thread start\n')
serve(app, host='localhost', port=13000, trusted_proxy='localhost')
print('thread done\n')

def get_id(self):
# returns id of the respective thread
if hasattr(self, '_thread_id'):
return self._thread_id
for id, thread in threading._active.items():
if thread is self:
return id

def exit(self):
thread_id = self.get_id()
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
thread_id, ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
print('Exception raise failure')


class MyServiceFramework(win32serviceutil.ServiceFramework):

_svc_name_ = 't2wml_backend'
_svc_display_name_ = 'T2WML Backend Service'
_svc_description_ = 'T2WML Backend Service for Causx'

def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.stopEvt = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)

def SvcStop(self):
"""Stop the service"""
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ''))
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.stopEvt)

def SvcDoRun(self):
"""Start the service; does not return until stopped"""
print('main start')
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.service_impl = WaitressService()
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
# Run the service
self.service_impl.start()

print('waiting on win32event')
win32event.WaitForSingleObject(self.stopEvt, win32event.INFINITE)
self.service_impl.exit() # raise SystemExit in inner thread
print('waiting on thread')
self.service_impl.join()
print('main done')


def init():
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(MyServiceFramework)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(MyServiceFramework)


if __name__ == '__main__':
init()
73 changes: 73 additions & 0 deletions backend/t2wml-service.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# -*- mode: python ; coding: utf-8 -*-

"""
# Prerequisites:
cd backend
virtualenv env-service
(activate virtual env)
pip install -r requirements.txt
pip install --upgrade pyinstaller
pip install pywin32
pip install waitress
pip install requests
pip install t2wml-api
# Build:
pyinstaller --clean --noupx t2wml-service.spec
# With Administrator privilges
# Install:
dist\t2wml-service.exe install
# Start:
dist\t2wml-service.exe start
# Debug:
dist\t2wml-service.exe debug
# Stop:
dist\t2wml-service.exe stop
# Uninstall:
dist\t2wml-service.exe remove
"""

import sys
from os import path, getcwd
site_packages = next(p for p in sys.path if 'site-packages' in p)

def copy_package(name):
return [(path.join(site_packages, name), name)]

block_cipher = None


a = Analysis(['t2wml-service.py'],
pathex=[getcwd()],
binaries=[],
datas=copy_package('distributed'),
hiddenimports=['win32timezone', 'pandas','pandas._libs.tslibs.base', 'rltk', 'logging.config', 'cmath'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)

pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)

exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='t2wml-service',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir='.',
console=True,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None
)
10 changes: 10 additions & 0 deletions backend/t2wml-waitress.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from waitress import serve

from causx_application import app

#def run():
# app.run(port=13000, debug=False, host=None, use_reloader=False)

serve(app, port=13000, host='localhost')

# serve(wsgiapp, host='localhost', port=13000)
46 changes: 46 additions & 0 deletions backend/t2wml-waitress.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- mode: python ; coding: utf-8 -*-
# Pyinstaller spec file.

# pip install --upgrade pyinstaller
# pyinstaller --clean --noupx .\t2wml-waitress.spec

from PyInstaller.utils.hooks import copy_metadata
import sys
from os import path, getcwd
site_packages = next(p for p in sys.path if 'site-packages' in p)

def copy_package(name):
return [(path.join(site_packages, name), name)]

block_cipher = None


a = Analysis(['t2wml-waitress.py'],
pathex=[getcwd()],
binaries=[],
datas=copy_package('distributed'),
hiddenimports=['pandas','pandas._libs.tslibs.base', 'rltk', 'logging.config', 'cmath'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)

pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='t2wml-waitress',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True )

0 comments on commit 2083726

Please sign in to comment.