Compare commits

...

2 Commits

3 changed files with 50 additions and 21 deletions

Binary file not shown.

View File

@@ -4,6 +4,7 @@ import subprocess
import platform
import os
import base64
import sys
# Simple Secret Salt - In a real app, obfuscate this or use asymmetric keys (RSA)
# For this level, a symmetric secret is "good enough" for basic protection.
@@ -14,6 +15,35 @@ CREATE_NO_WINDOW = 0x08000000
class LicenseManager:
@staticmethod
def _get_base_dir():
if getattr(sys, 'frozen', False):
return os.path.dirname(sys.executable)
return os.path.dirname(os.path.abspath(__file__))
@staticmethod
def _get_license_path():
return os.path.join(LicenseManager._get_base_dir(), "license.dat")
@staticmethod
def save_license(key):
try:
with open(LicenseManager._get_license_path(), "w") as f:
f.write(key.strip())
return True
except:
return False
@staticmethod
def load_license():
path = LicenseManager._get_license_path()
if not os.path.exists(path):
return None
try:
with open(path, "r") as f:
return f.read().strip()
except:
return None
@staticmethod
def get_motherboard_id():
"""Gets the motherboard UUID using WMIC (Windows only)."""
try:
@@ -124,21 +154,4 @@ class LicenseManager:
# Neither matches - could be both changed or completely invalid key
return False, 'both_changed'
@staticmethod
def save_license(key):
try:
with open("license.dat", "w") as f:
f.write(key.strip())
return True
except:
return False
@staticmethod
def load_license():
if not os.path.exists("license.dat"):
return None
try:
with open("license.dat", "r") as f:
return f.read().strip()
except:
return None

24
main.py
View File

@@ -278,8 +278,11 @@ class BackupApp(QMainWindow):
# Ensure sql_tools folder exists
self.ensure_sql_tools_folder()
self.settings = self.load_settings()
self.trial_limit = 10 # Max uses in trial mode
self.load_settings()
# Job Queue System
self.job_queue = []
if self.trial_mode:
# Check if strict limit reached immediately
@@ -1308,9 +1311,9 @@ class BackupApp(QMainWindow):
def scheduled_backup_wrapper(self, job_id):
# Determine if we can run
if self.worker and self.worker.isRunning():
# Concurrent jobs? For now let's skip or queue?
# Simple approach: Skip if busy.
self.log(">>> Jadwal Skip (App Sibuk) untuk Job ID: {}".format(job_id))
# Concurrent jobs? Queue them!
self.log(">>> App Sibuk. Job ID {} masuk antrian.".format(job_id))
self.job_queue.append(job_id)
return
# --- Check Trial Limit ---
@@ -1370,6 +1373,13 @@ class BackupApp(QMainWindow):
if hasattr(self, 'run_single_btn'):
self.run_single_btn.setEnabled(True)
self.log(">>> Eksekusi Selesai.")
# Check Queue
if self.job_queue:
next_job_id = self.job_queue.pop(0)
self.log(">>> Memproses antrian: Job ID {}".format(next_job_id))
# Use QTimer to schedule it on main thread to be safe, though we are likely already on main thread slot
QTimer.singleShot(100, lambda: self.scheduled_backup_wrapper(next_job_id))
def processing_error(self, error_msg):
self.run_all_btn.setEnabled(True)
@@ -1378,6 +1388,12 @@ class BackupApp(QMainWindow):
if hasattr(self, 'run_single_btn'):
self.run_single_btn.setEnabled(True)
self.log("!!! Kesalahan Thread: {}".format(error_msg))
# Check Queue even on error
if self.job_queue:
next_job_id = self.job_queue.pop(0)
self.log(">>> Memproses antrian (setelah error): Job ID {}".format(next_job_id))
QTimer.singleShot(100, lambda: self.scheduled_backup_wrapper(next_job_id))
# --- Tray ---
def setup_tray(self):