github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/siad/daemon.go (about) 1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strconv" 9 "strings" 10 "time" 11 12 "github.com/NebulousLabs/Sia/api" 13 "github.com/NebulousLabs/Sia/crypto" 14 "github.com/NebulousLabs/Sia/modules" 15 "github.com/NebulousLabs/Sia/modules/consensus" 16 "github.com/NebulousLabs/Sia/modules/explorer" 17 "github.com/NebulousLabs/Sia/modules/gateway" 18 "github.com/NebulousLabs/Sia/modules/host" 19 "github.com/NebulousLabs/Sia/modules/miner" 20 "github.com/NebulousLabs/Sia/modules/renter" 21 "github.com/NebulousLabs/Sia/modules/transactionpool" 22 "github.com/NebulousLabs/Sia/modules/wallet" 23 "github.com/NebulousLabs/Sia/profile" 24 25 "github.com/spf13/cobra" 26 ) 27 28 // processNetAddr adds a ':' to a bare integer, so that it is a proper port 29 // number. 30 func processNetAddr(addr string) string { 31 _, err := strconv.Atoi(addr) 32 if err == nil { 33 return ":" + addr 34 } 35 return addr 36 } 37 38 // processModules makes the modules string lowercase to make checking if a 39 // module in the string easier, and returns an error if the string contains an 40 // invalid module character. 41 func processModules(modules string) (string, error) { 42 modules = strings.ToLower(modules) 43 validModules := "cghmrtwe" 44 invalidModules := modules 45 for _, m := range validModules { 46 invalidModules = strings.Replace(invalidModules, string(m), "", 1) 47 } 48 if len(invalidModules) > 0 { 49 return "", errors.New("Unable to parse --modules flag, unrecognized or duplicate modules: " + invalidModules) 50 } 51 return modules, nil 52 } 53 54 // processConfig checks the configuration values and performs cleanup on 55 // incorrect-but-allowed values. 56 func processConfig(config Config) (Config, error) { 57 var err error 58 config.Siad.APIaddr = processNetAddr(config.Siad.APIaddr) 59 config.Siad.RPCaddr = processNetAddr(config.Siad.RPCaddr) 60 config.Siad.HostAddr = processNetAddr(config.Siad.HostAddr) 61 config.Siad.Modules, err = processModules(config.Siad.Modules) 62 if err != nil { 63 return Config{}, err 64 } 65 return config, nil 66 } 67 68 // startDaemonCmd uses the config parameters to start siad. 69 func startDaemon(config Config) (err error) { 70 // Print a startup message. 71 fmt.Println("Loading...") 72 loadStart := time.Now() 73 74 // Create all of the modules. 75 i := 0 76 var g modules.Gateway 77 if strings.Contains(config.Siad.Modules, "g") { 78 i++ 79 fmt.Printf("(%d/%d) Loading gateway...\n", i, len(config.Siad.Modules)) 80 g, err = gateway.New(config.Siad.RPCaddr, filepath.Join(config.Siad.SiaDir, modules.GatewayDir)) 81 if err != nil { 82 return err 83 } 84 } 85 var cs modules.ConsensusSet 86 if strings.Contains(config.Siad.Modules, "c") { 87 i++ 88 fmt.Printf("(%d/%d) Loading consensus...\n", i, len(config.Siad.Modules)) 89 cs, err = consensus.New(g, filepath.Join(config.Siad.SiaDir, modules.ConsensusDir)) 90 if err != nil { 91 return err 92 } 93 } 94 var e modules.Explorer 95 if strings.Contains(config.Siad.Modules, "e") { 96 i++ 97 fmt.Printf("(%d/%d) Loading explorer...\n", i, len(config.Siad.Modules)) 98 e, err = explorer.New(cs, filepath.Join(config.Siad.SiaDir, modules.ExplorerDir)) 99 if err != nil { 100 return err 101 } 102 } 103 var tpool modules.TransactionPool 104 if strings.Contains(config.Siad.Modules, "t") { 105 i++ 106 fmt.Printf("(%d/%d) Loading transaction pool...\n", i, len(config.Siad.Modules)) 107 tpool, err = transactionpool.New(cs, g, filepath.Join(config.Siad.SiaDir, modules.TransactionPoolDir)) 108 if err != nil { 109 return err 110 } 111 } 112 var w modules.Wallet 113 if strings.Contains(config.Siad.Modules, "w") { 114 i++ 115 fmt.Printf("(%d/%d) Loading wallet...\n", i, len(config.Siad.Modules)) 116 w, err = wallet.New(cs, tpool, filepath.Join(config.Siad.SiaDir, modules.WalletDir)) 117 if err != nil { 118 return err 119 } 120 } 121 var m modules.Miner 122 if strings.Contains(config.Siad.Modules, "m") { 123 i++ 124 fmt.Printf("(%d/%d) Loading miner...\n", i, len(config.Siad.Modules)) 125 m, err = miner.New(cs, tpool, w, filepath.Join(config.Siad.SiaDir, modules.MinerDir)) 126 if err != nil { 127 return err 128 } 129 } 130 var h modules.Host 131 if strings.Contains(config.Siad.Modules, "h") { 132 i++ 133 fmt.Printf("(%d/%d) Loading host...\n", i, len(config.Siad.Modules)) 134 h, err = host.New(cs, tpool, w, config.Siad.HostAddr, filepath.Join(config.Siad.SiaDir, modules.HostDir)) 135 if err != nil { 136 return err 137 } 138 } 139 var r modules.Renter 140 if strings.Contains(config.Siad.Modules, "r") { 141 i++ 142 fmt.Printf("(%d/%d) Loading renter...\n", i, len(config.Siad.Modules)) 143 r, err = renter.New(cs, w, tpool, filepath.Join(config.Siad.SiaDir, modules.RenterDir)) 144 if err != nil { 145 return err 146 } 147 } 148 srv, err := api.NewServer( 149 config.Siad.APIaddr, 150 config.Siad.RequiredUserAgent, 151 cs, 152 e, 153 g, 154 h, 155 m, 156 r, 157 tpool, 158 w, 159 ) 160 if err != nil { 161 return err 162 } 163 164 // Bootstrap to the network. 165 if !config.Siad.NoBootstrap && g != nil { 166 // connect to 3 random bootstrap nodes 167 perm, err := crypto.Perm(len(modules.BootstrapPeers)) 168 if err != nil { 169 return err 170 } 171 for _, i := range perm[:3] { 172 go g.Connect(modules.BootstrapPeers[i]) 173 } 174 } 175 176 // Print a 'startup complete' message. 177 startupTime := time.Since(loadStart) 178 fmt.Println("Finished loading in", startupTime.Seconds(), "seconds") 179 180 // Start serving api requests. 181 err = srv.Serve() 182 if err != nil { 183 return err 184 } 185 return nil 186 } 187 188 // startDaemonCmd is a passthrough function for startDaemon. 189 func startDaemonCmd(cmd *cobra.Command, _ []string) { 190 // Create the profiling directory if profiling is enabled. 191 if globalConfig.Siad.Profile { 192 go profile.StartContinuousProfile(globalConfig.Siad.ProfileDir) 193 } 194 195 // Process the config variables after they are parsed by cobra. 196 config, err := processConfig(globalConfig) 197 if err != nil { 198 fmt.Fprintln(os.Stderr, err) 199 cmd.Usage() 200 os.Exit(exitCodeUsage) 201 } 202 203 // Start siad. startDaemon will only return when it is shutting down. 204 err = startDaemon(config) 205 if err != nil { 206 die(err) 207 } 208 }