完成了基本功能。
This commit is contained in:
parent
d616f686e3
commit
4528e81211
|
|
@ -1,5 +1,6 @@
|
|||
cd src
|
||||
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\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,135 +1,72 @@
|
|||
from datetime import datetime
|
||||
|
||||
import shutil
|
||||
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:
|
||||
lines = file.readlines()
|
||||
modified = False
|
||||
new_lines = []
|
||||
for line in lines:
|
||||
if 'CREATE TABLE' in line and 'IF NOT EXISTS' not in line:
|
||||
new_line = line.replace('CREATE TABLE', 'CREATE TABLE IF NOT EXISTS ')
|
||||
new_lines.append(new_line)
|
||||
modified = True
|
||||
else:
|
||||
new_lines.append(line)
|
||||
|
||||
def __init__(self, current_dir):
|
||||
# 如果有修改,则写回文件
|
||||
if modified:
|
||||
with open(sql_path, 'w', encoding='utf-8') as file:
|
||||
file.writelines(new_lines)
|
||||
|
||||
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
|
||||
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 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_jar():
|
||||
dest_jar_path = os.path.join(current_dir, "electromagnetic.jar")
|
||||
shutil.copy(jar_path, dest_jar_path)
|
||||
logger.info("jar设置成功")
|
||||
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 update_service(cmd):
|
||||
command = [manage_service_exe, cmd]
|
||||
result = subprocess.run(command, capture_output=True, text=True)
|
||||
|
||||
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()
|
||||
modified = False
|
||||
new_lines = []
|
||||
for line in lines:
|
||||
if 'CREATE TABLE' in line and 'IF NOT EXISTS' not in line:
|
||||
new_line = line.replace('CREATE TABLE', 'CREATE TABLE IF NOT EXISTS ')
|
||||
new_lines.append(new_line)
|
||||
modified = True
|
||||
else:
|
||||
new_lines.append(line)
|
||||
|
||||
# 如果有修改,则写回文件
|
||||
if modified:
|
||||
with open(self.sql_path, 'w', encoding='utf-8') as file:
|
||||
file.writelines(new_lines)
|
||||
if result.returncode != 0:
|
||||
logger.warning(f"操作失败,cmd is {cmd}")
|
||||
else:
|
||||
logger.info(f"操作成功,cmd is {cmd}")
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
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)
|
||||
ensure_dir(app_log_dir)
|
||||
logger.add(
|
||||
sink=os.path.join(log_dir, "InstallComacDB_{time}.log"), # 文件路径模板
|
||||
sink=os.path.join(app_log_dir, "InstallOrUpgradeComacDB.log"), # 文件路径模板
|
||||
rotation="10 MB", # 文件大小达到10MB时轮转
|
||||
retention="1 days", # 保留最近1天的日志
|
||||
compression="zip", # 压缩旧日志节省空间
|
||||
enqueue=True, # 线程安全写入
|
||||
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
|
||||
|
|
@ -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