2020-03-28 14:38:14 +02:00
package faraday
2019-10-28 15:29:20 +02:00
import (
2020-09-08 10:25:39 +02:00
"crypto/tls"
"crypto/x509"
2019-10-28 15:29:20 +02:00
"fmt"
2026-06-22 10:10:00 +02:00
"math"
2020-08-10 15:08:59 +02:00
"os"
2021-05-31 13:38:12 +02:00
"path"
2020-08-10 15:08:59 +02:00
"path/filepath"
2019-12-16 10:46:18 +02:00
"time"
2019-10-28 15:29:20 +02:00
2022-03-11 15:00:48 -08:00
"github.com/btcsuite/btcd/btcutil"
2022-11-21 17:12:17 +01:00
"github.com/lightninglabs/faraday/chain"
2025-09-24 13:20:46 +02:00
"github.com/lightninglabs/faraday/chanevents"
"github.com/lightninglabs/faraday/db"
"github.com/lightninglabs/faraday/db/sqlc"
2020-09-08 10:01:56 +02:00
"github.com/lightninglabs/lndclient"
2025-03-05 08:40:27 +02:00
"github.com/lightningnetwork/lnd/build"
2020-09-08 10:25:39 +02:00
"github.com/lightningnetwork/lnd/cert"
2025-09-24 13:20:46 +02:00
"github.com/lightningnetwork/lnd/clock"
2020-09-08 10:12:56 +02:00
"github.com/lightningnetwork/lnd/lncfg"
2020-09-08 10:25:39 +02:00
"github.com/lightningnetwork/lnd/lnrpc"
2025-09-24 13:20:46 +02:00
"github.com/lightningnetwork/lnd/sqldb/v2"
2020-09-08 10:25:39 +02:00
"google.golang.org/grpc/credentials"
2019-10-28 15:29:20 +02:00
)
const (
2019-12-16 10:46:18 +02:00
defaultRPCPort = "10009"
defaultRPCHostPort = "localhost:" + defaultRPCPort
2020-09-08 10:01:56 +02:00
DefaultNetwork = "mainnet"
2019-12-16 10:46:18 +02:00
defaultMinimumMonitor = time . Hour * 24 * 7 * 4 // four weeks in hours
2019-12-16 10:46:19 +02:00
defaultDebugLevel = "info"
2020-03-05 17:47:05 +02:00
defaultRPCListen = "localhost:8465"
2020-06-27 14:36:04 +02:00
// By default we do not require connecting to a bitcoin node so that
// we can serve basic functionality by default.
defaultChainConn = false
2021-09-21 13:38:11 +02:00
2024-02-14 15:14:10 +00:00
// defaultTLSCertDuration is the default validity of a self-signed
2021-09-21 13:38:11 +02:00
// certificate. The value corresponds to 14 months
// (14 months * 30 days * 24 hours).
2024-02-14 15:14:10 +00:00
defaultTLSCertDuration = 14 * 30 * 24 * time . Hour
2025-09-24 13:20:46 +02:00
// DatabaseBackendSqlite is the name of the SQLite database backend.
DatabaseBackendSqlite = "sqlite"
// DatabaseBackendPostgres is the name of the Postgres database backend.
DatabaseBackendPostgres = "postgres"
// defaultSqliteDatabaseFileName is the default name of the SQLite
// database file.
defaultSqliteDatabaseFileName = "faraday.db"
2026-06-22 10:10:00 +02:00
// defaultChanEventsMaxEvents is the default maximum number of channel
// events to retain. At roughly 140 bytes per event this acts as a hard
// ceiling of approximately 1 GB. A value of 0 disables the size-based
// limit.
defaultChanEventsMaxEvents = 7000000
// defaultChanEventsRetention is the default retention window for channel
// events. Age-based pruning is disabled by default (0): out of the box
// only the max-events size ceiling bounds the table, and operators opt
// into a retention window explicitly.
defaultChanEventsRetention = 0
2019-10-28 15:29:20 +02:00
)
2020-09-08 10:12:56 +02:00
var (
// FaradayDirBase is the default main directory where faraday stores its
// data.
FaradayDirBase = btcutil . AppDataDir ( "faraday" , false )
2020-09-08 10:17:26 +02:00
// DefaultTLSCertFilename is the default file name for the autogenerated
// TLS certificate.
DefaultTLSCertFilename = "tls.cert"
// DefaultTLSKeyFilename is the default file name for the autogenerated
// TLS key.
DefaultTLSKeyFilename = "tls.key"
2020-09-08 10:25:39 +02:00
defaultSelfSignedOrganization = "faraday autogenerated cert"
2020-09-08 10:17:26 +02:00
// DefaultTLSCertPath is the default full path of the autogenerated TLS
// certificate.
DefaultTLSCertPath = filepath . Join (
FaradayDirBase , DefaultNetwork , DefaultTLSCertFilename ,
)
// DefaultTLSKeyPath is the default full path of the autogenerated TLS
// key.
DefaultTLSKeyPath = filepath . Join (
FaradayDirBase , DefaultNetwork , DefaultTLSKeyFilename ,
)
2020-09-09 10:34:25 +02:00
// DefaultMacaroonFilename is the default file name for the
// autogenerated faraday macaroon.
DefaultMacaroonFilename = "faraday.macaroon"
// DefaultMacaroonPath is the default full path of the base faraday
// macaroon.
DefaultMacaroonPath = filepath . Join (
FaradayDirBase , DefaultNetwork , DefaultMacaroonFilename ,
)
2021-05-31 13:38:12 +02:00
// defaultLndMacaroon is the default macaroon file we use to connect to
// lnd.
2022-01-14 14:58:30 +02:00
defaultLndMacaroon = "admin.macaroon"
2021-05-31 13:38:12 +02:00
// DefaultLndDir is the default location where we look for lnd's tls and
// macaroon files.
DefaultLndDir = btcutil . AppDataDir ( "lnd" , false )
// DefaultLndMacaroonPath is the default location where we look for a
// macaroon to use when connecting to lnd.
DefaultLndMacaroonPath = filepath . Join (
DefaultLndDir , "data" , "chain" , "bitcoin" , DefaultNetwork ,
defaultLndMacaroon ,
)
2020-09-08 10:12:56 +02:00
)
2020-09-08 09:55:14 +02:00
type LndConfig struct {
2019-10-28 15:29:20 +02:00
// RPCServer is host:port that lnd's RPC server is listening on.
RPCServer string ` long:"rpcserver" description:"host:port that LND is listening for RPC connections on" `
2021-05-31 13:38:12 +02:00
// MacaroonDir is the directory that contains all the macaroon files
// required for the remote connection.
MacaroonDir string ` long:"macaroondir" description:"DEPRECATED: Use macaroonpath." `
// MacaroonPath is the path to the single macaroon that should be used
// instead of needing to specify the macaroon directory that contains
// all of lnd's macaroons. The specified macaroon MUST have all
// permissions that all the subservers use, otherwise permission errors
// will occur.
2022-01-14 14:58:30 +02:00
MacaroonPath string ` long:"macaroonpath" description:"The full path to the single macaroon to use, either the admin.macaroon or a custom baked one. Cannot be specified at the same time as macaroondir. A custom macaroon must contain ALL permissions required for all subservers to work, otherwise permission errors will occur." `
2019-10-28 15:29:20 +02:00
2020-03-28 14:38:14 +02:00
// TLSCertPath is the path to the tls cert that faraday should use.
2019-10-28 15:29:20 +02:00
TLSCertPath string ` long:"tlscertpath" description:"Path to TLS cert" `
2023-12-07 19:49:26 +01:00
// RequestTimeout is the maximum time to wait for a response from lnd.
RequestTimeout time . Duration ` long:"requesttimeout" description:"The maximum time to wait for a response from lnd, if not set the default of 30 seconds will be used." `
2020-09-08 09:55:14 +02:00
}
2020-09-08 10:25:39 +02:00
type Config struct { //nolint:maligned
2020-09-08 09:55:14 +02:00
// Lnd holds the configuration options for the connection to lnd.
Lnd * LndConfig ` group:"lnd" namespace:"lnd" `
2019-10-28 15:29:20 +02:00
2020-09-08 10:12:56 +02:00
// FaradayDir is the main directory where faraday stores all its data.
2020-09-09 10:34:25 +02:00
FaradayDir string ` long:"faradaydir" description:"The directory for all of faraday's data. If set, this option overwrites --macaroonpath, --tlscertpath and --tlskeypath." `
2020-09-08 10:12:56 +02:00
2020-06-27 14:36:04 +02:00
// ChainConn specifies whether to attempt connecting to a bitcoin backend.
ChainConn bool ` long:"connect_bitcoin" description:"Whether to attempt to connect to a backing bitcoin node. Some endpoints will not be available if this option is not enabled." `
2020-08-10 15:08:59 +02:00
ShowVersion bool ` long:"version" description:"Display version information and exit" `
2019-12-16 10:46:18 +02:00
// MinimumMonitored is the minimum amount of time that a channel must be monitored for before we consider it for termination.
MinimumMonitored time . Duration ` long:"min_monitored" description:"The minimum amount of time that a channel must be monitored for before recommending termination. Valid time units are { s, m, h}." `
2020-09-08 10:01:56 +02:00
// Network is a string containing the network we're running on.
2024-08-15 16:46:25 +02:00
Network string ` long:"network" description:"The network to run on." choice:"regtest" choice:"testnet" choice:"mainnet" choice:"simnet" choice:"signet" `
2019-12-16 10:46:19 +02:00
// DebugLevel is a string defining the log level for the service either
// for all subsystems the same or individual level by subsystem.
2020-03-28 14:38:14 +02:00
DebugLevel string ` long:"debuglevel" description:"Debug level for faraday and its subsystems." `
2020-01-16 09:13:14 +02:00
2024-02-14 15:14:10 +00:00
TLSCertPath string ` long:"tlscertpath" description:"Path to write the TLS certificate for faraday's RPC and REST services." `
TLSKeyPath string ` long:"tlskeypath" description:"Path to write the TLS private key for faraday's RPC and REST services." `
TLSExtraIPs [ ] string ` long:"tlsextraip" description:"Adds an extra IP to the generated certificate." `
TLSExtraDomains [ ] string ` long:"tlsextradomain" description:"Adds an extra domain to the generated certificate." `
TLSAutoRefresh bool ` long:"tlsautorefresh" description:"Re-generate TLS certificate and key if the IPs or domains are changed." `
TLSDisableAutofill bool ` long:"tlsdisableautofill" description:"Do not include the interface IPs or the system hostname in TLS certificate, use first --tlsextradomain as Common Name instead, if set." `
TLSCertDuration time . Duration ` long:"tlscertduration" description:"The duration for which the auto-generated TLS certificate will be valid for." `
2020-09-08 10:17:26 +02:00
2020-09-09 10:34:25 +02:00
MacaroonPath string ` long:"macaroonpath" description:"Path to write the macaroon for faraday's RPC and REST services if it doesn't exist." `
2020-03-28 14:38:14 +02:00
// RPCListen is the listen address for the faraday rpc server.
2020-04-06 13:58:54 +02:00
RPCListen string ` long:"rpclisten" description:"Address to listen on for gRPC clients." `
// RESTListen is the listen address for the faraday REST server.
RESTListen string ` long:"restlisten" description:"Address to listen on for REST clients. If not specified, no REST listener will be started." `
// CORSOrigin specifies the CORS header that should be set on REST responses. No header is added if the value is empty.
CORSOrigin string ` long:"corsorigin" description:"The value to send in the Access-Control-Allow-Origin header. Header will be omitted if empty." `
2020-06-27 14:36:04 +02:00
// Bitcoin is the configuration required to connect to a bitcoin node.
Bitcoin * chain . BitcoinConfig ` group:"bitcoin" namespace:"bitcoin" `
2025-03-05 08:40:27 +02:00
// Logging controls various aspects of pool logging.
Logging * build . LogConfig ` group:"logging" namespace:"logging" `
2025-09-24 13:20:46 +02:00
// DatabaseBackend is the database backend we will use for storing all
// liveness data.
DatabaseBackend string ` long:"databasebackend" description:"The database backend to use for storing all liveness data." choice:"sqlite" choice:"postgres" `
// Sqlite holds the configuration options for a SQLite database
// backend.
Sqlite * db . SqliteConfig ` group:"sqlite" namespace:"sqlite" `
// Postgres holds the configuration options for a Postgres database
Postgres * sqldb . PostgresConfig ` group:"postgres" namespace:"postgres" `
2026-06-22 10:10:00 +02:00
// ChanEvents holds the configuration options for channel event safety
// pruning.
ChanEvents * chanevents . Config ` group:"chanevents" namespace:"chanevents" `
2019-10-28 15:29:20 +02:00
}
2020-04-30 10:31:46 +02:00
// DefaultConfig returns all default values for the Config struct.
func DefaultConfig ( ) Config {
return Config {
2020-09-08 09:55:14 +02:00
Lnd : & LndConfig {
2021-05-31 13:38:12 +02:00
RPCServer : defaultRPCHostPort ,
MacaroonPath : DefaultLndMacaroonPath ,
2020-09-08 09:55:14 +02:00
} ,
2020-09-08 10:12:56 +02:00
FaradayDir : FaradayDirBase ,
2020-09-08 10:01:56 +02:00
Network : DefaultNetwork ,
2019-12-16 10:46:18 +02:00
MinimumMonitored : defaultMinimumMonitor ,
2019-12-16 10:46:19 +02:00
DebugLevel : defaultDebugLevel ,
2020-09-08 10:17:26 +02:00
TLSCertPath : DefaultTLSCertPath ,
TLSKeyPath : DefaultTLSKeyPath ,
2024-02-14 15:14:10 +00:00
TLSCertDuration : defaultTLSCertDuration ,
2020-09-09 10:34:25 +02:00
MacaroonPath : DefaultMacaroonPath ,
2020-01-16 09:13:14 +02:00
RPCListen : defaultRPCListen ,
2020-06-27 14:36:04 +02:00
ChainConn : defaultChainConn ,
Bitcoin : chain . DefaultConfig ,
2025-03-05 08:40:27 +02:00
Logging : build . DefaultLogConfig ( ) ,
2025-09-24 13:20:46 +02:00
DatabaseBackend : DatabaseBackendSqlite ,
Sqlite : & db . SqliteConfig {
DatabaseFileName : defaultSqliteDatabaseFileName ,
} ,
2026-06-22 10:10:00 +02:00
ChanEvents : & chanevents . Config {
MaxEvents : defaultChanEventsMaxEvents ,
Retention : defaultChanEventsRetention ,
} ,
2019-10-28 15:29:20 +02:00
}
2020-04-30 10:31:07 +02:00
}
2020-09-09 11:07:15 +02:00
// ValidateConfig sanitizes all file system paths and makes sure no incompatible
// configuration combinations are used.
func ValidateConfig ( config * Config ) error {
2020-09-08 10:01:56 +02:00
// Validate the network.
_ , err := lndclient . Network ( config . Network ) . ChainParams ( )
if err != nil {
2020-09-09 11:07:15 +02:00
return fmt . Errorf ( "error validating network: %v" , err )
2019-10-28 15:29:20 +02:00
}
2020-09-08 10:12:56 +02:00
// Clean up and validate paths, then make sure the directories exist.
config . FaradayDir = lncfg . CleanAndExpandPath ( config . FaradayDir )
2020-09-08 10:17:26 +02:00
config . TLSCertPath = lncfg . CleanAndExpandPath ( config . TLSCertPath )
config . TLSKeyPath = lncfg . CleanAndExpandPath ( config . TLSKeyPath )
2020-09-09 10:34:25 +02:00
config . MacaroonPath = lncfg . CleanAndExpandPath ( config . MacaroonPath )
2020-09-08 10:12:56 +02:00
2024-08-15 08:52:20 +02:00
// Before adding the network namespace below, check if the user has
// overwritten the default faraday directory.
faradayDirSet := config . FaradayDir != FaradayDirBase
2020-09-08 10:12:56 +02:00
// Append the network type to faraday directory so they are "namespaced"
// per network.
config . FaradayDir = filepath . Join ( config . FaradayDir , config . Network )
// Create the full path of directories now, including the network path.
if err := os . MkdirAll ( config . FaradayDir , os . ModePerm ) ; err != nil {
2020-09-09 11:07:15 +02:00
return err
2020-09-08 10:12:56 +02:00
}
2020-09-09 10:34:25 +02:00
// Since our faraday directory overrides our TLS dir and macaroon path
// values, make sure that they are not set when faraday dir is set. We
// fail hard here rather than overwriting and potentially confusing the
// user.
2020-09-08 10:17:26 +02:00
if faradayDirSet {
tlsCertPathSet := config . TLSCertPath != DefaultTLSCertPath
tlsKeyPathSet := config . TLSKeyPath != DefaultTLSKeyPath
2020-09-09 10:34:25 +02:00
macaroonPathSet := config . MacaroonPath != DefaultMacaroonPath
2020-09-08 10:17:26 +02:00
if tlsCertPathSet {
2020-09-09 11:07:15 +02:00
return fmt . Errorf ( "faradaydir overwrites " +
2020-09-08 10:17:26 +02:00
"tlscertpath, please only set one value" )
}
if tlsKeyPathSet {
2020-09-09 11:07:15 +02:00
return fmt . Errorf ( "faradaydir overwrites " +
2020-09-08 10:17:26 +02:00
"tlskeypath, please only set one value" )
}
2020-09-09 10:34:25 +02:00
if macaroonPathSet {
return fmt . Errorf ( "faradaydir overwrites " +
"macaroonpath, please only set one value" )
}
2020-09-08 10:17:26 +02:00
}
// We want the TLS files to also be in the "namespaced" sub directory.
// Replace the default values with actual values in case the user
// specified faradaydir.
if config . TLSCertPath == DefaultTLSCertPath {
config . TLSCertPath = filepath . Join (
config . FaradayDir , DefaultTLSCertFilename ,
)
}
if config . TLSKeyPath == DefaultTLSKeyPath {
config . TLSKeyPath = filepath . Join (
config . FaradayDir , DefaultTLSKeyFilename ,
)
}
2020-09-09 10:34:25 +02:00
if config . MacaroonPath == DefaultMacaroonPath {
config . MacaroonPath = filepath . Join (
config . FaradayDir , DefaultMacaroonFilename ,
)
}
2020-09-08 10:17:26 +02:00
2020-06-27 14:36:04 +02:00
// If the user has opted into connecting to a bitcoin backend, check
// that we have a rpc user and password, and that tls path is set if
// required.
if config . ChainConn {
if config . Bitcoin . User == "" || config . Bitcoin . Password == "" {
2020-09-09 11:07:15 +02:00
return fmt . Errorf ( "rpc user and password " +
2020-06-27 14:36:04 +02:00
"required when chainconn is set" )
}
if config . Bitcoin . UseTLS && config . Bitcoin . TLSPath == "" {
2020-09-09 11:07:15 +02:00
return fmt . Errorf ( "bitcoin.tlspath required " +
2020-06-27 14:36:04 +02:00
"when chainconn is set" )
}
}
2021-05-31 13:38:12 +02:00
// Make sure only one of the macaroon options is used.
switch {
case config . Lnd . MacaroonPath != DefaultLndMacaroonPath &&
config . Lnd . MacaroonDir != "" :
return fmt . Errorf ( "use --lnd.macaroonpath only" )
case config . Lnd . MacaroonDir != "" :
// With the new version of lndclient we can only specify a
// single macaroon instead of all of them. If the old
// macaroondir is used, we use the readonly macaroon located in
// that directory.
config . Lnd . MacaroonPath = path . Join (
lncfg . CleanAndExpandPath ( config . Lnd . MacaroonDir ) ,
defaultLndMacaroon ,
)
case config . Lnd . MacaroonPath != "" :
config . Lnd . MacaroonPath = lncfg . CleanAndExpandPath (
config . Lnd . MacaroonPath ,
)
default :
return fmt . Errorf ( "must specify --lnd.macaroonpath" )
}
// Adjust the default lnd macaroon path if only the network is
// specified.
if config . Network != DefaultNetwork &&
config . Lnd . MacaroonPath == DefaultLndMacaroonPath {
config . Lnd . MacaroonPath = path . Join (
DefaultLndDir , "data" , "chain" , "bitcoin" ,
config . Network , defaultLndMacaroon ,
)
}
2022-01-19 09:52:17 +01:00
// Expand the lnd cert path, in case the user is specifying the home
// directory with ~ (which only the shell understands, not the low-level
// file system).
config . Lnd . TLSCertPath = lncfg . CleanAndExpandPath (
config . Lnd . TLSCertPath ,
)
2026-06-22 10:10:00 +02:00
if config . ChanEvents != nil {
// The channel event size limit becomes an int32 SQL OFFSET
// during pruning, so reject values that would overflow it and
// silently corrupt the prune bound.
if config . ChanEvents . MaxEvents > math . MaxInt32 {
return fmt . Errorf ( "chanevents.max-events must not " +
"exceed %d" , math . MaxInt32 )
}
// A negative retention is silently ignored by the prune checks,
// which only treat a strictly positive duration as enabling
// age-based pruning. Reject it so a misconfigured window fails
// loudly instead of disabling pruning unexpectedly.
if config . ChanEvents . Retention < 0 {
return fmt . Errorf ( "chanevents.retention must not be " +
"negative" )
}
}
2020-09-09 11:07:15 +02:00
return nil
2019-10-28 15:29:20 +02:00
}
2020-09-08 10:25:39 +02:00
// getTLSConfig generates a new self signed certificate or refreshes an existing
// one if necessary, then returns the full TLS configuration for initializing
// a secure server interface.
func getTLSConfig ( cfg * Config ) ( * tls . Config , * credentials . TransportCredentials ,
error ) {
// Let's load our certificate first or create then load if it doesn't
// yet exist.
certData , parsedCert , err := loadCertWithCreate ( cfg )
if err != nil {
return nil , nil , err
}
// If the certificate expired or it was outdated, delete it and the TLS
// key and generate a new pair.
if time . Now ( ) . After ( parsedCert . NotAfter ) {
log . Info ( "TLS certificate is expired or outdated, " +
"removing old file then generating a new one" )
err := os . Remove ( cfg . TLSCertPath )
if err != nil {
return nil , nil , err
}
err = os . Remove ( cfg . TLSKeyPath )
if err != nil {
return nil , nil , err
}
certData , _ , err = loadCertWithCreate ( cfg )
if err != nil {
return nil , nil , err
}
}
tlsCfg := cert . TLSConfFromCert ( certData )
restCreds , err := credentials . NewClientTLSFromFile (
cfg . TLSCertPath , "" ,
)
if err != nil {
return nil , nil , err
}
return tlsCfg , & restCreds , nil
}
// loadCertWithCreate tries to load the TLS certificate from disk. If the
// specified cert and key files don't exist, the certificate/key pair is created
// first.
func loadCertWithCreate ( cfg * Config ) ( tls . Certificate , * x509 . Certificate ,
error ) {
// Ensure we create TLS key and certificate if they don't exist.
if ! lnrpc . FileExists ( cfg . TLSCertPath ) &&
! lnrpc . FileExists ( cfg . TLSKeyPath ) {
log . Infof ( "Generating TLS certificates..." )
2023-01-30 22:39:44 +01:00
certBytes , keyBytes , err := cert . GenCertPair (
defaultSelfSignedOrganization , cfg . TLSExtraIPs ,
2020-09-08 10:25:39 +02:00
cfg . TLSExtraDomains , cfg . TLSDisableAutofill ,
2024-02-14 15:14:10 +00:00
cfg . TLSCertDuration ,
2020-09-08 10:25:39 +02:00
)
if err != nil {
return tls . Certificate { } , nil , err
}
2023-01-30 22:39:44 +01:00
// Now that we have the certificate and key, we'll store them
// to the file system.
err = cert . WriteCertPair (
cfg . TLSCertPath , cfg . TLSKeyPath , certBytes , keyBytes ,
)
if err != nil {
return tls . Certificate { } , nil , err
}
2020-09-08 10:25:39 +02:00
log . Infof ( "Done generating TLS certificates" )
}
return cert . LoadCert ( cfg . TLSCertPath , cfg . TLSKeyPath )
}
2025-09-24 13:20:46 +02:00
// stores holds a collection of the DB stores that are used by faraday.
type stores struct {
// ChanEventsStore is used to watch for channel events.
ChanEventsStore * chanevents . Store
// closeFns holds various callbacks that can be used to close any open
// stores in the stores struct.
closeFns map [ string ] func ( ) error
}
// NewStores creates a new stores instance based on the chosen database backend.
func NewStores ( cfg Config , clock clock . Clock ) ( * stores , error ) {
var (
stores = & stores {
closeFns : make ( map [ string ] func ( ) error ) ,
}
)
switch cfg . DatabaseBackend {
case DatabaseBackendSqlite :
dbPath := filepath . Join (
cfg . FaradayDir , cfg . Sqlite . DatabaseFileName ,
)
sqlStore , err := sqldb . NewSqliteStore ( & sqldb . SqliteConfig {
SkipMigrations : cfg . Sqlite . SkipMigrations ,
SkipMigrationDbBackup : cfg . Sqlite . SkipMigrationDbBackup ,
} , dbPath )
if err != nil {
return stores , err
}
if ! cfg . Sqlite . SkipMigrations {
err = sqldb . ApplyAllMigrations (
sqlStore , db . FaradayMigrationSets ,
)
if err != nil {
return stores , fmt . Errorf ( "error applying " +
"migrations to SQLite store: %w" , err ,
)
}
}
queries := sqlc . NewForType ( sqlStore , sqlStore . BackendType )
stores . ChanEventsStore = chanevents . NewStore (
sqlStore . BaseDB , queries , clock ,
)
stores . closeFns [ "sqlite" ] = sqlStore . Close
case DatabaseBackendPostgres :
sqlStore , err := sqldb . NewPostgresStore ( cfg . Postgres )
if err != nil {
return stores , err
}
if ! cfg . Postgres . SkipMigrations {
err = sqldb . ApplyAllMigrations (
sqlStore , db . FaradayMigrationSets ,
)
if err != nil {
return stores , fmt . Errorf ( "error applying " +
"migrations to Postgres store: %w" , err ,
)
}
}
queries := sqlc . NewForType ( sqlStore , sqlStore . BackendType )
stores . ChanEventsStore = chanevents . NewStore (
sqlStore . BaseDB , queries , clock ,
)
stores . closeFns [ "postgres" ] = sqlStore . Close
default :
return nil , fmt . Errorf ( "unsupported database backend: " +
"%s" , cfg . DatabaseBackend )
}
return stores , nil
}
// Close closes all the stores.
func ( s * stores ) Close ( ) error {
for name , closeFn := range s . closeFns {
err := closeFn ( )
if err != nil {
return fmt . Errorf ( "error closing %s store: %v" , name , err )
}
}
return nil
}