content: {-
    Copyright (c) Meta Platforms, Inc. and affiliates.
    All rights reserved.
  
    This source code is licensed under the BSD-style license found in the
    LICENSE file in the root directory of this source tree.
  -}
  
  module Glean.Database.Backup.Locator
    ( fromSiteLocator
    , fromRepoLocator
    , toSiteLocator
    , toRepoLocator
    , getSite
    , getAllSites
    ) where
  
  import qualified Data.Map as Map
  import qualified Data.HashMap.Strict as HashMap
  import Data.Maybe
  import Data.Text (Text)
  import qualified Data.Text as Text
  
  import Util.List
  import Util.STM
  
  import Glean.Database.Backup.Backend as Backend
  import Glean.Database.Types
  import Glean.Repo.Text
  import Glean.ServerConfig.Types (DatabaseBackupPolicy(..))
  import qualified Glean.ServerConfig.Types as ServerConfig
  import Glean.Types
  import Glean.Util.Some
  import Glean.Util.Observed as Observed
  
  fromSiteLocator :: Backends -> Text -> Maybe (Text, Some Site)
  fromSiteLocator backends s = do
    let (prefix,colon_path) = Text.breakOn ":" s
    Some backend <- HashMap.lookup prefix backends
    (_,path) <- Text.uncons colon_path
    site <- fromPath backend path
    return (prefix, site)
  
  -- A repo locator has the following form:
  --  backend_name:some/path/repo.name.hash
  fromRepoLocator :: Backends -> Text -> Maybe (Text, Some Site, Repo)
  fromRepoLocator backends loc = do
    let (site_slash, repo_text) = Text.breakOnEnd "/" loc
    (site_text, _) <- Text.unsnoc site_slash
    (prefix, site) <- fromSiteLocator backends site_text
    repo <- parseRepoTextSep "." repo_text
    return (prefix, site, repo)
  
  toSiteLocator :: Site site => Text -> site -> Text
  toSiteLocator prefix site = prefix <> ":" <> toPath site
  
  toRepoLocator :: Site site => Text -> site -> Repo -> Text
  toRepoLocator prefix site repo =
    toSiteLocator prefix site <> "/" <> repoToTextSep "." repo
  
  getSite :: Env -> Text -> STM (Maybe (Text, Some Site))
  getSite Env{..} repoName = do
    policy <- ServerConfig.config_backup <$> Observed.get envServerConfig
    let locator = Map.findWithDefault
          (databaseBackupPolicy_location policy)
          repoName
          (Map.map ServerConfig.backup_location $
            databaseBackupPolicy_repos policy)
    return $ fromSiteLocator envBackupBackends locator
  
  getAllSites :: Env -> STM [(Text, Some Site)]
  getAllSites Env{..} = do
    policy <- ServerConfig.config_backup <$> Observed.get envServerConfig
    return $
      mapMaybe (fromSiteLocator envBackupBackends) $
      uniq $ -- don't forget to remove duplicates
        databaseBackupPolicy_location policy :
        map ServerConfig.backup_location
          (Map.elems $ databaseBackupPolicy_repos policy)
  