完成了基本功能。
This commit is contained in:
parent
d616f686e3
commit
4528e81211
|
|
@ -1,5 +1,6 @@
|
||||||
cd src
|
cd src
|
||||||
pyinstaller --onefile --add-data "install/Common.py:install" .\install\InstallMariaDB.py
|
pyinstaller --onefile --add-data "install/Common.py:install" .\install\InstallMariaDB.py
|
||||||
pyinstaller --onefile --add-data "install/Common.py:install" --add-data "datas/nssm.exe:datas" --add-data "datas/electromagnetic.jar:datas" --add-data "datas/init.sql:datas" .\install\InstallOrUpgradeComacDB.py
|
pyinstaller --onefile --add-data "install/Common.py:install" --add-data "datas/electromagnetic.jar:datas" --add-data "datas/init.sql:datas" --hidden-import win32timezone .\install\InstallOrUpgradeComacDB.py
|
||||||
pyinstaller --onefile .\install\Uninstall.py
|
pyinstaller --onefile .\install\Uninstall.py
|
||||||
pyinstaller --onefile .\install\SetFile.py
|
pyinstaller --onefile .\install\SetFile.py
|
||||||
|
pyinstaller --onefile --add-data "install/Common.py:install" --hidden-import win32timezone .\install\ManagerService.py
|
||||||
Binary file not shown.
|
|
@ -1,106 +1,15 @@
|
||||||
from datetime import datetime
|
import shutil
|
||||||
|
|
||||||
from Common import *
|
from Common import *
|
||||||
|
|
||||||
|
current_dir = os.path.dirname(sys.executable) if getattr(sys, 'frozen', False) else os.path.dirname(
|
||||||
|
os.path.abspath(__file__))
|
||||||
|
manage_service_exe = os.path.join(current_dir, "ManagerService.exe")
|
||||||
|
app_log_dir = os.path.join(current_dir, "logs")
|
||||||
|
sql_path = get_resource_path(os.path.join("datas", "init.sql"))
|
||||||
|
jar_path = get_resource_path(os.path.join("datas", "electromagnetic.jar"))
|
||||||
|
|
||||||
class InstallOrUpgradeComacDb:
|
def set_sql():
|
||||||
|
with open(sql_path, 'r', encoding='utf-8') as file:
|
||||||
def __init__(self, current_dir):
|
|
||||||
|
|
||||||
self.run_dir = current_dir
|
|
||||||
self.app_log_dir = os.path.join(current_dir, "logs")
|
|
||||||
self.comac_db_running_port = 12396
|
|
||||||
self.jar_path = get_resource_path(os.path.join("datas", "electromagnetic.jar"))
|
|
||||||
self.url = f'http://127.0.0.1:{self.comac_db_running_port}/index'
|
|
||||||
self.service_name = "ComacDatabase"
|
|
||||||
self.service_description = "数据库组件服务"
|
|
||||||
# 路径配置
|
|
||||||
self.datas_dir = get_resource_path(os.path.join('datas'))
|
|
||||||
# NSSM可执行文件路径
|
|
||||||
self.nssm_exe = get_resource_path(os.path.join('datas', 'nssm.exe'))
|
|
||||||
# Java和JAR文件路径
|
|
||||||
self.java_path = os.path.join(current_dir, "jdk", "bin", "java.exe")
|
|
||||||
self.sql_path = get_resource_path(os.path.join("datas", "init.sql"))
|
|
||||||
pass
|
|
||||||
|
|
||||||
def start_comac_db(self):
|
|
||||||
delete_old_files(self.app_log_dir, 2)
|
|
||||||
self.__remove_pre_service()
|
|
||||||
self.__set_sql()
|
|
||||||
self.__register_and_start_service()
|
|
||||||
logger.info("运行完成,10秒钟后自动退出")
|
|
||||||
time.sleep(10)
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __set_sql(self):
|
|
||||||
self.__set_replace()
|
|
||||||
logger.info("设置数据")
|
|
||||||
command2 = fr'{self.run_dir}\mariadb\bin\mysql --no-defaults -u root -p{mariadb_passowrd} -P {mariadb_port} {mariadb_init_schema} < {self.sql_path}'
|
|
||||||
with os.popen(command2) as stream:
|
|
||||||
res2 = stream.read()
|
|
||||||
logger.info(res2)
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __register_and_start_service(self):
|
|
||||||
# 服务配置
|
|
||||||
# 构建NSSM安装命令
|
|
||||||
formatted_time = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
||||||
cmd = [
|
|
||||||
str(self.nssm_exe),
|
|
||||||
"install",
|
|
||||||
self.service_name,
|
|
||||||
self.java_path,
|
|
||||||
f"-jar {self.jar_path} "
|
|
||||||
f"--logging.file.path={self.app_log_dir} "
|
|
||||||
f"--logging.file.name={self.app_log_dir}/app_{formatted_time}.log "
|
|
||||||
f"--winPrefix={self.run_dir} "
|
|
||||||
f"--spring.datasource.username={mariadb_user} "
|
|
||||||
f"--spring.datasource.password={mariadb_passowrd} "
|
|
||||||
f"--server.port={comac_db_port} "
|
|
||||||
f"--spring.datasource.url=jdbc:mariadb://127.0.0.1:{mariadb_port}/{mariadb_init_schema}?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&sslModel=true&serverTimezone=GMT%2B8&allowMultiQueries=true&rewriteBatchedStatements=true"
|
|
||||||
]
|
|
||||||
|
|
||||||
# 执行安装命令
|
|
||||||
logger.info("Installing service...")
|
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
||||||
|
|
||||||
if result.returncode != 0:
|
|
||||||
logger.info("Error installing service:")
|
|
||||||
logger.info(result.stderr)
|
|
||||||
return False
|
|
||||||
|
|
||||||
logger.info("Service installed successfully!")
|
|
||||||
|
|
||||||
# 设置服务显示名称和描述
|
|
||||||
subprocess.run([str(self.nssm_exe), "set", self.service_name, "DisplayName", self.service_name])
|
|
||||||
subprocess.run([str(self.nssm_exe), "set", self.service_name, "Description", self.service_description])
|
|
||||||
|
|
||||||
# 设置启动目录(可选,但推荐)
|
|
||||||
# subprocess.run([str(nssm_exe), "set", service_name, "AppDirectory", str(datas_dir)])
|
|
||||||
|
|
||||||
# 设置启动类型为自动(可选)
|
|
||||||
subprocess.run([str(self.nssm_exe), "set", self.service_name, "Start", "SERVICE_AUTO_START"])
|
|
||||||
|
|
||||||
logger.info("Service configuration completed.")
|
|
||||||
subprocess.run(rf"net start {self.service_name}")
|
|
||||||
time.sleep(10)
|
|
||||||
|
|
||||||
def __remove_pre_service(self):
|
|
||||||
exist = check_service_exist(self.service_name)
|
|
||||||
if not exist:
|
|
||||||
return
|
|
||||||
logger.info("清理历史服务")
|
|
||||||
stop_command = ["sc", "stop", self.service_name]
|
|
||||||
delete_command = ["sc", "delete", self.service_name]
|
|
||||||
res1 = subprocess.run(stop_command, capture_output=True, text=True)
|
|
||||||
logger.info(res1.stdout)
|
|
||||||
res2 = subprocess.run(delete_command, capture_output=True, text=True)
|
|
||||||
logger.info(res2.stdout)
|
|
||||||
time.sleep(5)
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __set_replace(self):
|
|
||||||
with open(self.sql_path, 'r', encoding='utf-8') as file:
|
|
||||||
lines = file.readlines()
|
lines = file.readlines()
|
||||||
modified = False
|
modified = False
|
||||||
new_lines = []
|
new_lines = []
|
||||||
|
|
@ -114,22 +23,50 @@ class InstallOrUpgradeComacDb:
|
||||||
|
|
||||||
# 如果有修改,则写回文件
|
# 如果有修改,则写回文件
|
||||||
if modified:
|
if modified:
|
||||||
with open(self.sql_path, 'w', encoding='utf-8') as file:
|
with open(sql_path, 'w', encoding='utf-8') as file:
|
||||||
file.writelines(new_lines)
|
file.writelines(new_lines)
|
||||||
|
|
||||||
|
command2 = fr'{current_dir}\mariadb\bin\mysql --no-defaults -u root -p{mariadb_passowrd} -P {mariadb_port} {mariadb_init_schema} < {sql_path}'
|
||||||
|
with os.popen(command2) as stream:
|
||||||
|
res2 = stream.read()
|
||||||
|
logger.info(res2)
|
||||||
|
logger.info("sql设置成功")
|
||||||
|
pass
|
||||||
|
|
||||||
|
def set_jar():
|
||||||
|
dest_jar_path = os.path.join(current_dir, "electromagnetic.jar")
|
||||||
|
shutil.copy(jar_path, dest_jar_path)
|
||||||
|
logger.info("jar设置成功")
|
||||||
|
pass
|
||||||
|
|
||||||
|
def update_service(cmd):
|
||||||
|
command = [manage_service_exe, cmd]
|
||||||
|
result = subprocess.run(command, capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
logger.warning(f"操作失败,cmd is {cmd}")
|
||||||
|
else:
|
||||||
|
logger.info(f"操作成功,cmd is {cmd}")
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
ensure_dir(app_log_dir)
|
||||||
current_dir = os.path.dirname(sys.executable) if getattr(sys, 'frozen', False) else os.path.dirname(os.path.abspath(__file__))
|
|
||||||
log_dir = os.path.join(current_dir, "logs")
|
|
||||||
ensure_dir(log_dir)
|
|
||||||
logger.add(
|
logger.add(
|
||||||
sink=os.path.join(log_dir, "InstallComacDB_{time}.log"), # 文件路径模板
|
sink=os.path.join(app_log_dir, "InstallOrUpgradeComacDB.log"), # 文件路径模板
|
||||||
rotation="10 MB", # 文件大小达到10MB时轮转
|
rotation="10 MB", # 文件大小达到10MB时轮转
|
||||||
retention="1 days", # 保留最近1天的日志
|
retention="1 days", # 保留最近1天的日志
|
||||||
compression="zip", # 压缩旧日志节省空间
|
compression="zip", # 压缩旧日志节省空间
|
||||||
enqueue=True, # 线程安全写入
|
enqueue=True, # 线程安全写入
|
||||||
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}" # 自定义格式
|
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}" # 自定义格式
|
||||||
)
|
)
|
||||||
InstallOrUpgradeComacDb(current_dir).start_comac_db()
|
|
||||||
|
set_sql()
|
||||||
|
set_jar()
|
||||||
|
|
||||||
|
update_service("stop")
|
||||||
|
update_service("remove")
|
||||||
|
update_service("install")
|
||||||
|
update_service("start")
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
@ -0,0 +1,173 @@
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import servicemanager
|
||||||
|
import win32event
|
||||||
|
import win32service
|
||||||
|
import win32serviceutil
|
||||||
|
|
||||||
|
from Common import *
|
||||||
|
|
||||||
|
current_dir = os.path.dirname(sys.executable) if getattr(sys, 'frozen', False) else os.path.dirname(
|
||||||
|
os.path.abspath(__file__))
|
||||||
|
service_name = "ComacDatabase"
|
||||||
|
service_description = "Comac数据库组件服务"
|
||||||
|
java_exe = os.path.join(current_dir, "jdk", "bin", "java.exe")
|
||||||
|
jar_path = os.path.join(current_dir, "electromagnetic.jar")
|
||||||
|
app_log_dir = os.path.join(current_dir, "logs")
|
||||||
|
|
||||||
|
class ComacDBService(win32serviceutil.ServiceFramework):
|
||||||
|
_svc_name_ = service_name # 服务名称
|
||||||
|
_svc_display_name_ = service_name # 显示名称
|
||||||
|
_svc_description_ = service_description # 服务描述
|
||||||
|
|
||||||
|
def __init__(self, args):
|
||||||
|
win32serviceutil.ServiceFramework.__init__(self, args)
|
||||||
|
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
|
||||||
|
self.process = None
|
||||||
|
self.service_ready = False
|
||||||
|
|
||||||
|
def SvcDoRun(self):
|
||||||
|
try:
|
||||||
|
# 报告服务正在启动
|
||||||
|
self.ReportServiceStatus(win32service.SERVICE_START_PENDING, waitHint=10000)
|
||||||
|
formatted_time = datetime.now().strftime("%Y%m%d%H%M%S")
|
||||||
|
cmd = [
|
||||||
|
java_exe,
|
||||||
|
f"-jar",
|
||||||
|
jar_path,
|
||||||
|
f"--logging.file.path={app_log_dir}",
|
||||||
|
f"--logging.file.name={app_log_dir}/app_{formatted_time}.log",
|
||||||
|
f"--winPrefix={current_dir}",
|
||||||
|
f"--spring.datasource.username={mariadb_user}",
|
||||||
|
f"--spring.datasource.password={mariadb_passowrd}",
|
||||||
|
f"--server.port={comac_db_port}",
|
||||||
|
f"--spring.datasource.url=jdbc:mariadb://127.0.0.1:{mariadb_port}/{mariadb_init_schema}?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&sslModel=true&serverTimezone=GMT%2B8&allowMultiQueries=true&rewriteBatchedStatements=true"
|
||||||
|
]
|
||||||
|
# 添加完整的错误处理
|
||||||
|
env = os.environ.copy()
|
||||||
|
startupinfo = subprocess.STARTUPINFO()
|
||||||
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||||
|
startupinfo.wShowWindow = 0 # 隐藏窗口
|
||||||
|
|
||||||
|
# 启动Java进程(使用subprocess.Popen捕获输出)
|
||||||
|
try:
|
||||||
|
self.process = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
cwd=app_log_dir,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
creationflags=subprocess.CREATE_NO_WINDOW,
|
||||||
|
env=env,
|
||||||
|
startupinfo=startupinfo
|
||||||
|
)
|
||||||
|
logger.info(f"Java process started with PID: {self.process.pid}")
|
||||||
|
|
||||||
|
# 检查进程是否存活
|
||||||
|
time.sleep(2) # 给Java启动时间
|
||||||
|
if self.process.poll() is not None:
|
||||||
|
# 读取输出以诊断问题
|
||||||
|
output, _ = self.process.communicate(timeout=2)
|
||||||
|
output = output.decode('gbk', errors='ignore')
|
||||||
|
logger.error(f"Java process exited prematurely. Output: {output}")
|
||||||
|
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to start Java process: {str(e)}")
|
||||||
|
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 服务完全启动
|
||||||
|
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
|
||||||
|
self.service_ready = True
|
||||||
|
logger.info("Service fully started and running")
|
||||||
|
|
||||||
|
# 启动线程监控Java进程
|
||||||
|
self.monitor_java_process()
|
||||||
|
|
||||||
|
# 等待停止信号
|
||||||
|
win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Service failed: {str(e)}", exc_info=True)
|
||||||
|
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
|
||||||
|
finally:
|
||||||
|
# 确保清理资源
|
||||||
|
if self.process and self.process.poll() is None:
|
||||||
|
self.process.terminate()
|
||||||
|
self.process = None
|
||||||
|
|
||||||
|
def monitor_java_process(self):
|
||||||
|
"""在后台线程中监控Java进程"""
|
||||||
|
import threading
|
||||||
|
|
||||||
|
def monitor():
|
||||||
|
try:
|
||||||
|
if self.process:
|
||||||
|
# 持续读取输出
|
||||||
|
while self.process.poll() is None and self.service_ready:
|
||||||
|
line = self.process.stdout.readline()
|
||||||
|
if line:
|
||||||
|
line = line.decode('gbk', errors='ignore').strip()
|
||||||
|
logger.info(f"JAVA: {line}")
|
||||||
|
else:
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
# 检查进程退出原因
|
||||||
|
if self.process.poll() is not None:
|
||||||
|
logger.warning(f"Java process exited with code: {self.process.poll()}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Monitor thread error: {str(e)}")
|
||||||
|
|
||||||
|
# 启动监控线程
|
||||||
|
threading.Thread(target=monitor, daemon=True).start()
|
||||||
|
|
||||||
|
def SvcStop(self):
|
||||||
|
# 报告服务正在停止
|
||||||
|
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
|
||||||
|
|
||||||
|
# 停止Java进程(如果存在)
|
||||||
|
if self.process:
|
||||||
|
try:
|
||||||
|
# 更优雅的关闭方式
|
||||||
|
logger.info("Terminating Java process...")
|
||||||
|
self.process.terminate()
|
||||||
|
|
||||||
|
# 等待最多10秒
|
||||||
|
for _ in range(10):
|
||||||
|
if self.process.poll() is not None:
|
||||||
|
break
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
logger.warning("Java process did not exit, using force kill")
|
||||||
|
self.process.kill()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error stopping Java process: {str(e)}")
|
||||||
|
|
||||||
|
# 通知主线程停止
|
||||||
|
win32event.SetEvent(self.hWaitStop)
|
||||||
|
self.service_ready = False
|
||||||
|
|
||||||
|
# 报告服务已停止
|
||||||
|
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
|
||||||
|
logger.info("Service stopped successfully")
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
ensure_dir(app_log_dir)
|
||||||
|
logger.add(
|
||||||
|
sink=os.path.join(app_log_dir, "ManagerService.log"), # 文件路径模板
|
||||||
|
rotation="10 MB", # 文件大小达到10MB时轮转
|
||||||
|
retention="1 days", # 保留最近1天的日志
|
||||||
|
compression="zip", # 压缩旧日志节省空间
|
||||||
|
enqueue=True, # 线程安全写入
|
||||||
|
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}" # 自定义格式
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
servicemanager.Initialize()
|
||||||
|
servicemanager.PrepareToHostSingle(ComacDBService)
|
||||||
|
servicemanager.StartServiceCtrlDispatcher()
|
||||||
|
else:
|
||||||
|
err = win32serviceutil.HandleCommandLine(ComacDBService)
|
||||||
Loading…
Reference in New Issue