1
This commit is contained in:
304
backend/dvadmin3_build/server.py
Normal file
304
backend/dvadmin3_build/server.py
Normal file
@@ -0,0 +1,304 @@
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import signal
|
||||
import subprocess
|
||||
import webbrowser
|
||||
import time
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt6.QtCore import QObject, QRunnable, QThreadPool, QTimer, pyqtSignal, Qt
|
||||
from PyQt6.QtNetwork import QLocalServer
|
||||
from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QSystemTrayIcon, QMenu, QMessageBox
|
||||
from PyQt6.QtGui import QIcon, QTextCharFormat, QColor, QTextCursor
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
# # 编译ui
|
||||
# pyuic6 dvadmin_main.ui -o dvadmin_main.py
|
||||
# 由于编译问题,把dvadmin_main.py代码复制到本脚本中
|
||||
class Ui_DvadminManager(object):
|
||||
def setupUi(self, DvadminManager):
|
||||
DvadminManager.setObjectName("DvadminManager")
|
||||
DvadminManager.resize(400, 300)
|
||||
DvadminManager.setMinimumSize(QtCore.QSize(400, 300))
|
||||
DvadminManager.setMaximumSize(QtCore.QSize(400, 300))
|
||||
self.label = QtWidgets.QLabel(parent=DvadminManager)
|
||||
self.label.setGeometry(QtCore.QRect(10, 13, 60, 21))
|
||||
self.label.setObjectName("label")
|
||||
self.status_label = QtWidgets.QLabel(parent=DvadminManager)
|
||||
self.status_label.setGeometry(QtCore.QRect(80, 12, 60, 21))
|
||||
self.status_label.setObjectName("status_label")
|
||||
self.start_button = QtWidgets.QPushButton(parent=DvadminManager)
|
||||
self.start_button.setGeometry(QtCore.QRect(210, 10, 81, 26))
|
||||
self.start_button.setObjectName("start_button")
|
||||
self.stop_button = QtWidgets.QPushButton(parent=DvadminManager)
|
||||
self.stop_button.setGeometry(QtCore.QRect(310, 9, 81, 26))
|
||||
self.stop_button.setObjectName("stop_button")
|
||||
self.line = QtWidgets.QFrame(parent=DvadminManager)
|
||||
self.line.setGeometry(QtCore.QRect(0, 40, 401, 16))
|
||||
self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine)
|
||||
self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
|
||||
self.line.setObjectName("line")
|
||||
self.log_label = QtWidgets.QTextEdit(parent=DvadminManager)
|
||||
self.log_label.setGeometry(QtCore.QRect(-1, 47, 411, 261))
|
||||
self.log_label.setObjectName("log_label")
|
||||
|
||||
self.retranslateUi(DvadminManager)
|
||||
QtCore.QMetaObject.connectSlotsByName(DvadminManager)
|
||||
|
||||
def retranslateUi(self, DvadminManager):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
DvadminManager.setWindowTitle(_translate("DvadminManager", "服务管理器"))
|
||||
self.label.setText(_translate("DvadminManager", "运行状态:"))
|
||||
self.status_label.setText(_translate("DvadminManager", "未启动"))
|
||||
self.start_button.setText(_translate("DvadminManager", "启动服务"))
|
||||
self.stop_button.setText(_translate("DvadminManager", "结束服务"))
|
||||
self.log_label.setHtml(_translate("DvadminManager", ""))
|
||||
|
||||
|
||||
class SelectWorkerSignals(QObject):
|
||||
result = pyqtSignal(str)
|
||||
stop = pyqtSignal(bool)
|
||||
|
||||
|
||||
list_process = []
|
||||
|
||||
|
||||
class ServerWorkerSignals(QObject):
|
||||
result = pyqtSignal(str)
|
||||
|
||||
|
||||
class SelectWorker(QRunnable):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.signals = SelectWorkerSignals()
|
||||
self.is_run = True
|
||||
|
||||
def run(self):
|
||||
# 模拟异步操作
|
||||
import time
|
||||
import psutil
|
||||
while self.is_run:
|
||||
# 遍历进程列表,结束即关闭服务
|
||||
# 获取所有正在运行的进程列表
|
||||
processes = psutil.process_iter()
|
||||
new_list_process = []
|
||||
for process in processes:
|
||||
# 如果进程名称包含"uvicorn",则进行监控
|
||||
if process.pid in list_process:
|
||||
new_list_process.append(process.pid)
|
||||
if list_process and not new_list_process:
|
||||
self.signals.result.emit("异步,进程不存在!")
|
||||
# 等待1秒
|
||||
time.sleep(1)
|
||||
|
||||
def handle_stop_result(self, result):
|
||||
"""
|
||||
异步获取进程结果后执行
|
||||
"""
|
||||
self.is_run = result
|
||||
|
||||
|
||||
class ServerWorker(QRunnable):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.signals = ServerWorkerSignals()
|
||||
|
||||
def run(self):
|
||||
# 启动dvadmin服务
|
||||
import os
|
||||
print("启动dvadmin服务")
|
||||
# import main
|
||||
# main.run()
|
||||
# 定义要执行的命令
|
||||
command = f"./main"
|
||||
if os.sys.platform.startswith('win'):
|
||||
# Windows操作系统
|
||||
print("当前环境是Windows", Path(__file__).resolve().parent)
|
||||
print("当前环境是Windows", Path(__file__).resolve())
|
||||
command = f"{Path(__file__).resolve().parent.parent}/main.exe"
|
||||
elif os.sys.platform.startswith('linux'):
|
||||
# Linux操作系统
|
||||
print("当前环境是Linux")
|
||||
elif os.sys.platform.startswith('darwin'):
|
||||
# macOS操作系统
|
||||
print("当前环境是macOS")
|
||||
command = f"{Path(__file__).resolve().parent.parent}/MacOS/main"
|
||||
else:
|
||||
# 其他操作系统
|
||||
print("当前环境是其他操作系统")
|
||||
self.signals.result.emit(json.dumps({"code": 2001, "msg": command}))
|
||||
global list_process
|
||||
# 使用subprocess.Popen执行命令
|
||||
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
||||
self.signals.result.emit(json.dumps({"code": 2000, "msg": "服务启动成功..."}))
|
||||
# 持续获取输出结果
|
||||
pid = process.pid
|
||||
list_process.append(pid)
|
||||
for line in process.stdout:
|
||||
match = re.search(r'Started server process \[(\d+)\]', line)
|
||||
# 判断是否匹配成功
|
||||
if match:
|
||||
# 获取匹配到的数字
|
||||
number = match.group(1)
|
||||
list_process.append(number)
|
||||
list_process = list(set(list_process))
|
||||
self.signals.result.emit(json.dumps({"code": 2001, "msg": line.replace('\n', '')}))
|
||||
# 等待进程结束
|
||||
process.wait()
|
||||
|
||||
|
||||
class MainWindow(QMainWindow, Ui_DvadminManager):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setupUi(self)
|
||||
# 开始、结束按钮
|
||||
self.start_button.clicked.connect(self.start_service)
|
||||
self.stop_button.clicked.connect(self.stop_service)
|
||||
# 托盘按钮及事件
|
||||
self.tray_icon = QSystemTrayIcon(QIcon(os.path.join(Path(__file__).resolve().parent, 'static','logo.icns')), self)
|
||||
self.tray_icon.activated.connect(self.tray_icon_activated)
|
||||
self.tray_menu = QMenu(self)
|
||||
self.tray_menu.addAction(self.start_button.text(), self.start_service)
|
||||
self.tray_menu.addAction(self.stop_button.text(), self.stop_service)
|
||||
self.tray_menu.addSeparator()
|
||||
self.tray_menu.addAction("退出", QApplication.quit)
|
||||
self.tray_icon.setContextMenu(self.tray_menu)
|
||||
self.tray_icon.show()
|
||||
|
||||
self.log_label.setReadOnly(True)
|
||||
|
||||
# 信号
|
||||
self.select_worker = SelectWorker()
|
||||
self.select_worker.signals.result.connect(self.handle_select_result)
|
||||
self.select_worker.signals.stop.connect(self.select_worker.handle_stop_result)
|
||||
self.server_worker = ServerWorker()
|
||||
self.server_worker.signals.result.connect(self.handle_server_servers)
|
||||
# 异步
|
||||
self.select_threadpool = QThreadPool()
|
||||
self.server_threadpool = QThreadPool()
|
||||
|
||||
def handle_select_result(self, result):
|
||||
"""
|
||||
异步获取进程结果后执行
|
||||
"""
|
||||
self.append_to_log('服务进程异常,服务已停止...', color='red')
|
||||
global list_process
|
||||
list_process = []
|
||||
self.status_label.setText("已停止")
|
||||
self.status_label.setStyleSheet("color: red;")
|
||||
|
||||
def handle_server_servers(self, result):
|
||||
"""
|
||||
启动服务
|
||||
"""
|
||||
json_result = json.loads(result)
|
||||
if json_result.get('code') == 2000:
|
||||
self.append_to_log(json_result.get('msg'), color='green')
|
||||
# 启动成功打开浏览器
|
||||
url = "http://127.0.0.1:8000/web/"
|
||||
def open_browser_after_delay(url, delay):
|
||||
time.sleep(delay)
|
||||
webbrowser.open(url)
|
||||
|
||||
threading.Thread(target=open_browser_after_delay, args=(url, 3)).start()
|
||||
self.status_label.setText("运行中")
|
||||
self.status_label.setStyleSheet("color: green;")
|
||||
elif json_result.get('code') == 2001:
|
||||
self.append_to_log(json_result.get('msg'))
|
||||
else:
|
||||
self.append_to_log(json_result.get('msg'), color='red')
|
||||
self.status_label.setText("已停止")
|
||||
self.status_label.setStyleSheet("color: red;")
|
||||
|
||||
def append_to_log(self, message, color=None):
|
||||
"""
|
||||
添加日志颜色
|
||||
"""
|
||||
cursor = self.log_label.textCursor()
|
||||
format = QTextCharFormat()
|
||||
if color:
|
||||
if color == "green":
|
||||
format.setForeground(QColor("green"))
|
||||
elif color == "red":
|
||||
format.setForeground(QColor("red"))
|
||||
cursor.movePosition(QTextCursor.MoveOperation.End)
|
||||
cursor.insertText(message, format)
|
||||
cursor.insertBlock()
|
||||
self.log_label.setTextCursor(cursor)
|
||||
self.log_label.ensureCursorVisible()
|
||||
self.log_label.verticalScrollBar().setValue(self.log_label.verticalScrollBar().maximum())
|
||||
|
||||
def start_service(self):
|
||||
global list_process
|
||||
if not list_process:
|
||||
# 启动服务,执行启动脚本
|
||||
self.server_threadpool.clear()
|
||||
self.select_threadpool.clear()
|
||||
self.select_worker.signals.stop.emit(True)
|
||||
self.select_threadpool.startOnReservedThread(self.select_worker.run)
|
||||
self.server_threadpool.startOnReservedThread(self.server_worker.run)
|
||||
self.status_label.setText("正在启动中")
|
||||
self.status_label.setStyleSheet("color: green;")
|
||||
else:
|
||||
self.append_to_log("服务已启动...")
|
||||
|
||||
def stop_service(self):
|
||||
"""
|
||||
停止服务
|
||||
"""
|
||||
global list_process
|
||||
if list_process:
|
||||
for pid in list_process:
|
||||
try:
|
||||
os.kill(int(pid), signal.SIGTERM)
|
||||
except Exception as e:
|
||||
print('Exception', e)
|
||||
pass
|
||||
list_process = []
|
||||
self.select_worker.signals.stop.emit(False)
|
||||
self.select_threadpool.clear()
|
||||
self.server_threadpool.clear()
|
||||
self.status_label.setText("已停止")
|
||||
self.status_label.setStyleSheet("color: red;")
|
||||
self.service_running = False
|
||||
self.append_to_log("服务已停止...", color='red')
|
||||
|
||||
def tray_icon_activated(self, reason):
|
||||
"""
|
||||
托盘激活
|
||||
"""
|
||||
if reason == QSystemTrayIcon.ActivationReason.Trigger:
|
||||
self.showNormal()
|
||||
self.activateWindow()
|
||||
|
||||
def showEvent(self, event):
|
||||
# 自定义的显示事件处理
|
||||
if self.status_label.text() != '已停止':
|
||||
self.select_worker.signals.stop.emit(True)
|
||||
self.select_threadpool.startOnReservedThread(self.select_worker.run)
|
||||
return super().showEvent(event)
|
||||
|
||||
def closeEvent(self, event):
|
||||
event.ignore()
|
||||
self.hide()
|
||||
self.select_worker.signals.stop.emit(False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
server = QLocalServer()
|
||||
if server.listen('DVAServer'):
|
||||
app.setQuitOnLastWindowClosed(False)
|
||||
app.setWindowIcon(QIcon(os.path.join(Path(__file__).resolve().parent, 'static','logo.icns')))
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
||||
else:
|
||||
message_box = QMessageBox(QMessageBox.Icon.Information, 'Information', '应用程序已在运行')
|
||||
message_box.exec()
|
||||
sys.exit(0) # 如果已有实例在运行,则退出应用程序
|
||||
Reference in New Issue
Block a user