Files
SupervisorAI/main_start.py

161 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# main_start.py
# 主启动脚本:读取配置并通过 subprocess 启动 rtsp_service_ws_kadian.py
# 支持 start 和 status 命令,默认执行 start
import json
import yaml
import base64
import subprocess
import sys
import os
import signal
import argparse
from typing import List
from common.camera_config import CameraConfig
from utils.logger import get_logger
logger = get_logger(__name__)
# PID 文件路径
PID_FILE = "rtsp_service.pid"
def load_cameras_from_yaml(config_path: str = "config.yaml") -> List[dict]:
"""从 YAML 文件加载摄像头配置"""
with open(config_path, "r", encoding="utf-8") as f:
cfg = yaml.safe_load(f)
return cfg.get("cameras", [])
def cameras_to_base64_json(cameras: List[dict]) -> str:
"""将摄像头配置转换为 base64 编码的 JSON 字符串"""
json_str = json.dumps(cameras, ensure_ascii=False)
return base64.b64encode(json_str.encode('utf-8')).decode('ascii')
def start_rtsp_service(cameras_base64: str, script_path: str = "rtsp_service_ws_kadian.py"):
"""启动 RTSP 服务子进程(后台运行)"""
cmd = [
sys.executable, # 当前 Python 解释器路径
script_path,
"--cameras", cameras_base64
]
logger.info(f"[INFO] Starting RTSP service with command: python {script_path} --cameras <base64_config>")
# 使用 start_new_session=True 创建新会话,类似 nohup 效果
process = subprocess.Popen(cmd, start_new_session=True)
return process
def save_pid(pid: int):
"""保存进程ID到文件"""
try:
with open(PID_FILE, "w") as f:
f.write(str(pid))
logger.info(f"[INFO] Saved PID {pid} to {PID_FILE}")
except Exception as e:
logger.error(f"[ERROR] Failed to save PID file: {e}")
def read_pid():
"""从PID文件读取进程ID"""
try:
with open(PID_FILE, "r") as f:
return int(f.read().strip())
except FileNotFoundError:
logger.warning(f"[WARN] PID file {PID_FILE} not found")
return None
except Exception as e:
logger.error(f"[ERROR] Failed to read PID file: {e}")
return None
def is_process_running(pid: int):
"""检查进程是否在运行"""
try:
# 发送信号0不实际发送信号仅检查进程是否存在
os.kill(pid, 0)
return True
except OSError:
return False
def start_service():
"""启动服务"""
# 检查是否已经在运行
pid = read_pid()
if pid and is_process_running(pid):
logger.warning(f"[WARN] Service is already running with PID {pid}")
return False
config_path = "config.yaml"
# 1. 读取配置
cameras_data = load_cameras_from_yaml(config_path)
logger.info(f"[INFO] Loaded {len(cameras_data)} cameras from {config_path}")
if not cameras_data:
logger.error("[ERROR] No cameras found in config, exiting...")
return False
# 2. 转换为 base64 JSON
cameras_base64 = cameras_to_base64_json(cameras_data)
# 3. 启动子进程
try:
process = start_rtsp_service(cameras_base64)
# 等待一下确保进程启动
import time
time.sleep(1)
# 4. 保存PID
save_pid(process.pid)
logger.info(f"[INFO] Service started successfully with PID {process.pid}")
logger.info("[INFO] Main process exiting, service will continue running in background")
return True
except Exception as e:
logger.error(f"[ERROR] Failed to start service: {e}")
return False
def status_service():
"""检查服务状态"""
pid = read_pid()
if not pid:
logger.info("[INFO] Service is not running (no PID file)")
return False
if is_process_running(pid):
logger.info(f"[INFO] Service is running with PID {pid}")
return True
else:
logger.info(f"[INFO] Service is not running (PID {pid} not found), cleaning up PID file")
try:
os.remove(PID_FILE)
except:
pass
return False
def main():
parser = argparse.ArgumentParser(description="RTSP Service Manager")
parser.add_argument("command", nargs="?", choices=["start", "status"], default="start",
help="Command to execute: start, status (default: start)")
args = parser.parse_args()
if args.command == "start":
success = start_service()
sys.exit(0 if success else 1)
elif args.command == "status":
success = status_service()
sys.exit(0 if success else 0) # 状态检查总是返回0退出码
if __name__ == "__main__":
main()