func main() { flag.Parse() if *flagVersion { fmt.Fprintf(os.Stderr, "publisher version: %s\nGo version: %s (%s/%s)\n", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) return } logf("Starting publisher version %s; Go %s (%s/%s)", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) listenAddr, err := app.ListenAddress() if err != nil { logger.Fatalf("Listen address: %v", err) } conf := appConfig() ph := newPublishHandler(conf) if err := ph.initRootNode(); err != nil { logf("%v", err) } ws := webserver.New() ws.Logger = logger ws.Handle("/", ph) if conf.HTTPSCert != "" && conf.HTTPSKey != "" { ws.SetTLS(conf.HTTPSCert, conf.HTTPSKey) } if err := ws.Listen(listenAddr); err != nil { logger.Fatalf("Listen: %v", err) } ws.Serve() }
func main() { flag.Parse() if *flagVersion { fmt.Fprintf(os.Stderr, "hello version: %s\nGo version: %s (%s/%s)\n", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) return } log.Printf("Starting hello version %s; Go %s (%s/%s)", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) listenAddr, err := app.ListenAddress() if err != nil { log.Fatalf("Listen address: %v", err) } conf := appConfig() ws := webserver.New() ws.Handle("/", &helloHandler{who: conf.Word}) // TODO(mpl): handle status requests too. Camlistore will send an auth // token in the extra config that should be used as the "password" for // subsequent status requests. if err := ws.Listen(listenAddr); err != nil { log.Fatalf("Listen: %v", err) } ws.Serve() }
func (sh *StatusHandler) currentStatus() *status { res := &status{ Version: buildinfo.Version(), Storage: make(map[string]storageStatus), } _, hi, err := sh.handlerFinder.FindHandlerByType("root") if err != nil { res.Error = fmt.Sprintf("Error finding root handler: %v", err) return res } rh := hi.(*RootHandler) res.rootPrefix = rh.Prefix for _, sh := range rh.sync { res.SyncStatus = append(res.SyncStatus, sh.currentStatus()) } types, handlers := sh.handlerFinder.AllHandlers() // Storage for pfx, typ := range types { if !strings.HasPrefix(typ, "storage-") { continue } h := handlers[pfx] _, isIndex := h.(*index.Index) res.Storage[pfx] = storageStatus{ Type: strings.TrimPrefix(typ, "storage-"), Primary: pfx == rh.BlobRoot, IsIndex: isIndex, } } return res }
func (rh *RootHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if wantsDiscovery(req) { if auth.Allowed(req, auth.OpDiscovery) { rh.serveDiscovery(rw, req) return } if !rh.Stealth { http.Error(rw, "Unauthorized", http.StatusUnauthorized) } return } if rh.Stealth { return } if req.URL.Path == "/favicon.ico" { serveStaticFile(rw, req, Files, "favicon.ico") return } f := func(p string, a ...interface{}) { fmt.Fprintf(rw, p, a...) } f("<html><body><p>This is camlistored (%s), a "+ "<a href='http://camlistore.org'>Camlistore</a> server.</p>", buildinfo.Version()) if auth.IsLocalhost(req) && !isDevServer() { f("<p>If you're coming from localhost, configure your Camlistore server at <a href='/setup'>/setup</a>.</p>") } if rh.ui != nil { f("<p>To manage your content, access the <a href='%s'>%s</a>.</p>", rh.ui.prefix, rh.ui.prefix) } if rh.statusRoot != "" { f("<p>To view status, see <a href='%s'>%s</a>", rh.statusRoot, rh.statusRoot) } fmt.Fprintf(rw, "</body></html>") }
// camputMain is separated from main for testing from camput func camputMain(args ...string) { if *flagVersion { fmt.Fprintf(stderr, "camget version: %s\n", buildinfo.Version()) return } if *flagHelp { usage("") } if len(args) == 0 { usage("No mode given.") } mode := args[0] cmd, ok := modeCommand[mode] if !ok { usage(fmt.Sprintf("Unknown mode %q", mode)) } var up *Uploader if mode != "init" { up = newUploader() } cmdFlags := modeFlags[mode] err := cmdFlags.Parse(args[1:]) if err != nil { err = ErrUsage } else { err = cmd.RunCommand(up, cmdFlags.Args()) } if ue, isUsage := err.(UsageError); isUsage { if isUsage { errf("%s\n", ue) } cmd.Usage() errf("\nGlobal options:\n") flag.PrintDefaults() if hasFlags(cmdFlags) { errf("\nMode-specific options for mode %q:\n", mode) cmdFlags.PrintDefaults() } exit(1) } if *flagVerbose { stats := up.Stats() log.Printf("Client stats: %s", stats.String()) log.Printf(" #HTTP reqs: %d", up.transport.Requests()) } previousErrors := wereErrors if err != nil { wereErrors = true if !previousErrors { log.Printf("Error: %v", err) } } if wereErrors { exit(2) } }
func (sh *StatusHandler) serveStatus(rw http.ResponseWriter, req *http.Request) { res := &statusResponse{ Version: buildinfo.Version(), } httputil.ReturnJSON(rw, res) }
// Main is meant to be the core of a command that has // subcommands (modes), such as camput or camtool. func Main() { registerFlagOnce.Do(ExtraFlagRegistration) if setCommandLineOutput != nil { setCommandLineOutput(Stderr) } flag.Parse() args := flag.Args() if *FlagVersion { fmt.Fprintf(Stderr, "%s version: %s\n", os.Args[0], buildinfo.Version()) return } if *FlagHelp { usage("") } if len(args) == 0 { usage("No mode given.") } mode := args[0] cmd, ok := modeCommand[mode] if !ok { usage(fmt.Sprintf("Unknown mode %q", mode)) } cmdFlags := modeFlags[mode] cmdFlags.SetOutput(Stderr) err := cmdFlags.Parse(args[1:]) if err != nil { err = ErrUsage } else { if *wantHelp[mode] { help(mode) return } err = cmd.RunCommand(cmdFlags.Args()) } if ue, isUsage := err.(UsageError); isUsage { if isUsage { Errorf("%s\n", ue) } cmd.Usage() Errorf("\nGlobal options:\n") flag.PrintDefaults() if hasFlags(cmdFlags) { Errorf("\nMode-specific options for mode %q:\n", mode) cmdFlags.PrintDefaults() } Exit(1) } PreExit() if err != nil { if !ExitWithFailure { // because it was already logged if ExitWithFailure log.Printf("Error: %v", err) } Exit(2) } }
// Main is meant to be the core of a command that has // subcommands (modes), such as camput or camtool. func Main() { ExtraFlagRegistration() flag.Parse() args := flag.Args() if *FlagVersion { fmt.Fprintf(Stderr, "%s version: %s\n", os.Args[0], buildinfo.Version()) return } if *FlagHelp { usage("") } if len(args) == 0 { usage("No mode given.") } mode := args[0] cmd, ok := modeCommand[mode] if !ok { usage(fmt.Sprintf("Unknown mode %q", mode)) } cmdFlags := modeFlags[mode] var cmdHelp bool cmdFlags.BoolVar(&cmdHelp, "help", false, "Help for this mode.") err := cmdFlags.Parse(args[1:]) if err != nil { err = ErrUsage } else { if cmdHelp { help(mode) return } err = cmd.RunCommand(cmdFlags.Args()) } if ue, isUsage := err.(UsageError); isUsage { if isUsage { Errorf("%s\n", ue) } cmd.Usage() Errorf("\nGlobal options:\n") flag.PrintDefaults() if hasFlags(cmdFlags) { Errorf("\nMode-specific options for mode %q:\n", mode) cmdFlags.PrintDefaults() } Exit(1) } if *FlagVerbose { PreExit() } if err != nil { if !ExitWithFailure { // because it was already logged if ExitWithFailure log.Printf("Error: %v", err) } Exit(2) } }
func main() { flag.Parse() if *flagVersion { fmt.Fprintf(os.Stderr, "camlistored version: %s\n", buildinfo.Version()) return } fileName, err := findConfigFile(*flagConfigFile) if err != nil { exitf("Error finding config file %q: %v", fileName, err) } log.Printf("Using config file %s", fileName) config, err := serverconfig.Load(fileName) if err != nil { exitf("Could not load server config: %v", err) } ws := webserver.New() listen, baseURL := listenAndBaseURL(config) setupTLS(ws, config, listen) err = config.InstallHandlers(ws, baseURL, nil) if err != nil { exitf("Error parsing config: %v", err) } err = ws.Listen(listen) if err != nil { exitf("Listen: %v", err) } urlOpened := false if config.UIPath != "" { uiURL := ws.ListenURL() + config.UIPath if baseURL != "" { uiURL = baseURL + config.UIPath } log.Printf("UI available at %s", uiURL) if runtime.GOOS == "windows" { // Might be double-clicking an icon with no shell window? // Just open the URL for them. urlOpened = true go osutil.OpenURL(uiURL) } } if *flagConfigFile == "" && !urlOpened { go osutil.OpenURL(ws.ListenURL()) } go ws.Serve() go handleSignals() if flagPollParent { osutil.DieOnParentDeath() } select {} }
func main() { flag.Parse() if *flagVersion { fmt.Fprintf(os.Stderr, "camlistored version: %s\n", buildinfo.Version()) return } shutdownc := make(chan io.Closer, 1) // receives io.Closer to cleanly shut down go handleSignals(shutdownc) fileName, isNewConfig, err := findConfigFile(*flagConfigFile) if err != nil { exitf("Error finding config file %q: %v", fileName, err) } log.Printf("Using config file %s", fileName) config, err := serverconfig.Load(fileName) if err != nil { exitf("Could not load server config: %v", err) } ws := webserver.New() listen, baseURL := listenAndBaseURL(config) setupTLS(ws, config, listen) shutdownCloser, err := config.InstallHandlers(ws, baseURL, nil) if err != nil { exitf("Error parsing config: %v", err) } shutdownc <- shutdownCloser err = ws.Listen(listen) if err != nil { exitf("Listen: %v", err) } urlToOpen := ws.ListenURL() if baseURL != "" { urlToOpen = baseURL } if !isNewConfig { // user may like to configure the server at the initial startup, // open UI if this is not the first run with a new config file. urlToOpen += config.UIPath } log.Printf("Available on %s", urlToOpen) if *flagOpenBrowser { go osutil.OpenURL(urlToOpen) } go ws.Serve() if flagPollParent { osutil.DieOnParentDeath() } select {} }
func main() { flag.Parse() if *flagVersion { fmt.Fprintf(os.Stderr, "publisher version: %s\nGo version: %s (%s/%s)\n", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) return } logf("Starting publisher version %s; Go %s (%s/%s)", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) listenAddr, err := app.ListenAddress() if err != nil { logger.Fatalf("Listen address: %v", err) } conf, err := appConfig() if err != nil { logger.Fatalf("no app config: %v", err) } ph := newPublishHandler(conf) masterQueryURL := os.Getenv("CAMLI_APP_MASTERQUERY_URL") if masterQueryURL == "" { logger.Fatalf("Publisher application needs a CAMLI_APP_MASTERQUERY_URL env var") } ph.masterQueryURL = masterQueryURL if err := ph.initRootNode(); err != nil { logf("%v", err) } else { if err := ph.setMasterQuery(ph.rootNode); err != nil { logf("%v", err) } } ws := webserver.New() ws.Logger = logger if err := setupTLS(ws, conf); err != nil { logger.Fatal("could not setup TLS: %v", err) } ws.Handle("/", ph) if err := ws.Listen(listenAddr); err != nil { logger.Fatalf("Listen: %v", err) } ws.Serve() }
func (sh *StatusHandler) currentStatus() *status { res := &status{ Version: buildinfo.Version(), Storage: make(map[string]storageStatus), Sync: make(map[string]syncStatus), } if v := os.Getenv("CAMLI_FAKE_STATUS_ERROR"); v != "" { res.addError(v, "/status/#fakeerror") } _, hi, err := sh.handlerFinder.FindHandlerByType("root") if err != nil { res.addError(fmt.Sprintf("Error finding root handler: %v", err), "") return res } rh := hi.(*RootHandler) res.rootPrefix = rh.Prefix if pfx, h, err := sh.handlerFinder.FindHandlerByType("importer"); err == nil { res.importerRoot = pfx as := h.(interface { AccountsStatus() (interface{}, []camtypes.StatusError) }) var errs []camtypes.StatusError res.ImporterAccounts, errs = as.AccountsStatus() res.Errors = append(res.Errors, errs...) } types, handlers := sh.handlerFinder.AllHandlers() // Sync for pfx, h := range handlers { sh, ok := h.(*SyncHandler) if !ok { continue } res.Sync[pfx] = sh.currentStatus() } // Storage for pfx, typ := range types { if !strings.HasPrefix(typ, "storage-") { continue } h := handlers[pfx] _, isIndex := h.(*index.Index) res.Storage[pfx] = storageStatus{ Type: strings.TrimPrefix(typ, "storage-"), Primary: pfx == rh.BlobRoot, IsIndex: isIndex, } } return res }
func (sh *StatusHandler) serveStatusHTML(rw http.ResponseWriter, req *http.Request) { st := sh.currentStatus() f := func(p string, a ...interface{}) { if len(a) == 0 { io.WriteString(rw, p) } else { fmt.Fprintf(rw, p, a...) } } f("<html><head><title>camlistored status</title></head>") f("<body>") f("<h1>camlistored status</h1>") f("<h2>Versions</h2><ul>") var envStr string if env.OnGCE() { envStr = " (on GCE)" } f("<li><b>Camlistore</b>: %s%s</li>", html.EscapeString(buildinfo.Version()), envStr) f("<li><b>Go</b>: %s/%s %s, cgo=%v</li>", runtime.GOOS, runtime.GOARCH, runtime.Version(), cgoEnabled) f("<li><b>djpeg</b>: %s", html.EscapeString(buildinfo.DjpegStatus())) f("</ul>") f("<h2>Logs</h2><ul>") f(" <li><a href='/debug/config'>/debug/config</a> - server config</li>\n") if env.OnGCE() { f(" <li><a href='/debug/logs/camlistored'>camlistored logs on Google Cloud Logging</a></li>\n") f(" <li><a href='/debug/logs/system'>system logs from Google Compute Engine</a></li>\n") } f("</ul>") f("<h2>Admin</h2>") f("<form method='post' action='restart' onsubmit='return confirm(\"Really restart now?\")'><button>restart server</button></form>") f("<h2>Handlers</h2>") f("<p>As JSON: <a href='status.json'>status.json</a>; and the <a href='%s?camli.mode=config'>discovery JSON</a>.</p>", st.rootPrefix) f("<p>Not yet pretty HTML UI:</p>") js, err := json.MarshalIndent(st, "", " ") if err != nil { log.Printf("JSON marshal error: %v", err) } jsh := html.EscapeString(string(js)) jsh = quotedPrefix.ReplaceAllStringFunc(jsh, func(in string) string { pfx := in[1 : len(in)-1] if st.isHandler(pfx) { return fmt.Sprintf("%s<a href='%s'>%s</a>%s", in[:1], pfx, pfx, in[len(in)-1:]) } return in }) f("<pre>%s</pre>", jsh) }
// Main is meant to be the core of a command that has // subcommands (modes), such as camput or camtool. func Main() error { ExtraFlagRegistration() flag.Parse() args := flag.Args() if *FlagVersion { fmt.Fprintf(Stderr, "camput version: %s\n", buildinfo.Version()) return nil } if *FlagHelp { usage("") } if len(args) == 0 { usage("No mode given.") } mode := args[0] cmd, ok := modeCommand[mode] if !ok { usage(fmt.Sprintf("Unknown mode %q", mode)) } cmdFlags := modeFlags[mode] err := cmdFlags.Parse(args[1:]) if err != nil { err = ErrUsage } else { err = cmd.RunCommand(cmdFlags.Args()) } if ue, isUsage := err.(UsageError); isUsage { if isUsage { Errf("%s\n", ue) } cmd.Usage() Errf("\nGlobal options:\n") flag.PrintDefaults() if hasFlags(cmdFlags) { Errf("\nMode-specific options for mode %q:\n", mode) cmdFlags.PrintDefaults() } Exit(1) } if *FlagVerbose { PreExit() } return err }
func (rh *RootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if wantsDiscovery(r) { if auth.Allowed(r, auth.OpDiscovery) { rh.serveDiscovery(w, r) return } if !rh.Stealth { auth.SendUnauthorized(w, r) } return } if rh.Stealth { return } if r.RequestURI == "/" && rh.ui != nil { http.Redirect(w, r, "/ui/", http.StatusMovedPermanently) return } if r.URL.Path == "/favicon.ico" { ServeStaticFile(w, r, Files, "favicon.ico") return } f := func(p string, a ...interface{}) { fmt.Fprintf(w, p, a...) } f("<html><body><p>This is camlistored (%s), a "+ "<a href='http://camlistore.org'>Camlistore</a> server.</p>", buildinfo.Version()) if rh.ui != nil { f("<p>To manage your content, access the <a href='%s'>%s</a>.</p>", rh.ui.prefix, rh.ui.prefix) } if rh.statusRoot != "" { f("<p>To view status, see <a href='%s'>%s</a>.</p>", rh.statusRoot, rh.statusRoot) } if rh.helpRoot != "" { f("<p>To view more information on accessing the server, see <a href='%s'>%s</a>.</p>", rh.helpRoot, rh.helpRoot) } fmt.Fprintf(w, "</body></html>") }
// Main sends on up when it's running, and shuts down when it receives from down. func Main(up chan<- struct{}, down <-chan struct{}) { flag.Parse() if *flagVersion { fmt.Fprintf(os.Stderr, "camlistored version: %s\nGo version: %s (%s/%s)\n", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) return } if legalprint.MaybePrint(os.Stderr) { return } if env.OnGCE() { log.SetOutput(gce.LogWriter()) } if *flagReindex { index.SetImpendingReindex() } log.Printf("Starting camlistored version %s; Go %s (%s/%s)", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) shutdownc := make(chan io.Closer, 1) // receives io.Closer to cleanly shut down go handleSignals(shutdownc) // In case we're running in a Docker container with no // filesytem from which to load the root CAs, this // conditionally installs a static set if necessary. We do // this before we load the config file, which might come from // an https URL. httputil.InstallCerts() config, isNewConfig, err := loadConfig(*flagConfigFile) if err != nil { exitf("Error loading config file: %v", err) } ws := webserver.New() listen, baseURL := listenAndBaseURL(config) hostname, err := certHostname(listen, baseURL) if err != nil { exitf("Bad baseURL or listen address: %v", err) } setupTLS(ws, config, hostname) err = ws.Listen(listen) if err != nil { exitf("Listen: %v", err) } if baseURL == "" { baseURL = ws.ListenURL() } shutdownCloser, err := config.InstallHandlers(ws, baseURL, *flagReindex, nil) if err != nil { exitf("Error parsing config: %v", err) } shutdownc <- shutdownCloser urlToOpen := baseURL if !isNewConfig { // user may like to configure the server at the initial startup, // open UI if this is not the first run with a new config file. urlToOpen += config.UIPath } if *flagOpenBrowser { go osutil.OpenURL(urlToOpen) } go ws.Serve() if flagPollParent { osutil.DieOnParentDeath() } if err := config.StartApps(); err != nil { exitf("StartApps: %v", err) } for appName, appURL := range config.AppURL() { addr, err := netutil.HostPort(appURL) if err != nil { log.Printf("Could not get app %v address: %v", appName, err) continue } if err := netutil.AwaitReachable(addr, 5*time.Second); err != nil { log.Printf("Could not reach app %v: %v", appName, err) } } log.Printf("Available on %s", urlToOpen) if env.OnGCE() && strings.HasPrefix(baseURL, "https://") { go redirectFromHTTP(baseURL) } // Block forever, except during tests. up <- struct{}{} <-down osExit(0) }
func (sh *StatusHandler) serveStatusHTML(rw http.ResponseWriter, req *http.Request) { st := sh.currentStatus() f := func(p string, a ...interface{}) { if len(a) == 0 { io.WriteString(rw, p) } else { fmt.Fprintf(rw, p, a...) } } f("<html><head><title>camlistored status</title></head>") f("<body>") f("<h1>camlistored status</h1>") f("<h2>Versions</h2><ul>") var envStr string if env.OnGCE() { envStr = " (on GCE)" } f("<li><b>Camlistore</b>: %s%s</li>", html.EscapeString(buildinfo.Version()), envStr) f("<li><b>Go</b>: %s/%s %s, cgo=%v</li>", runtime.GOOS, runtime.GOARCH, runtime.Version(), cgoEnabled) f("<li><b>djpeg</b>: %s", html.EscapeString(buildinfo.DjpegStatus())) f("</ul>") f("<h2>Logs</h2><ul>") f(" <li><a href='/debug/config'>/debug/config</a> - server config</li>\n") if env.OnGCE() { f(" <li><a href='/debug/logs/camlistored'>camlistored logs on Google Cloud Logging</a></li>\n") f(" <li><a href='/debug/logs/system'>system logs from Google Compute Engine</a></li>\n") } f("</ul>") f("<h2>Admin</h2>") f("<ul>") f(" <li><form method='post' action='restart' onsubmit='return confirm(\"Really restart now?\")'><button>restart server</button>") f("<input type='checkbox' name='reindex'> reindex</form></li>") if env.OnGCE() { console, err := sh.googleCloudConsole() if err != nil { log.Printf("error getting Google Cloud Console URL: %v", err) } else { f(" <li><b>Updating:</b> When a new image for Camlistore on GCE is available, you can update by hitting \"Reset\" (or \"Stop\", then \"Start\") for your instance on your <a href='%s'>Google Cloud Console</a>.<br>Alternatively, you can ssh to your instance and restart the Camlistore service with: <b>sudo systemctl restart camlistored</b>.</li>", console) } } f("</ul>") f("<h2>Handlers</h2>") f("<p>As JSON: <a href='status.json'>status.json</a>; and the <a href='%s?camli.mode=config'>discovery JSON</a>.</p>", st.rootPrefix) f("<p>Not yet pretty HTML UI:</p>") js, err := json.MarshalIndent(st, "", " ") if err != nil { log.Printf("JSON marshal error: %v", err) } jsh := html.EscapeString(string(js)) jsh = quotedPrefix.ReplaceAllStringFunc(jsh, func(in string) string { pfx := in[1 : len(in)-1] if st.isHandler(pfx) { return fmt.Sprintf("%s<a href='%s'>%s</a>%s", in[:1], pfx, pfx, in[len(in)-1:]) } return in }) f("<pre>%s</pre>", jsh) }
func main() { client.AddFlags() flag.Parse() if *flagVersion { fmt.Fprintf(os.Stderr, "camget version: %s\n", buildinfo.Version()) return } if *flagGraph && flag.NArg() != 1 { log.Fatalf("The --graph option requires exactly one parameter.") } var cl *client.Client var items []*blobref.BlobRef if *flagShared != "" { if client.ExplicitServer() != "" { log.Fatal("Can't use --shared with an explicit blobserver; blobserver is implicit from the --shared URL.") } if flag.NArg() != 0 { log.Fatal("No arguments permitted when using --shared") } cl1, target, err := client.NewFromShareRoot(*flagShared, client.OptionInsecure(*flagInsecureTLS)) if err != nil { log.Fatal(err) } cl = cl1 items = append(items, target) } else { cl = client.NewOrFail() for n := 0; n < flag.NArg(); n++ { arg := flag.Arg(n) br := blobref.Parse(arg) if br == nil { log.Fatalf("Failed to parse argument %q as a blobref.", arg) } items = append(items, br) } } cl.InsecureTLS = *flagInsecureTLS tr := cl.TransportForConfig(&client.TransportConfig{ Verbose: *flagHTTP, }) httpStats, _ := tr.(*httputil.StatsTransport) cl.SetHTTPClient(&http.Client{Transport: tr}) diskCacheFetcher, err := cacher.NewDiskCache(cl) if err != nil { log.Fatalf("Error setting up local disk cache: %v", err) } defer diskCacheFetcher.Clean() if *flagVerbose { log.Printf("Using temp blob cache directory %s", diskCacheFetcher.Root) } for _, br := range items { if *flagGraph { printGraph(diskCacheFetcher, br) return } if *flagCheck { // TODO: do HEAD requests checking if the blobs exists. log.Fatal("not implemented") return } if *flagOutput == "-" { var rc io.ReadCloser var err error if *flagContents { rc, err = schema.NewFileReader(diskCacheFetcher, br) if err == nil { rc.(*schema.FileReader).LoadAllChunks() } } else { rc, err = fetch(diskCacheFetcher, br) } if err != nil { log.Fatal(err) } defer rc.Close() if _, err := io.Copy(os.Stdout, rc); err != nil { log.Fatalf("Failed reading %q: %v", br, err) } } else { if err := smartFetch(diskCacheFetcher, *flagOutput, br); err != nil { log.Fatal(err) } } } if *flagVerbose { log.Printf("HTTP requests: %d\n", httpStats.Requests()) } }
func main() { client.AddFlags() flag.Parse() if *cmdmain.FlagHelp { flag.PrintDefaults() } if *flagVersion { fmt.Fprintf(os.Stderr, "camget version: %s\n", buildinfo.Version()) return } if *cmdmain.FlagLegal { cmdmain.PrintLicenses() return } if *flagGraph && flag.NArg() != 1 { log.Fatalf("The --graph option requires exactly one parameter.") } var cl *client.Client var items []blob.Ref optTransportConfig := client.OptionTransportConfig(&client.TransportConfig{ Verbose: *flagHTTP, }) if *flagShared != "" { if client.ExplicitServer() != "" { log.Fatal("Can't use --shared with an explicit blobserver; blobserver is implicit from the --shared URL.") } if flag.NArg() != 0 { log.Fatal("No arguments permitted when using --shared") } cl1, target, err := client.NewFromShareRoot(*flagShared, client.OptionInsecure(*flagInsecureTLS), client.OptionTrustedCert(*flagTrustedCert), optTransportConfig, ) if err != nil { log.Fatal(err) } cl = cl1 items = append(items, target) } else { if *flagTrustedCert != "" { log.Fatal("Can't use --cert without --shared.") } cl = client.NewOrFail(client.OptionInsecure(*flagInsecureTLS), optTransportConfig) for n := 0; n < flag.NArg(); n++ { arg := flag.Arg(n) br, ok := blob.Parse(arg) if !ok { log.Fatalf("Failed to parse argument %q as a blobref.", arg) } items = append(items, br) } } httpStats := cl.HTTPStats() diskCacheFetcher, err := cacher.NewDiskCache(cl) if err != nil { log.Fatalf("Error setting up local disk cache: %v", err) } defer diskCacheFetcher.Clean() if *flagVerbose { log.Printf("Using temp blob cache directory %s", diskCacheFetcher.Root) } if *flagShared != "" { diskCacheFetcher.SetCacheHitHook(func(br blob.Ref, rc io.ReadCloser) (io.ReadCloser, error) { var buf bytes.Buffer if err := cl.UpdateShareChain(br, io.TeeReader(rc, &buf)); err != nil { rc.Close() return nil, err } return struct { io.Reader io.Closer }{io.MultiReader(&buf, rc), rc}, nil }) } for _, br := range items { if *flagGraph { printGraph(diskCacheFetcher, br) return } if *flagCheck { // TODO: do HEAD requests checking if the blobs exists. log.Fatal("not implemented") return } if *flagOutput == "-" { var rc io.ReadCloser var err error if *flagContents { rc, err = schema.NewFileReader(diskCacheFetcher, br) if err == nil { rc.(*schema.FileReader).LoadAllChunks() } } else { rc, err = fetch(diskCacheFetcher, br) } if err != nil { log.Fatal(err) } defer rc.Close() if _, err := io.Copy(os.Stdout, rc); err != nil { log.Fatalf("Failed reading %q: %v", br, err) } } else { if err := smartFetch(diskCacheFetcher, *flagOutput, br); err != nil { log.Fatal(err) } } } if *flagVerbose { log.Printf("HTTP requests: %d\n", httpStats.Requests()) h1, h2 := httpStats.ProtoVersions() log.Printf(" responses: %d (h1), %d (h2)\n", h1, h2) } }
// Main sends on up when it's running, and shuts down when it receives from down. func Main(up chan<- struct{}, down <-chan struct{}) { flag.Parse() if *flagVersion { fmt.Fprintf(os.Stderr, "camlistored version: %s\nGo version: %s (%s/%s)\n", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) return } if *flagReindex { index.SetImpendingReindex() } log.Printf("Starting camlistored version %s; Go %s (%s/%s)", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) shutdownc := make(chan io.Closer, 1) // receives io.Closer to cleanly shut down go handleSignals(shutdownc) fileName, isNewConfig, err := findConfigFile(*flagConfigFile) if err != nil { exitf("Error finding config file %q: %v", fileName, err) } log.Printf("Using config file %s", fileName) config, err := serverinit.Load(fileName) if err != nil { exitf("Could not load server config: %v", err) } ws := webserver.New() listen, baseURL := listenAndBaseURL(config) setupTLS(ws, config, listen) err = ws.Listen(listen) if err != nil { exitf("Listen: %v", err) } if baseURL == "" { baseURL = ws.ListenURL() } shutdownCloser, err := config.InstallHandlers(ws, baseURL, *flagReindex, nil) if err != nil { exitf("Error parsing config: %v", err) } shutdownc <- shutdownCloser urlToOpen := baseURL if !isNewConfig { // user may like to configure the server at the initial startup, // open UI if this is not the first run with a new config file. urlToOpen += config.UIPath } log.Printf("Available on %s", urlToOpen) if *flagOpenBrowser { go osutil.OpenURL(urlToOpen) } go ws.Serve() if flagPollParent { osutil.DieOnParentDeath() } // Block forever, except during tests. up <- struct{}{} <-down osExit(0) }