1 /* 2 Copyright 2011 The Perkeep Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package blobserver 18 19 import ( 20 "errors" 21 "fmt" 22 "net/http" 23 "sync" 24 25 "go4.org/jsonconfig" 26 ) 27 28 var ErrHandlerTypeNotFound = errors.New("requested handler type not loaded") 29 30 type FindHandlerByTyper interface { 31 // FindHandlerByType finds a handler by its handlerType and 32 // returns its prefix and handler if it's loaded. If it's not 33 // loaded, the error will be ErrHandlerTypeNotFound. 34 // 35 // This is used by handlers to find siblings (such as the "ui" type handler) 36 // which might have more knowledge about the configuration for discovery, etc. 37 // 38 // Note that if this is called during handler construction 39 // time, only the prefix may be returned with a nil handler 40 // and nil err. Unlike GetHandler and GetStorage, this does 41 // not cause the prefix to load immediately. At runtime (after 42 // construction of all handlers), then prefix and handler will 43 // both be non-nil when err is nil. 44 FindHandlerByType(handlerType string) (prefix string, handler interface{}, err error) 45 46 // AllHandlers returns a map from prefix to handler type, and 47 // a map from prefix to handler. 48 AllHandlers() (map[string]string, map[string]interface{}) 49 } 50 51 type Loader interface { 52 FindHandlerByTyper 53 54 // MyPrefix returns the prefix of the handler currently being constructed, 55 // with both leading and trailing slashes (e.g. "/ui/"). 56 MyPrefix() string 57 58 // BaseURL returns the server's base URL, without trailing slash, and not including 59 // the prefix (as returned by MyPrefix). 60 BaseURL() string 61 62 // GetHandlerType returns the handler's configured type, but does 63 // not force it to start being loaded yet. 64 GetHandlerType(prefix string) string // returns "" if unknown 65 66 // GetHandler returns either a Storage or an http.Handler. 67 // It forces the handler to be loaded and returns an error if 68 // a cycle is created. 69 GetHandler(prefix string) (interface{}, error) 70 71 // GetStorage is like GetHandler but requires that the Handler be 72 // a storage Handler. 73 GetStorage(prefix string) (Storage, error) 74 } 75 76 // HandlerIniter is an optional interface which can be implemented 77 // by Storage or http.Handlers (from StorageConstructor or HandlerConstructor) 78 // to be called once all the handlers have been created. 79 type HandlerIniter interface { 80 InitHandler(FindHandlerByTyper) error 81 } 82 83 // A StorageConstructor returns a Storage implementation from a Loader 84 // environment and a configuration. 85 type StorageConstructor func(Loader, jsonconfig.Obj) (Storage, error) 86 87 // A HandlerConstructor returns an http.Handler from a Loader 88 // environment and a configuration. 89 type HandlerConstructor func(Loader, jsonconfig.Obj) (http.Handler, error) 90 91 var mapLock sync.Mutex 92 var storageConstructors = make(map[string]StorageConstructor) 93 var handlerConstructors = make(map[string]HandlerConstructor) 94 95 func RegisterStorageConstructor(typ string, ctor StorageConstructor) { 96 mapLock.Lock() 97 defer mapLock.Unlock() 98 if _, ok := storageConstructors[typ]; ok { 99 panic("blobserver: StorageConstructor already registered for type: " + typ) 100 } 101 storageConstructors[typ] = ctor 102 } 103 104 func CreateStorage(typ string, loader Loader, config jsonconfig.Obj) (Storage, error) { 105 mapLock.Lock() 106 ctor, ok := storageConstructors[typ] 107 mapLock.Unlock() 108 if !ok { 109 return nil, fmt.Errorf("Storage type %q not known or loaded", typ) 110 } 111 return ctor(loader, config) 112 } 113 114 // RegisterHandlerConstructor registers an http Handler constructor function 115 // for a given handler type. 116 // 117 // It is an error to register the same handler type twice. 118 func RegisterHandlerConstructor(typ string, ctor HandlerConstructor) { 119 mapLock.Lock() 120 defer mapLock.Unlock() 121 if _, ok := handlerConstructors[typ]; ok { 122 panic("blobserver: HandlerConstrutor already registered for type: " + typ) 123 } 124 handlerConstructors[typ] = ctor 125 } 126 127 // CreateHandler instantiates an http Handler of type 'typ' from the 128 // provided JSON configuration, and finding peer handlers and 129 // configuration from the environment in 'loader'. 130 // 131 // The handler 'typ' must have been previously registered with 132 // RegisterHandlerConstructor. 133 func CreateHandler(typ string, loader Loader, config jsonconfig.Obj) (http.Handler, error) { 134 mapLock.Lock() 135 ctor, ok := handlerConstructors[typ] 136 mapLock.Unlock() 137 if !ok { 138 return nil, fmt.Errorf("blobserver: Handler type %q not known or loaded", typ) 139 } 140 return ctor(loader, config) 141 }