{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}

module Simplex.Messaging.Server.Main.Init
  ( InitOptions (..),
    ServerPassword (..),
    defaultControlPort,
    defaultDBOpts,
    defaultDeletedTTL,
    iniFileContent,
    informationIniContent,
    iniDbOpts,
    optDisabled,
    optDisabled',
  ) where

import Data.Int (Int64)
import qualified Data.List.NonEmpty as L
import Data.Maybe (fromMaybe, isNothing)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Text.Encoding (decodeLatin1)
import Network.Socket (HostName)
import Simplex.Messaging.Agent.Store.Postgres.Options (DBOpts (..))
import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Protocol (BasicAuth)
import Simplex.Messaging.Server.CLI (SignAlgorithm, onOff)
import Simplex.Messaging.Server.Env.STM
import Simplex.Messaging.Server.Expiration (ExpirationConfig (..))
import Simplex.Messaging.Server.Information (Entity (..), ServerPublicInfo (..))
import Simplex.Messaging.Transport.Client (SocksProxy, TransportHost)
import Simplex.Messaging.Util (safeDecodeUtf8, tshow)
import System.FilePath ((</>))

defaultControlPort :: Int
defaultControlPort :: Int
defaultControlPort = Int
5224

defaultDBOpts :: DBOpts
defaultDBOpts :: DBOpts
defaultDBOpts =
  DBOpts
    { connstr :: ByteString
connstr = ByteString
"postgresql://smp@/smp_server_store",
      schema :: ByteString
schema = ByteString
"smp_server",
      poolSize :: Natural
poolSize = Natural
10,
      createSchema :: Bool
createSchema = Bool
False
    }

-- time to retain deleted queues in the database (days), for debugging
defaultDeletedTTL :: Int64
defaultDeletedTTL :: Int64
defaultDeletedTTL = Int64
21

data InitOptions = InitOptions
  { InitOptions -> Bool
enableStoreLog :: Bool,
    InitOptions -> DBOpts
dbOptions :: DBOpts,
    InitOptions -> Bool
logStats :: Bool,
    InitOptions -> SignAlgorithm
signAlgorithm :: SignAlgorithm,
    InitOptions -> HostName
ip :: HostName,
    InitOptions -> Maybe HostName
fqdn :: Maybe HostName,
    InitOptions -> Maybe ServerPassword
password :: Maybe ServerPassword,
    InitOptions -> Maybe Int
controlPort :: Maybe Int,
    InitOptions -> Maybe SocksProxy
socksProxy :: Maybe SocksProxy,
    InitOptions -> Maybe (NonEmpty TransportHost)
ownDomains :: Maybe (L.NonEmpty TransportHost),
    InitOptions -> Maybe Text
sourceCode :: Maybe Text,
    InitOptions -> ServerPublicInfo
serverInfo :: ServerPublicInfo,
    InitOptions -> Maybe Text
operatorCountry :: Maybe Text,
    InitOptions -> Maybe Text
hostingCountry :: Maybe Text,
    InitOptions -> Maybe HostName
webStaticPath :: Maybe FilePath,
    InitOptions -> Bool
disableWeb :: Bool,
    InitOptions -> Bool
scripted :: Bool
  }
  deriving (Int -> InitOptions -> ShowS
[InitOptions] -> ShowS
InitOptions -> HostName
(Int -> InitOptions -> ShowS)
-> (InitOptions -> HostName)
-> ([InitOptions] -> ShowS)
-> Show InitOptions
forall a.
(Int -> a -> ShowS) -> (a -> HostName) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> InitOptions -> ShowS
showsPrec :: Int -> InitOptions -> ShowS
$cshow :: InitOptions -> HostName
show :: InitOptions -> HostName
$cshowList :: [InitOptions] -> ShowS
showList :: [InitOptions] -> ShowS
Show)

data ServerPassword = ServerPassword BasicAuth | SPRandom
  deriving (Int -> ServerPassword -> ShowS
[ServerPassword] -> ShowS
ServerPassword -> HostName
(Int -> ServerPassword -> ShowS)
-> (ServerPassword -> HostName)
-> ([ServerPassword] -> ShowS)
-> Show ServerPassword
forall a.
(Int -> a -> ShowS) -> (a -> HostName) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ServerPassword -> ShowS
showsPrec :: Int -> ServerPassword -> ShowS
$cshow :: ServerPassword -> HostName
show :: ServerPassword -> HostName
$cshowList :: [ServerPassword] -> ShowS
showList :: [ServerPassword] -> ShowS
Show)

iniFileContent :: FilePath -> FilePath -> InitOptions -> HostName -> Maybe BasicAuth -> Maybe (Text, Text) -> Text
iniFileContent :: HostName
-> HostName
-> InitOptions
-> HostName
-> Maybe BasicAuth
-> Maybe (Text, Text)
-> Text
iniFileContent HostName
cfgPath HostName
logPath InitOptions
opts HostName
host Maybe BasicAuth
basicAuth Maybe (Text, Text)
controlPortPwds =
  InitOptions -> Text
informationIniContent InitOptions
opts
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"[STORE_LOG]\n\
        \# The server uses memory or PostgreSQL database for persisting queue records.\n\
        \# Use `enable = on` to use append-only log to preserve and restore queue records on restart.\n\
        \# Log is compacted on start (deleted objects are removed).\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"enable = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Bool -> Text
onOff Bool
enableStoreLog Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"# Queue storage mode: `memory` or `database` (to store queue records in PostgreSQL database).\n\
        \# `memory` - in-memory persistence, with optional append-only log (`enable = on`).\n\
        \# `database`- PostgreSQL databass (requires `store_messages = journal`).\n\
        \store_queues = memory\n\n\
        \# Database connection settings for PostgreSQL database (`store_queues = database`).\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> DBOpts -> DBOpts -> Text
iniDbOpts DBOpts
dbOptions DBOpts
defaultDBOpts
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"# Write database changes to store log file\n\
        \# db_store_log = off\n\n\
        \# Time to retain deleted queues in the database, days.\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"# db_deleted_ttl = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int64 -> Text
forall a. Show a => a -> Text
tshow Int64
defaultDeletedTTL Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"# Message storage mode: `memory` or `journal`.\n\
        \store_messages = memory\n\n\
        \# When store_messages is `memory`, undelivered messages are optionally saved and restored\n\
        \# when the server restarts, they are preserved in the .bak file until the next restart.\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"restore_messages = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Bool -> Text
onOff Bool
enableStoreLog Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"# Messages and notifications expiration periods.\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"expire_messages_days = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int64 -> Text
forall a. Show a => a -> Text
tshow Int64
defMsgExpirationDays Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"expire_messages_on_start = on\n\
        \expire_messages_on_send = off\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"expire_ntfs_hours = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int64 -> Text
forall a. Show a => a -> Text
tshow Int64
defNtfExpirationHours Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"# Log daily server statistics to CSV file\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"log_stats = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Bool -> Text
onOff Bool
logStats Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"# Log interval for real-time Prometheus metrics\n\
        \# prometheus_interval = 60\n\n\
        \[AUTH]\n\
        \# Set new_queues option to off to completely prohibit creating new messaging queues.\n\
        \# This can be useful when you want to decommission the server, but not all connections are switched yet.\n\
        \new_queues = on\n\n\
        \# Use create_password option to enable basic auth to create new messaging queues.\n\
        \# The password should be used as part of server address in client configuration:\n\
        \# smp://fingerprint:password@host1,host2\n\
        \# The password will not be shared with the connecting contacts, you must share it only\n\
        \# with the users who you want to allow creating messaging queues on your server.\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ( let noPassword :: Text
noPassword = Text
"password to create new queues and forward messages (any printable ASCII characters without whitespace, '@', ':' and '/')"
          in Maybe BasicAuth -> Text
forall a. Maybe a -> Text
optDisabled Maybe BasicAuth
basicAuth Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"create_password = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> (BasicAuth -> Text) -> Maybe BasicAuth -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
noPassword (ByteString -> Text
safeDecodeUtf8 (ByteString -> Text)
-> (BasicAuth -> ByteString) -> BasicAuth -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BasicAuth -> ByteString
forall a. StrEncoding a => a -> ByteString
strEncode) Maybe BasicAuth
basicAuth
        )
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Maybe (Text, Text) -> Text
forall a. Maybe a -> Text
optDisabled Maybe (Text, Text)
controlPortPwds Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"control_port_admin_password = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> ((Text, Text) -> Text) -> Maybe (Text, Text) -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"" (Text, Text) -> Text
forall a b. (a, b) -> a
fst Maybe (Text, Text)
controlPortPwds Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Maybe (Text, Text) -> Text
forall a. Maybe a -> Text
optDisabled Maybe (Text, Text)
controlPortPwds Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"control_port_user_password = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> ((Text, Text) -> Text) -> Maybe (Text, Text) -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"" (Text, Text) -> Text
forall a b. (a, b) -> b
snd Maybe (Text, Text)
controlPortPwds Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"# The limit for queues that can be blocked via control port per day, resets at 0:00 UTC.\n\
        \# Set to 0 to disable limit, to -1 to prohibit blocking. Default is 20.\n\
        \# daily_block_queue_quota = 20\n\
        \\n\
        \[TRANSPORT]\n\
        \# Host is only used to print server address on start.\n\
        \# You can specify multiple server ports.\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"host = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> HostName -> Text
T.pack HostName
host Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"port = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
defaultServerPorts Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"log_tls_errors = off\n\n\
        \# Use `websockets = 443` to run websockets server in addition to plain TLS.\n\
        \# This option is deprecated and should be used for testing only.\n\
        \# , port 443 should be specified in port above\n\
        \websockets = off\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Maybe Int -> Text
forall a. Maybe a -> Text
optDisabled Maybe Int
controlPort Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"control_port = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall a. Show a => a -> Text
tshow (Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
defaultControlPort Maybe Int
controlPort))
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n\
        \[PROXY]\n\
        \# Network configuration for SMP proxy client.\n\
        \# `host_mode` can be 'public' (default) or 'onion'.\n\
        \# It defines prefferred hostname for destination servers with multiple hostnames.\n\
        \# host_mode = public\n\
        \# required_host_mode = off\n\n\
        \# The domain suffixes of the relays you operate (space-separated) to count as separate proxy statistics.\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Maybe (NonEmpty TransportHost) -> Text
forall a. Maybe a -> Text
optDisabled Maybe (NonEmpty TransportHost)
ownDomains Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"own_server_domains = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
-> (NonEmpty TransportHost -> Text)
-> Maybe (NonEmpty TransportHost)
-> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"" (ByteString -> Text
safeDecodeUtf8 (ByteString -> Text)
-> (NonEmpty TransportHost -> ByteString)
-> NonEmpty TransportHost
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty TransportHost -> ByteString
forall a. StrEncoding a => a -> ByteString
strEncode) Maybe (NonEmpty TransportHost)
ownDomains)
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n\
        \# SOCKS proxy port for forwarding messages to destination servers.\n\
        \# You may need a separate instance of SOCKS proxy for incoming single-hop requests.\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Maybe SocksProxy -> Text
forall a. Maybe a -> Text
optDisabled Maybe SocksProxy
socksProxy Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"socks_proxy = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> (SocksProxy -> Text) -> Maybe SocksProxy -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"localhost:9050" (ByteString -> Text
safeDecodeUtf8 (ByteString -> Text)
-> (SocksProxy -> ByteString) -> SocksProxy -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SocksProxy -> ByteString
forall a. StrEncoding a => a -> ByteString
strEncode) Maybe SocksProxy
socksProxy)
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n\
        \# `socks_mode` can be 'onion' for SOCKS proxy to be used for .onion destination hosts only (default)\n\
        \# or 'always' to be used for all destination hosts (can be used if it is an .onion server).\n\
        \# socks_mode = onion\n\n\
        \# Limit number of threads a client can spawn to process proxy commands in parrallel.\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"# client_concurrency = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall a. Show a => a -> Text
tshow Int
defaultProxyClientConcurrency)
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n\
        \[INACTIVE_CLIENTS]\n\
        \# TTL and interval to check inactive clients\n\
        \disconnect = on\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"ttl = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int64 -> Text
forall a. Show a => a -> Text
tshow (ExpirationConfig -> Int64
ttl ExpirationConfig
defaultInactiveClientExpiration) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"check_interval = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int64 -> Text
forall a. Show a => a -> Text
tshow (ExpirationConfig -> Int64
checkInterval ExpirationConfig
defaultInactiveClientExpiration))
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n\
        \[WEB]\n\
        \# Set path to generate static mini-site for server information and qr codes/links\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"static_path = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> HostName -> Text
T.pack (HostName -> Maybe HostName -> HostName
forall a. a -> Maybe a -> a
fromMaybe HostName
defaultStaticPath Maybe HostName
webStaticPath) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"# Run an embedded server on this port\n\
        \# Onion sites can use any port and register it in the hidden service config.\n\
        \# Running on a port 80 may require setting process capabilities.\n\
        \# http = 8000\n\n\
        \# You can run an embedded TLS web server too if you provide port and cert and key files.\n\
        \# Not required for running relay on onion address.\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
webDisabled Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"https = 443\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
webDisabled Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"cert = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> HostName -> Text
T.pack HostName
httpsCertFile Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
webDisabled Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"key = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> HostName -> Text
T.pack HostName
httpsKeyFile Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n")
  where
    InitOptions {Bool
$sel:enableStoreLog:InitOptions :: InitOptions -> Bool
enableStoreLog :: Bool
enableStoreLog, DBOpts
$sel:dbOptions:InitOptions :: InitOptions -> DBOpts
dbOptions :: DBOpts
dbOptions, Maybe SocksProxy
$sel:socksProxy:InitOptions :: InitOptions -> Maybe SocksProxy
socksProxy :: Maybe SocksProxy
socksProxy, Maybe (NonEmpty TransportHost)
$sel:ownDomains:InitOptions :: InitOptions -> Maybe (NonEmpty TransportHost)
ownDomains :: Maybe (NonEmpty TransportHost)
ownDomains, Maybe Int
$sel:controlPort:InitOptions :: InitOptions -> Maybe Int
controlPort :: Maybe Int
controlPort, Maybe HostName
$sel:webStaticPath:InitOptions :: InitOptions -> Maybe HostName
webStaticPath :: Maybe HostName
webStaticPath, Bool
$sel:disableWeb:InitOptions :: InitOptions -> Bool
disableWeb :: Bool
disableWeb, Bool
$sel:logStats:InitOptions :: InitOptions -> Bool
logStats :: Bool
logStats} = InitOptions
opts
    defaultServerPorts :: Text
defaultServerPorts = Text
"5223,443"
    defaultStaticPath :: HostName
defaultStaticPath = HostName
logPath HostName -> ShowS
</> HostName
"www"
    httpsCertFile :: HostName
httpsCertFile = HostName
cfgPath HostName -> ShowS
</> HostName
"web.crt"
    httpsKeyFile :: HostName
httpsKeyFile = HostName
cfgPath HostName -> ShowS
</> HostName
"web.key"
    webDisabled :: Text
webDisabled = if Bool
disableWeb then Text
"# " else Text
""

informationIniContent :: InitOptions -> Text
informationIniContent :: InitOptions -> Text
informationIniContent InitOptions {Maybe Text
$sel:sourceCode:InitOptions :: InitOptions -> Maybe Text
sourceCode :: Maybe Text
sourceCode, ServerPublicInfo
$sel:serverInfo:InitOptions :: InitOptions -> ServerPublicInfo
serverInfo :: ServerPublicInfo
serverInfo} =
  Text
"[INFORMATION]\n\
  \# AGPLv3 license requires that you make any source code modifications\n\
  \# available to the end users of the server.\n\
  \# LICENSE: https://github.com/simplex-chat/simplexmq/blob/stable/LICENSE\n\
  \# Include correct source code URI in case the server source code is modified in any way.\n\
  \# If any other information fields are present, source code property also MUST be present.\n\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Maybe Text -> Text
forall a. Maybe a -> Text
optDisabled Maybe Text
sourceCode Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"source_code = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
"URI" Maybe Text
sourceCode)
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n\
       \# Declaring all below information is optional, any of these fields can be omitted.\n\
       \\n\
       \# Server usage conditions and amendments.\n\
       \# It is recommended to use standard conditions with any amendments in a separate document.\n\
       \# usage_conditions = https://github.com/simplex-chat/simplex-chat/blob/stable/PRIVACY.md\n\
       \# condition_amendments = link\n\
       \\n\
       \# Server location and operator.\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Maybe Text -> Text
countryStr Text
"server" Maybe Text
serverCountry
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Maybe Entity -> Text
enitiyStrs Text
"operator" Maybe Entity
operator
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Maybe Text -> Text
forall a. Maybe a -> Text
optDisabled Maybe Text
website Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"website = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
"" Maybe Text
website)
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n\
       \# Administrative contacts.\n\
       \# admin_simplex = SimpleX address\n\
       \# admin_email =\n\
       \# admin_pgp =\n\
       \# admin_pgp_fingerprint =\n\
       \\n\
       \# Contacts for complaints and feedback.\n\
       \# complaints_simplex = SimpleX address\n\
       \# complaints_email =\n\
       \# complaints_pgp =\n\
       \# complaints_pgp_fingerprint =\n\
       \\n\
       \# Hosting provider.\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Maybe Entity -> Text
enitiyStrs Text
"hosting" Maybe Entity
hosting
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\
       \# Hosting type can be `virtual`, `dedicated`, `colocation`, `owned`\n"
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text
"hosting_type = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> (HostingType -> Text) -> Maybe HostingType -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"virtual" (ByteString -> Text
decodeLatin1 (ByteString -> Text)
-> (HostingType -> ByteString) -> HostingType -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HostingType -> ByteString
forall a. StrEncoding a => a -> ByteString
strEncode) Maybe HostingType
hostingType Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n")
  where
    ServerPublicInfo {Maybe Entity
operator :: Maybe Entity
$sel:operator:ServerPublicInfo :: ServerPublicInfo -> Maybe Entity
operator, Maybe Text
website :: Maybe Text
$sel:website:ServerPublicInfo :: ServerPublicInfo -> Maybe Text
website, Maybe Entity
hosting :: Maybe Entity
$sel:hosting:ServerPublicInfo :: ServerPublicInfo -> Maybe Entity
hosting, Maybe HostingType
hostingType :: Maybe HostingType
$sel:hostingType:ServerPublicInfo :: ServerPublicInfo -> Maybe HostingType
hostingType, Maybe Text
serverCountry :: Maybe Text
$sel:serverCountry:ServerPublicInfo :: ServerPublicInfo -> Maybe Text
serverCountry} = ServerPublicInfo
serverInfo
    countryStr :: Text -> Maybe Text -> Text
countryStr Text
optName Maybe Text
country = Maybe Text -> Text
forall a. Maybe a -> Text
optDisabled Maybe Text
country Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
optName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_country = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
"ISO-3166 2-letter code" Maybe Text
country Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n"
    enitiyStrs :: Text -> Maybe Entity -> Text
enitiyStrs Text
optName Maybe Entity
entity =
      Maybe Entity -> Text
forall a. Maybe a -> Text
optDisabled Maybe Entity
entity
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
optName
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" = "
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> (Entity -> Text) -> Maybe Entity -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"entity (organization or person name)" Entity -> Text
name Maybe Entity
entity
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n"
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Maybe Text -> Text
countryStr Text
optName (Entity -> Maybe Text
country (Entity -> Maybe Text) -> Maybe Entity -> Maybe Text
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Entity
entity)

iniDbOpts :: DBOpts -> DBOpts -> Text
iniDbOpts :: DBOpts -> DBOpts -> Text
iniDbOpts DBOpts {ByteString
connstr :: DBOpts -> ByteString
connstr :: ByteString
connstr, ByteString
schema :: DBOpts -> ByteString
schema :: ByteString
schema, Natural
poolSize :: DBOpts -> Natural
poolSize :: Natural
poolSize} DBOpts {connstr :: DBOpts -> ByteString
connstr = ByteString
defConnstr, schema :: DBOpts -> ByteString
schema = ByteString
defSchema, poolSize :: DBOpts -> Natural
poolSize = Natural
defPoolSize} =
  (Bool -> Text
optDisabled' (ByteString
connstr ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
defConnstr) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"db_connection = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ByteString -> Text
safeDecodeUtf8 ByteString
connstr Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Bool -> Text
optDisabled' (ByteString
schema ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
defSchema) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"db_schema = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ByteString -> Text
safeDecodeUtf8 ByteString
schema Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n")
    Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Bool -> Text
optDisabled' (Natural
poolSize Natural -> Natural -> Bool
forall a. Eq a => a -> a -> Bool
== Natural
defPoolSize) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"db_pool_size = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Natural -> Text
forall a. Show a => a -> Text
tshow Natural
poolSize Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n\n")

optDisabled :: Maybe a -> Text
optDisabled :: forall a. Maybe a -> Text
optDisabled = Bool -> Text
optDisabled' (Bool -> Text) -> (Maybe a -> Bool) -> Maybe a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe a -> Bool
forall a. Maybe a -> Bool
isNothing
{-# INLINE optDisabled #-}

optDisabled' :: Bool -> Text
optDisabled' :: Bool -> Text
optDisabled' Bool
cond = if Bool
cond then Text
"# " else Text
""
{-# INLINE optDisabled' #-}