fichiers oubliés
This commit is contained in:
1 parent
d048732613
commit
857efcef18
8 files changed
+722
No files matched your search
@@ -0,0 +1,113 @@
|
||||
"""Non-blocking controls for the system Syncthing instance."""
|
||||
import queue
|
||||
import subprocess
|
||||
import threading
|
||||
from tkinter import ttk, messagebox
|
||||
|
||||
SERVICE = "syncthing@sebastien.service"
|
||||
|
||||
|
||||
def service_status():
|
||||
result = subprocess.run(
|
||||
["systemctl", "show", SERVICE, "--property=ActiveState", "--value"],
|
||||
capture_output=True, text=True, timeout=10,
|
||||
)
|
||||
if result.returncode:
|
||||
raise RuntimeError(result.stderr.strip() or "Statut indisponible")
|
||||
return result.stdout.strip() or "unknown"
|
||||
|
||||
|
||||
def control_service(action):
|
||||
if action == "ensure" and service_status() == "active":
|
||||
return "active"
|
||||
command = "start" if action == "ensure" else action
|
||||
result = subprocess.run(
|
||||
["systemctl", "--no-ask-password", command, SERVICE],
|
||||
capture_output=True, text=True, timeout=60,
|
||||
)
|
||||
if result.returncode:
|
||||
raise RuntimeError(result.stderr.strip() or f"Échec de systemctl {command}")
|
||||
status = service_status()
|
||||
if command == "start" and status != "active":
|
||||
raise RuntimeError(f"Syncthing n’est pas actif : {status}")
|
||||
return status
|
||||
|
||||
|
||||
class SyncthingPanel(ttk.Frame):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self.events = queue.Queue()
|
||||
self.busy = False
|
||||
self.pending_export = None
|
||||
self.status = ttk.Label(self, text=f"{SERVICE} : vérification…")
|
||||
self.status.pack(anchor="w")
|
||||
controls = ttk.Frame(self)
|
||||
controls.pack(anchor="w", pady=4)
|
||||
self.start_button = ttk.Button(controls, text="Démarrer Syncthing",
|
||||
command=lambda: self.request("start"))
|
||||
self.start_button.pack(side="left")
|
||||
self.stop_button = ttk.Button(controls, text="Arrêter Syncthing",
|
||||
command=lambda: self.request("stop"))
|
||||
self.stop_button.pack(side="left", padx=6)
|
||||
self.timer = self.after(100, self.poll)
|
||||
self.refresh_timer = None
|
||||
self.bind("<Destroy>", self.cleanup, add=True)
|
||||
self.request("status")
|
||||
|
||||
def ensure_started(self, callback):
|
||||
self.pending_export = callback
|
||||
if not self.busy:
|
||||
self.request("ensure")
|
||||
|
||||
def request(self, action):
|
||||
if self.busy:
|
||||
return
|
||||
self.busy = True
|
||||
self.start_button.configure(state="disabled")
|
||||
self.stop_button.configure(state="disabled")
|
||||
if action != "status":
|
||||
self.status.configure(text=f"{SERVICE} : opération en cours…")
|
||||
|
||||
def work():
|
||||
try:
|
||||
status = service_status() if action == "status" else control_service(action)
|
||||
self.events.put((action, status, None))
|
||||
except (OSError, RuntimeError, subprocess.TimeoutExpired) as exc:
|
||||
self.events.put((action, None, str(exc)))
|
||||
|
||||
threading.Thread(target=work, daemon=True).start()
|
||||
|
||||
def poll(self):
|
||||
try:
|
||||
action, status, error = self.events.get_nowait()
|
||||
except queue.Empty:
|
||||
pass
|
||||
else:
|
||||
self.busy = False
|
||||
self.start_button.configure(state="normal")
|
||||
self.stop_button.configure(state="normal")
|
||||
self.status.configure(text=f"{SERVICE} : {error or status}")
|
||||
if error and action != "status":
|
||||
self.pending_export = None
|
||||
messagebox.showerror("Syncthing", error)
|
||||
elif action == "ensure":
|
||||
callback, self.pending_export = self.pending_export, None
|
||||
if callback:
|
||||
callback()
|
||||
elif self.pending_export:
|
||||
self.request("ensure")
|
||||
if self.winfo_exists():
|
||||
self.timer = self.after(100, self.poll)
|
||||
if self.refresh_timer is None:
|
||||
self.refresh_timer = self.after(5000, self.refresh)
|
||||
|
||||
def refresh(self):
|
||||
self.refresh_timer = None
|
||||
self.request("status")
|
||||
|
||||
def cleanup(self, event):
|
||||
if event.widget == self:
|
||||
self.pending_export = None
|
||||
for timer in (self.timer, self.refresh_timer):
|
||||
if timer:
|
||||
self.after_cancel(timer)
|
||||
Reference in new issue
Block a user