// Fast path for blobpacked. func fileInfoPacked(sh *search.Handler, src blob.Fetcher, req *http.Request, file blob.Ref) (packFileInfo fileInfo, ok bool) { if sh == nil { return fileInfo{whyNot: "no search"}, false } wf, ok := src.(blobserver.WholeRefFetcher) if !ok { return fileInfo{whyNot: "fetcher type"}, false } if req != nil && req.Header.Get("Range") != "" { // TODO: not handled yet. Maybe not even important, // considering rarity. return fileInfo{whyNot: "range header"}, false } des, err := sh.Describe(&search.DescribeRequest{BlobRef: file}) if err != nil { log.Printf("ui: fileInfoPacked: skipping fast path due to error from search: %v", err) return fileInfo{whyNot: "search error"}, false } db, ok := des.Meta[file.String()] if !ok || db.File == nil { return fileInfo{whyNot: "search index doesn't know file"}, false } fi := db.File if !fi.WholeRef.Valid() { return fileInfo{whyNot: "no wholeref from search index"}, false } offset := int64(0) rc, wholeSize, err := wf.OpenWholeRef(fi.WholeRef, offset) if err == os.ErrNotExist { return fileInfo{whyNot: "WholeRefFetcher returned ErrNotexist"}, false } if wholeSize != fi.Size { log.Printf("ui: fileInfoPacked: OpenWholeRef size %d != index size %d; ignoring fast path", wholeSize, fi.Size) return fileInfo{whyNot: "WholeRefFetcher and index don't agree"}, false } if err != nil { log.Printf("ui: fileInfoPacked: skipping fast path due to error from WholeRefFetcher (%T): %v", src, err) return fileInfo{whyNot: "WholeRefFetcher error"}, false } return fileInfo{ mime: fi.MIMEType, name: fi.FileName, size: fi.Size, rs: readerutil.NewFakeSeeker(rc, fi.Size-offset), close: rc.Close, }, true }
// InitHandler goes through all the other configured handlers to discover // the publisher ones, and uses them to populate ui.publishRoots. func (ui *UIHandler) InitHandler(hl blobserver.FindHandlerByTyper) error { // InitHandler is called after all handlers have been setup, so the bootstrap // of the camliRoot node for publishers in dev-mode is already done. searchPrefix, _, err := hl.FindHandlerByType("search") if err != nil { return errors.New("No search handler configured, which is necessary for the ui handler") } var sh *search.Handler htype, hi := hl.AllHandlers() if h, ok := hi[searchPrefix]; !ok { return errors.New("failed to find the \"search\" handler") } else { sh = h.(*search.Handler) ui.search = sh } camliRootQuery := func(camliRoot string) (*search.SearchResult, error) { return sh.Query(&search.SearchQuery{ Limit: 1, Constraint: &search.Constraint{ Permanode: &search.PermanodeConstraint{ Attr: "camliRoot", Value: camliRoot, }, }, }) } for prefix, typ := range htype { if typ != "app" { continue } ah, ok := hi[prefix].(*app.Handler) if !ok { panic(fmt.Sprintf("UI: handler for %v has type \"app\" but is not app.Handler", prefix)) } if ah.ProgramName() != "publisher" { continue } appConfig := ah.AppConfig() if appConfig == nil { log.Printf("UI: app handler for %v has no appConfig", prefix) continue } camliRoot, ok := appConfig["camliRoot"].(string) if !ok { log.Printf("UI: camliRoot in appConfig is %T, want string", appConfig["camliRoot"]) continue } result, err := camliRootQuery(camliRoot) if err != nil { log.Printf("UI: could not find permanode for camliRoot %v: %v", camliRoot, err) continue } if len(result.Blobs) == 0 || !result.Blobs[0].Blob.Valid() { log.Printf("UI: no valid permanode for camliRoot %v", camliRoot) continue } if ui.publishRoots == nil { ui.publishRoots = make(map[string]*publishRoot) } ui.publishRoots[prefix] = &publishRoot{ Name: camliRoot, Prefix: prefix, Permanode: result.Blobs[0].Blob, } } return nil }