github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/internal/cli/server/command.go (about) 1 package server 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "os/signal" 8 "strings" 9 "syscall" 10 11 "github.com/maticnetwork/heimdall/cmd/heimdalld/service" 12 "github.com/mitchellh/cli" 13 "github.com/pelletier/go-toml" 14 15 "github.com/ethereum/go-ethereum/log" 16 ) 17 18 // Command is the command to start the sever 19 type Command struct { 20 UI cli.Ui 21 22 // cli configuration 23 cliConfig *Config 24 25 // final configuration 26 config *Config 27 28 configFile string 29 30 srv *Server 31 } 32 33 // MarkDown implements cli.MarkDown interface 34 func (c *Command) MarkDown() string { 35 items := []string{ 36 "# Server", 37 "The ```bor server``` command runs the Bor client.", 38 c.Flags().MarkDown(), 39 } 40 41 return strings.Join(items, "\n\n") 42 } 43 44 // Help implements the cli.Command interface 45 func (c *Command) Help() string { 46 return `Usage: bor [options] 47 48 Run the Bor server. 49 ` + c.Flags().Help() 50 } 51 52 // Synopsis implements the cli.Command interface 53 func (c *Command) Synopsis() string { 54 return "Run the Bor server" 55 } 56 57 func (c *Command) extractFlags(args []string) error { 58 config := *DefaultConfig() 59 60 flags := c.Flags() 61 if err := flags.Parse(args); err != nil { 62 c.UI.Error(err.Error()) 63 c.config = &config 64 65 return err 66 } 67 68 // TODO: Check if this can be removed or not 69 // read cli flags 70 if err := config.Merge(c.cliConfig); err != nil { 71 c.UI.Error(err.Error()) 72 c.config = &config 73 74 return err 75 } 76 // read if config file is provided, this will overwrite the cli flags, if provided 77 if c.configFile != "" { 78 log.Warn("Config File provided, this will overwrite the cli flags", "path", c.configFile) 79 cfg, err := readConfigFile(c.configFile) 80 if err != nil { 81 c.UI.Error(err.Error()) 82 c.config = &config 83 84 return err 85 } 86 if err := config.Merge(cfg); err != nil { 87 c.UI.Error(err.Error()) 88 c.config = &config 89 90 return err 91 } 92 } 93 94 // nolint: nestif 95 // check for log-level and verbosity here 96 if c.configFile != "" { 97 data, _ := toml.LoadFile(c.configFile) 98 if data.Has("verbosity") && data.Has("log-level") { 99 log.Warn("Config contains both, verbosity and log-level, log-level will be deprecated soon. Use verbosity only.", "using", data.Get("verbosity")) 100 } else if !data.Has("verbosity") && data.Has("log-level") { 101 log.Warn("Config contains log-level only, note that log-level will be deprecated soon. Use verbosity instead.", "using", data.Get("log-level")) 102 config.Verbosity = VerbosityStringToInt(strings.ToLower(data.Get("log-level").(string))) 103 } 104 } else { 105 tempFlag := 0 106 for _, val := range args { 107 if (strings.HasPrefix(val, "-verbosity") || strings.HasPrefix(val, "--verbosity")) && config.LogLevel != "" { 108 tempFlag = 1 109 break 110 } 111 } 112 if tempFlag == 1 { 113 log.Warn("Both, verbosity and log-level flags are provided, log-level will be deprecated soon. Use verbosity only.", "using", config.Verbosity) 114 } else if tempFlag == 0 && config.LogLevel != "" { 115 log.Warn("Only log-level flag is provided, note that log-level will be deprecated soon. Use verbosity instead.", "using", config.LogLevel) 116 config.Verbosity = VerbosityStringToInt(strings.ToLower(config.LogLevel)) 117 } 118 } 119 120 c.config = &config 121 122 return nil 123 } 124 125 // Run implements the cli.Command interface 126 func (c *Command) Run(args []string) int { 127 err := c.extractFlags(args) 128 if err != nil { 129 c.UI.Error(err.Error()) 130 return 1 131 } 132 133 if c.config.Heimdall.RunHeimdall { 134 shutdownCtx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGINT, syscall.SIGTERM) 135 defer stop() 136 137 go func() { 138 service.NewHeimdallService(shutdownCtx, c.getHeimdallArgs()) 139 }() 140 } 141 142 srv, err := NewServer(c.config, WithGRPCAddress()) 143 if err != nil { 144 c.UI.Error(err.Error()) 145 return 1 146 } 147 c.srv = srv 148 149 return c.handleSignals() 150 } 151 152 func (c *Command) handleSignals() int { 153 signalCh := make(chan os.Signal, 4) 154 signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP) 155 156 sig := <-signalCh 157 158 c.UI.Output(fmt.Sprintf("Caught signal: %v", sig)) 159 c.UI.Output("Gracefully shutting down agent...") 160 161 gracefulCh := make(chan struct{}) 162 go func() { 163 c.srv.Stop() 164 close(gracefulCh) 165 }() 166 167 for i := 10; i > 0; i-- { 168 select { 169 case <-signalCh: 170 log.Warn("Already shutting down, interrupt more force stop.", "times", i-1) 171 case <-gracefulCh: 172 return 0 173 } 174 } 175 return 1 176 } 177 178 // GetConfig returns the user specified config 179 func (c *Command) GetConfig() *Config { 180 return c.cliConfig 181 } 182 183 func (c *Command) getHeimdallArgs() []string { 184 heimdallArgs := strings.Split(c.config.Heimdall.RunHeimdallArgs, ",") 185 return append([]string{"start"}, heimdallArgs...) 186 }