capstan

package module
Version: v0.0.0-...-4be3a9e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 22, 2021 License: NCSA Imports: 40 Imported by: 1

README

Capstan: A Convenience Framework for Golang

Capstan is a framework that aims to simplify complex use cases that reach beyond basic HTTP handlers, such as dependency management, and reduces the amount of code required as handlers grow and evolve beyond what is possible with the standard library. It provides helpers for common (and not so common) tasks, including graceful shutdowns, rebinding mount points, and more. Capstan uses go-chi for its route muxer. Philosophically, Capstan is inspired in part by Flask and Flask-Classy.

Capstan is not for you if you require handlers that retain compatibility with net/http. Though this could (and arguably should) be rememdied by using the context package, there are no plans currently to reimplement Capstan in this fashion. Be ware! The Capstan API may appear simple at first blush, but it has a depth and complexity that may not be viable for all projects. If you need a simple API server, consider using go-chi directly.

Bear in mind that the project is still very much in its infancy, and APIs are subject to change. There are numerous rough patches and sharp objects in the code.

Features

Capstan's implementation comprises these features (and some anti-features):

  • Controller-centric MVC. At present, it's largely "VC" as there is no defined model implementation. Capstan is very much "bring your own model."
  • Requests are designed to call method-named functions per controller per path. This means that individual functions are named after and define an HTTP verb, such as Get or Post. Controllers therefore should be highly focused to a single endpoint. (This isn't strictly necessary; see below.)
  • Custom methods can be defined by implementing either the Binder interface, MapperHandler interface (work-in-progress), or by naming functions according to the pattern <Method><Name><SlashState>. This will become clearer later in the documentation once it's written.
  • Multiple renderers are supported through the Templater interface. We primarily encourage the use of pongo2 but provide wrappers for Go's built in template rendering library. (Note: Using anything but pongo2 may limit features available to templates, and using multiple template types in a single project will present unique challenges and difficulties that, while not insurmountable, are unnecessary and will be fraught with sleepless nights.)
  • Renderers may be defined globally or per-controller. If a renderer is defined globally, all controller bindings that don't define a renderer will use the global one by default.
  • Capstan's pongo2 wrappers can make use of our VFS layer that integrates with Embedder for embedding assets into the compiled binary. The template engine is therefore capable of reading templates and other assets directly from disk, the binary distribution, or from a cascade of VFS loaders with the option to override template sources at any point in the loader's process. ZIP files are also supported. As such, when combined with VFS, it's possible to layer reads from multiple sources (e.g. the binary, a ZIP file, or the file system).
  • Built-in TLS configuration helpers are provided. ACME support is a work in progress which will allow use of services like Let's Encrypt.
  • Capstan can listen on Unix sockets for use with local front end proxies like nginx or HAProxy. Doing so does not provide noticeable performance improvements over using TCP sockets. It may improve security somewhat by reducing your application's attack surface, particularly when launched behind a front-facing proxy (such as nginx or HAProxy).
  • Supports remapping endpoints (called "rebinding" in Capstan parlance) without restarting the service. Endpoints may be deleted (Router.Unmount) or renamed (Router.ReplacePath).
  • Optional websocket endpoint handlers as part of the controller semantics.
  • Graceful shutdown and in-place replacement/restart for seamless upgrades. Not presently supported on Windows and likely never will be. I don't know enough about Windows' internals to know if this is even possible.
  • URL mapper that exposes URL resolution for templates. In pongo2, this is provided via the functions url() and external(). URLs are typically mapped as [<prefix>.]<name>.<suffix>; for example, if you have a controller IndexController and were accessing its Get method, you would retrieve the mapped URL by calling url("IndexController:get"). Custom url() binding is provided by Router.ManualBind. The <prefix> is dictated by router groups or through manual declaration at controller bind time. Naming conflicts can be resolved during controller initialization manually, by providing a symbolic name for the controller, or automatically through a numeric suffix (e.g. IndexController2). If you're familiar with python-flask you'll be familiar with this mechanic.
  • Trailing slashes can be controlled via the ?, ! or + syntax when declaring controller configuration. ? indicates a trailing slash is optional. ! indicates a trailing slash must not be provided (and a 404 is generated). + indicates a trailing slash is mandatory for subroute declarations (but is typically unnecessary). Otherwise, if a route is declared with a trailing slash it is considered mandatory and requests made without the trailing slash will result in a 404. Optional slashes (indicated by a trailing ?) can either have a slash-provided or slash-absent default state; if a ? is immediately preceded by a slash, e.g. /?, a redirection route will be created that directs requests minus the trailing slash to a route that has the trailing slash appended. Likewise, if there is no slash preceding the ?, the redirection route will direct requests with a trailing / to the route without it. You should use optional slash routes sparingly since this does necessitate the generation of (potentially) superfluous routes and may present performance implications do to the additional route resolution required during the request cycle.
  • Typed route variables. This requires a syntax differing slightly from go-chi. Type enforcement is not presently implemented (but likely will be). We use < and > to delineate route variables and deliberately introduce incompatibilities with go-chi to prevent confusion. Variable types are declared with a :<type> suffix, e.g. /path/<name:string>, which would create a parameterized variable of the name name and type string. Regex is passed through to go-chi. Beware: go-chi may eventually be replaced by our own route resolver, hence another reason for introducing semantic incompatibilities.
  • Route groups wrap go-chi's groups and provide methods namespacing them from other routes both for url() template function(s) and for isolation.
  • Supports any middleware supported by go-chi and provides slight modifications for middleware supplied by go-chi (such as supporting the NO_COLOR envvar for go-chi's logger).
  • Supports before and after response bindings for cases where middleware may be too low level and where the route context needs to be fully configured prior to or after handling the endpoint.
  • Supports signals (albeit currently limited in scope) via signals (v2.0+) allowing for client applications to bind to specific events or modify the request state prior to processing. See signals.go via the master branch for a current list of supported signals.
  • Custom error page support with context helpers.
  • Extension support that includes a few out-of-the-box extensions, such as CSRF protection and session management. Authentication support is forthcoming.
  • Fully-featured dependency injection.
  • Limited support for privilege reduction; e.g., setting Capstan's RunAs configuration option and running initially as the root user will provoke Capstan into first binding to its configured ports then dropping privileges. This is useful for listening on privileged ports (<1024), such as port 80 and 443. Although Capstan is fully capable of hosting applications directly, it is advisable to use reverse proxies in front of a Capstan application.
  • Open port scanner for automatically picking open ports. Useful for writing installers that need to find a free port in order to start a visual browser-based installer.
  • Multiple application support for running multiple instances of Capstan applications under the same Capstan instance. It's Capstans all the way down!
  • Additional utilities. See the utils subpackage.

Sample Application

package main

import (
    "git.destrealm.org/go/capstan"
)

type IndexController struct {
    capstan.BaseController
    Server capstan.Server `inject:"app"`
}

func (c *IndexController) Index(ctx capstan.Context) error {
    return ctx.Write([]byte("Hello! Listening on address: "+c.Server.Config().ListenAddress))
}

func main() {
    app := capstan.New(&capstan.Config{
      Server: &capstan.ServerConfig{
        ListenAddress: ":8080",
      },
    })

    app.Bind(&IndexController{
        BaseController: capstan.BaseController{
            Path: "/",
        },
    })

    app.Listen()
}

Documentation

The Capstan source distribution contains documentation under the docs/ subdirectory. Presently, this documentation is somewhat sparse but the basic-usage.md file contains a beginner's guide adequate enough to get started. There is also a small but mostly complete discussion on Capstan's dependency injection framework.

License

Capstan is licensed under the fairly liberal and highly permissive NCSA license. We prefer this license as it combines the best of BSD and MIT licenses while also providing coverage for associated documentation and other works that are not strictly considered original source code. Consequently, all Capstan documentation is likewise covered under the same license as the codebase itself.

As with BSD-like licenses, attribution is, of course, required.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultMappableNodeFunc = func() mappableNode {
	return &binaryTree{}
}

DefaultMappableNodeFunc is the default mappableNode generator used whenever a mappableNodeFunc has not been assigned to the radix trie.

View Source
var NewScanner = utils.NewScanner

NewScanner pseudo-alias for utils.NewScanner. Used by CLI to abstract away OS differences when scanning end-of-line ("\n" vs "\r\n").

View Source
var NoColor string

NoColor flag. If set to anything but the empty string, this will enable NO_COLOR processing.

View Source
var SigAfterResponse = signals.New((OnAfterResponse)(nil))

SigAfterResponse emits after the route has been handled and a response is in-flight but before any error handling code is processed.

This signal will only emit with an error condition if and only if there is no error prior to handling the route's endpoint. Error conditions raised by other signals, by connection upgrades, or redirects will not be caught by this signal. To catch all error conditions, use SigRouteError.

View Source
var SigApplicationAttached = signals.New((OnApplicationAttached)(nil))

SigApplicationAttached emits when a new application is attached to the currently running Capstan instance.

View Source
var SigApplicationInterrupt = signals.New((OnApplicationInterrupt)(nil))

SigApplicationInterrupt emits when the application has received an interrupt request. Such requests may be dispatched via the OS sending us a SIGINT or, if the host application overrides the DefaultInterruptHandler, this will emit when the host application decides to halt execution.

This signal emits before SigApplicationShutdownHook.

View Source
var SigApplicationListening = signals.New((OnApplicationListening)(nil))

SigApplicationListening emits immediatley prior to the call site where the application begins listening to its configured socket(s).

View Source
var SigApplicationReady = signals.New((OnApplicationReady)(nil))

SigApplicationReady emits when Application.Ready() is called but before any listener startup actually takes effect from the main application.. This is useful for extending Capstan's behavior just prior to the actual application startup and is triggered for every subapplication when initialization is complete.

View Source
var SigApplicationShutdownHook = signals.New((OnApplicationShutdownHook)(nil))

SigApplicationShutdownHook emits for each shutdown hook that is executed. This can be used to halt execution of a specific hook or to abort processing of all shutdown hooks.

View Source
var SigBeforeResponse = signals.New((OnBeforeResponse)(nil))

SigBeforeResponse emits after the response context and headers have been setup but before any potential protocol upgrades are made (e.g. WebSockets).

View Source
var SigBindRoute = signals.New((OnBindRoute)(nil))

SigBindRoute emits for each invocation of bindRoute (see funcs.go). This provides preliminary access to the router and muxer state prior to configuration.

View Source
var SigConnectionUpgraded = signals.New((OnConnectionUpgraded)(nil))

SigConnectionUpgraded emits when the route has been configured to produce a connection upgrade header, such as for WebSockets. This signal will not be raised if an error occurs during the upgrade process. To catch errors from a failed connection upgrade, you will need to bind to SigRouteError.

View Source
var SigEachRoute = signals.New((OnEachRoute)(nil))

SigEachRoute emits for each method handler bound per route.

In Capstan's semantics, routes are defined individually by path *and* by method. For example, the end point "/demo" would have two separate routes initialized if its controller contains both Get and Post methods (one for each of GET and POST). This signal will emit separately for each of these.

Capstan uses this signal internally to expose the renderer's convenience function for attaching template functions and definitions.

This signal emits for routes configured with ManualBind.

View Source
var SigEndRouteHandler = signals.New((OnEndRouteHandler)(nil))

SigEndRouteHandler emits when the route has finished all code paths and is preparing to exit. It is not possible to modify the response, response headers, nor will changing any Route attributes provide expected results. This signal is exclusively for any cleanup code that needs to be run by extensions that have hooked into the route signaling.

View Source
var SigManualRouteSetup = signals.New((OnManualRouteSetup)(nil))

SigManulRouteSetup emits when routes are manually bound using ManualBind().

This is an uncommon trigger since most routes will be configured via their controllers but some users may have a need to manually configure a route.

There is no way to differentiate between routes configured via a controller and routes configured via ManualBind; use this signal when catching the latter.

View Source
var SigRouteComplete = signals.New((OnRouteComplete)(nil))

SigRouteComplete emits for each route after the setup, bindRoute, and URL mapping has been finalized.

This signal is also emitted when manually bound routes are completed.

View Source
var SigRouteError = signals.New((OnRouteError)(nil))

SigRouteError emits immediately after any error condition has been raised but will not emit if the handled route's endpoint has returned nil (this is in contrast with the actual code which does process nil return values from route endpoints).

View Source
var SigRouteSetup = signals.New((OnRouteSetup)(nil))

SigRouteSetup emits after the route has been setup and method handlers have been configured.

View Source
var SigRouteWriteError = signals.New((OnRouteWriteError)(nil))

SigRouteWriteError emits when an error condition has been reached but prior to the error being written to the HTTP client. This signal may be used to modify the results of the generated error (such as customizing responses without having access to the template system or other internals or configurations).

View Source
var SigStartRouteHandler = signals.New((OnStartRouteHandler)(nil))

SigStartRouteHandler emits when the ServeHTTP Route method is called prior to any internal state handling and after the Context is first initialized. This can be used to modify route parameters prior to processing or modify the Context.

Functions

func AddPreLaunchFunc

func AddPreLaunchFunc(fn PreLaunchFunc)

func ArrayMapperFunc

func ArrayMapperFunc() mappableNode

ArrayMapperFunc returns a new, initialized arrayNode.

func AttachTemplateFunc

func AttachTemplateFunc(app Application, name string, fn interface{})

AttachTemplateFunc attaches a function or callable to the global template context using the provided name to the given application.

func AttachTemplateVar

func AttachTemplateVar(app Application, name string, val interface{})

AttachTemplateVar attaches a variable to the global template context with the specified name and value to the given application.

func BinaryTreeMapperFunc

func BinaryTreeMapperFunc() mappableNode

BinaryTreeMapperFunc returns a new binary tree.

func InitNetwork

func InitNetwork() (err error, errc chan error, close chan struct{})

func Listen

func Listen(network, addr string) (net.Listener, error)

func MakeID

func MakeID(s string) string

func New

func New(conf ...*config.Config) *application

New returns a new Capstan application with the optional configuration `conf`. If no configuration is specified one will be created with its values initialized to sensible defaults.

func NewExtension

func NewExtension(name, provides string) *extension

NewExtension returns a new, mostly-unintialized extension containing the name and the service(s) provided by this extension. Metadata beyond the values controlled by this function's arguments must be filled in separately by the caller.

func NewMappedLoader

func NewMappedLoader(def http.Handler) *mappedLoader

NewMappedLoader returns a map-backed loader for multi-application support. Map-backed loaders can only map hostnames to handlers and cannot map base paths.

The application loader interface is defined as an internal API interface (see internal/api/application.go for ApplicationLoader).

func NewMappedNode

func NewMappedNode() *mappedNode

NewMappedNode returns a new, initialized mappedNode.

func NewMultiAppProxy

func NewMultiAppProxy(loader api.ApplicationLoader) *multiAppProxy

func NewProxyTrie

func NewProxyTrie() *proxyTrie

NewProxyTrie returns a root radix trie node.

func NewRadixLoader

func NewRadixLoader(def http.Handler) *radixLoader

NewRadixLoader returns a loader backed by a radix trie providing longest matching prefix support. If you need to match both the hostname and the base path for routing incoming requests per-application, use this loader.

Be aware that there are some limitations with assigning handlers via longest matching prefixes. In particular, the radix loader is NOT path aware, meaning that a request containing the hostname + base path assignment of "example.com/store" will, by its nature, also match "example.com/stores" and any derivative thereafter.

The intent behind this loader is to match the first hostname + base path segment of the incoming request, pass it along to the assigned application, and allow that application to determine whether the request should be handled or an error should be returned.

func NewTrieNode

func NewTrieNode(label rune, prefix string, fn mappableNodeFunc) *proxyTrie

NewTrieNode returns a new radix trie node for use within a radix trie root node.

func Relaunch

func Relaunch() error

Relaunch the current binary inheriting all socket connection file descriptors.

This should be called from a goroutine. Parent/child process management is not handled by this function.

func RenderErrorFunc

func RenderErrorFunc(path, filepattern string) func(*Router) func(Context)

RenderErrorFunc is an error function that uses the Context-specified renderer. If the Context has no renderer enabled, or otherwise encounters and error, this will return an error result from the default error handling function.

This function encapsulated multiple layers of functions to reduce the responsibility of the caller.

func Restart

func Restart() error

Restart the current binary without inheriting socket file descriptors. For blank slate reinitialization, this is the best method to call. The parent process environment, current working directory, command line arguments, and STDIN, STDOUT, and STDERR are inherited by the child process.

Consider using Router.Rebind() instead of Restart unless you need to listen on different ports.

Be aware that there appears to be a bug with fsnotify in that O_CLOEXEC on its file descriptors isn't honored. You should consider closing any fsnotify watchers that are active before this call if you don't want to leak descriptors.

This should be called from a goroutine. Parent/child process management is not handled by this function.

func StopListening

func StopListening(listener net.Listener) error

func URLForGen

func URLForGen(router *Router, external bool) func(string, ...string) string

URLForGen returns a URLFor generator for each configured renderer. This will be attached to the global renderer first, if configured, and then to each route-specific view renderer if supplied.

Types

type Application

type Application interface {
	AttachApplication(Application)
	DestroyApplication(Application)
	Each(func(Application))
	ID() string
	Application() *application
	LoadSession()
	BindGroup(path string) *RouterGroup
	Bind(controller Controller) error
	ReplaceController(from, to Controller) error
	ReplacePath(from, to string)
	Unmount(path string)
	UnmountController(controller Controller) error
	UnmountGroup(path string) error
	DefaultMiddleware()
	SetMiddleware(middleware ...func(http.Handler) http.Handler) Application
	SetDefaultRenderer(renderer render.Renderer) Application
	SetMaster(app Application)
	RegisterShutdownHook(hook ShutdownHook)
	Ready()
	Listen() error
	Stop()
	Config() *config.Config
	Dependencies() DependencyMapper
	Logger() *logging.Log
	Router() *Router
	Signals() *signalContainer
	Extensions() *ExtensionManager
	Reload(config *config.Config)
}

type ApplicationConfig

type ApplicationConfig = config.ApplicationConfig

ApplicationConfig is the top-level pseudo-alias for Capstan's application configuration. Warning: This entity may be deprecated in a future version since CLI application support has been dropped (that's up to the caller).

type BaseController

type BaseController struct {

	// Middleware defined for this controller.
	Middleware Middleware

	// Name to assign to this controller. Leave empty to automatically deduce
	// the name from the implementing struct.
	Name string

	// Path against which this controller will bind its routes. This may have
	// special meaning for index and other methods (e.g. custom).
	Path string

	// Prefix to prepend to the controller's symbolic name. This may be useful
	// for namespacing controller references for reversing the URL in templates.
	Prefix string

	// OptionalSlash indicates the trailing slash is optional. It is usually
	// advised to set this via the Path component.
	OptionalSlash bool

	// Endpoints is a list of custom endpoints attached to this controller.
	Endpoints map[string]RouteFlag

	// MandatoryNoSlash indicates the trailing slash must not be present. It is
	// usually advised to set this via the Path component.
	MandatoryNoSlash bool

	// MandatorySlash indicates the trailing slash is required. It is usually
	// advised to set this via the Path component.
	MandatorySlash bool

	// SlashIsDefault indicates the presence or absence of the trailing slash is
	// the default state. This flag only holds meaning when OptionalSlash is set
	// to true. It is usually advised to set this via the Path component by
	// including a slash followed by a question mark ("/?") to indicate that the
	// slash is optional and the default redirection target.
	SlashIsDefault bool

	// NoInterpolation disables path interpolation and mandates the flags
	// (above) to configure the route slash states. This is useful for routes
	// where the special characters used to communicate slash behavior are
	// required as part of the route and should be accepted as literals.
	NoInterpolation bool

	// WebSocketPath, if set, will attach the WebSocket() method to the
	// specified path underneath the path defined for this controller.
	// Recommended.
	//
	// Leave this blank if your controller is intended strictly for websocket
	// handling.
	WebSocketPath string

	// Upgrader is the configured websocket upgrader via gorilla/websocket. This
	// provides both the configuration details for websocket connections in
	// addition to bound methods for upgrading the connection. If this is nil
	// and the controller implements the WebSocketHandler interface, the default
	// upgrader will be used instead.
	Upgrader *websocket.Upgrader

	// Renderer reference for this controller. This may be unique to each
	// controller or may be set globally via a helper.
	Renderer render.Renderer

	// Index path override. This may contain a path component, a single slash
	// indicating the path terminates with this index, a slash followed by a
	// question mark which indicates the slash is optional, or a slash followed
	// by an exclamation point indicating the route must not terminate with a
	// slash.
	Index string

	// Get overrides the default path for GET requests, appending the path
	// component specified here.
	Get string

	// Post overrides the default path for POST requests, appending the path
	// component specified here.
	Post string

	// Put overrides the default path for PUT requests, appending the path
	// component specified here.
	Put string

	// Patch overrides the default path for PATCH requests, appending the path
	// component specified here.
	Patch string

	// Delete overrides the default path for DELETE requests, appending the path
	// component specified here.
	Delete string

	// Head overrides the default path for HEAD requests, appending the path
	// component specified here.
	Head string
	// contains filtered or unexported fields
}

type Binder

type Binder interface {
	Bind(*Router)
}

Binder controllers are those that wish to implement or handle binding themselves. Consequently, a *Router is passed as the Bind() function's sole argument such that the controller may use it to interface directly with the router instance or may call Router.Mux() to use the muxer directly. If an implementation uses the latter, the underlying configured go-chi instance is exposed for external management.

type CSRFExtensionConfig

type CSRFExtensionConfig = iconfig.CSRFOptions

CSRFExtensionConfig.

type Config

type Config = config.Config

Config is the top-level pseudo-alias for Capstan's configuration struct. Provided for import convenience.

type ConnectHandler

type ConnectHandler interface {
	Connect(Context) error
}

type ContentType

type ContentType string

ContentType determines the content type for a request. This is used primarily by the Capstan Context entity to determine how the response should be generated.

const (
	TextPlain       ContentType = "text/plain"
	TextHTML        ContentType = "text/html"
	ApplicationJSON ContentType = "application/json; charset=utf8"
)

type Context

type Context interface {
	Float(string) (float64, error)
	FloatDefault(string, float64) float64
	Int(string) (int64, error)
	IntDefault(string, int64) int64
	Param(string) string
	ParamDefault(string, string) string
	Params(string) []string
	String(string) (string, error)
	StringDefault(string, string) string
	In(interface{}) error
	JSON(interface{}) error
	ParamTypes() map[string]string
	Render(string, interface{}) error
	Renderer() (render.ContextRenderer, error)
	SetRenderer(render.Renderer)
	Headers() http.Header
	Request() *http.Request
	Response() http.ResponseWriter
	RequestContext(key string, value interface{})
	Route() *Route
	SetCookie(*http.Cookie)
	WebSocket() *websocket.Conn
	SetWebSocket(*websocket.Conn)
	Session() session.Session
	URLFor(string) *URLBuilder
	Write([]byte) (int, error)
	WriteHeader(int)
	WriteJSON(interface{}) error
	WriteString(string) error
	ContentType(ContentType)
	HasError() error
	Panic(string)
	Error() string
	SetError(error)
	Code() int
	SetCode(int)
}

func MakeMiddlewareContext

func MakeMiddlewareContext(w http.ResponseWriter, r *http.Request) Context

MakeMiddlewareContext returns a Context instance that's suitable for use within middleware. In this case, Type is the empty string, and ParamTypes is an empty map.

func MakeRouteContext

func MakeRouteContext(w http.ResponseWriter, r *http.Request, rt *Route) Context

type ContextMaker

type ContextMaker func(http.ResponseWriter, *http.Request, *Route) Context

type Controller

type Controller interface {
	// contains filtered or unexported methods
}

type DeleteHandler

type DeleteHandler interface {
	Delete(Context) error
}

type DependencyMapper

type DependencyMapper interface {
	// Apply dependencies to the target interface type.
	Apply(target interface{})

	// ApplyLater applies the dependency map to the specified target when Bind()
	// is called at a later point.
	ApplyLater(target interface{})

	// Bind the delayed-load dependencies attached via ApplyLater().
	Bind()

	ClearDelayed()

	// Copy returns a complete copy of this DependencyMapper.
	Copy() DependencyMapper

	// Map the dependendency to the specified name.
	Map(name string, dependency interface{})

	// Register the dependency as the specified name.
	Register(name string, dependency interface{})

	// SetErrOnNil causes the dependency mapper to panic if a dependency is
	// requested via a tag or type that has not been configured in the
	// dependency mapper or if the type is nil.
	//
	// By default, if a dependency hasn't been configured or was deliberately
	// set to nil, the struct target will likewise be set as nil. Since this can
	// introduce surprising bugs, it may be useful to enable this feature during
	// development to catch common mistakes like misspelled `inject` tags or
	// missing dependencies.
	SetErrOnNil(value bool)
}

func NewDependencyMapper

func NewDependencyMapper() DependencyMapper

NewDependencyMapper returns a new DependencyMapper pre-initialized with the appropriate internal data types. This function should be used in lieu of creating the type and initializing it manually, particularly since Capstan's API is likely to remain in a state of flux for some time.

type Endpoint

type Endpoint func(Context) error

Endpoint defines functions that serve as Capstan endpoints. These are usually members of a struct and there's currently no provision for creating "bare" endpoints.

type EnvironmentConfig

type EnvironmentConfig = config.EnvironmentConfig

EnvironmentConfig is the top-level pseudo-alias for Capstan's environment configuration.

The environment configurations allows one to configure a Capstan container when running in multiapp mode, allowing individualized versions, names, or descriptions per application while presenting different information for the containing environment.

type Extension

type Extension interface {
	// Name for this extension; symbolic.
	Name() string

	// Provides indicates the dependency fulfilled by this extension.
	Provides() string

	// Requires indicates which dependency or dependencies must be loaded prior
	// to this extension.
	Requires() []string

	// Init this extension. This is called after the extension has been loaded;
	// for extensions that have dependencies on other extensions, this is called
	// after the dependency has been loaded. Circular dependencies will result
	// in a panic.
	Init(app Application)
}

type ExtensionDeinitializer

type ExtensionDeinitializer interface {
	// Deinit this extension. This is called before Capstan finalizes all
	// connections and shuts down. Extensions that implement this interface will
	// be given an opportunity to perform teardowns required.
	//
	// De-initialization methods will be called from separate goroutines and
	// will block application exit until all Deinit() functions have returned.
	Deinit(app Application)
}

type ExtensionManager

type ExtensionManager struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func NewExtensionManager

func NewExtensionManager(app Application) *ExtensionManager

func (*ExtensionManager) ByName

func (m *ExtensionManager) ByName(name string) Extension

ByName returns the extension registered by `name`.

If no such extension is registerd, this will return nil.

func (*ExtensionManager) Init

func (*ExtensionManager) Register

func (m *ExtensionManager) Register(extension Extension) error

Register the supplied extension.

func (*ExtensionManager) WhoProvides

func (m *ExtensionManager) WhoProvides(provides string) Extension

WhoProvides returns the extension that provides the feature set described by `provides`.

If no such extension is registered, this will return nil.

type GetHandler

type GetHandler interface {
	Get(Context) error
}

type HTTPServer

type HTTPServer struct {
	http.Server
	// contains filtered or unexported fields
}

func (*HTTPServer) Listener

func (h *HTTPServer) Listener() net.Listener

func (*HTTPServer) Serve

func (h *HTTPServer) Serve(listener net.Listener) error

type HeadHandler

type HeadHandler interface {
	Head(Context) error
}

type IndexHandler

type IndexHandler interface {
	Index(Context) error
}

type KeyStarExtensionConfig

type KeyStarExtensionConfig = config.KeyStarExtensionConfig

KeyStarExtensionConfig.

type Listener

type Listener interface {
	net.Listener
	syscall.Conn
}

type ListenerTLSConfig

type ListenerTLSConfig struct {
	// CertPath is the location of a TLS certificate on the file system.
	CertPath string
	// KeyPath is the location of the server's private key on the file system.
	KeyPath string
	// CertBytes is a PEM-encoded certificate.
	CertBytes []byte
	// KeyBytes is a PEM-encoded private key.
	KeyBytes []byte
}

type MapValues

type MapValues = render.MapValues

MapValues is a top-level pseudo-alias for Capstan's wrapper type render.MapValues wrapping the pongo2 Context.

type MapperHandler

type MapperHandler interface {
	Mapper() map[string]RouteMap
}

MapperHandler returns a map of a route (map key) and the endpoint + method (RouteMap) it should be bound to. MapperHandlers are controllers that define their own route-to-endpoint handling routines.

type Middleware

type Middleware chi.Middlewares

Middleware is a pseudo-alias for go-chi's awkwardly-named "Middlewares."

type MiddlewareExtension

type MiddlewareExtension interface {
	Extension

	// Middleware should return any middleware required by this extension.
	Middleware() []func(http.Handler) http.Handler
}

type MiddlewareFunc

type MiddlewareFunc func(http.Handler) http.Handler

MiddlewareFunc defines the type used by middleware declarations. This is provided mostly for convenience as middleware will generally define the returned handler function directly rather than assigning it to a type.

type MiddlewareHandler

type MiddlewareHandler interface {
	Middleware() []func(http.Handler) http.Handler
}

MiddlewareHandler, when implemented, allows controllers to return middleware that utilizes attached fields and methods as internal context. This is useful if your middleware requires access to a database or other dependencies (including injected dependencies).

type MultiAppConfig

type MultiAppConfig = config.MultiAppConfig

MultiAppConfig is the top-level pseudo-alias for Capstan's multi-application support. This controls multiapp behavior when muli-application mode has been enabled by calling Application.AttachApplication.

type MultiAppProxyHandler

type MultiAppProxyHandler interface {
	ProxyHandler
	Loader() api.ApplicationLoader
}

MultiAppProxyHandler defines the interface to expose for types supporting multi-application loading.

type OnAfterResponse

type OnAfterResponse func(Context, signals.Context, error)

OnAfterResponse accepts the Capstan Context and a possible error value. Note that the error value may be nil, capstan.Context, capstan/errors.Redirect, capstan/errors.Internal, or of error.

type OnApplicationAttached

type OnApplicationAttached func(Application, Application)

OnApplicationAttached accepts two arguments: The current application, and the master application.

In some cases, the master application and current application may be a pointer to the same interface.

type OnApplicationInterrupt

type OnApplicationInterrupt func(Application, sync.WaitGroup)

OnApplicationInterrupt receives a copy of the current application (this is the master instance) followed by the WaitGroup currently responsible for holding the interrupt state from exiting the listener loop.

type OnApplicationListening

type OnApplicationListening func(Application)

OnApplicationListening accepts the current application at the time of call.

type OnApplicationReady

type OnApplicationReady func(Application)

OnApplicationReady accepts the current application at the time of call. Return values from subordinate callees are ignored.

type OnApplicationShutdownHook

type OnApplicationShutdownHook func(Application, ShutdownHook) signals.Context

OnApplicationShutdownHook accepts the current application followed by the currently executing shutdown hook. This signal must also return a context.

If the signal context returns an abort code, execution of the current shutdown hook will not proceed.

If the signal context returns a stop code (with MustStop), no shutdown hooks will be executed.

type OnBeforeResponse

type OnBeforeResponse func(Context, *Route, signals.Context)

OnBeforeResponse accepts the Capstan Context and Route. If a signals.Context value is returned and its Error() value is set with a code >= 400, this will skip immediately to the route's error handling.

type OnBindRoute

type OnBindRoute func(*Router, *Route, chi.Router) signals.Context

OnBindRoute accepts as its arguments the router context, the route currently being processed, and the assigned muxer.

type OnConnectionUpgraded

type OnConnectionUpgraded func(Context, signals.Context)

OnConnectionUpgraded accepts the capstan.Context and its state immediately after a successful upgrade.

type OnEachRoute

type OnEachRoute func(*Router, *Route)

OnEachRoute accepts the router context and the Route currently being processed. This is triggered before bindRoute is called (meaning the Route is not yet attached to any muxer) and before the route is completely configured.

type OnEndRouteHandler

type OnEndRouteHandler func(*Route, Context, signals.Context)

OnEndRouteHandler accepts a capstan.Route, capstan.Context, and the current signals.Context as returned by OnStartRouteHandler.

The capstan.Route cannot be modified in this phase.

type OnManualRouteSetup

type OnManualRouteSetup func(*Router, *Route)

type OnRouteComplete

type OnRouteComplete func(*Router, *Route)

OnRouteComplete accepts the router context and the Route currently processed.

type OnRouteError

type OnRouteError func(*Route, Context, signals.Context, error)

OnRouteError accepts the capstan.Route, capstan.Context, and the error value encountered at the time of the error.

Error returns from routes do not always indicate an error condition. The error type must be checked to see if it is also of type capstan.Context, capstan/errors.Redirect, capstan/errors.Internal, or of type error.

If an error condition has occurred and a capstan.Context type was returned, it may be necessary to introspect the Context.Code() value for a value >= 400 as well as Context.HasError(). If a capstan.Context has been returned and there is an error condition, both Context.HasError() and Context.Error() will return useful information.

type OnRouteSetup

type OnRouteSetup func(*Router, []*Route)

OnRouteSetup accepts the router context and a slice of all Route structs derived from the controller as it is processed. Routes will be generated for each HTTP method, each special struct method, and any bind routes that were configured at runtime.

type OnRouteWriteError

type OnRouteWriteError func(*Route, Context, error) signals.Context

OnRouteWriteError accepts the capstan.Route, capstan.Context, and the error condition that caused the return status.

This signal may return a signals.Context. If the signals.Context returns an error, the error value initialize passed to the route error writer will be replaced with the contents of this error and any modifications made to capstan.Conext may be reflected in the returned response. If either MustAbort() or MustStop() are set on the signals.Context, the error writer will exit without writing anything.

Setting MustStop() is suggested if callers plan to perform their own error writing directly. MustAbort() is not guaranteed to produce expected results in the near term and its semantics in the function calling OnRouteWriteError may change.

type OnStartRouteHandler

type OnStartRouteHandler func(*Route, Context, signals.Context)

OnStartRouteHandler accepts the Capstan Route and Context. This can return a signals.Context indicating an error condition which, if non-nil, will interrupt the route handling before any other processing occurs (this also bypasses OnBeforeResponse) if the error code is >= 400.

If the signals.Context returned here has MustAbort flagged, this will immediately pass control to the route's error handling without making any changes to the context values as will happen if signals.Context's Error is set. Setting MustAbort() is useful if the caller has modified the capstan.Context directly to reflect a specific error or redirect condition but does not wish for the signal to overwrite these values.

Only call signals.Context.SetError() if you actually intend for the signal handler to set an error condition on the request.

Access to the raw net/http.ResponseWriter and net/http.Request can be had through the Context.Response() and Context.Request() methods.

type OptionsHandler

type OptionsHandler interface {
	Options(Context) error
}

type PassthroughFunc

type PassthroughFunc func(Context) http.Handler

type PassthroughHandler

type PassthroughHandler interface {
	Passthrough(http.ResponseWriter, *http.Request)
}

PassthroughHandler handles all HTTP methods, passing them through to the implementation of the Passthrough method defined by the handler.

BaseController definitions for per-method path locations are not honored by the PassthroughHandler.

type PatchHandler

type PatchHandler interface {
	Patch(Context) error
}

type PostHandler

type PostHandler interface {
	Post(Context) error
}

type PreLaunchFunc

type PreLaunchFunc func() error

type ProxyHandler

type ProxyHandler interface {
	// ServeHTTP allows ProxyHandler to implement http.Handler.
	ServeHTTP(http.ResponseWriter, *http.Request)

	// Switch the current router to a new router instance.
	Switch(chi.Router)
}

ProxyHandler is the interface that must be implemented by types that intend to be used as proxy handlers. Proxy handlers may be comparatively simple, such as the `proxy` type, or they may be more complex and implement host-lookup functionality such as the `multiAppProxy` type.

Proxies are required in order to support rebinding and endpoint deletion since go-chi doesn't currently allow us to overwrite or delete endpoints directly. So, what we do instead, is to regenerate the go-chi bindings when a rebind or endpoint deletion is requested, call Switch() on the proxy, and "switch" to the new chi.Router.

Multiple proxies are arranged in a hierarchical structure, such as for multiapp support. In this case, the multiapp proxy handles dispatching requests based on the incoming domain, path, or domain + path, and then passes it to the underlying `proxy` which performs the rest of the work. This allows us to Switch() on a per-application bases, as required, while still supporting multiple applications within the same Capstan-hosted instance.

type PutHandler

type PutHandler interface {
	Put(Context) error
}

type ReadyExtension

type ReadyExtension interface {
	Ready(app Application)
}

type Route

type Route struct {

	// Name of this handler. This is a symbolic name
	Name string

	// Path derived from route descriptor.
	Path string

	// CapPath contains the original Capstan-formatted path for this route.
	CapPath string

	// BasePath as indicated by the router. This is used by the URL builder but
	// may provide informational context to controllers indicating that this
	// route isn't mounted at the site root.
	BasePath string

	// CapBasePath is similar to BasePath with the exception that it contains
	// Capstan-formatted path information.
	CapBasePath string

	// MandatoryNoSlash strips any trailing slash from the route and creates a
	// single route with no trailing slash. This enforces the absense of a
	// slash. No redirection may occur from routes with a trailing slash to
	// routes without a slash when flagged with this feature.
	//
	// Mandatory absense of a slash is enforced when the route is defined with a
	// trailing exclamation point, e.g. "/route!". Such routes may also include
	// a trailing slash to ensure the meaning is clearer (e.g. "not slash" or
	// "/route/!").
	MandatoryNoSlash bool

	// MandatorySlash is the precise opposite of MandatoryNoSlash: Routes are
	// required to terminate with a trailing slash and no redirection may occur
	// from routes without a slash.
	//
	// Routes with a mandatory slash must terminate with a trailing slash, e.g.
	// "/route/".
	MandatorySlash bool

	// OptionalSlash creates two separate routing table entries: One with a
	// trailing slash and one without. If the route ends with a slash, this is
	// considered the route's default state, and requests to this route without
	// a trailing slash will be redirected to a route of the same name with the
	// slash appended. Likewise, the converse is true.
	//
	// Optional slashes may be delineated with a terminating question mark, e.g.
	// "/route/?" for routes that will redirect to a trailing slash or "/route?"
	// for those that do not. The question mark itself is optional for routes
	// defined without a trailing slash and may be omitted, e.g., "/route" and
	// "/route?" define the same behavior. The question mark is advisable to
	// make clear the developer's intention, and may be required in some
	// contexts (such as defining the behavior of an index route).
	//
	// Note: A trailing slash, e.g. "/route/" indicates that the route must
	// terminate with a *mandatory* slash. Hence, a terminating ? is required
	// when defining a default redirection state from "/route" to "/route/",
	// e.g. "/route/?".
	//
	// This section will be clarified in the documentation.
	OptionalSlash bool

	// SlashIsDefault indicates that the default route state is to terminate
	// with a slash. The value of this flag is only applicable if OptionalSlash
	// is true.
	SlashIsDefault bool

	// RouteTimeout indicates this route should enforce a timeout of the
	// specified duration, in seconds. If ForceTimeout is true, the handler will
	// exit after RouteTimeout seconds. If ForceTimeout is false, then timeout
	// handling must be managed by the controller (and will be ignored
	// otherwise).
	RouteTimeout int

	// ForceTimeout will forcibly exit the handler after RouteTimeout seconds or
	// do nothing until the controller endpoint managed by this route exists of
	// its own volition.
	ForceTimeout bool

	// Paths for multiple routes that may be handled by the same controller.
	Paths map[string][]string

	// ContentType is a convenience mechanism for setting the content type of
	// the route if it is one of text/plain, text/json, or application/json. You
	// should use this instead of setting the headers directly.
	//
	// This value is mostly intended for API endpoints that generate JSON
	// output.
	ContentType string

	// Handler for passthrough routes. If this is non-nil, this will override
	// all other configurations.
	Handler http.HandlerFunc

	// Headers used as route defaults.
	Headers http.Header

	// Prefix to prepend to the handler's name to limit naming collisions when
	// reverse-mapping URLs.
	Prefix string

	// Suffix to append to the handler's name. This will typically be the
	// request method but may be overridden here. If this value isn't set, the
	// request method is used instead.
	Suffix string

	// ParamTypes maps parameter names to their type for use by *Param() context
	// functions.
	ParamTypes map[string]string

	// Method associated with this route.
	Method string

	// Middleware for this route.
	//
	// TODO: Eventually support redeclaration of middleware types such that it
	// accepts a Context. This will require also wrapping external middleware,
	// such as that which ships with chi and others.
	Middleware []func(http.Handler) http.Handler

	// Endpoint function.
	Endpoint Endpoint

	// Controller reference.
	Controller Controller

	// Upgrader for websocket connections.
	Upgrader *websocket.Upgrader

	// Renderer defines a controller-specific renderer to use for this handler.
	// If this is nil, the global renderer will be used instead.
	Renderer render.Renderer
	// contains filtered or unexported fields
}

Route descriptor ultimately used for constructing chi routes. This encapsulates the actual user code handler and passes in the appropriate arguments.

func (*Route) Copy

func (rt *Route) Copy() *Route

Copy and return a new instance of the current route.

Beware: Non-value types are only copied as pointers to their original values. This means that maps local to the Route struct are not copied by value.

func (*Route) ForName

func (rt *Route) ForName() string

func (*Route) FullPath

func (rt *Route) FullPath() string

func (*Route) ServeHTTP

func (rt *Route) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP provides an HTTP handler implementation that makes routes compatible with Go's default HTTP server.

This function is somewhat messy and handles the entirety of Capstan's request handling logic. Refactoring is welcome.

func (*Route) WriteError

func (rt *Route) WriteError(ctx Context, err error)

type RouteFlag

type RouteFlag struct {
	Method   string
	Endpoint string
}

type RouteMap

type RouteMap struct {
	Method   string
	Endpoint Endpoint
}

RouteMap is currently unused. It will be includes as part of the Mapper() handler for controllers that define their own route map.

type Router

type Router struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func NewEmptyRouter

func NewEmptyRouter() *Router

func NewRouter

func NewRouter(app Application) *Router

func (*Router) AddListener

func (r *Router) AddListener(listener net.Listener)

AddListener accepts a listener against which the Chi handler will be attached and will be used as the base listener for an HTTP or HTTPS service.

This listener will be mapped to the configured network management as defined in network.go and netlisten_*.go. If the specified listener does not implement both net.Listen and syscall.Conn it will not be used for high availability graceful restart. If you depend on a custom listener, you may need to implement graceful restart yourself or implement syscall.Conn.

func (*Router) AttachListener

func (r *Router) AttachListener(listener net.Listener)

AttachListener to the current route handler.

This may be used by external code to enable listeners.

func (*Router) AttachNamedListener

func (r *Router) AttachNamedListener(name string, listener net.Listener)

func (*Router) Bind

func (r *Router) Bind(endpoint Controller) error

Bind the specified endpoint.

This method is the core of the router and handles all method routes directly and farms out other route types to separate functions (also located in this file). Bind() will also setup routes and map them.

The use of route.Copy() may appear confusing at first blush, but its purpose is to create a copy of (most of) the route and its data, which is then used to bind a method/endpoint tuple with go-chi. route.Copy() only performs a shallow copy; slices and map pointers are replicated across all dependents.

func (*Router) Close

func (r *Router) Close()

Close all configured listeners gracefully. This calls Shutdown on each http.Server and waits until all connections have closed before terminating.

func (*Router) CloseNamed

func (r *Router) CloseNamed(name string) (err error)

CloseNamed listener.

This will gracefully shut down the named listener, if available. The special names "tls," "tcp," and "file" are used to close reserved listeners for TLS, TCP, and Unix domain socket traffic.

This will also remove the listener from the router's listeners store.

func (*Router) Group

func (r *Router) Group(path string) *RouterGroup

Group creates and returns a new router group.

func (*Router) HTTPError

func (r *Router) HTTPError(ctx Context)

func (*Router) HasSocket

func (r *Router) HasSocket() bool

HasSocket returns true if Capstan was configured to listen on a domain socket.

As with other Has* functions for listeners, this does not indicate a status for manually-configured listeners and applies only to those that were started via the Listen* methods (either automatically, via configuration, or manually).

func (*Router) HasTCP

func (r *Router) HasTCP() bool

HasTCP returns true if Capstan was configured to listen on a TCP socket.

As with other Has* functions for listeners, this does not indicate a status for manually-configured listeners and applies only to those that were started via the Listen* methods (either automatically, via configuration, or manually).

func (*Router) HasTLS

func (r *Router) HasTLS() bool

HasTLS returns true if Capstan was configured to listen on a TLS socket.

As with other Has* functions for listeners, this does not indicate a status for manually-configured listeners and applies only to those that were started via the Listen* methods (either automatically, via configuration, or manually).

func (*Router) Listen

func (r *Router) Listen() error

Listen on all configured listeners and wait until they close.

If an error is received by this function it will call Router.Close itself and begin the shutdown process.

func (*Router) ListenHTTP

func (r *Router) ListenHTTP(addr string) (net.Listener, error)

ListenHTTP allows client code to configure a new port to listen on. This should not be called if the server is already listening on an HTTP port. This is called internally if ListenAddress is set.

func (*Router) ListenSocket

func (r *Router) ListenSocket(sock string) (net.Listener, error)

ListenSocket allows client code to configure a new UNIX domain socket to listen on. This should not be called if the server is already listening on the same socket. This is called internally if ListenSocket is set.

func (*Router) ListenTLS

func (r *Router) ListenTLS(addr string) (net.Listener, error)

ListenTLS allows client code to configure a new TLS port to listen on. This should not be called if the server is already listening on a TLS port. This is called internally if ListenAddressTLS is set.

func (*Router) ManualBind

func (r *Router) ManualBind(method, path, suffix string, controller Controller, endpoint Endpoint)

ManualBind is used with Bind() routes to manually bind a given `endpoint` to the specified `path` with the HTTP request `method` and URLFor `suffix` provided. The controller must also be specified to correctly assemble the route.

func (*Router) Middleware

func (r *Router) Middleware(middleware ...func(http.Handler) http.Handler) *Router

Middleware configures Router-global middleware for all routes bound to this Router.

func (*Router) Mux

func (r *Router) Mux() chi.Router

Mux returns the chi.Router mux associated with this Router instance.

func (*Router) ParseRoute

func (r *Router) ParseRoute(route string) *routeProps

ParseRoute processes the specified route, processes it, and returns a routeProps struct describing the route using go-chi syntax.

Route parsing is somewhat analogous to go-chi but uses a different syntax. In particular, route variables are delineated by "<" and ">" rather than "{" and "}" as per go-chi. Further, besides regex types, Capstan routes also define string, float, float32, float64, int, int32, and int64 types. Route syntax is:

String:

/<varname:string>

Integer types:

/<varname:int32>

Regular expressions:

/<varname:regex>

func (*Router) Proxy

func (r *Router) Proxy() ProxyHandler

Proxy returns the ProxyHandler associated with this Router instance.

func (*Router) Rebind

func (r *Router) Rebind() chi.Router

Rebind() incrementally rebinds all routes associated with this Router. This is useful when remapping a route's endpoint. A new muxer is returned with all the bindings set. This function should be used with the proxy Switch method.

When a Rebind is called, the routes are not immediately rebound. Instead, a new muxer is created with the same configuration already used by the existing muxer and all routes associated with this Router are bound, individually, to this muxer. Only when the routes have successfully been bound will the muxer be returned.

FIXME: This needs to work across subrouters as well.

func (*Router) ReplacePath

func (r *Router) ReplacePath(from, to string)

ReplacePath swaps a route endpoint for the route associated with `from` to the new endpoint `to`. Rebind is triggered if this call is successful.

This method also switches the proxy handler to the one returned by Rebind.

func (*Router) ReservedFunctions

func (r *Router) ReservedFunctions(reserved ...string)

func (*Router) ServeHTTP

func (r *Router) ServeHTTP(w http.ResponseWriter, rq *http.Request)

func (*Router) SetProxy

func (r *Router) SetProxy(p ProxyHandler)

SetProxy changes the proxy for this router.

func (*Router) SetRenderer

func (r *Router) SetRenderer(renderer render.Renderer)

SetRender configures a global render.Renderer for all endpoints handled by this router. This may be overridden by renderer specified via the BaseController options for any given route. If this is never set, the Context.Render() becomes a noop and returns the noop implementation of Renderer.

func (*Router) SetupMuxer

func (r *Router) SetupMuxer()

func (*Router) Static

func (r *Router) Static(urlroot, path string)

Static binds the path described by `urlroot` to the filesystem `path` as a source for hosting static assets.

Being as this makes use of the Golang default http.FileServer implementation, it's worth considering a reverse proxy for better performance.

func (*Router) StaticVFS

func (r *Router) StaticVFS(urlroot, path string, fs vfs.FS)

Static binds the path described by `urlroot` to the filesystem `path` as contained in the virtual filesystem implementation `fs` as a source for hosting static assets. This should work with any VFS implementation compatible with vfs.FileSystem but is primarily intended to work with Embedder.

Being as this makes use of the Golang default http.FileServer implementation, it's worth considering a reverse proxy for better performance.

func (*Router) URLs

func (r *Router) URLs() *URLMapper

URLs retrieves the Router's configured URLMapper.

func (*Router) Unmount

func (r *Router) Unmount(path string)

Unmount removes the route associated with `path` from the router. This calls Rebind if successful.

This method also switches the proxy handler to the one returned by Rebind.

type RouterGroup

type RouterGroup struct {
	// contains filtered or unexported fields
}

func NewRouterGroup

func NewRouterGroup(path string, parent *Router) *RouterGroup

func (*RouterGroup) Add

func (rg *RouterGroup) Add(fn func(*Router))

func (*RouterGroup) Header

func (rg *RouterGroup) Header() http.Header

func (*RouterGroup) Middleware

func (rg *RouterGroup) Middleware(middleware chi.Middlewares)

func (*RouterGroup) Name

func (rg *RouterGroup) Name(name string) *RouterGroup

func (*RouterGroup) Options

func (rg *RouterGroup) Options() *RouterOptions

func (*RouterGroup) Rebase

func (rg *RouterGroup) Rebase(path string)

func (*RouterGroup) Rebind

func (rg *RouterGroup) Rebind() chi.Router

func (*RouterGroup) RebindSelf

func (rg *RouterGroup) RebindSelf()

func (*RouterGroup) ReplacePath

func (rg *RouterGroup) ReplacePath(from, to string)

func (*RouterGroup) WithRenderer

func (rg *RouterGroup) WithRenderer(renderer render.Renderer) *RouterGroup

type RouterOptions

type RouterOptions struct {
	ContentType string
}

type ServerConfig

type ServerConfig = config.ServerConfig

ServerConfig is the top-level pseudo-alias for Capstan's server configuration. This is a convenience type to reduce imports.

type SessionConfig

type SessionConfig = config.SessionConfig

SessionConfig is a top-level pseudo-alas for Capstan's session configuration.

type ShutdownHook

type ShutdownHook func() error

ShutdownHook types are registered to be called whenever the application is terminated normally.

type StartableExtension

type StartableExtension interface {
	Start(Application) interface{}
}

type TraceHandler

type TraceHandler interface {
	Trace(Context) error
}

type URLBuilder

type URLBuilder struct {
	External bool
	Scheme   string
	Host     string
	// contains filtered or unexported fields
}

func (*URLBuilder) Asset

func (b *URLBuilder) Asset(asset string)

func (*URLBuilder) Encode

func (b *URLBuilder) Encode() string

func (*URLBuilder) Param

func (b *URLBuilder) Param(name, value string) *URLBuilder

Param attaches a parameter to the internal parameters map. Parameters that are named in the URL pathspec will be expanded as path components; others will be treated as query string parameters.

func (*URLBuilder) Params

func (b *URLBuilder) Params(params url.Values) *URLBuilder

Params overwrites the internal parameters map with the one specified. Parameters that are named in the URL pathspec will be expanded as path components; others will be treated as query string parameters.

func (*URLBuilder) SetQuery

func (b *URLBuilder) SetQuery(query string) error

type URLMapper

type URLMapper struct {
	Config  *config.ServerConfig
	Routes  map[string]*Route
	Domains map[string]*URLMapper
	Static  string
	sync.RWMutex
	// contains filtered or unexported fields
}

func NewURLMapper

func NewURLMapper(conf *config.ServerConfig) *URLMapper

NewURLMapper returns a new URLMapper configured to use the specified config. We use a pointer to config.Config as some changes to URL behavior may be set dynamically depending on how the application is running. For example, enabling just HTTP or TLS will switch the protocol scheme between "http" and "https," respectively, or enabling both will remove the scheme entirely and use "relative" protocols (e.g. "//example.org/some/path").

func (*URLMapper) For

func (u *URLMapper) For(name string) *URLBuilder

func (*URLMapper) Has

func (u *URLMapper) Has(route *Route) bool

func (*URLMapper) Map

func (u *URLMapper) Map(route *Route)

func (*URLMapper) Remove

func (u *URLMapper) Remove(route *Route)

type VFS

type VFS interface {
}

type VFSFileSystem

type VFSFileSystem struct {
}

type VFSFilebox

type VFSFilebox struct {
}

type VFSPassThrough

type VFSPassThrough struct {
}

type VFSRegistry

type VFSRegistry struct {
	Registry map[string][]VFS
	// contains filtered or unexported fields
}

VFSRegistry works by storing available virtual file systems and a series of upgrade/downgrade listeners. As a new VFS is added as an upgrade, metadata related to it is passed to all registered upgraders which may then elect to utilize the new VFS (or not). If an error or panic occurs when attempting to access a VFS, the downgrade callbacks are triggered for that VFS automatically and the VFS reverts to its prior state.

As an example, assume you have an application that is distributed with migration scripts for a database embedded into the binary. The VFS, by default, will utilize these migrations by default. However, also assume that you provide migration upgrades that can occur out-of-band from the binary. When you distribute these upgrades, your application can instruct the VFSRegistry to upgrade the migrations listener, which will pass along another VFS instance that reads from the updated .zip. This may be configured as a passthrough VFS that will first attempt to read files from the .zip and then fall back to those integrated into the binary.

Another example: Assume you download a new theme that extends one of the core templates distributed with your binary. You need access to both the new theme's .zip and the integrated templates; you can have a VFS passthrough that will read from both the .zip and the built-in theme separately, allowing you to upgrade the new theme with add on .zips. If a new add on .zip doesn't work to your liking, you could remove it, and when the VFS layer panics from the missing file, it will downgrade itself until it either reverts to one of the previous .zip files (my-theme-v2.zip to my-theme-v1.zip, for example) or until it reverts to reading from the binary directly.

Alternatively, you may also set up priorities such that files that exist in the current working directory can override those contained in archives or vice-versa.

func (*VFSRegistry) OnDowngrade

func (r *VFSRegistry) OnDowngrade(fn downgradeFunc, passthrough bool)

func (*VFSRegistry) OnUpgrade

func (r *VFSRegistry) OnUpgrade(fn upgradeFunc, passthrough bool)

type VFSZipFile

type VFSZipFile struct {
}

type WebSocketHandler

type WebSocketHandler interface {
	WebSocket(Context) error
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL