-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathroot.go
More file actions
282 lines (244 loc) · 9.66 KB
/
root.go
File metadata and controls
282 lines (244 loc) · 9.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
package cmd
import (
"context"
"fmt"
"os"
"os/signal"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/mattn/go-sqlite3"
"github.com/pegnet/pegnetd/config"
"github.com/pegnet/pegnetd/exit"
"github.com/pegnet/pegnetd/fat/fat2"
"github.com/pegnet/pegnetd/node"
"github.com/pegnet/pegnetd/node/pegnet"
"github.com/pegnet/pegnetd/srv"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func init() {
rootCmd.PersistentFlags().String("log", "info", "Change the logging level. Can choose from 'trace', 'debug', 'info', 'warn', 'error', or 'fatal'")
rootCmd.PersistentFlags().StringP("server", "s", "http://localhost:8088/v2", "The url to the factomd endpoint without a trailing slash")
rootCmd.PersistentFlags().StringP("wallet", "w", "http://localhost:8089/v2", "The url to the factomd-wallet endpoint without a trailing slash")
rootCmd.PersistentFlags().String("walletuser", "", "The username for Wallet RPC")
rootCmd.PersistentFlags().String("walletpassword", "", "The password for Wallet RPC")
rootCmd.PersistentFlags().StringP("pegnetd", "p", "http://localhost:8070", "The url to the pegnetd endpoint without a trailing slash")
rootCmd.PersistentFlags().String("api", "8070", "Change the api listening port for the api")
rootCmd.PersistentFlags().String("config", "", "Optional file location of the config file")
rootCmd.Flags().String("dbmode", "", "Turn on custom sqlite modes")
rootCmd.Flags().Bool("wal", false, "Turn on WAL mode for sqlite")
rootCmd.PersistentFlags().BoolP("no-warn", "n", false, "Ignore all warnings/notices")
rootCmd.PersistentFlags().Bool("no-hf", false, "Disable the check that your node was updated before each hard fork. It will still print a warning")
// This is for testing purposes
rootCmd.PersistentFlags().Bool("testing", false, "If this flag is set, all activations heights are set to 0.")
rootCmd.PersistentFlags().Int("act", -1, "Able to manually set the activation heights")
rootCmd.PersistentFlags().Int32("testingact", -1, "This is a hidden flag that can be used by QA and developers to set some custom activation heights.")
_ = rootCmd.PersistentFlags().MarkHidden("testingact")
rootCmd.AddCommand(properties)
}
// Execute is cobra's entry point
func Execute() {
if err := rootCmd.Execute(); err != nil {
//fmt.Println(err)
os.Exit(1)
}
}
var rootCmd = &cobra.Command{
Use: "pegnetd",
Short: "pegnetd is the pegnet daemon to track balances/conversion/transactions",
PersistentPreRun: always,
PreRun: ReadConfig,
Run: func(cmd *cobra.Command, args []string) {
// Handle ctl+c
ctx, cancel := context.WithCancel(context.Background())
exit.GlobalExitHandler.AddCancel(cancel)
// Get the config
conf := viper.GetViper()
node, err := node.NewPegnetd(ctx, conf)
if err != nil {
log.WithError(err).Errorf("failed to launch pegnet node")
os.Exit(1)
}
apiserver := srv.NewAPIServer(conf, node)
go apiserver.Start(ctx.Done())
// Run
node.DBlockSync(ctx)
},
}
var properties = &cobra.Command{
Use: "properties",
Short: "Pegnetd properties",
PersistentPreRun: always,
PreRun: SoftReadConfig,
Run: func(cmd *cobra.Command, args []string) {
// Handle ctl+c
ctx, cancel := context.WithCancel(context.Background())
exit.GlobalExitHandler.AddCancel(cancel)
defer ctx.Done()
// Get the db
conf := viper.GetViper()
sqliteVersion, _, _ := sqlite3.Version()
format := "\t%20s: %v\n"
fmt.Println("Pegnetd CLI Version and Properties")
fmt.Printf(format, "Build Version", config.CompiledInVersion)
fmt.Printf(format, "Build Commit", config.CompiledInBuild)
fmt.Printf(format, "SQLite Version", sqliteVersion)
fmt.Printf(format, "Golang Version", runtime.Version())
// Remote pegnetd properties. The cli and pegnetd daemon can differ
fmt.Println("\nRemote Pegnetd")
props := getProperties()
fmt.Printf(format, "Build Version", props.BuildVersion)
fmt.Printf(format, "Build Commit", props.BuildCommit)
fmt.Printf(format, "SQLite Version", props.SQLiteVersion)
fmt.Printf(format, "Golang Version", props.GolangVersion)
// Factomd and walletd versions
fmt.Println()
cl := node.FactomClientFromConfig(conf)
factomdProperties := struct {
FactomdVersion string `json:"factomdversion"`
FactomdAPIVersion string `json:"factomdapiversion"`
}{
FactomdVersion: "Unknown", FactomdAPIVersion: "Unknown",
}
_ = cl.FactomdRequest(nil, "properties", nil, &factomdProperties)
fmt.Printf(format, "Factomd Version", factomdProperties.FactomdVersion)
fmt.Printf(format, "Factomd API Version", factomdProperties.FactomdAPIVersion)
walletdProperties := struct {
WalletdVersion string `json:"walletversion"`
WalletdAPIVersion string `json:"walletapiversion"`
}{
WalletdVersion: "Unknown", WalletdAPIVersion: "Unknown",
}
_ = cl.WalletdRequest(nil, "properties", nil, &walletdProperties)
fmt.Printf(format, "Walletd Version", walletdProperties.WalletdVersion)
fmt.Printf(format, "Walletd API Version", walletdProperties.WalletdAPIVersion)
},
}
// always is run before any command
func always(cmd *cobra.Command, args []string) {
// See if we are in testing mode
if ok, _ := cmd.Flags().GetBool("testing"); ok {
log.Infof("in testing mode, activation heights are 0")
act, _ := cmd.Flags().GetInt("act")
if act <= 0 {
act = 0
}
// Set all activations for testing
node.SetAllActivations(uint32(act))
}
if testingact, _ := cmd.Flags().GetInt32("testingact"); testingact >= 0 {
fat2.Fat2RCDEActivation = uint32(testingact)
node.V20HeightActivation = uint32(testingact)
// Also updaet hardfork
pegnet.Hardforks[1].ActivationHeight = uint32(testingact)
}
// Setup config reading
if cFilePath, _ := cmd.Flags().GetString("config"); cFilePath != "" {
base := filepath.Base(cFilePath)
dir := filepath.Dir(cFilePath)
viper.SetConfigFile(base)
viper.AddConfigPath(dir)
} else {
viper.SetConfigName("pegnetd-conf")
// Add as many config paths as we want to check
viper.AddConfigPath("$HOME/.pegnetd")
viper.AddConfigPath(".")
}
// Setup global command line flag overrides
// This gets run before any command executes. It will init global flags to the config
_ = viper.BindPFlag(config.LoggingLevel, cmd.Flags().Lookup("log"))
_ = viper.BindPFlag(config.Server, cmd.Flags().Lookup("server"))
_ = viper.BindPFlag(config.Wallet, cmd.Flags().Lookup("wallet"))
_ = viper.BindPFlag(config.WalletUser, cmd.Flags().Lookup("walletuser"))
_ = viper.BindPFlag(config.WalletPass, cmd.Flags().Lookup("walletpassword"))
_ = viper.BindPFlag(config.Pegnetd, cmd.Flags().Lookup("pegnetd"))
_ = viper.BindPFlag(config.APIListen, cmd.Flags().Lookup("api"))
_ = viper.BindPFlag(config.SQLDBWalMode, cmd.Flags().Lookup("wal"))
_ = viper.BindPFlag(config.CustomSQLDBMode, cmd.Flags().Lookup("dbmode"))
_ = viper.BindPFlag(config.DisableHardForkCheck, cmd.Flags().Lookup("no-hf"))
// Also init some defaults
viper.SetDefault(config.DBlockSyncRetryPeriod, time.Second*5)
viper.SetDefault(config.SqliteDBPath, "$HOME/.pegnetd/mainnet/sql.db")
// Catch ctl+c
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
go func() {
<-signalChan
log.Info("Gracefully closing")
exit.GlobalExitHandler.Close()
log.Info("closing application")
// If something is hanging, we have to kill it
os.Exit(0)
}()
}
// ReadConfig can be put as a PreRun for a command that uses the config file
func ReadConfig(cmd *cobra.Command, args []string) {
err := viper.ReadInConfig()
// If no config is found, we will attempt to make one
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// No config found? We will write the default config for the user
// If the custom config path is set, then we should not write a new config.
if custom, _ := cmd.Flags().GetString("config"); custom == "" {
home, err := os.UserHomeDir()
if err != nil {
log.WithError(err).Fatal("failed to create config path")
}
// Create the pegnetd directory if it is not already
err = os.MkdirAll(filepath.Join(home, ".pegnetd"), 0777)
if err != nil {
log.WithError(err).Fatal("failed to create config path")
}
configpath := filepath.Join(home, ".pegnetd", "pegnetd-conf.toml")
_, err = os.Stat(configpath)
if os.IsExist(err) { // Double check a file does not already exist. Don't overwrite a config
log.WithField("path", configpath).Fatal("config exists, but unable to read")
}
// Attempt to write a new config file
err = viper.WriteConfigAs(configpath)
if err != nil {
log.WithField("path", configpath).WithError(err).Fatal("failed to create config")
}
// Inform the user we made a config
log.WithField("path", configpath).Infof("no config file, one was created")
// Try to read it again
err = viper.ReadInConfig()
if err != nil {
log.WithError(err).Fatal("failed to load config")
}
}
} else if err != nil {
log.WithError(err).Fatal("failed to load config")
}
// Indicate which config was used
log.Infof("Using config from %s", viper.ConfigFileUsed())
initLogger()
}
// SoftReadConfig will not fail. It can be used for a command that needs the config,
// but is happy with the defaults
func SoftReadConfig(cmd *cobra.Command, args []string) {
err := viper.ReadInConfig()
if err != nil {
log.WithError(err).Debugf("failed to load config")
}
initLogger()
}
// TODO implement a dedicated logger
func initLogger() {
switch strings.ToLower(viper.GetString(config.LoggingLevel)) {
case "trace":
log.SetLevel(log.TraceLevel)
case "debug":
log.SetLevel(log.DebugLevel)
case "info":
log.SetLevel(log.InfoLevel)
case "warn":
log.SetLevel(log.WarnLevel)
case "error":
log.SetLevel(log.ErrorLevel)
case "fatal":
log.SetLevel(log.FatalLevel)
}
}