// internal/config/leveldb.go package config import ( "fmt" "os" "path/filepath" "codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/pkg/storage/leveldb" ) // LevelDB support functions - desktop-specific databases // These functions return errors instead of using log.Fatalf to allow proper error handling. // // Storage is organized as follows: // - Global storage (session): {appDir}/session/ // - User-specific storage: {appDir}/users/{emailHash}/{dbName}/ // // This ensures: // 1. Different users have isolated data // 2. Dev and production modes have separate directories ({appName} vs {appName}-dev) // 3. Email addresses are not exposed in directory names (hashed) // getAppDir returns the application data directory path, creating it if needed. // Uses 0700 permissions for security (owner read/write/execute only). // The directory name is mode-aware: "maplefile-dev" for dev mode, "maplefile" for production. func getAppDir() (string, error) { configDir, err := os.UserConfigDir() if err != nil { return "", fmt.Errorf("failed to get user config directory: %w", err) } appName := GetAppName() appDir := filepath.Join(configDir, appName) // Ensure the directory exists with restrictive permissions if err := os.MkdirAll(appDir, 0700); err != nil { return "", fmt.Errorf("failed to create app directory: %w", err) } return appDir, nil } // getUserDir returns the user-specific data directory, creating it if needed. // Returns an error if userEmail is empty (no user logged in). func getUserDir(userEmail string) (string, error) { if userEmail == "" { return "", fmt.Errorf("no user email provided - user must be logged in") } appName := GetAppName() userDir, err := GetUserSpecificDataDir(appName, userEmail) if err != nil { return "", fmt.Errorf("failed to get user data directory: %w", err) } return userDir, nil } // ============================================================================= // GLOBAL STORAGE PROVIDERS (not user-specific) // ============================================================================= // NewLevelDBConfigurationProviderForSession returns a LevelDB configuration provider for user sessions. // Session storage is GLOBAL (not per-user) because it stores the current login session. func NewLevelDBConfigurationProviderForSession() (leveldb.LevelDBConfigurationProvider, error) { appDir, err := getAppDir() if err != nil { return nil, fmt.Errorf("session storage: %w", err) } return leveldb.NewLevelDBConfigurationProvider(appDir, "session"), nil } // ============================================================================= // USER-SPECIFIC STORAGE PROVIDERS // These require a logged-in user's email to determine the storage path. // ============================================================================= // NewLevelDBConfigurationProviderForLocalFilesWithUser returns a LevelDB configuration provider // for local file metadata, scoped to a specific user. func NewLevelDBConfigurationProviderForLocalFilesWithUser(userEmail string) (leveldb.LevelDBConfigurationProvider, error) { userDir, err := getUserDir(userEmail) if err != nil { return nil, fmt.Errorf("local files storage: %w", err) } return leveldb.NewLevelDBConfigurationProvider(userDir, "local_files"), nil } // NewLevelDBConfigurationProviderForSyncStateWithUser returns a LevelDB configuration provider // for sync state, scoped to a specific user. func NewLevelDBConfigurationProviderForSyncStateWithUser(userEmail string) (leveldb.LevelDBConfigurationProvider, error) { userDir, err := getUserDir(userEmail) if err != nil { return nil, fmt.Errorf("sync state storage: %w", err) } return leveldb.NewLevelDBConfigurationProvider(userDir, "sync_state"), nil } // NewLevelDBConfigurationProviderForCacheWithUser returns a LevelDB configuration provider // for local cache, scoped to a specific user. func NewLevelDBConfigurationProviderForCacheWithUser(userEmail string) (leveldb.LevelDBConfigurationProvider, error) { userDir, err := getUserDir(userEmail) if err != nil { return nil, fmt.Errorf("cache storage: %w", err) } return leveldb.NewLevelDBConfigurationProvider(userDir, "cache"), nil } // NewLevelDBConfigurationProviderForUserDataWithUser returns a LevelDB configuration provider // for user-specific data, scoped to a specific user. func NewLevelDBConfigurationProviderForUserDataWithUser(userEmail string) (leveldb.LevelDBConfigurationProvider, error) { userDir, err := getUserDir(userEmail) if err != nil { return nil, fmt.Errorf("user data storage: %w", err) } return leveldb.NewLevelDBConfigurationProvider(userDir, "user_data"), nil } // ============================================================================= // LEGACY FUNCTIONS (deprecated - use user-specific versions instead) // These exist for backward compatibility during migration. // ============================================================================= // NewLevelDBConfigurationProviderForCache returns a LevelDB configuration provider for local cache. // Deprecated: Use NewLevelDBConfigurationProviderForCacheWithUser instead. func NewLevelDBConfigurationProviderForCache() (leveldb.LevelDBConfigurationProvider, error) { appDir, err := getAppDir() if err != nil { return nil, fmt.Errorf("cache storage: %w", err) } return leveldb.NewLevelDBConfigurationProvider(appDir, "cache"), nil } // NewLevelDBConfigurationProviderForLocalFiles returns a LevelDB configuration provider for local file metadata. // Deprecated: Use NewLevelDBConfigurationProviderForLocalFilesWithUser instead. func NewLevelDBConfigurationProviderForLocalFiles() (leveldb.LevelDBConfigurationProvider, error) { appDir, err := getAppDir() if err != nil { return nil, fmt.Errorf("local files storage: %w", err) } return leveldb.NewLevelDBConfigurationProvider(appDir, "local_files"), nil } // NewLevelDBConfigurationProviderForSyncState returns a LevelDB configuration provider for sync state. // Deprecated: Use NewLevelDBConfigurationProviderForSyncStateWithUser instead. func NewLevelDBConfigurationProviderForSyncState() (leveldb.LevelDBConfigurationProvider, error) { appDir, err := getAppDir() if err != nil { return nil, fmt.Errorf("sync state storage: %w", err) } return leveldb.NewLevelDBConfigurationProvider(appDir, "sync_state"), nil } // NewLevelDBConfigurationProviderForUser returns a LevelDB configuration provider for user data. // Deprecated: Use NewLevelDBConfigurationProviderForUserDataWithUser instead. func NewLevelDBConfigurationProviderForUser() (leveldb.LevelDBConfigurationProvider, error) { appDir, err := getAppDir() if err != nil { return nil, fmt.Errorf("user storage: %w", err) } return leveldb.NewLevelDBConfigurationProvider(appDir, "user"), nil }