Skip to content

Commit

Permalink
windows - multi-Instance support
Browse files Browse the repository at this point in the history
  • Loading branch information
slatinsky committed Feb 12, 2023
1 parent d19a553 commit 15f5ecd
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 34 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ __pycache__
/backend/windows-runner/dist/
logs.txt
dcef.exe
/backend/windows-runner/dcef.spec

# nginx
/backend/nginx/logs
Expand Down
3 changes: 2 additions & 1 deletion backend/windows-runner/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pywebview==4.0.1
pywebview==4.0.1
pywin32==305
116 changes: 83 additions & 33 deletions backend/windows-runner/windows-runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,39 @@
import atexit
import threading

# https://stackoverflow.com/a/65501621
from win32event import CreateMutex
from win32api import CloseHandle, GetLastError
from winerror import ERROR_ALREADY_EXISTS
class SingleInstance:
""" Limits application to single instance """

def __init__(self):
self.mutexname = "dcef-qwertyuiopasdfghjklzxcvbnm1234567890"
self.mutex = CreateMutex(None, False, self.mutexname)
self.lasterror = GetLastError()

def is_secondary_instance(self):
return (self.lasterror == ERROR_ALREADY_EXISTS)

def is_primary_instance(self):
return not self.is_secondary_instance()

def __del__(self):
if self.mutex:
CloseHandle(self.mutex)




def is_compiled():
if os.path.exists(__file__):
return False
else:
return True
if os.path.exists(__file__):
return False
else:
return True

is_compiled = is_compiled()
processes = []
terminating_now = False

if is_compiled:
BASE_DIR = os.path.realpath(os.path.dirname(sys.executable))
else:
BASE_DIR = os.path.realpath(os.path.dirname(__file__) + '/../../release')

LOG_FILE = BASE_DIR + '/dcef/logs.txt'
if os.path.exists(LOG_FILE):
os.remove(LOG_FILE)

def custom_print(source, *args, **kwargs):

Expand All @@ -46,6 +60,12 @@ def cleanup():
global terminating_now
if not terminating_now: # Prevents cleanup from being called twice
terminating_now = True

# kill other instances of dcef.exe except this one
if is_compiled() and myapp.is_primary_instance():
custom_print("windows-runner:", "killing other instances of dcef.exe except primary with PID " + str(os.getpid()))
os.system('taskkill /f /im dcef.exe /fi "PID ne ' + str(os.getpid()) + '"')

custom_print("windows-runner:", "cleaning up")
for process in processes:
custom_print("windows-runner:", "killing process", process.pid)
Expand All @@ -55,9 +75,13 @@ def cleanup():
custom_print("windows-runner:", "error killing process", process.pid, e)



def create_window():
custom_print("windows-runner:", "creating window")
window = webview.create_window('DiscordChatExported-frontend','http://127.0.0.1:21011/',
title = 'DiscordChatExported-frontend'
if myapp.is_secondary_instance():
title += ' (secondary instance)'
window = webview.create_window(title, 'http://127.0.0.1:21011/',
width=1280,
height=720,
background_color='#36393F',
Expand Down Expand Up @@ -128,13 +152,13 @@ def start_nginx():

def hide_console():
# https://github.com/pyinstaller/pyinstaller/issues/1339#issuecomment-122909830
if is_compiled:
if is_compiled():
whnd = ctypes.windll.kernel32.GetConsoleWindow()
if whnd != 0:
ctypes.windll.user32.ShowWindow(whnd, 0)

def show_console():
if is_compiled:
if is_compiled():
whnd = ctypes.windll.kernel32.GetConsoleWindow()
if whnd != 0:
ctypes.windll.user32.ShowWindow(whnd, 1)
Expand All @@ -143,23 +167,49 @@ def show_console():


def main():
custom_print("windows-runner:", "started")
atexit.register(cleanup)
th_nginx = start_nginx()
time.sleep(1)
th_mongodb = start_mongodb()
th_http_server = start_http_server()
th_fastapi = start_fastapi()
th_preprocess = start_preprocess()


th_preprocess.join() # Wait for preprocess to finish
hide_console()
create_window()
show_console()
custom_print("windows-runner:", "finished")
cleanup()
if myapp.is_secondary_instance():
# second instance just needs to open another window, the backend services are already running
custom_print("windows-runner:", "started secondary instance")
hide_console()
create_window()
show_console()
custom_print("windows-runner:", "finished secondary instance")

else:
if os.path.exists(LOG_FILE):
os.remove(LOG_FILE)

custom_print("windows-runner:", "started primary instance")
atexit.register(cleanup)
th_nginx = start_nginx()
time.sleep(1)
th_mongodb = start_mongodb()
th_http_server = start_http_server()
th_fastapi = start_fastapi()
th_preprocess = start_preprocess()


th_preprocess.join() # Wait for preprocess to finish

hide_console()
create_window()
show_console()

custom_print("windows-runner:", "finished primary instance")
cleanup()



myapp = SingleInstance()
processes = []
terminating_now = False

if is_compiled():
BASE_DIR = os.path.realpath(os.path.dirname(sys.executable))
else:
BASE_DIR = os.path.realpath(os.path.dirname(__file__) + '/../../release')

LOG_FILE = BASE_DIR + '/dcef/logs.txt'

if __name__ == '__main__':
main()

0 comments on commit 15f5ecd

Please sign in to comment.