mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-12 16:15:33 +00:00
Merge branch 'dashboard-monitor-parent' into v1.1-develop
This commit is contained in:
commit
c7b4fb49cb
3 files changed
+50
-10
No files matched your search
+5
-1
@@ -4,11 +4,15 @@ Status of the `main` branch. Changes prior to the next official version change w
|
||||
|
||||
* General:
|
||||
- Added `serena init` command
|
||||
|
||||
* Language Servers:
|
||||
- Added Crystal language support (uses [Crystalline](https://github.com/elbywan/crystalline) language server)
|
||||
- `JetBrainsFindReferencingSymbolTool`: Include context lines (when using plugin version 2023.2.15+)
|
||||
|
||||
* Dashboard:
|
||||
- Add version display
|
||||
- Add version display
|
||||
- Dashboard viewer (Windows): Add a parent monitoring thread to ensure termination.
|
||||
Some clients would terminate the MCP server in a way that did not ensure proper termination.
|
||||
|
||||
* Fixes:
|
||||
- Fix reactivation of the same project restarting language servers #1280
|
||||
|
||||
+3
-3
@@ -554,12 +554,12 @@ class SerenaAgent:
|
||||
return self._dashboard_url
|
||||
|
||||
@staticmethod
|
||||
def _start_dashboard_viewer_process_function(url: str, minimized: bool) -> None:
|
||||
def _start_dashboard_viewer_process_function(url: str, minimized: bool, parent_process_id: int) -> None:
|
||||
"""
|
||||
Main function of the subprocess for starting the dashboard viewer
|
||||
"""
|
||||
try:
|
||||
SerenaDashboardViewer(url, start_minimized=minimized).run()
|
||||
SerenaDashboardViewer(url, start_minimized=minimized, parent_process_id=parent_process_id).run()
|
||||
except webview.errors.WebViewException as e:
|
||||
log.warning(f"Could not open Serena Dashboard viewer. Cause:\n{e}")
|
||||
# Fall back to opening the browser window if the window was supposed to be shown directly
|
||||
@@ -582,7 +582,7 @@ class SerenaAgent:
|
||||
assert url is not None
|
||||
if SerenaDashboardViewer.is_current_platform_supported():
|
||||
self._dashboard_viewer_process = multiprocessing.Process(
|
||||
target=self._start_dashboard_viewer_process_function, args=(url, minimized), daemon=True
|
||||
target=self._start_dashboard_viewer_process_function, args=(url, minimized, os.getpid()), daemon=True
|
||||
)
|
||||
self._dashboard_viewer_process.start()
|
||||
else:
|
||||
|
||||
+42
-6
@@ -3,11 +3,13 @@ import os
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Self
|
||||
|
||||
import psutil
|
||||
import webview
|
||||
from flask import Flask, Response, redirect, request, send_from_directory
|
||||
from PIL import Image
|
||||
@@ -743,6 +745,8 @@ class SerenaDashboardViewer:
|
||||
Minimal pywebview wrapper with optional system tray.
|
||||
"""
|
||||
|
||||
DEBUG = False
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
url: str,
|
||||
@@ -750,6 +754,7 @@ class SerenaDashboardViewer:
|
||||
start_minimized: bool = False,
|
||||
width: int = 1400,
|
||||
height: int = 900,
|
||||
parent_process_id: int | None = None,
|
||||
):
|
||||
self.url = url
|
||||
# Use system tray to allow hiding to tray and intercepting close to hide instead of quit
|
||||
@@ -758,6 +763,7 @@ class SerenaDashboardViewer:
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.start_minimized = start_minimized
|
||||
self.parent_process_id = parent_process_id
|
||||
|
||||
self.window: webview.Window
|
||||
self._tray_icon: Any
|
||||
@@ -786,6 +792,10 @@ class SerenaDashboardViewer:
|
||||
|
||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("oraios.serena")
|
||||
|
||||
if self.DEBUG:
|
||||
logging.configure(level=logging.DEBUG)
|
||||
logging.add_file_logger(SerenaPaths().get_next_log_file_path("dashboard-viewer"))
|
||||
|
||||
dashboard_path = Path(SERENA_DASHBOARD_DIR)
|
||||
# .ico is Windows-only; macOS expects a PNG for the window/dock icon.
|
||||
icon_filename = "serena.ico" if sys.platform == "win32" else "serena-icon-1024-mac.png"
|
||||
@@ -815,8 +825,27 @@ class SerenaDashboardViewer:
|
||||
else:
|
||||
self._show_window()
|
||||
|
||||
# start a thread to monitor the parent process
|
||||
if self.parent_process_id is not None:
|
||||
threading.Thread(target=self._monitor_parent_process, daemon=True).start()
|
||||
|
||||
webview.start(_start_callback, icon=icon_path)
|
||||
|
||||
def _monitor_parent_process(self) -> None:
|
||||
"""
|
||||
Monitors the parent process and shuts down the dashboard viewer if the parent process exits.
|
||||
"""
|
||||
pid = self.parent_process_id
|
||||
log.info("Starting parent process monitor thread (parent_pid=%d, pid=%s)", pid, os.getpid())
|
||||
try:
|
||||
parent_process = psutil.Process(pid)
|
||||
while parent_process.is_running():
|
||||
time.sleep(1)
|
||||
except psutil.NoSuchProcess:
|
||||
pass # Parent process already exited
|
||||
log.info("Parent process (pid=%d) has exited, shutting down dashboard viewer", pid)
|
||||
self._terminate()
|
||||
|
||||
def _show_window(self) -> None:
|
||||
if not self.window:
|
||||
return
|
||||
@@ -885,6 +914,18 @@ class SerenaDashboardViewer:
|
||||
self._hide_window()
|
||||
return False # prevent the window from actually closing
|
||||
|
||||
def _terminate(self) -> None:
|
||||
"""
|
||||
Terminates the viewer application and the tray icon
|
||||
"""
|
||||
self._quitting = True
|
||||
try:
|
||||
if self._tray_icon:
|
||||
self._tray_icon.stop()
|
||||
finally:
|
||||
if self.window:
|
||||
self.window.destroy()
|
||||
|
||||
def _start_tray(self) -> None:
|
||||
# import pystray locally, because the import fails when there is no display!
|
||||
import pystray
|
||||
@@ -905,12 +946,7 @@ class SerenaDashboardViewer:
|
||||
self._hide_window()
|
||||
|
||||
def quit_app(_icon: TrayIcon, _item: Item) -> None:
|
||||
self._quitting = True
|
||||
try:
|
||||
_icon.stop()
|
||||
finally:
|
||||
if self.window:
|
||||
self.window.destroy()
|
||||
self._terminate()
|
||||
|
||||
menu = pystray.Menu(
|
||||
Item("Open", show, default=True),
|
||||
|
||||
Reference in new issue
Block a user