2025-01-06 11:38:04 +02:00
//go:build dev
package terminal
import (
2025-07-24 02:43:17 +02:00
"context"
2025-04-01 12:14:01 +02:00
"fmt"
2025-01-06 11:38:04 +02:00
"path/filepath"
"github.com/lightninglabs/lightning-terminal/accounts"
2025-01-06 11:44:18 +02:00
"github.com/lightninglabs/lightning-terminal/db"
2026-03-26 11:59:04 +01:00
"github.com/lightninglabs/lightning-terminal/db/migsets"
2025-07-22 12:20:04 +02:00
"github.com/lightninglabs/lightning-terminal/db/sqlc"
2025-04-01 12:14:01 +02:00
"github.com/lightninglabs/lightning-terminal/firewalldb"
2025-03-02 12:55:00 +02:00
"github.com/lightninglabs/lightning-terminal/session"
2025-01-06 11:38:04 +02:00
"github.com/lightningnetwork/lnd/clock"
2025-07-24 02:43:17 +02:00
"github.com/lightningnetwork/lnd/lnrpc"
2025-07-22 12:20:04 +02:00
"github.com/lightningnetwork/lnd/sqldb/v2"
2025-01-06 11:38:04 +02:00
)
2025-01-06 11:44:18 +02:00
const (
// DatabaseBackendSqlite is the name of the SQLite database backend.
DatabaseBackendSqlite = "sqlite"
// DatabaseBackendPostgres is the name of the Postgres database backend.
DatabaseBackendPostgres = "postgres"
// DatabaseBackendBbolt is the name of the bbolt database backend.
DatabaseBackendBbolt = "bbolt"
// defaultSqliteDatabaseFileName is the default name of the SQLite
// database file.
defaultSqliteDatabaseFileName = "litd.db"
)
// defaultSqliteDatabasePath is the default path under which we store
// the SQLite database file.
var defaultSqliteDatabasePath = filepath . Join (
DefaultLitDir , DefaultNetwork , defaultSqliteDatabaseFileName ,
)
2025-01-06 11:38:04 +02:00
// DevConfig is a struct that holds the configuration options for a development
// environment. The purpose of this struct is to hold config options for
// features not yet available in production. Since our itests are built with
// the dev tag, we can test these features in our itests.
//
2025-12-09 15:57:14 +00:00
// nolint:ll
2025-01-06 11:38:04 +02:00
type DevConfig struct {
2025-01-06 11:44:18 +02:00
// DatabaseBackend is the database backend we will use for storing all
// account related data. While this feature is still in development, we
// include the bbolt type here so that our itests can continue to be
// tested against a bbolt backend. Once the full bbolt to SQL migration
// is complete, however, we will remove the bbolt option.
DatabaseBackend string ` long:"databasebackend" description:"The database backend to use for storing all account related data." choice:"bbolt" 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 * db . PostgresConfig ` group:"postgres" namespace:"postgres" `
2025-01-06 11:38:04 +02:00
}
// Validate checks that all the values set in our DevConfig are valid and uses
// the passed parameters to override any defaults if necessary.
func ( c * DevConfig ) Validate ( dbDir , network string ) error {
2025-01-06 11:44:18 +02:00
// We'll update the database file location if it wasn't set.
if c . Sqlite . DatabaseFileName == defaultSqliteDatabasePath {
c . Sqlite . DatabaseFileName = filepath . Join (
dbDir , network , defaultSqliteDatabaseFileName ,
)
}
2025-01-06 11:38:04 +02:00
return nil
}
// defaultDevConfig returns a new DevConfig with default values set.
func defaultDevConfig ( ) * DevConfig {
2025-01-06 11:44:18 +02:00
return & DevConfig {
Sqlite : & db . SqliteConfig {
DatabaseFileName : defaultSqliteDatabasePath ,
} ,
Postgres : & db . PostgresConfig {
Host : "localhost" ,
Port : 5432 ,
MaxOpenConnections : 10 ,
} ,
}
2025-01-06 11:38:04 +02:00
}
2025-03-02 12:55:00 +02:00
// NewStores creates a new stores instance based on the chosen database backend.
2025-07-24 02:43:17 +02:00
func NewStores ( ctx context . Context , cfg * Config ,
basicClient lnrpc . LightningClient , clock clock . Clock ) ( * stores , error ) {
2025-03-02 12:55:00 +02:00
var (
networkDir = filepath . Join ( cfg . LitDir , cfg . Network )
2025-04-03 15:23:23 +02:00
stores = & stores {
closeFns : make ( map [ string ] func ( ) error ) ,
}
2025-03-02 12:55:00 +02:00
)
2025-01-06 11:44:18 +02:00
switch cfg . DatabaseBackend {
case DatabaseBackendSqlite :
// Before we initialize the SQLite store, we'll make sure that
// the directory where we will store the database file exists.
err := makeDirectories ( networkDir )
if err != nil {
2025-04-03 15:23:23 +02:00
return stores , err
2025-01-06 11:44:18 +02:00
}
2025-07-22 12:20:04 +02:00
sqlStore , err := sqldb . NewSqliteStore ( & sqldb . SqliteConfig {
SkipMigrations : cfg . Sqlite . SkipMigrations ,
SkipMigrationDbBackup : cfg . Sqlite . SkipMigrationDbBackup ,
} , cfg . Sqlite . DatabaseFileName )
2025-01-06 11:44:18 +02:00
if err != nil {
2025-04-03 15:23:23 +02:00
return stores , err
2025-01-06 11:44:18 +02:00
}
2025-07-22 12:20:04 +02:00
if ! cfg . Sqlite . SkipMigrations {
err = sqldb . ApplyAllMigrations (
2025-07-24 02:43:17 +02:00
sqlStore ,
2026-03-26 11:59:04 +01:00
migsets . MakeMigrationSets (
2025-07-24 02:43:17 +02:00
ctx , basicClient , cfg . MacaroonPath ,
clock ,
) ,
2025-07-22 12:20:04 +02:00
)
if err != nil {
return stores , fmt . Errorf ( "error applying " +
"migrations to SQLite store: %w" , err ,
)
}
}
queries := sqlc . NewForType ( sqlStore , sqlStore . BackendType )
acctStore := accounts . NewSQLStore (
sqlStore . BaseDB , queries , clock ,
)
2025-07-22 12:21:06 +02:00
sessStore := session . NewSQLStore (
sqlStore . BaseDB , queries , clock ,
)
2025-07-22 12:20:04 +02:00
firewallStore := firewalldb . NewSQLDB (
2026-01-22 11:53:18 +01:00
sqlStore . BaseDB , queries , clock ,
2025-07-22 12:20:04 +02:00
)
2025-04-03 15:23:23 +02:00
stores . accounts = acctStore
stores . sessions = sessStore
2025-03-13 11:12:06 -05:00
stores . firewall = firewalldb . NewDB ( firewallStore )
2025-04-03 15:23:23 +02:00
stores . closeFns [ "sqlite" ] = sqlStore . BaseDB . Close
2025-01-06 11:44:18 +02:00
case DatabaseBackendPostgres :
2025-07-22 12:20:04 +02:00
sqlStore , err := sqldb . NewPostgresStore ( & sqldb . PostgresConfig {
Dsn : cfg . Postgres . DSN ( false ) ,
MaxOpenConnections : cfg . Postgres . MaxOpenConnections ,
MaxIdleConnections : cfg . Postgres . MaxIdleConnections ,
ConnMaxLifetime : cfg . Postgres . ConnMaxLifetime ,
ConnMaxIdleTime : cfg . Postgres . ConnMaxIdleTime ,
RequireSSL : cfg . Postgres . RequireSSL ,
SkipMigrations : cfg . Postgres . SkipMigrations ,
} )
2025-01-06 11:44:18 +02:00
if err != nil {
2025-04-03 15:23:23 +02:00
return stores , err
2025-01-06 11:44:18 +02:00
}
2025-07-22 12:20:04 +02:00
if ! cfg . Postgres . SkipMigrations {
err = sqldb . ApplyAllMigrations (
2025-07-24 02:43:17 +02:00
sqlStore ,
2026-03-26 11:59:04 +01:00
migsets . MakeMigrationSets (
2025-07-24 02:43:17 +02:00
ctx , basicClient , cfg . MacaroonPath ,
clock ,
) ,
2025-07-22 12:20:04 +02:00
)
if err != nil {
return stores , fmt . Errorf ( "error applying " +
"migrations to Postgres store: %w" , err ,
)
}
}
queries := sqlc . NewForType ( sqlStore , sqlStore . BackendType )
acctStore := accounts . NewSQLStore (
sqlStore . BaseDB , queries , clock ,
)
2025-07-22 12:21:06 +02:00
sessStore := session . NewSQLStore (
sqlStore . BaseDB , queries , clock ,
)
2025-07-22 12:20:04 +02:00
firewallStore := firewalldb . NewSQLDB (
2026-01-22 11:53:18 +01:00
sqlStore . BaseDB , queries , clock ,
2025-07-22 12:20:04 +02:00
)
2025-04-03 15:23:23 +02:00
stores . accounts = acctStore
stores . sessions = sessStore
2025-03-13 11:12:06 -05:00
stores . firewall = firewalldb . NewDB ( firewallStore )
2025-04-03 15:23:23 +02:00
stores . closeFns [ "postgres" ] = sqlStore . BaseDB . Close
2025-01-06 11:44:18 +02:00
default :
2025-03-02 12:55:00 +02:00
accountStore , err := accounts . NewBoltStore (
2025-01-06 11:44:18 +02:00
filepath . Dir ( cfg . MacaroonPath ) , accounts . DBFilename ,
clock ,
)
2025-03-02 12:55:00 +02:00
if err != nil {
2025-04-03 15:23:23 +02:00
return stores , err
2025-03-02 12:55:00 +02:00
}
2025-04-03 15:23:23 +02:00
stores . accounts = accountStore
stores . closeFns [ "bbolt-accounts" ] = accountStore . Close
2025-03-02 12:55:00 +02:00
sessionStore , err := session . NewDB (
networkDir , session . DBFilename , clock , accountStore ,
)
if err != nil {
2025-04-03 15:23:23 +02:00
return stores , err
2025-03-02 12:55:00 +02:00
}
2025-04-03 15:23:23 +02:00
stores . sessions = sessionStore
stores . closeFns [ "bbolt-sessions" ] = sessionStore . Close
2025-03-02 12:55:00 +02:00
2025-05-13 14:33:37 +02:00
firewallBoltDB , err := firewalldb . NewBoltDB (
networkDir , firewalldb . DBFilename , stores . sessions ,
stores . accounts , clock ,
)
if err != nil {
return stores , fmt . Errorf ( "error creating firewall " +
"BoltDB: %v" , err )
}
2025-04-03 15:23:23 +02:00
2025-03-13 11:12:06 -05:00
stores . firewall = firewalldb . NewDB ( firewallBoltDB )
2025-05-13 14:33:37 +02:00
stores . closeFns [ "bbolt-firewalldb" ] = firewallBoltDB . Close
2025-03-13 11:12:06 -05:00
}
2025-04-03 15:23:23 +02:00
return stores , nil
2025-01-06 11:38:04 +02:00
}