sync
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
import os
|
||||
import sqlite3
|
||||
import smbclient
|
||||
import tempfile
|
||||
import json
|
||||
import threading
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
# --- App Initialization & Path Configuration ---
|
||||
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
|
||||
INSTANCE_PATH = os.path.join(os.path.dirname(APP_ROOT), 'instance')
|
||||
LOCAL_DB_PATH = "local_cache.db"
|
||||
CONFIG_FILE = "config.json"
|
||||
REMOTE_DB_LOCK = threading.Lock()
|
||||
DB_PATH = "//servervm.local/main/appdata/stashapp/config/stash-go.sqlite"
|
||||
credentials = {}
|
||||
|
||||
def get_local_db():
|
||||
db_path = os.path.join(INSTANCE_PATH, LOCAL_DB_PATH)
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
def init_local_db():
|
||||
"""Initializes and resets cache tables to ensure schema is correct."""
|
||||
try:
|
||||
os.makedirs(INSTANCE_PATH)
|
||||
except OSError:
|
||||
pass # Already exists
|
||||
with get_local_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("CREATE TABLE IF NOT EXISTS config (key TEXT PRIMARY KEY, value TEXT)")
|
||||
cursor.execute("CREATE TABLE IF NOT EXISTS sync_metadata (key TEXT PRIMARY KEY, value TEXT)")
|
||||
# cursor.execute("CREATE TABLE IF NOT EXISTS scan_history (id INTEGER PRIMARY KEY AUTOINCREMENT, scan_type TEXT NOT NULL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, status TEXT NOT NULL, message TEXT, log TEXT)")
|
||||
# cursor.execute("CREATE TABLE IF NOT EXISTS duplicate_results (id INTEGER PRIMARY KEY AUTOINCREMENT, scan_id INTEGER NOT NULL, file_path TEXT NOT NULL, file_size INTEGER, file_basename TEXT, set_id INTEGER NOT NULL, FOREIGN KEY (scan_id) REFERENCES scan_history (id) ON DELETE CASCADE)")
|
||||
# cursor.execute("CREATE TABLE IF NOT EXISTS transcode_plan_results (id INTEGER PRIMARY KEY AUTOINCREMENT, scan_id INTEGER NOT NULL, original_path TEXT NOT NULL, transcoded_path TEXT NOT NULL, FOREIGN KEY (scan_id) REFERENCES scan_history (id) ON DELETE CASCADE)")
|
||||
|
||||
print("Rebuilding local cache tables to ensure schema is up-to-date.")
|
||||
cursor.execute("DROP TABLE IF EXISTS scenes")
|
||||
cursor.execute("DROP TABLE IF EXISTS files")
|
||||
cursor.execute("DROP TABLE IF EXISTS paths")
|
||||
cursor.execute("CREATE TABLE scenes (id INTEGER PRIMARY KEY, oshash TEXT)")
|
||||
cursor.execute("CREATE TABLE files (scene_id INTEGER, path TEXT, basename TEXT, path_id INTEGER)")
|
||||
cursor.execute("CREATE TABLE paths (id INTEGER PRIMARY KEY, path TEXT)")
|
||||
conn.commit()
|
||||
|
||||
def load_credentials():
|
||||
global credentials
|
||||
# In a test script, we can simplify this to just load from the migrated file
|
||||
# if it exists, for simplicity.
|
||||
old_config_path = os.path.join(os.path.dirname(APP_ROOT), CONFIG_FILE + ".migrated")
|
||||
if os.path.exists(old_config_path):
|
||||
print("Migrating credentials from config.json.migrated...")
|
||||
try:
|
||||
with open(old_config_path, "r") as f:
|
||||
credentials = json.load(f)
|
||||
print("Successfully loaded credentials from migrated config.")
|
||||
except (json.JSONDecodeError, OSError) as e:
|
||||
print(f"Error loading from config.json.migrated: {e}")
|
||||
credentials = {}
|
||||
else:
|
||||
print("config.json.migrated not found. No credentials loaded.")
|
||||
|
||||
def get_smb_credentials(path):
|
||||
server = path.split("/")[2].split('@')[-1]
|
||||
return credentials.get(server, {})
|
||||
|
||||
def sync_remote_db():
|
||||
print("Background sync thread started.")
|
||||
print("Sync thread trying to acquire DB lock...")
|
||||
with REMOTE_DB_LOCK:
|
||||
print("Sync thread acquired DB lock.")
|
||||
try:
|
||||
creds = get_smb_credentials(DB_PATH)
|
||||
remote_stat = smbclient.stat(DB_PATH, **creds)
|
||||
remote_mtime = remote_stat.st_mtime
|
||||
except Exception as e:
|
||||
print(f"Sync thread failed to check remote DB status: {e}")
|
||||
return
|
||||
|
||||
with get_local_db() as conn_local:
|
||||
row = conn_local.execute("SELECT value FROM sync_metadata WHERE key = 'last_sync_mtime'").fetchone()
|
||||
last_sync_mtime = float(row['value']) if (row and row['value']) else 0
|
||||
|
||||
# For testing, let's always sync
|
||||
# if remote_mtime <= last_sync_mtime:
|
||||
# print("Local database is already up to date.")
|
||||
# return
|
||||
|
||||
print(f"Remote DB is newer. Syncing from {remote_mtime} > {last_sync_mtime}.")
|
||||
temp_db_path = None
|
||||
try:
|
||||
with smbclient.open_file(DB_PATH, mode='rb', **creds) as smb_file:
|
||||
with tempfile.NamedTemporaryFile(delete=False, suffix=".sqlite") as temp_db:
|
||||
temp_db.write(smb_file.read())
|
||||
temp_db_path = temp_db.name
|
||||
|
||||
with sqlite3.connect(temp_db_path) as conn_remote:
|
||||
conn_local.execute("DELETE FROM scenes"); conn_local.execute("DELETE FROM files"); conn_local.execute("DELETE FROM paths")
|
||||
|
||||
cursor_remote_scenes = conn_remote.execute("SELECT id, oshash FROM scenes")
|
||||
conn_local.executemany("INSERT INTO scenes (id, oshash) VALUES (?, ?)", cursor_remote_scenes)
|
||||
|
||||
cursor_remote_files = conn_remote.execute("SELECT scene_id, path, basename, path_id FROM files")
|
||||
conn_local.executemany("INSERT INTO files (scene_id, path, basename, path_id) VALUES (?, ?, ?, ?)", cursor_remote_files)
|
||||
|
||||
cursor_remote_paths = conn_remote.execute("SELECT id, path FROM paths")
|
||||
conn_local.executemany("INSERT INTO paths (id, path) VALUES (?, ?)", cursor_remote_paths)
|
||||
|
||||
conn_local.execute("REPLACE INTO sync_metadata (key, value) VALUES (?, ?)", ('last_sync_mtime', remote_mtime))
|
||||
conn_local.commit()
|
||||
print("Database sync completed successfully.")
|
||||
except sqlite3.Error as e:
|
||||
print(f"Error during database sync: {e}")
|
||||
conn_local.rollback()
|
||||
finally:
|
||||
if temp_db_path and os.path.exists(temp_db_path): os.remove(temp_db_path)
|
||||
print("Sync thread released DB lock.")
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Setting up test environment...")
|
||||
init_local_db()
|
||||
load_credentials()
|
||||
|
||||
print("\nStarting DB sync test...")
|
||||
sync_remote_db()
|
||||
print("\nDB sync test finished.")
|
||||
|
||||
print("\nVerifying local database content...")
|
||||
with get_local_db() as conn:
|
||||
scenes_count = conn.execute("SELECT COUNT(*) FROM scenes").fetchone()[0]
|
||||
files_count = conn.execute("SELECT COUNT(*) FROM files").fetchone()[0]
|
||||
paths_count = conn.execute("SELECT COUNT(*) FROM paths").fetchone()[0]
|
||||
print(f"Scenes table count: {scenes_count}")
|
||||
print(f"Files table count: {files_count}")
|
||||
print(f"Paths table count: {paths_count}")
|
||||
|
||||
if scenes_count > 0 and files_count > 0 and paths_count > 0:
|
||||
print("\nVerification successful: Local database appears to be populated.")
|
||||
else:
|
||||
print("\nVerification failed: Local database is empty after sync.")
|
||||
Reference in New Issue
Block a user