169 lines
6.1 KiB
Python
169 lines
6.1 KiB
Python
import customtkinter as ctk
|
|
import os
|
|
import threading
|
|
import datetime
|
|
from pystray import Icon as TrayIcon, Menu, MenuItem
|
|
from PIL import Image, ImageDraw
|
|
import sys
|
|
import subprocess
|
|
import webbrowser
|
|
import psutil
|
|
|
|
LOG_REFRESH_SECONDS = 10
|
|
MAIN_DIR = os.getcwd()
|
|
LOG_DIR = os.path.join(MAIN_DIR, 'Logs')
|
|
EXPORTER_LOG = os.path.join(LOG_DIR, f"MSSQL_exporter_log_{datetime.datetime.now().strftime('%Y-%m-%d')}.txt")
|
|
IMPORTER_LOG = os.path.join(LOG_DIR, f"SDF_importer_log_{datetime.datetime.now().strftime('%Y-%m-%d')}.txt")
|
|
MAIN_EXE = os.path.join(MAIN_DIR, 'main.exe')
|
|
ENV_FILE = os.path.join(MAIN_DIR, '.env')
|
|
|
|
|
|
def resource_path(relative_path):
|
|
"""Korrekt aufgelöst für PyInstaller und normale Ausführung"""
|
|
try:
|
|
base_path = sys._MEIPASS
|
|
except AttributeError:
|
|
base_path = os.path.abspath('.')
|
|
return os.path.join(base_path, relative_path)
|
|
|
|
|
|
class LogMonitorApp(ctk.CTk):
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.title('SDF-Dienstüberwachung')
|
|
self.geometry('500x350')
|
|
ctk.set_appearance_mode('dark')
|
|
ctk.set_default_color_theme('blue')
|
|
|
|
self.title_label = ctk.CTkLabel(self, text='SDF Monitor', font=ctk.CTkFont(size=24, weight='bold'))
|
|
self.title_label.pack(pady=(10, 0))
|
|
|
|
self.status_label = ctk.CTkLabel(self, text='Letzte Ausführungen laden...')
|
|
self.status_label.pack(pady=(20, 0))
|
|
|
|
self.seconds_remaining = LOG_REFRESH_SECONDS
|
|
self.countdown_label = ctk.CTkLabel(self, text=f'Nächster Check in: {self.seconds_remaining}s')
|
|
self.countdown_label.pack(pady=5)
|
|
|
|
self.update_logs()
|
|
self.update_countdown()
|
|
|
|
self.folder_button = ctk.CTkButton(self, text='Logs-Ordner öffnen', command=self.open_log_folder)
|
|
self.folder_button.pack(pady=10)
|
|
|
|
self.env_button = ctk.CTkButton(self, text='.env Datei öffnen', command=self.open_env_file)
|
|
self.env_button.pack(pady=5)
|
|
|
|
self.restart_button = ctk.CTkButton(self, text='Services neu starten', command=self.restart_main_exe)
|
|
self.restart_button.pack(pady=10)
|
|
|
|
self.stop_button = ctk.CTkButton(self, text='Services beenden', command=self.stop_main_exe)
|
|
self.stop_button.pack(pady=5)
|
|
|
|
logo_path = resource_path('logo.png')
|
|
if os.path.exists(logo_path):
|
|
from PIL import Image as PILImage
|
|
logo_img = PILImage.open(logo_path).resize((120, 40))
|
|
self.logo_image = ctk.CTkImage(light_image=logo_img, dark_image=logo_img, size=(120, 40))
|
|
self.logo_label = ctk.CTkLabel(self, image=self.logo_image, text='', cursor='hand2')
|
|
else:
|
|
self.logo_label = ctk.CTkLabel(self, text='www.deine-website.de', text_color='skyblue', cursor='hand2')
|
|
self.logo_label.pack(pady=5)
|
|
self.logo_label.bind('<Button-1>', lambda e: webbrowser.open('https://www.deine-website.de'))
|
|
|
|
self.protocol('WM_DELETE_WINDOW', self.hide_to_tray)
|
|
self.bind('<Unmap>', self.on_minimize)
|
|
|
|
self.create_tray_icon()
|
|
|
|
def format_time(self, path):
|
|
if os.path.exists(path):
|
|
t = datetime.datetime.fromtimestamp(os.path.getmtime(path))
|
|
return t.strftime('%Y-%m-%d %H:%M:%S')
|
|
return 'Nie'
|
|
|
|
def update_logs(self):
|
|
exporter_time = self.format_time(EXPORTER_LOG)
|
|
importer_time = self.format_time(IMPORTER_LOG)
|
|
self.status_label.configure(text=f'Letzter Export: {exporter_time}\nLetzter Import: {importer_time}')
|
|
|
|
def update_countdown(self):
|
|
self.countdown_label.configure(text=f'Nächster Check in: {self.seconds_remaining}s')
|
|
self.seconds_remaining -= 1
|
|
if self.seconds_remaining <= 0:
|
|
self.update_logs()
|
|
self.seconds_remaining = LOG_REFRESH_SECONDS
|
|
self.after(1000, self.update_countdown)
|
|
|
|
def restart_main_exe(self):
|
|
try:
|
|
if os.path.exists(MAIN_EXE):
|
|
subprocess.Popen([MAIN_EXE])
|
|
self.write_status('main.exe wurde neu gestartet.')
|
|
else:
|
|
self.write_status('main.exe nicht gefunden.')
|
|
except Exception as e:
|
|
self.write_status(f'Fehler beim Starten von main.exe: {e}')
|
|
|
|
def write_status(self, msg):
|
|
now = datetime.datetime.now().strftime('%H:%M:%S')
|
|
self.status_label.configure(text=f'[{now}] {msg}')
|
|
|
|
def open_log_folder(self):
|
|
os.startfile(LOG_DIR)
|
|
|
|
def open_env_file(self):
|
|
if os.path.exists(ENV_FILE):
|
|
os.startfile(ENV_FILE)
|
|
else:
|
|
self.write_status('.env Datei nicht gefunden.')
|
|
|
|
def hide_to_tray(self):
|
|
self.withdraw()
|
|
self.tray_icon.visible = True
|
|
|
|
def show_from_tray(self, icon=None, item=None):
|
|
self.deiconify()
|
|
self.tray_icon.visible = False
|
|
|
|
def quit_app(self, icon, item):
|
|
self.tray_icon.stop()
|
|
self.destroy()
|
|
sys.exit()
|
|
|
|
def on_minimize(self, event):
|
|
if self.state() == 'iconic':
|
|
self.hide_to_tray()
|
|
|
|
def create_tray_icon(self):
|
|
icon_path = resource_path('icon.ico')
|
|
if os.path.exists(icon_path):
|
|
image = Image.open(icon_path).resize((64, 64))
|
|
else:
|
|
image = Image.new('RGB', (64, 64), 'black')
|
|
draw = ImageDraw.Draw(image)
|
|
draw.rectangle((16, 16, 48, 48), fill='white')
|
|
menu = Menu(MenuItem('Öffnen', self.show_from_tray), MenuItem('Beenden', self.quit_app))
|
|
self.tray_icon = TrayIcon('SDF-Monitor', image, 'SDF-Monitor', menu)
|
|
threading.Thread(target=self.tray_icon.run, daemon=True).start()
|
|
|
|
def stop_main_exe(self):
|
|
found = False
|
|
for proc in psutil.process_iter(['pid', 'name']):
|
|
try:
|
|
if proc.info['name'].lower() == 'main.exe':
|
|
proc.kill()
|
|
found = True
|
|
self.write_status('main.exe wurde beendet.')
|
|
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
pass
|
|
|
|
if not found:
|
|
self.write_status('main.exe läuft nicht.')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
app = LogMonitorApp()
|
|
app.mainloop()
|