package rms import ( "fmt" "sync" "github.com/google/uuid" "go.uber.org/zap" "rmser/internal/domain/account" "rmser/pkg/crypto" "rmser/pkg/logger" ) // Factory управляет созданием и переиспользованием клиентов RMS type Factory struct { accountRepo account.Repository cryptoManager *crypto.CryptoManager // Кэш активных клиентов: ServerID -> *Client mu sync.RWMutex clients map[uuid.UUID]*Client } func NewFactory(repo account.Repository, cm *crypto.CryptoManager) *Factory { return &Factory{ accountRepo: repo, cryptoManager: cm, clients: make(map[uuid.UUID]*Client), } } // GetClientForUser возвращает клиент для текущего активного сервера пользователя. // Использует личные или наследуемые (от Owner) учетные данные. func (f *Factory) GetClientForUser(userID uuid.UUID) (ClientI, error) { // 1. Пытаемся найти в кэше f.mu.RLock() client, exists := f.clients[userID] f.mu.RUnlock() if exists { return client, nil } // 2. Создаем новый клиент под блокировкой f.mu.Lock() defer f.mu.Unlock() // Double check if client, exists := f.clients[userID]; exists { return client, nil } // 3. Получаем креды из репозитория (учитывая фоллбэк на Owner'а) baseURL, login, encryptedPass, err := f.accountRepo.GetActiveConnectionCredentials(userID) if err != nil { return nil, fmt.Errorf("ошибка получения настроек подключения: %w", err) } // 4. Расшифровка пароля plainPass, err := f.cryptoManager.Decrypt(encryptedPass) if err != nil { return nil, fmt.Errorf("ошибка расшифровки пароля RMS: %w", err) } // 5. Создание клиента newClient := NewClient(baseURL, login, plainPass) f.clients[userID] = newClient logger.Log.Info("RMS Factory: Client created for user", zap.String("user_id", userID.String()), zap.String("login", login), zap.String("url", baseURL)) return newClient, nil } // CreateClientFromRawCredentials создает клиент без сохранения в кэш (для тестов подключения) func (f *Factory) CreateClientFromRawCredentials(url, login, password string) *Client { return NewClient(url, login, password) } // ClearCacheForUser сбрасывает кэш пользователя (при смене сервера или выходе) func (f *Factory) ClearCacheForUser(userID uuid.UUID) { f.mu.Lock() defer f.mu.Unlock() delete(f.clients, userID) } // ClearCacheForServer сбрасывает кэш для ВСЕХ пользователей сервера (например, при смене пароля владельцем) // Это дорогая операция, но необходимая при изменении общих кредов. func (f *Factory) ClearCacheForServer(serverID uuid.UUID) { // Пока не реализовано эффективно (нужен обратный индекс). // Для MVP можно просто очистить весь кэш или оставить как есть, // так как токены iiko все равно протухнут. }