2017-03-28 09:04:52 +00:00
package main
import (
2018-01-30 11:51:48 +00:00
"context"
2024-05-13 13:02:22 +00:00
"database/sql"
2018-05-08 21:57:29 +00:00
"errors"
2017-11-03 22:07:13 +00:00
"flag"
2017-03-28 09:04:52 +00:00
"fmt"
2018-03-23 13:26:28 +00:00
stdlog "log"
2017-03-28 09:04:52 +00:00
"os"
2018-01-23 05:16:13 +00:00
"os/signal"
2018-09-21 14:09:31 +00:00
"path/filepath"
2017-03-28 09:04:52 +00:00
"runtime"
2017-11-03 22:07:13 +00:00
"strings"
2018-06-25 15:21:04 +00:00
"time"
2017-03-28 09:04:52 +00:00
2020-08-20 07:26:00 +00:00
"github.com/google/uuid"
2020-01-02 09:10:19 +00:00
"github.com/okzk/sdnotify"
"golang.org/x/crypto/ssh/terminal"
2018-03-20 18:35:28 +00:00
"github.com/ethereum/go-ethereum/log"
2018-06-25 15:21:04 +00:00
gethmetrics "github.com/ethereum/go-ethereum/metrics"
2020-01-02 09:10:19 +00:00
2018-06-08 11:29:50 +00:00
"github.com/status-im/status-go/api"
2020-08-20 07:26:00 +00:00
"github.com/status-im/status-go/appdatabase"
2023-10-02 09:28:42 +00:00
"github.com/status-im/status-go/common/dbsetup"
2020-08-20 07:26:00 +00:00
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
"github.com/status-im/status-go/eth-node/crypto"
2018-09-13 16:31:29 +00:00
"github.com/status-im/status-go/logutils"
2019-10-09 15:04:16 +00:00
"github.com/status-im/status-go/metrics"
2018-01-30 11:51:48 +00:00
nodemetrics "github.com/status-im/status-go/metrics/node"
2018-06-08 11:29:50 +00:00
"github.com/status-im/status-go/node"
"github.com/status-im/status-go/params"
2018-03-23 13:58:40 +00:00
"github.com/status-im/status-go/profiling"
2020-08-20 07:26:00 +00:00
"github.com/status-im/status-go/protocol"
2023-10-02 09:28:42 +00:00
"github.com/status-im/status-go/protocol/pushnotificationserver"
2024-06-02 18:28:55 +00:00
"github.com/status-im/status-go/protocol/requests"
2023-08-11 11:28:45 +00:00
"github.com/status-im/status-go/walletdatabase"
2017-03-28 09:04:52 +00:00
)
2018-06-08 09:20:30 +00:00
const (
serverClientName = "Statusd"
)
2017-03-28 09:04:52 +00:00
var (
2022-03-08 13:17:26 +00:00
configFiles configFlags
logLevel = flag . String ( "log" , "" , ` Log level, one of: "ERROR", "WARN", "INFO", "DEBUG", and "TRACE" ` )
logWithoutColors = flag . Bool ( "log-without-color" , false , "Disables log colors" )
ipcEnabled = flag . Bool ( "ipc" , false , "Enable IPC RPC endpoint" )
ipcFile = flag . String ( "ipcfile" , "" , "Set IPC file path" )
pprofEnabled = flag . Bool ( "pprof" , false , "Enable runtime profiling via pprof" )
pprofPort = flag . Int ( "pprof-port" , 52525 , "Port for runtime profiling via pprof" )
communityArchiveSupportEnabled = flag . Bool ( "community-archives" , false , "Enable community history archive support" )
torrentClientPort = flag . Int ( "torrent-client-port" , 9025 , "Port for BitTorrent protocol connections" )
version = flag . Bool ( "version" , false , "Print version and dump configuration" )
2018-01-17 20:07:45 +00:00
2018-09-21 14:09:31 +00:00
dataDir = flag . String ( "dir" , getDefaultDataDir ( ) , "Directory used by node to store data" )
register = flag . Bool ( "register" , false , "Register and make the node discoverable by other nodes" )
mailserver = flag . Bool ( "mailserver" , false , "Enable Mail Server with default configuration" )
2018-09-26 06:49:31 +00:00
networkID = flag . Int (
"network-id" ,
2022-10-20 10:33:23 +00:00
params . GoerliNetworkID ,
2018-09-26 06:49:31 +00:00
fmt . Sprintf (
2022-10-20 10:33:23 +00:00
"A network ID: %d (Mainnet), %d (Goerli)" ,
params . MainNetworkID , params . GoerliNetworkID ,
2018-09-26 06:49:31 +00:00
) ,
)
2020-02-26 19:36:25 +00:00
fleet = flag . String (
"fleet" ,
params . FleetProd ,
fmt . Sprintf (
"Select fleet: %s (default %s)" ,
2024-05-16 00:09:28 +00:00
[ ] string {
params . FleetProd ,
params . FleetShardsStaging ,
2024-03-15 15:30:16 +00:00
params . FleetShardsTest ,
params . FleetStatusProd ,
params . FleetStatusTest ,
2024-05-17 15:22:45 +00:00
params . FleetWakuSandbox ,
params . FleetWakuTest ,
2024-03-15 15:30:16 +00:00
} ,
params . FleetProd ,
2020-02-26 19:36:25 +00:00
) ,
)
2020-03-10 12:40:35 +00:00
listenAddr = flag . String ( "addr" , "" , "address to bind listener to" )
2018-09-21 14:09:31 +00:00
2018-02-05 19:25:40 +00:00
// don't change the name of this flag, https://github.com/ethereum/go-ethereum/blob/master/metrics/metrics.go#L41
2019-10-09 15:04:16 +00:00
metricsEnabled = flag . Bool ( "metrics" , false , "Expose ethereum metrics with debug_metrics jsonrpc call" )
metricsPort = flag . Int ( "metrics-port" , 9305 , "Port for the Prometheus /metrics endpoint" )
2024-06-02 18:28:55 +00:00
seedPhrase = flag . String ( "seed-phrase" , "" , "Seed phrase for account creation" )
password = flag . String ( "password" , "" , "Password for account" )
2017-11-03 22:07:13 +00:00
)
2017-05-03 14:24:48 +00:00
2018-03-20 18:35:28 +00:00
// All general log messages in this package should be routed through this logger.
var logger = log . New ( "package" , "status-go/cmd/statusd" )
2018-07-25 14:03:35 +00:00
func init ( ) {
2018-09-13 16:31:29 +00:00
flag . Var ( & configFiles , "c" , "JSON configuration file(s). Multiple configuration files can be specified, and will be merged in occurrence order" )
2019-10-04 15:21:24 +00:00
}
2018-09-13 16:31:29 +00:00
2019-10-04 15:21:24 +00:00
// nolint:gocyclo
func main ( ) {
2018-09-13 16:31:29 +00:00
colors := terminal . IsTerminal ( int ( os . Stdin . Fd ( ) ) )
2019-03-01 13:37:13 +00:00
if err := logutils . OverrideRootLog ( true , "ERROR" , logutils . FileOptions { } , colors ) ; err != nil {
2018-09-13 16:31:29 +00:00
stdlog . Fatalf ( "Error initializing logger: %v" , err )
}
2018-04-10 06:44:09 +00:00
2017-11-03 22:07:13 +00:00
flag . Usage = printUsage
flag . Parse ( )
2018-05-17 13:03:23 +00:00
if flag . NArg ( ) > 0 {
printUsage ( )
2018-09-13 16:31:29 +00:00
logger . Error ( "Extra args in command line: %v" , flag . Args ( ) )
2018-05-17 13:03:23 +00:00
os . Exit ( 1 )
}
2018-07-25 14:03:35 +00:00
2024-06-02 18:28:55 +00:00
if * seedPhrase != "" && * password == "" {
printUsage ( )
logger . Error ( "password is required when seed phrase is provided" )
os . Exit ( 1 )
}
2020-02-26 19:36:25 +00:00
opts := [ ] params . Option { params . WithFleet ( * fleet ) }
2018-09-21 14:09:31 +00:00
if * mailserver {
opts = append ( opts , params . WithMailserver ( ) )
}
2018-09-19 18:29:42 +00:00
config , err := params . NewNodeConfigWithDefaultsAndFiles (
2018-09-21 14:09:31 +00:00
* dataDir ,
2018-09-26 06:49:31 +00:00
uint64 ( * networkID ) ,
2018-09-21 14:09:31 +00:00
opts ,
configFiles ,
2018-09-19 18:29:42 +00:00
)
2017-11-03 22:07:13 +00:00
if err != nil {
2018-09-13 16:31:29 +00:00
printUsage ( )
2019-06-12 09:16:00 +00:00
logger . Error ( err . Error ( ) )
2018-09-13 16:31:29 +00:00
os . Exit ( 1 )
2017-05-16 03:24:56 +00:00
}
2018-09-13 16:31:29 +00:00
2020-03-10 12:40:35 +00:00
// Use listenAddr if and only if explicitly provided in the arguments.
// The default value is set in params.NewNodeConfigWithDefaultsAndFiles().
if * listenAddr != "" {
config . ListenAddr = * listenAddr
}
2020-02-26 19:36:25 +00:00
2018-09-21 14:09:31 +00:00
if * register && * mailserver {
config . RegisterTopics = append ( config . RegisterTopics , params . MailServerDiscv5Topic )
} else if * register {
config . RegisterTopics = append ( config . RegisterTopics , params . WhisperDiscv5Topic )
2018-09-19 18:29:42 +00:00
}
2018-10-11 10:29:59 +00:00
// enable IPC RPC
if * ipcEnabled {
config . IPCEnabled = true
config . IPCFile = * ipcFile
}
2022-03-08 13:17:26 +00:00
if * communityArchiveSupportEnabled {
config . TorrentConfig . Enabled = true
config . TorrentConfig . Port = * torrentClientPort
}
2018-09-21 14:09:31 +00:00
// set up logging options
setupLogging ( config )
2018-09-13 16:31:29 +00:00
2018-06-08 09:20:30 +00:00
// We want statusd to be distinct from StatusIM client.
config . Name = serverClientName
2017-05-16 03:24:56 +00:00
2017-11-03 22:07:13 +00:00
if * version {
2020-03-10 12:40:35 +00:00
printVersion ( config )
2017-11-03 22:07:13 +00:00
return
2017-03-28 09:04:52 +00:00
}
2017-05-03 14:24:48 +00:00
2019-11-23 17:57:05 +00:00
backend := api . NewGethStatusBackend ( )
2024-05-13 13:02:22 +00:00
if config . NodeKey == "" {
logger . Error ( "node key needs to be set if running a push notification server" )
return
}
identity , err := crypto . HexToECDSA ( config . NodeKey )
if err != nil {
logger . Error ( "node key is invalid" , "error" , err )
return
}
// Generate installationID from public key, so it's always the same
installationID , err := uuid . FromBytes ( crypto . CompressPubkey ( & identity . PublicKey ) [ : 16 ] )
if err != nil {
logger . Error ( "cannot create installation id" , "error" , err )
return
}
2024-06-02 18:28:55 +00:00
if * seedPhrase != "" {
// Remove data inside dir to avoid conflicts with existing data or account restoration fails
if err := os . RemoveAll ( config . DataDir ) ; err != nil {
logger . Error ( "failed to remove data dir" , "error" , err )
return
}
2024-05-13 13:02:22 +00:00
2024-06-02 18:28:55 +00:00
if err := createDirsFromConfig ( config ) ; err != nil {
logger . Error ( "failed to create directories" , "error" , err )
return
}
2024-05-13 13:02:22 +00:00
2024-06-02 18:28:55 +00:00
request := requests . RestoreAccount {
Mnemonic : * seedPhrase ,
FetchBackup : false ,
CreateAccount : requests . CreateAccount {
DisplayName : "Account1" ,
DeviceName : "StatusIM" ,
Password : * password ,
CustomizationColor : "0x000000" ,
BackupDisabledDataDir : config . DataDir ,
APIConfig : & requests . APIConfig {
2024-06-26 14:33:22 +00:00
ConnectorEnabled : config . ClusterConfig . Enabled ,
HTTPEnabled : config . HTTPEnabled ,
HTTPHost : config . HTTPHost ,
HTTPPort : config . HTTPPort ,
2024-07-04 10:48:40 +00:00
HTTPVirtualHosts : config . HTTPVirtualHosts ,
2024-06-26 14:33:22 +00:00
WSEnabled : config . WSEnabled ,
WSHost : config . WSHost ,
WSPort : config . WSPort ,
APIModules : config . APIModules ,
2024-06-02 18:28:55 +00:00
} ,
NetworkID : & config . NetworkID ,
TestOverrideNetworks : config . Networks ,
} ,
}
2017-05-03 14:24:48 +00:00
2024-07-04 10:48:40 +00:00
api . OverrideApiConfigTest ( )
2024-06-02 18:28:55 +00:00
_ , err := backend . RestoreAccountAndLogin ( & request )
if err != nil {
logger . Error ( "failed to import account" , "error" , err )
return
}
2024-07-08 14:21:31 +00:00
appDB , walletDB , err := openDatabases ( config . DataDir + "/" + installationID . String ( ) )
if err != nil {
log . Error ( "failed to open databases" )
return
}
options := [ ] protocol . Option {
protocol . WithDatabase ( appDB ) ,
protocol . WithWalletDatabase ( walletDB ) ,
protocol . WithTorrentConfig ( & config . TorrentConfig ) ,
protocol . WithWalletConfig ( & config . WalletConfig ) ,
protocol . WithAccountManager ( backend . AccountManager ( ) ) ,
}
messenger , err := protocol . NewMessenger (
config . Name ,
identity ,
gethbridge . NewNodeBridge ( backend . StatusNode ( ) . GethNode ( ) , backend . StatusNode ( ) . WakuService ( ) , backend . StatusNode ( ) . WakuV2Service ( ) ) ,
installationID . String ( ) ,
nil ,
config . Version ,
options ... ,
)
if err != nil {
logger . Error ( "failed to create messenger" , "error" , err )
return
}
_ , err = messenger . Start ( )
if err != nil {
logger . Error ( "failed to start messenger" , "error" , err )
return
}
interruptCh := haltOnInterruptSignal ( backend . StatusNode ( ) )
go retrieveMessagesLoop ( messenger , 300 * time . Millisecond , interruptCh )
2020-08-20 09:05:39 +00:00
} else {
2024-06-02 18:28:55 +00:00
appDB , walletDB , err := startNode ( config , backend , installationID )
if err != nil {
logger . Error ( "failed to start node" , "error" , err )
return
}
2020-08-20 09:05:39 +00:00
2024-06-02 18:28:55 +00:00
err = sdnotify . Ready ( )
if err == sdnotify . ErrSdNotifyNoSocket {
logger . Debug ( "sd_notify socket not available" )
} else if err != nil {
logger . Warn ( "sd_notify READY call failed" , "error" , err )
} else {
// systemd aliveness notifications, affects only Linux
go startSystemDWatchdog ( )
}
2020-08-20 09:05:39 +00:00
2024-06-02 18:28:55 +00:00
// handle interrupt signals
interruptCh := haltOnInterruptSignal ( backend . StatusNode ( ) )
2020-08-20 09:05:39 +00:00
2024-06-02 18:28:55 +00:00
// Start collecting metrics. Metrics can be enabled by providing `-metrics` flag
// or setting `gethmetrics.Enabled` to true during compilation time:
// https://github.com/status-im/go-ethereum/pull/76.
if * metricsEnabled || gethmetrics . Enabled {
go startCollectingNodeMetrics ( interruptCh , backend . StatusNode ( ) )
go gethmetrics . CollectProcessMetrics ( 3 * time . Second )
go metrics . NewMetricsServer ( * metricsPort , gethmetrics . DefaultRegistry ) . Listen ( )
2020-08-20 07:26:00 +00:00
}
2024-06-02 18:28:55 +00:00
// Check if profiling shall be enabled.
if * pprofEnabled {
profiling . NewProfiler ( * pprofPort ) . Go ( )
2020-08-20 07:26:00 +00:00
}
2024-06-02 18:28:55 +00:00
if config . PushNotificationServerConfig . Enabled {
options := [ ] protocol . Option {
protocol . WithPushNotifications ( ) ,
protocol . WithPushNotificationServerConfig ( & pushnotificationserver . Config {
Enabled : config . PushNotificationServerConfig . Enabled ,
Identity : config . PushNotificationServerConfig . Identity ,
GorushURL : config . PushNotificationServerConfig . GorushURL ,
} ) ,
protocol . WithDatabase ( appDB ) ,
protocol . WithWalletDatabase ( walletDB ) ,
protocol . WithTorrentConfig ( & config . TorrentConfig ) ,
protocol . WithWalletConfig ( & config . WalletConfig ) ,
protocol . WithAccountManager ( backend . AccountManager ( ) ) ,
}
2020-08-20 09:05:39 +00:00
2024-06-02 18:28:55 +00:00
messenger , err := protocol . NewMessenger (
config . Name ,
identity ,
gethbridge . NewNodeBridge ( backend . StatusNode ( ) . GethNode ( ) , backend . StatusNode ( ) . WakuService ( ) , backend . StatusNode ( ) . WakuV2Service ( ) ) ,
installationID . String ( ) ,
nil ,
2024-06-13 22:31:09 +00:00
config . Version ,
2024-06-02 18:28:55 +00:00
options ... ,
)
if err != nil {
logger . Error ( "failed to create messenger" , "error" , err )
return
}
2024-06-10 15:02:42 +00:00
err = messenger . InitInstallations ( )
2024-06-02 18:28:55 +00:00
if err != nil {
2024-06-10 15:02:42 +00:00
logger . Error ( "failed to init messenger installations" , "error" , err )
return
}
err = messenger . InitFilters ( )
if err != nil {
logger . Error ( "failed to init messenger filters" , "error" , err )
2024-06-02 18:28:55 +00:00
return
}
// This will start the push notification server as well as
// the config is set to Enabled
_ , err = messenger . Start ( )
if err != nil {
logger . Error ( "failed to start messenger" , "error" , err )
return
}
go retrieveMessagesLoop ( messenger , 300 * time . Millisecond , interruptCh )
2020-08-20 07:26:00 +00:00
}
2018-02-07 10:48:03 +00:00
}
2018-06-12 16:50:25 +00:00
gethNode := backend . StatusNode ( ) . GethNode ( )
if gethNode != nil {
2018-04-16 12:36:09 +00:00
// wait till node has been stopped
2018-06-12 16:50:25 +00:00
gethNode . Wait ( )
2019-09-16 09:38:33 +00:00
if err := sdnotify . Stopping ( ) ; err != nil {
logger . Warn ( "sd_notify STOPPING call failed" , "error" , err )
}
2017-03-28 09:04:52 +00:00
}
2017-11-03 22:07:13 +00:00
}
2017-05-03 14:24:48 +00:00
2018-09-21 14:09:31 +00:00
func getDefaultDataDir ( ) string {
if home := os . Getenv ( "HOME" ) ; home != "" {
return filepath . Join ( home , ".statusd" )
}
return "./statusd-data"
}
func setupLogging ( config * params . NodeConfig ) {
if * logLevel != "" {
config . LogLevel = * logLevel
}
2021-08-18 12:44:10 +00:00
logSettings := logutils . LogSettings {
Enabled : config . LogEnabled ,
MobileSystem : config . LogMobileSystem ,
Level : config . LogLevel ,
File : config . LogFile ,
MaxSize : config . LogMaxSize ,
MaxBackups : config . LogMaxBackups ,
CompressRotated : config . LogCompressRotated ,
}
2018-09-21 14:09:31 +00:00
colors := ! ( * logWithoutColors ) && terminal . IsTerminal ( int ( os . Stdin . Fd ( ) ) )
2021-08-18 12:44:10 +00:00
if err := logutils . OverrideRootLogWithConfig ( logSettings , colors ) ; err != nil {
2018-09-21 14:09:31 +00:00
stdlog . Fatalf ( "Error initializing logger: %v" , err )
}
}
2019-09-16 09:38:33 +00:00
// loop for notifying systemd about process being alive
func startSystemDWatchdog ( ) {
for range time . Tick ( 30 * time . Second ) {
if err := sdnotify . Watchdog ( ) ; err != nil {
logger . Warn ( "sd_notify WATCHDOG call failed" , "error" , err )
}
}
}
2018-01-30 11:51:48 +00:00
// startCollectingStats collects various stats about the node and other protocols like Whisper.
2018-05-16 15:36:59 +00:00
func startCollectingNodeMetrics ( interruptCh <- chan struct { } , statusNode * node . StatusNode ) {
logger . Info ( "Starting collecting node metrics" )
2018-01-30 11:51:48 +00:00
2018-06-12 16:50:25 +00:00
gethNode := statusNode . GethNode ( )
if gethNode == nil {
2018-04-16 12:36:09 +00:00
logger . Error ( "Failed to run metrics because it could not get the node" )
2018-01-30 11:51:48 +00:00
return
}
ctx , cancel := context . WithCancel ( context . Background ( ) )
defer cancel ( )
go func ( ) {
2018-11-12 09:27:09 +00:00
// Try to subscribe and collect metrics. In case of an error, retry.
for {
if err := nodemetrics . SubscribeServerEvents ( ctx , gethNode ) ; err != nil {
logger . Error ( "Failed to subscribe server events" , "error" , err )
} else {
// no error means that the subscription was terminated by purpose
return
}
time . Sleep ( time . Second )
2018-01-30 11:51:48 +00:00
}
} ( )
<- interruptCh
}
2018-09-13 16:31:29 +00:00
var (
errStatusServiceRequiresIPC = errors . New ( "to enable the StatusService on IPC, -ipc flag must be set" )
errStatusServiceRequiresHTTP = errors . New ( "to enable the StatusService on HTTP, -http flag must be set" )
errStatusServiceInvalidFlag = errors . New ( "-status flag valid values are: ipc, http" )
)
2018-05-08 21:57:29 +00:00
func configureStatusService ( flagValue string , nodeConfig * params . NodeConfig ) ( * params . NodeConfig , error ) {
switch flagValue {
case "ipc" :
if ! nodeConfig . IPCEnabled {
return nil , errStatusServiceRequiresIPC
}
2019-01-17 12:56:22 +00:00
nodeConfig . EnableStatusService = true
2018-05-08 21:57:29 +00:00
case "http" :
2018-09-21 14:09:31 +00:00
if ! nodeConfig . HTTPEnabled {
2018-05-08 21:57:29 +00:00
return nil , errStatusServiceRequiresHTTP
}
2019-01-17 12:56:22 +00:00
nodeConfig . EnableStatusService = true
2018-05-08 21:57:29 +00:00
nodeConfig . AddAPIModule ( "status" )
case "" :
2019-01-17 12:56:22 +00:00
nodeConfig . EnableStatusService = false
2018-05-08 21:57:29 +00:00
default :
return nil , errStatusServiceInvalidFlag
}
return nodeConfig , nil
}
2017-11-03 22:07:13 +00:00
// printVersion prints verbose output about version and config.
2020-03-10 12:40:35 +00:00
func printVersion ( config * params . NodeConfig ) {
2018-06-08 09:20:30 +00:00
fmt . Println ( strings . Title ( config . Name ) )
fmt . Println ( "Version:" , config . Version )
2020-02-10 11:22:37 +00:00
fmt . Println ( "Network ID:" , config . NetworkID )
2017-11-03 22:07:13 +00:00
fmt . Println ( "Go Version:" , runtime . Version ( ) )
fmt . Println ( "OS:" , runtime . GOOS )
fmt . Printf ( "GOPATH=%s\n" , os . Getenv ( "GOPATH" ) )
fmt . Printf ( "GOROOT=%s\n" , runtime . GOROOT ( ) )
fmt . Println ( "Loaded Config: " , config )
2017-03-28 09:04:52 +00:00
}
2017-11-03 22:07:13 +00:00
func printUsage ( ) {
2018-01-17 16:46:21 +00:00
usage := `
Usage : statusd [ options ]
2017-11-03 22:07:13 +00:00
Examples :
2024-06-10 15:02:42 +00:00
statusd # run regular Whisper node that joins Status network
statusd - c . / default . json # run node with configuration specified in . / default . json file
statusd - c . / default . json - c . / standalone . json # run node with configuration specified in . / default . json file , after merging . / standalone . json file
statusd - c . / default . json - metrics # run node with configuration specified in . / default . json file , and expose ethereum metrics with debug_metrics jsonrpc call
statusd - c . / default . json - log DEBUG -- seed - phrase = "test test test test test test test test test test test junk" -- password = password # run node with configuration specified in . / default . json file , and import account with seed phrase and password
2017-11-03 22:07:13 +00:00
Options :
2018-01-17 16:46:21 +00:00
`
2019-10-04 15:21:24 +00:00
fmt . Fprint ( os . Stderr , usage )
2017-11-03 22:07:13 +00:00
flag . PrintDefaults ( )
2017-03-28 09:04:52 +00:00
}
2018-01-23 05:16:13 +00:00
// haltOnInterruptSignal catches interrupt signal (SIGINT) and
// stops the node. It times out after 5 seconds
// if the node can not be stopped.
2018-04-05 09:45:26 +00:00
func haltOnInterruptSignal ( statusNode * node . StatusNode ) <- chan struct { } {
2018-01-30 11:51:48 +00:00
interruptCh := make ( chan struct { } )
go func ( ) {
signalCh := make ( chan os . Signal , 1 )
signal . Notify ( signalCh , os . Interrupt )
defer signal . Stop ( signalCh )
<- signalCh
close ( interruptCh )
2018-03-20 18:35:28 +00:00
logger . Info ( "Got interrupt, shutting down..." )
2018-04-05 09:45:26 +00:00
if err := statusNode . Stop ( ) ; err != nil {
2018-03-20 18:35:28 +00:00
logger . Error ( "Failed to stop node" , "error" , err )
2018-01-30 11:51:48 +00:00
os . Exit ( 1 )
}
} ( )
return interruptCh
2018-01-23 05:16:13 +00:00
}
2020-08-20 09:05:39 +00:00
// retrieveMessagesLoop fetches messages from a messenger so that they are processed
func retrieveMessagesLoop ( messenger * protocol . Messenger , tick time . Duration , cancel <- chan struct { } ) {
ticker := time . NewTicker ( tick )
defer ticker . Stop ( )
for {
select {
case <- ticker . C :
2021-03-31 16:23:45 +00:00
_ , err := messenger . RetrieveAll ( )
2020-08-20 09:05:39 +00:00
if err != nil {
logger . Error ( "failed to retrieve raw messages" , "err" , err )
continue
}
case <- cancel :
return
}
}
}
2024-05-13 13:02:22 +00:00
func openDatabases ( path string ) ( * sql . DB , * sql . DB , error ) {
walletDB , err := walletdatabase . InitializeDB ( path + "-wallet.db" , "" , dbsetup . ReducedKDFIterationsNumber )
if err != nil {
logger . Error ( "failed to initialize wallet db" , "error" , err )
return nil , nil , err
}
appDB , err := appdatabase . InitializeDB ( path + ".db" , "" , dbsetup . ReducedKDFIterationsNumber )
if err != nil {
logger . Error ( "failed to initialize app db" , "error" , err )
return nil , nil , err
}
return appDB , walletDB , nil
}
func createDirsFromConfig ( config * params . NodeConfig ) error {
// If DataDir is empty, it means we want to create an ephemeral node
// keeping data only in memory.
if config . DataDir != "" {
// make sure data directory exists
if err := os . MkdirAll ( filepath . Clean ( config . DataDir ) , os . ModePerm ) ; err != nil {
return fmt . Errorf ( "make node: make data directory: %v" , err )
}
}
if config . KeyStoreDir != "" {
// make sure keys directory exists
if err := os . MkdirAll ( filepath . Clean ( config . KeyStoreDir ) , os . ModePerm ) ; err != nil {
return fmt . Errorf ( "make node: make keys directory: %v" , err )
}
}
return nil
}
2024-06-02 18:28:55 +00:00
func startNode ( config * params . NodeConfig , backend * api . GethStatusBackend , installationID uuid . UUID ) ( * sql . DB , * sql . DB , error ) {
err := backend . AccountManager ( ) . InitKeystore ( config . KeyStoreDir )
if err != nil {
logger . Error ( "Failed to init keystore" , "error" , err )
return nil , nil , err
}
err = createDirsFromConfig ( config )
if err != nil {
logger . Error ( "failed to create directories" , "error" , err )
return nil , nil , err
}
appDB , walletDB , err := openDatabases ( config . DataDir + "/" + installationID . String ( ) )
if err != nil {
log . Error ( "failed to open databases" )
return nil , nil , err
}
backend . StatusNode ( ) . SetAppDB ( appDB )
backend . StatusNode ( ) . SetWalletDB ( walletDB )
err = backend . StartNode ( config )
if err != nil {
logger . Error ( "Node start failed" , "error" , err )
return nil , nil , err
}
return appDB , walletDB , nil
}