kubo/core/corehttp/corehttp.go
Kevin Wallace fbd76ebb5b corehttp: ServeOption supports chaining muxes
Each option now additionally returns the mux to be used by future options. If
every options returns the mux it was passed, the current behavior is unchanged.

However, if the option returns an a new mux, it can mediate requests to handlers
provided by future options:

    return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
      childMux := http.NewServeMux()
      mux.Handle("/", handlerThatDelegatesToChildMux)
      return childMux, nil
    }

License: MIT
Signed-off-by: Kevin Wallace <kevin@pentabarf.net>
2015-02-08 11:27:06 -08:00

74 lines
2.2 KiB
Go

package corehttp
import (
"net/http"
manners "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/braintree/manners"
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
core "github.com/jbenet/go-ipfs/core"
eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog"
)
var log = eventlog.Logger("core/server")
// ServeOption registers any HTTP handlers it provides on the given mux.
// It returns the mux to expose to future options, which may be a new mux if it
// is interested in mediating requests to future options, or the same mux
// initially passed in if not.
type ServeOption func(*core.IpfsNode, *http.ServeMux) (*http.ServeMux, error)
// ListenAndServe runs an HTTP server listening at |listeningMultiAddr| with
// the given serve options. The address must be provided in multiaddr format.
//
// TODO intelligently parse address strings in other formats so long as they
// unambiguously map to a valid multiaddr. e.g. for convenience, ":8080" should
// map to "/ip4/0.0.0.0/tcp/8080".
func ListenAndServe(n *core.IpfsNode, listeningMultiAddr string, options ...ServeOption) error {
addr, err := ma.NewMultiaddr(listeningMultiAddr)
if err != nil {
return err
}
topMux := http.NewServeMux()
mux := topMux
for _, option := range options {
mux, err = option(n, mux)
if err != nil {
return err
}
}
return listenAndServe(n, addr, topMux)
}
func listenAndServe(node *core.IpfsNode, addr ma.Multiaddr, mux *http.ServeMux) error {
_, host, err := manet.DialArgs(addr)
if err != nil {
return err
}
server := manners.NewServer()
// if the server exits beforehand
var serverError error
serverExited := make(chan struct{})
go func() {
serverError = server.ListenAndServe(host, mux)
close(serverExited)
}()
// wait for server to exit.
select {
case <-serverExited:
// if node being closed before server exits, close server
case <-node.Closing():
log.Infof("server at %s terminating...", addr)
server.Shutdown <- true
<-serverExited // now, DO wait until server exit
}
log.Infof("server at %s terminated", addr)
return serverError
}