Aggiunge tray app e backup manuale

This commit is contained in:
2026-06-30 20:54:32 +02:00
parent 4dca5fbf95
commit 8f624f5b97
7 changed files with 444 additions and 0 deletions

113
src/bakrest/tray_app.py Normal file
View File

@@ -0,0 +1,113 @@
from __future__ import annotations
import json
import logging
import threading
import tkinter as tk
from tkinter import messagebox
from pathlib import Path
from PIL import Image, ImageDraw
import pystray
from .backup import run_backup, shutdown_after_backup
from .config import AppConfig, load_config
from .logging_setup import configure_logging
from .registry import ChangeRegistry
class BakRestTrayApp:
def __init__(self, config: AppConfig, logger: logging.Logger) -> None:
self.config = config
self.logger = logger
self.registry = ChangeRegistry(config.storage.change_registry)
self.icon = pystray.Icon(
"BakRestTray",
_create_icon_image(),
"Bak&Rest",
self._build_menu(),
)
def run(self) -> None:
self.logger.info("BakRestTray started")
self.icon.run()
def _build_menu(self) -> pystray.Menu:
return pystray.Menu(
pystray.MenuItem(lambda item: self._status_text(), None, enabled=False),
pystray.Menu.SEPARATOR,
pystray.MenuItem("Backup e spegni", self._backup_and_shutdown),
pystray.MenuItem("Aggiorna stato", self._refresh),
pystray.MenuItem("Esci", self._quit),
)
def _status_text(self) -> str:
pending = self.registry.pending_count()
server = self._read_server_status()
return f"Server: {server} | File in attesa: {pending}"
def _read_server_status(self) -> str:
path = self.config.storage.status_file
if not path.exists():
return "sconosciuto"
try:
data = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError):
return "errore stato"
return "raggiungibile" if data.get("reachable") else "non raggiungibile"
def _backup_and_shutdown(self, icon: pystray.Icon, item: pystray.MenuItem) -> None:
threading.Thread(target=self._backup_and_shutdown_worker, daemon=True).start()
def _backup_and_shutdown_worker(self) -> None:
self.logger.info("User requested Backup e spegni")
self.icon.title = "Bak&Rest - backup in corso"
result = run_backup(self.config, self.logger)
if result.success:
self.icon.title = "Bak&Rest - backup completato"
shutdown_after_backup(self.config, self.logger)
else:
self.icon.title = "Bak&Rest - backup fallito"
if result.error_code == "server_unreachable":
_show_error_message("Bak&Rest", "Server non raggiungibile. E' spento?")
else:
_show_error_message("Bak&Rest", result.message)
self.icon.update_menu()
def _refresh(self, icon: pystray.Icon, item: pystray.MenuItem) -> None:
self.icon.update_menu()
def _quit(self, icon: pystray.Icon, item: pystray.MenuItem) -> None:
self.logger.info("BakRestTray stopped")
self.icon.stop()
def _create_icon_image() -> Image.Image:
image = Image.new("RGBA", (64, 64), (26, 38, 52, 255))
draw = ImageDraw.Draw(image)
draw.rounded_rectangle((10, 14, 54, 50), radius=8, fill=(77, 163, 255, 255))
draw.rectangle((18, 24, 46, 44), fill=(245, 248, 252, 255))
draw.line((22, 34, 32, 42, 46, 26), fill=(26, 38, 52, 255), width=5)
return image
def _show_error_message(title: str, message: str) -> None:
root = tk.Tk()
root.withdraw()
root.attributes("-topmost", True)
try:
messagebox.showerror(title, message, parent=root)
finally:
root.destroy()
def main() -> int:
config = load_config()
logger = configure_logging(config.storage.logs_dir, "tray")
app = BakRestTrayApp(config, logger)
app.run()
return 0
if __name__ == "__main__":
raise SystemExit(main())