From 4317da03085a19eae14564996dab196456619cbc Mon Sep 17 00:00:00 2001
From: Brad Fitzpatrick <brad@danga.com>
Date: Thu, 26 May 2011 07:34:39 -0700
Subject: [PATCH] camlistored: convert ui, root, jsonsign to use handler
 registry

---
 lib/go/camli/blobserver/registry.go  |  2 ++
 server/go/camlistored/camlistored.go | 40 ++++++++++++++++------------
 server/go/camlistored/root.go        |  7 ++++-
 server/go/camlistored/sig.go         |  7 ++++-
 server/go/camlistored/ui.go          | 19 +++++++------
 5 files changed, 46 insertions(+), 29 deletions(-)

diff --git a/lib/go/camli/blobserver/registry.go b/lib/go/camli/blobserver/registry.go
index fce2b6dc2..5b6b9a42b 100644
--- a/lib/go/camli/blobserver/registry.go
+++ b/lib/go/camli/blobserver/registry.go
@@ -27,6 +27,8 @@ import (
 
 type Loader interface {
 	GetStorage(prefix string) (Storage, os.Error)
+	GetHandler(prefix string) (http.Handler, os.Error)
+	GetHandlerType(prefix string) string // or ""
 }
 
 type StorageConstructor func(Loader, jsonconfig.Obj) (Storage, os.Error)
diff --git a/server/go/camlistored/camlistored.go b/server/go/camlistored/camlistored.go
index b0cd842b0..1ab0994e3 100644
--- a/server/go/camlistored/camlistored.go
+++ b/server/go/camlistored/camlistored.go
@@ -270,6 +270,19 @@ func (hl *handlerLoader) GetStorage(prefix string) (blobserver.Storage, os.Error
 	return nil, fmt.Errorf("bogus storage handler referenced as %q", prefix)
 }
 
+func (hl *handlerLoader) GetHandler(prefix string) (http.Handler, os.Error) {
+	hl.setupHandler(prefix)
+	if h, ok := hl.handler[prefix].(http.Handler); ok {
+		return h, nil
+	}
+	return nil, fmt.Errorf("bogus http handler referenced as %q", prefix)
+}
+
+func (hl *handlerLoader) GetHandlerType(prefix string) string {
+	hl.setupHandler(prefix)
+	return hl.configType(prefix)
+}
+
 func (hl *handlerLoader) setupHandler(prefix string) {
 	h, ok := hl.config[prefix]
 	if !ok {
@@ -290,28 +303,21 @@ func (hl *handlerLoader) setupHandler(prefix string) {
 			panic(fmt.Sprintf("setupHandler for %q didn't install a handler", prefix))
 		}
 	}()
-	installHandler := func(creator func(*handlerLoader, jsonconfig.Obj) (h http.Handler, err os.Error)) {
-		hh, err := creator(hl, h.conf)
-		if err != nil {
-			exitFailure("error instantiating handler for prefix %s: %v",
-				prefix, err)
-		}
-		hl.handler[prefix] = hh
-		hl.ws.Handle(prefix, &httputil.PrefixHandler{prefix, hh})
-	}
 	checkConfig := func() {
 		if err := h.conf.Validate(); err != nil {
 			exitFailure("configuration error in \"handlerArgs\" for prefix %s: %v", prefix, err)
 		}
 	}
 	switch h.htype {
-	case "root":
-		installHandler((*handlerLoader).createRootHandler)
-	case "ui":
-		installHandler((*handlerLoader).createUIHandler)
-	case "jsonsign":
-		installHandler((*handlerLoader).createJSONSignHandler)
-	case "search":
+	case "ui", "root", "jsonsign":
+		hh, err := blobserver.CreateHandler(h.htype, hl, h.conf)
+		if err != nil {
+			exitFailure("error instantiating handler for prefix %q, type %q: %v",
+				h.prefix, h.htype, err)
+		}
+		hl.handler[prefix] = hh
+		hl.ws.Handle(prefix, &httputil.PrefixHandler{prefix, hh})
+	case "search": // TODO: use blobserver registry
 		indexPrefix := h.conf.RequiredString("index") // TODO: add optional help tips here?
 		ownerBlobStr := h.conf.RequiredString("owner")
 		checkConfig()
@@ -327,7 +333,7 @@ func (hl *handlerLoader) setupHandler(prefix string) {
 		searchh := auth.RequireAuth(search.CreateHandler(indexer, ownerBlobRef))
 		hl.handler[h.prefix] = searchh
 		hl.ws.HandleFunc(prefix+"camli/", searchh)
-	case "sync":
+	case "sync": // TODO: use blobserver registry
 		from := h.conf.RequiredString("from")
 		to := h.conf.RequiredString("to")
 		checkConfig()
diff --git a/server/go/camlistored/root.go b/server/go/camlistored/root.go
index 0dd0fa801..48c865944 100644
--- a/server/go/camlistored/root.go
+++ b/server/go/camlistored/root.go
@@ -21,6 +21,7 @@ import (
 	"http"
 	"os"
 
+	"camli/blobserver"
 	"camli/jsonconfig"
 )
 
@@ -34,7 +35,11 @@ type RootHandler struct {
 	OfferSetup bool
 }
 
-func (hl *handlerLoader) createRootHandler(conf jsonconfig.Obj) (h http.Handler, err os.Error) {
+func init() {
+	blobserver.RegisterHandlerConstructor("root", newRootFromConfig)
+}
+
+func newRootFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (h http.Handler, err os.Error) {
 	root := &RootHandler{}
 	root.Stealth = conf.OptionalBool("stealth", false)
 	if err = conf.Validate(); err != nil {
diff --git a/server/go/camlistored/sig.go b/server/go/camlistored/sig.go
index 994986d6b..50ce5c106 100644
--- a/server/go/camlistored/sig.go
+++ b/server/go/camlistored/sig.go
@@ -29,6 +29,7 @@ import (
 	"strings"
 
 	"camli/blobref"
+	"camli/blobserver"
 	"camli/blobserver/handlers"
 	"camli/httputil"
 	"camli/jsonconfig"
@@ -63,7 +64,11 @@ func (h *JSONSignHandler) secretRingPath() string {
 	return filepath.Join(os.Getenv("HOME"), ".gnupg", "secring.gog")
 }
 
-func (hl *handlerLoader) createJSONSignHandler(conf jsonconfig.Obj) (http.Handler, os.Error) {
+func init() {
+	blobserver.RegisterHandlerConstructor("jsonsign", newJsonSignFromConfig)
+}
+
+func newJsonSignFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (http.Handler, os.Error) {
 	h := &JSONSignHandler{
 		keyId:      strings.ToUpper(conf.RequiredString("keyId")),
 		secretRing: conf.OptionalString("secretRing", ""),
diff --git a/server/go/camlistored/ui.go b/server/go/camlistored/ui.go
index 159c71a9a..7125e2038 100644
--- a/server/go/camlistored/ui.go
+++ b/server/go/camlistored/ui.go
@@ -53,7 +53,11 @@ func defaultFilesDir() string {
 	return filepath.Join(dir, "ui")
 }
 
-func (hl *handlerLoader) createUIHandler(conf jsonconfig.Obj) (h http.Handler, err os.Error) {
+func init() {
+	blobserver.RegisterHandlerConstructor("ui", newUiFromConfig)
+}
+
+func newUiFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (h http.Handler, err os.Error) {
 	ui := &UIHandler{}
 	ui.BlobRoot = conf.OptionalString("blobRoot", "")
 	ui.SearchRoot = conf.OptionalString("searchRoot", "")
@@ -68,7 +72,7 @@ func (hl *handlerLoader) createUIHandler(conf jsonconfig.Obj) (h http.Handler, e
 		if v == "" {
 			return
 		}
-		ct := hl.configType(v)
+		ct := ld.GetHandlerType(v)
 		if ct == "" {
 			err = fmt.Errorf("UI handler's %q references non-existant %q", key, v)
 		} else if ct != htype {
@@ -83,14 +87,9 @@ func (hl *handlerLoader) createUIHandler(conf jsonconfig.Obj) (h http.Handler, e
 	}
 
 	if ui.BlobRoot != "" {
-		bh := hl.getOrSetup(ui.BlobRoot)
-		if bh == nil {
-			return nil, fmt.Errorf("UI handler's blobRoot references non-existant %q", ui.BlobRoot)
-		}
-		_, ok := bh.(blobserver.Storage)
-		if !ok {
-			return nil, fmt.Errorf("UI handler's blobRoot references %q of type %T; expected a storage target",
-				ui.BlobRoot, bh)
+		_, err := ld.GetStorage(ui.BlobRoot)
+		if err != nil {
+			return nil, fmt.Errorf("UI handler's blobRoot of %q error: %v", ui.BlobRoot, err)
 		}
 	}