Home Download Docs Code Community
     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	}
Website layout inspired by memcached.
Content by the authors.