-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathserver.py
executable file
·204 lines (160 loc) · 7.61 KB
/
server.py
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import threading
import os
import time
import subprocess
import eventlet
from flask import Flask, send_from_directory, render_template
from flask_socketio import SocketIO
from flask_cors import CORS
from . import settings
from .shared.shared_state import shared_state
# Flask configuration
server = Flask(__name__, template_folder=os.path.join(os.path.dirname(__file__), '..', 'frontend', 'dist'), static_folder=os.path.join(os.path.dirname(__file__), '..', 'frontend', 'dist', 'assets'), static_url_path='/assets')
server.config['SECRET_KEY'] = 'v-link'
CORS(server, resources={r"/*": {"origins": "*"}})
# Socket.io configuration
socketio = SocketIO(server, cors_allowed_origins="*", async_mode='eventlet')
# Define modules
modules = ["app", "mmi", "can", "lin", "adc", "rti"]
class ServerThread(threading.Thread):
def __init__(self):
super().__init__()
self.daemon = True # Ensure thread stops when main program exits
self.app = server
self.stop_event = threading.Event()
self.server_socket = eventlet.listen(('0.0.0.0', 4001))
def run(self):
if shared_state.verbose:
print("Starting Eventlet WSGI server...")
try:
# Run the server in a green thread
eventlet.spawn(self._serve)
# Handle ignition in a green thread
eventlet.spawn(self.monitor_ignition_state)
# Keep the thread alive until stop_event is set
while not self.stop_event.is_set():
eventlet.sleep(0.1)
except Exception as e:
print(e)
def _serve(self):
try:
eventlet.wsgi.server(
self.server_socket,
self.app,
log=open(os.devnull, "w"), # Suppress logs
)
except eventlet.StopServe:
if shared_state.verbose:
print("Server stopped gracefully.")
def stop_thread(self):
if shared_state.verbose:
print("Stopping Eventlet server...")
time.sleep(.5)
# Raise StopServe to terminate the WSGI server loop
eventlet.spawn(self.server_socket.close)
self.stop_event.set()
def monitor_ignition_state(self):
previous_ign_state = None # Variable to track the previous state of shared_state.ign
while not self.stop_event.is_set():
# Check if shared_state.ign has changed
current_ign_state = shared_state.ign_state.is_set()
# If the state has changed, send a message to the frontend
if current_ign_state != previous_ign_state:
if current_ign_state:
if shared_state.verbose:
print("Ignition ON, sending event to frontend.")
socketio.emit('ign', True, namespace='/sys')
else:
if shared_state.verbose:
print("Ignition OFF, sending event to frontend.")
socketio.emit('ign', False, namespace='/sys')
# Update the previous state to the current state
previous_ign_state = current_ign_state
eventlet.sleep(0.1) # Allow other tasks to run while checking ignition state
# Add custom headers to all responses
@server.after_request
def after_request(response):
return response
# Route to serve the index.html file
@server.route('/')
def serve_index():
return render_template('index.html')
# Route to serve static files (js, css, etc.) from the 'dist/assets' folder
@server.route('/assets/<path:filename>')
def serve_assets(filename):
response = send_from_directory(os.path.join(os.path.dirname(__file__), '..', 'frontend', 'dist', 'assets'), filename)
response.headers['Cross-Origin-Embedder-Policy'] = 'require-corp'
response.headers['Cross-Origin-Opener-Policy'] = 'same-origin'
return response
# Send notification when frontend connects via socket.io
@socketio.on('connect', namespace='/')
def handle_connect():
if (shared_state.verbose): print("Client connected")
# Create event handler
def register_socketio(module):
namespace = f'/{module}'
toggle_attr = f'toggle_{module}'
# Emit module Data
def emit_data(data):
socketio.emit('data', data, namespace=namespace)
# Save module settings
def save_settings(data):
settings.save_settings(module, data)
# Emit module settings
def load_settings():
socketio.emit('settings', settings.load_settings(module), namespace=namespace)
# Emit module status
def emit_state():
thread_state = shared_state.THREADS.get(module, None)
thread_state = thread_state.is_alive() if thread_state else False
socketio.emit('state', thread_state, namespace=namespace)
# Toggle module status
def toggle_state():
if (shared_state.verbose): print('Toggling Thread')
getattr(shared_state, toggle_attr).set()
thread_state = shared_state.THREADS.get(module, None)
thread_state = thread_state.is_alive() if thread_state else False
socketio.emit('state', not thread_state, namespace=namespace)
load_settings.__name__ = f'load_settings_{module}'
save_settings.__name__ = f'save_settings_{module}'
emit_state.__name__ = f'emit_status_{module}'
toggle_state.__name__ = f'handle_toggle_{module}'
emit_data.__name__ = f'handle_data_{module}'
socketio.on_event('load', load_settings, namespace=namespace)
socketio.on_event('save', save_settings, namespace=namespace)
socketio.on_event('ping', emit_state, namespace=namespace)
socketio.on_event('data', emit_data, namespace=namespace)
socketio.on_event('toggle', toggle_state, namespace=namespace)
# Register modules
for module in modules:
register_socketio(module)
# Handle IO tasks
@socketio.on('systemTask', namespace='/sys')
def handle_system_task(args):
if args == 'reboot':
subprocess.run("sudo reboot -h now", shell=True)
if args == 'shutdown':
subprocess.run("sudo shutdown -h now", shell=True)
elif args == 'reset':
settings.reset_settings("app")
socketio.emit("settings", settings.load_settings("app"), namespace='/app')
elif args == 'rti':
shared_state.rtiStatus = not shared_state.rtiStatus
shared_state.hdmiStatus = shared_state.rtiStatus
if (shared_state.verbose): print("hdmi status", shared_state.hdmiStatus)
if (shared_state.verbose): print("rti status", shared_state.rtiStatus)
socketio.emit('state', shared_state.rtiStatus, namespace="/rti")
shared_state.hdmi_event.set()
elif args == 'quit':
shared_state.exit_event.set()
elif args == 'restart':
shared_state.restart_event.set()
elif args == 'hdmi':
shared_state.hdmi_event.set()
elif args == 'update':
print('updating app')
shared_state.update_event.set()
elif args == 'ign':
socketio.emit('ign', shared_state.ign_state.is_set(), namespace="/sys")
else:
if (shared_state.verbose): print('Unknown action:', args)