github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/cmd/ipfs2/main.go (about) 1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "os" 8 "os/signal" 9 "runtime/pprof" 10 11 logging "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-logging" 12 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" 13 manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net" 14 15 cmds "github.com/jbenet/go-ipfs/commands" 16 cmdsCli "github.com/jbenet/go-ipfs/commands/cli" 17 cmdsHttp "github.com/jbenet/go-ipfs/commands/http" 18 "github.com/jbenet/go-ipfs/config" 19 "github.com/jbenet/go-ipfs/core" 20 commands "github.com/jbenet/go-ipfs/core/commands2" 21 daemon "github.com/jbenet/go-ipfs/daemon2" 22 u "github.com/jbenet/go-ipfs/util" 23 ) 24 25 // log is the command logger 26 var log = u.Logger("cmd/ipfs") 27 28 const ( 29 cpuProfile = "ipfs.cpuprof" 30 heapProfile = "ipfs.memprof" 31 errorFormat = "ERROR: %v\n\n" 32 ) 33 34 func main() { 35 err := run() 36 if err != nil { 37 fmt.Println(err) 38 os.Exit(1) 39 } 40 } 41 42 func run() error { 43 handleInterrupt() 44 45 args := os.Args[1:] 46 req, root, err := createRequest(args) 47 if err != nil { 48 return err 49 } 50 51 debug, err := req.Option("debug").Bool() 52 if err != nil { 53 return err 54 } 55 if debug { 56 u.Debug = true 57 u.SetAllLoggers(logging.DEBUG) 58 } 59 60 if u.Debug { 61 stopProfilingFunc, err := startProfiling() 62 if err != nil { 63 return err 64 } 65 defer stopProfilingFunc() // to be executed as late as possible 66 } 67 68 helpTextDisplayed, err := handleHelpOption(req, root) 69 if err != nil { 70 return err 71 } 72 if helpTextDisplayed { 73 return nil 74 } 75 76 res, err := callCommand(req, root) 77 if err != nil { 78 return err 79 } 80 81 err = outputResponse(res, root) 82 if err != nil { 83 return err 84 } 85 86 return nil 87 } 88 89 func createRequest(args []string) (cmds.Request, *cmds.Command, error) { 90 req, root, cmd, path, err := cmdsCli.Parse(args, Root, commands.Root) 91 92 // handle parse error (which means the commandline input was wrong, 93 // e.g. incorrect number of args, or nonexistent subcommand) 94 if err != nil { 95 // if the -help flag wasn't specified, show the error message 96 // or if a path was returned (user specified a valid subcommand), show the error message 97 // (this means there was an option or argument error) 98 if path != nil && len(path) > 0 { 99 help, _ := req.Option("help").Bool() 100 if !help { 101 fmt.Printf(errorFormat, err) 102 } 103 } 104 105 // when generating help for the root command, we don't want the autogenerated subcommand text 106 // (since we have better hand-made subcommand list in the root Help field) 107 if cmd == nil { 108 root = &*commands.Root 109 root.Subcommands = nil 110 } 111 112 // generate the help text for the command the user was trying to call (or root) 113 helpText, htErr := cmdsCli.HelpText("ipfs", root, path) 114 if htErr != nil { 115 fmt.Println(htErr) 116 } else { 117 fmt.Println(helpText) 118 } 119 return nil, nil, err 120 } 121 122 configPath, err := getConfigRoot(req) 123 if err != nil { 124 return nil, nil, err 125 } 126 127 conf, err := getConfig(configPath) 128 if err != nil { 129 return nil, nil, err 130 } 131 ctx := req.Context() 132 ctx.ConfigRoot = configPath 133 ctx.Config = conf 134 135 if !req.Option("encoding").Found() { 136 if req.Command().Marshallers != nil && req.Command().Marshallers[cmds.Text] != nil { 137 req.SetOption("encoding", cmds.Text) 138 } else { 139 req.SetOption("encoding", cmds.JSON) 140 } 141 } 142 143 return req, root, nil 144 } 145 146 func handleHelpOption(req cmds.Request, root *cmds.Command) (helpTextDisplayed bool, err error) { 147 help, err := req.Option("help").Bool() 148 if err != nil { 149 return false, err 150 } 151 if !help { 152 return false, nil 153 } 154 helpText, err := cmdsCli.HelpText("ipfs", root, req.Path()) 155 if err != nil { 156 return false, err 157 } 158 fmt.Println(helpText) 159 160 return true, nil 161 } 162 163 func callCommand(req cmds.Request, root *cmds.Command) (cmds.Response, error) { 164 var res cmds.Response 165 166 if root == Root { // TODO explain what it means when root == Root 167 res = root.Call(req) 168 169 } else { 170 local, err := req.Option("local").Bool() 171 if err != nil { 172 return nil, err 173 } 174 175 if (!req.Option("local").Found() || !local) && daemon.Locked(req.Context().ConfigRoot) { 176 addr, err := ma.NewMultiaddr(req.Context().Config.Addresses.API) 177 if err != nil { 178 return nil, err 179 } 180 181 _, host, err := manet.DialArgs(addr) 182 if err != nil { 183 return nil, err 184 } 185 186 client := cmdsHttp.NewClient(host) 187 188 res, err = client.Send(req) 189 if err != nil { 190 return nil, err 191 } 192 193 } else { 194 node, err := core.NewIpfsNode(req.Context().Config, false) 195 if err != nil { 196 return nil, err 197 } 198 defer node.Close() 199 req.Context().Node = node 200 201 res = root.Call(req) 202 } 203 } 204 205 return res, nil 206 } 207 208 func outputResponse(res cmds.Response, root *cmds.Command) error { 209 if res.Error() != nil { 210 fmt.Printf(errorFormat, res.Error().Error()) 211 212 if res.Error().Code != cmds.ErrClient { 213 return res.Error() 214 } 215 216 // if this is a client error, we try to display help text 217 if res.Error().Code == cmds.ErrClient { 218 helpText, err := cmdsCli.HelpText("ipfs", root, res.Request().Path()) 219 if err != nil { 220 fmt.Println(err.Error()) 221 } else { 222 fmt.Println(helpText) 223 } 224 } 225 226 emptyErr := errors.New("") // already displayed error text 227 return emptyErr 228 } 229 230 out, err := res.Reader() 231 if err != nil { 232 return err 233 } 234 235 io.Copy(os.Stdout, out) 236 return nil 237 } 238 239 func getConfigRoot(req cmds.Request) (string, error) { 240 configOpt, err := req.Option("config").String() 241 if err != nil { 242 return "", err 243 } 244 if configOpt != "" { 245 return configOpt, nil 246 } 247 248 configPath, err := config.PathRoot() 249 if err != nil { 250 return "", err 251 } 252 return configPath, nil 253 } 254 255 func getConfig(path string) (*config.Config, error) { 256 configFile, err := config.Filename(path) 257 if err != nil { 258 return nil, err 259 } 260 261 return config.Load(configFile) 262 } 263 264 // startProfiling begins CPU profiling and returns a `stop` function to be 265 // executed as late as possible. The stop function captures the memprofile. 266 func startProfiling() (func(), error) { 267 268 // start CPU profiling as early as possible 269 ofi, err := os.Create(cpuProfile) 270 if err != nil { 271 return nil, err 272 } 273 pprof.StartCPUProfile(ofi) 274 275 stopProfiling := func() { 276 pprof.StopCPUProfile() 277 defer ofi.Close() // captured by the closure 278 err := writeHeapProfileToFile() 279 if err != nil { 280 log.Critical(err) 281 } 282 } 283 return stopProfiling, nil 284 } 285 286 func writeHeapProfileToFile() error { 287 mprof, err := os.Create(heapProfile) 288 if err != nil { 289 return err 290 } 291 defer mprof.Close() // _after_ writing the heap profile 292 return pprof.WriteHeapProfile(mprof) 293 } 294 295 // listen for and handle SIGTERM 296 func handleInterrupt() { 297 c := make(chan os.Signal, 1) 298 signal.Notify(c, os.Interrupt) 299 300 go func() { 301 for _ = range c { 302 log.Info("Received interrupt signal, terminating...") 303 os.Exit(0) 304 } 305 }() 306 }