publish: show title, members, include javascript blob metadata

start of awesomeness.

Change-Id: I45d63b04fa223b9aafceb9452b179e4ddc52bce5
This commit is contained in:
Brad Fitzpatrick 2011-07-02 17:16:30 -07:00
parent 66c0e430d0
commit 6179e508e3
2 changed files with 128 additions and 16 deletions

View File

@ -17,6 +17,7 @@ limitations under the License.
package search
import (
"bytes"
"fmt"
"http"
"log"
@ -242,7 +243,20 @@ type DescribeRequest struct {
wg *sync.WaitGroup // for load requests
}
// Given a blobref string returns a Description or nil.
// dr may be nil itself.
func (dr *DescribeRequest) DescribedBlobStr(blobstr string) *DescribedBlob {
if dr == nil {
return nil
}
dr.lk.Lock()
defer dr.lk.Unlock()
return dr.m[blobstr]
}
type DescribedBlob struct {
Request *DescribeRequest
BlobRef *blobref.BlobRef
MimeType string
CamliType string
@ -254,6 +268,63 @@ type DescribedBlob struct {
// if camliType "file"
File *FileInfo
Stub bool // if not loaded, but referenced
}
func (b *DescribedBlob) Title() string {
if b == nil {
return ""
}
if b.Permanode != nil {
if t := b.Permanode.Attr.Get("title"); t != "" {
return t
}
if contentRef := b.Permanode.Attr.Get("camliContent"); contentRef != "" {
return b.Request.DescribedBlobStr(contentRef).Title()
}
}
if b.File != nil {
return b.File.FileName
}
return ""
}
func (b *DescribedBlob) Description() string {
if b == nil {
return ""
}
if b.Permanode != nil {
return b.Permanode.Attr.Get("description")
}
return ""
}
func (b *DescribedBlob) Members() []*DescribedBlob {
if b == nil {
return nil
}
m := make([]*DescribedBlob, 0)
if b.Permanode != nil {
for _, bstr := range b.Permanode.Attr["camliMember"] {
if br := blobref.Parse(bstr); br != nil {
m = append(m, b.peerBlob(br))
}
}
}
return m
}
func (b *DescribedBlob) peerBlob(br *blobref.BlobRef) *DescribedBlob {
if b.Request == nil {
return &DescribedBlob{BlobRef: br, Stub: true}
}
b.Request.lk.Lock()
defer b.Request.lk.Unlock()
if peer, ok := b.Request.m[br.String()]; ok {
return peer
}
return &DescribedBlob{Request: b.Request, BlobRef: br, Stub: true}
}
func (b *DescribedBlob) jsonMap() map[string]interface{} {
@ -276,7 +347,7 @@ func (b *DescribedBlob) jsonMap() map[string]interface{} {
}
type DescribedPermanode struct {
Attr map[string][]string
Attr http.Values // a map[string][]string
}
func (dp *DescribedPermanode) jsonMap() map[string]interface{} {
@ -308,23 +379,26 @@ func (sh *Handler) NewDescribeRequest() *DescribeRequest {
type DescribeError map[string]os.Error
func (e DescribeError) String() string {
return "one or more errors describing blobs"
func (de DescribeError) String() string {
var buf bytes.Buffer
for b, err := range de {
fmt.Fprintf(&buf, "%s: %v; ", b, err)
}
return fmt.Sprintf("Errors (%d) describing blobs: %s", len(de), buf.String())
}
// Result waits for all outstanding lookups to complete and
// returns the map of blobref (strings) to their described
// results. The returned error is non-nil if any errors
// occured.
func (dr *DescribeRequest) Result() (map[string]*DescribedBlob, DescribeError) {
// occured, and will be of type DescribeError.
func (dr *DescribeRequest) Result() (desmap map[string]*DescribedBlob, err os.Error) {
dr.wg.Wait()
// TODO: set "done" / locked flag, so no more DescribeBlob can
// be called.
var err DescribeError
if len(dr.errs) > 0 {
err = DescribeError(dr.errs)
return dr.m, DescribeError(dr.errs)
}
return dr.m, err
return dr.m, nil
}
// PopulateJSON waits for all outstanding lookups to complete and populates
@ -350,7 +424,7 @@ func (dr *DescribeRequest) describedBlob(b *blobref.BlobRef) *DescribedBlob {
if des, ok := dr.m[bs]; ok {
return des
}
des := &DescribedBlob{BlobRef: b}
des := &DescribedBlob{Request: dr, BlobRef: b}
dr.m[bs] = des
return des
}
@ -463,7 +537,7 @@ func (sh *Handler) serveFiles(rw http.ResponseWriter, req *http.Request) {
}
func (dr *DescribeRequest) populatePermanodeFields(pi *DescribedPermanode, pn, signer *blobref.BlobRef, depth int) {
pi.Attr = make(map[string][]string)
pi.Attr = make(http.Values)
attr := pi.Attr
claims, err := dr.sh.index.GetOwnerClaims(pn, signer)

View File

@ -111,24 +111,62 @@ func (pub *PublishHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request)
return
}
fmt.Fprintf(rw, "I am publish handler at base %q, serving root %q (permanode=%s), suffix %q<hr>",
base, pub.RootName, pn, html.EscapeString(suffix))
if req.FormValue("debug") == "1" {
fmt.Fprintf(rw, "I am publish handler at base %q, serving root %q (permanode=%s), suffix %q<hr>",
base, pub.RootName, pn, html.EscapeString(suffix))
}
path, err := pub.Search.Index().PathLookup(pub.Search.Owner(), pn, suffix, nil)
if err != nil {
fmt.Fprintf(rw, "<b>Error:</b> %v", err)
return
}
fmt.Fprintf(rw, "<p><b>Target:</b> <a href='/ui/?p=%s'>%s</a></p>", path.Target, path.Target)
if req.FormValue("debug") == "1" {
fmt.Fprintf(rw, "<p><b>Target:</b> <a href='/ui/?p=%s'>%s</a></p>", path.Target, path.Target)
return
}
dr := pub.Search.NewDescribeRequest()
dr.Describe(path.Target, 3)
res, err := dr.Result()
if err != nil {
log.Printf("Errors loading %s, permanode %s: %v, %#v", req.URL, path.Target, err, err)
fmt.Fprintf(rw, "<p>Errors loading.</p>")
return
}
subject := res[path.Target.String()]
title := subject.Title()
// HTML header + Javascript
{
jm := make(map[string]interface{})
dr.PopulateJSON(jm)
fmt.Fprintf(rw, "<pre>")
fmt.Fprintf(rw, "<html>\n<head>\n <title>%s</title>\n <script>\nvar camliPageMeta = \n",
html.EscapeString(title))
json, _ := json.MarshalIndent(jm, "", " ")
rw.Write(json)
fmt.Fprintf(rw, "</pre>")
fmt.Fprintf(rw, ";\n </script>\n</head>\n<body>\n")
defer fmt.Fprintf(rw, "</body>\n</html>\n")
}
if title != "" {
fmt.Fprintf(rw, "<h1>%s</h1>\n", html.EscapeString(title))
}
if members := subject.Members(); len(members) > 0 {
fmt.Fprintf(rw, "<ul>\n")
for _, member := range members {
des := member.Description()
if des != "" {
des = " - " + des
}
link := "#"
fmt.Fprintf(rw, " <li><a href='%s'>%s</a>%s</li>\n",
link,
html.EscapeString(member.Title()),
des)
}
fmt.Fprintf(rw, "</ul>\n")
}
}
@ -159,6 +197,6 @@ func (pub *PublishHandler) bootstrapPermanode(jsonSign *JSONSignHandler) (err os
pn := signUpload("permanode", schema.NewUnsignedPermanode())
signUpload("set-attr camliRoot", schema.NewSetAttributeClaim(pn, "camliRoot", pub.RootName))
signUpload("set-attr title", schema.NewSetAttributeClaim(pn, "title", "Publish root node for " + pub.RootName))
signUpload("set-attr title", schema.NewSetAttributeClaim(pn, "title", "Publish root node for "+pub.RootName))
return nil
}