-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlauncher.py
More file actions
138 lines (117 loc) · 3.62 KB
/
launcher.py
File metadata and controls
138 lines (117 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import os
import sys
import subprocess
import threading
import time
import webbrowser
from pystray import Icon, Menu, MenuItem
from PIL import Image
# Paths
BACKEND_CMD = ['cmd', '/c', 'cd backend && npm run dev']
FRONTEND_CMD = ['cmd', '/c', 'cd frontend && npm run dev']
ICON_PATH = os.path.join('frontend', 'public', 'undertale-sans.jpg')
BACKEND_URL = 'http://localhost:4000/'
FRONTEND_URL = 'http://localhost:5173/'
# Process handles
backend_proc = None
frontend_proc = None
def is_running(proc):
return proc is not None and proc.poll() is None
def start_backend():
global backend_proc
if not is_running(backend_proc):
backend_proc = subprocess.Popen(
BACKEND_CMD,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.CREATE_NO_WINDOW
)
def start_frontend():
global frontend_proc
if not is_running(frontend_proc):
frontend_proc = subprocess.Popen(
FRONTEND_CMD,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.CREATE_NO_WINDOW
)
def stop_backend():
global backend_proc
if is_running(backend_proc):
backend_proc.terminate()
backend_proc.wait()
backend_proc = None
else:
backend_proc = None
def stop_frontend():
global frontend_proc
if is_running(frontend_proc):
frontend_proc.terminate()
frontend_proc.wait()
frontend_proc = None
else:
frontend_proc = None
def open_frontend(icon, item=None):
webbrowser.open(FRONTEND_URL)
def open_backend(icon, item=None):
webbrowser.open(BACKEND_URL)
def update_menu(icon):
# Simple menu: frontend, backend, exit
icon.menu = Menu(
MenuItem(
"Frontend",
open_frontend,
enabled=is_running(frontend_proc)
),
MenuItem(
"Backend",
open_backend,
enabled=is_running(backend_proc)
),
MenuItem('Exit', lambda icon, item: exit_launcher(icon))
)
icon.update_menu()
def exit_launcher(icon):
stop_backend()
stop_frontend()
icon.stop()
def menu_builder(icon):
# Periodically update menu to reflect status
while icon.visible:
# Check if backend process has exited unexpectedly
global backend_proc, frontend_proc
if backend_proc and not is_running(backend_proc):
backend_proc = None
if frontend_proc and not is_running(frontend_proc):
frontend_proc = None
update_menu(icon)
time.sleep(2)
def main():
# Start both servers
start_backend()
start_frontend()
# Open frontend in browser after starting
time.sleep(2) # Give frontend a moment to start
webbrowser.open(FRONTEND_URL)
# Load icon image
if not os.path.exists(ICON_PATH):
print(f"Icon not found: {ICON_PATH}")
sys.exit(1)
image = Image.open(ICON_PATH)
# Initial menu
menu = Menu(
MenuItem(
"Frontend",
open_frontend,
enabled=is_running(frontend_proc)
),
MenuItem(
"Backend",
open_backend,
enabled=is_running(backend_proc)
),
MenuItem('Exit', lambda icon, item: exit_launcher(icon))
)
icon = Icon("ProgressDashboard", image, "Progress Dashboard", menu)
# Start menu updater thread
updater_thread = threading.Thread(target=menu_builder, args=(icon,), daemon=True)
updater_thread.start()
icon.run()
if __name__ == '__main__':
main()