vendor github.com/tylerb/graceful and dependencies

This commit is contained in:
Mike Lang
2016-08-31 18:07:56 -07:00
parent fd82651f96
commit 46249fd403
18 changed files with 1804 additions and 0 deletions

21
vendor/github.com/tylerb/graceful/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Tyler Bunnell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

487
vendor/github.com/tylerb/graceful/graceful.go generated vendored Normal file
View File

@@ -0,0 +1,487 @@
package graceful
import (
"crypto/tls"
"log"
"net"
"net/http"
"os"
"os/signal"
"sync"
"syscall"
"time"
)
// Server wraps an http.Server with graceful connection handling.
// It may be used directly in the same way as http.Server, or may
// be constructed with the global functions in this package.
//
// Example:
// srv := &graceful.Server{
// Timeout: 5 * time.Second,
// Server: &http.Server{Addr: ":1234", Handler: handler},
// }
// srv.ListenAndServe()
type Server struct {
*http.Server
// Timeout is the duration to allow outstanding requests to survive
// before forcefully terminating them.
Timeout time.Duration
// Limit the number of outstanding requests
ListenLimit int
// TCPKeepAlive sets the TCP keep-alive timeouts on accepted
// connections. It prunes dead TCP connections ( e.g. closing
// laptop mid-download)
TCPKeepAlive time.Duration
// ConnState specifies an optional callback function that is
// called when a client connection changes state. This is a proxy
// to the underlying http.Server's ConnState, and the original
// must not be set directly.
ConnState func(net.Conn, http.ConnState)
// BeforeShutdown is an optional callback function that is called
// before the listener is closed. Returns true if shutdown is allowed
BeforeShutdown func() bool
// ShutdownInitiated is an optional callback function that is called
// when shutdown is initiated. It can be used to notify the client
// side of long lived connections (e.g. websockets) to reconnect.
ShutdownInitiated func()
// NoSignalHandling prevents graceful from automatically shutting down
// on SIGINT and SIGTERM. If set to true, you must shut down the server
// manually with Stop().
NoSignalHandling bool
// Logger used to notify of errors on startup and on stop.
Logger *log.Logger
// LogFunc can be assigned with a logging function of your choice, allowing
// you to use whatever logging approach you would like
LogFunc func(format string, args ...interface{})
// Interrupted is true if the server is handling a SIGINT or SIGTERM
// signal and is thus shutting down.
Interrupted bool
// interrupt signals the listener to stop serving connections,
// and the server to shut down.
interrupt chan os.Signal
// stopLock is used to protect against concurrent calls to Stop
stopLock sync.Mutex
// stopChan is the channel on which callers may block while waiting for
// the server to stop.
stopChan chan struct{}
// chanLock is used to protect access to the various channel constructors.
chanLock sync.RWMutex
// connections holds all connections managed by graceful
connections map[net.Conn]struct{}
// idleConnections holds all idle connections managed by graceful
idleConnections map[net.Conn]struct{}
}
// Run serves the http.Handler with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func Run(addr string, timeout time.Duration, n http.Handler) {
srv := &Server{
Timeout: timeout,
TCPKeepAlive: 3 * time.Minute,
Server: &http.Server{Addr: addr, Handler: n},
// Logger: DefaultLogger(),
}
if err := srv.ListenAndServe(); err != nil {
if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
srv.logf("%s", err)
os.Exit(1)
}
}
}
// RunWithErr is an alternative version of Run function which can return error.
//
// Unlike Run this version will not exit the program if an error is encountered but will
// return it instead.
func RunWithErr(addr string, timeout time.Duration, n http.Handler) error {
srv := &Server{
Timeout: timeout,
TCPKeepAlive: 3 * time.Minute,
Server: &http.Server{Addr: addr, Handler: n},
Logger: DefaultLogger(),
}
return srv.ListenAndServe()
}
// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func ListenAndServe(server *http.Server, timeout time.Duration) error {
srv := &Server{Timeout: timeout, Server: server, Logger: DefaultLogger()}
return srv.ListenAndServe()
}
// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
func (srv *Server) ListenAndServe() error {
// Create the listener so we can control their lifetime
addr := srv.Addr
if addr == "" {
addr = ":http"
}
conn, err := srv.newTCPListener(addr)
if err != nil {
return err
}
return srv.Serve(conn)
}
// ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func ListenAndServeTLS(server *http.Server, certFile, keyFile string, timeout time.Duration) error {
srv := &Server{Timeout: timeout, Server: server, Logger: DefaultLogger()}
return srv.ListenAndServeTLS(certFile, keyFile)
}
// ListenTLS is a convenience method that creates an https listener using the
// provided cert and key files. Use this method if you need access to the
// listener object directly. When ready, pass it to the Serve method.
func (srv *Server) ListenTLS(certFile, keyFile string) (net.Listener, error) {
// Create the listener ourselves so we can control its lifetime
addr := srv.Addr
if addr == "" {
addr = ":https"
}
config := &tls.Config{}
if srv.TLSConfig != nil {
*config = *srv.TLSConfig
}
var err error
config.Certificates = make([]tls.Certificate, 1)
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, err
}
// Enable http2
enableHTTP2ForTLSConfig(config)
conn, err := srv.newTCPListener(addr)
if err != nil {
return nil, err
}
srv.TLSConfig = config
tlsListener := tls.NewListener(conn, config)
return tlsListener, nil
}
// Enable HTTP2ForTLSConfig explicitly enables http/2 for a TLS Config. This is due to changes in Go 1.7 where
// http servers are no longer automatically configured to enable http/2 if the server's TLSConfig is set.
// See https://github.com/golang/go/issues/15908
func enableHTTP2ForTLSConfig(t *tls.Config) {
if TLSConfigHasHTTP2Enabled(t) {
return
}
t.NextProtos = append(t.NextProtos, "h2")
}
// TLSConfigHasHTTP2Enabled checks to see if a given TLS Config has http2 enabled.
func TLSConfigHasHTTP2Enabled(t *tls.Config) bool {
for _, value := range t.NextProtos {
if value == "h2" {
return true
}
}
return false
}
// ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
l, err := srv.ListenTLS(certFile, keyFile)
if err != nil {
return err
}
return srv.Serve(l)
}
// ListenAndServeTLSConfig can be used with an existing TLS config and is equivalent to
// http.Server.ListenAndServeTLS with graceful shutdown enabled,
func (srv *Server) ListenAndServeTLSConfig(config *tls.Config) error {
addr := srv.Addr
if addr == "" {
addr = ":https"
}
conn, err := srv.newTCPListener(addr)
if err != nil {
return err
}
srv.TLSConfig = config
tlsListener := tls.NewListener(conn, config)
return srv.Serve(tlsListener)
}
// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func Serve(server *http.Server, l net.Listener, timeout time.Duration) error {
srv := &Server{Timeout: timeout, Server: server, Logger: DefaultLogger()}
return srv.Serve(l)
}
// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
func (srv *Server) Serve(listener net.Listener) error {
if srv.ListenLimit != 0 {
listener = LimitListener(listener, srv.ListenLimit)
}
// Make our stopchan
srv.StopChan()
// Track connection state
add := make(chan net.Conn)
idle := make(chan net.Conn)
active := make(chan net.Conn)
remove := make(chan net.Conn)
srv.Server.ConnState = func(conn net.Conn, state http.ConnState) {
switch state {
case http.StateNew:
add <- conn
case http.StateActive:
active <- conn
case http.StateIdle:
idle <- conn
case http.StateClosed, http.StateHijacked:
remove <- conn
}
srv.stopLock.Lock()
defer srv.stopLock.Unlock()
if srv.ConnState != nil {
srv.ConnState(conn, state)
}
}
// Manage open connections
shutdown := make(chan chan struct{})
kill := make(chan struct{})
go srv.manageConnections(add, idle, active, remove, shutdown, kill)
interrupt := srv.interruptChan()
// Set up the interrupt handler
if !srv.NoSignalHandling {
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
}
quitting := make(chan struct{})
go srv.handleInterrupt(interrupt, quitting, listener)
// Serve with graceful listener.
// Execution blocks here until listener.Close() is called, above.
err := srv.Server.Serve(listener)
if err != nil {
// If the underlying listening is closed, Serve returns an error
// complaining about listening on a closed socket. This is expected, so
// let's ignore the error if we are the ones who explicitly closed the
// socket.
select {
case <-quitting:
err = nil
default:
}
}
srv.shutdown(shutdown, kill)
return err
}
// Stop instructs the type to halt operations and close
// the stop channel when it is finished.
//
// timeout is grace period for which to wait before shutting
// down the server. The timeout value passed here will override the
// timeout given when constructing the server, as this is an explicit
// command to stop the server.
func (srv *Server) Stop(timeout time.Duration) {
srv.stopLock.Lock()
defer srv.stopLock.Unlock()
srv.Timeout = timeout
interrupt := srv.interruptChan()
interrupt <- syscall.SIGINT
}
// StopChan gets the stop channel which will block until
// stopping has completed, at which point it is closed.
// Callers should never close the stop channel.
func (srv *Server) StopChan() <-chan struct{} {
srv.chanLock.Lock()
defer srv.chanLock.Unlock()
if srv.stopChan == nil {
srv.stopChan = make(chan struct{})
}
return srv.stopChan
}
// DefaultLogger returns the logger used by Run, RunWithErr, ListenAndServe, ListenAndServeTLS and Serve.
// The logger outputs to STDERR by default.
func DefaultLogger() *log.Logger {
return log.New(os.Stderr, "[graceful] ", 0)
}
func (srv *Server) manageConnections(add, idle, active, remove chan net.Conn, shutdown chan chan struct{}, kill chan struct{}) {
var done chan struct{}
srv.connections = map[net.Conn]struct{}{}
srv.idleConnections = map[net.Conn]struct{}{}
for {
select {
case conn := <-add:
srv.connections[conn] = struct{}{}
case conn := <-idle:
srv.idleConnections[conn] = struct{}{}
case conn := <-active:
delete(srv.idleConnections, conn)
case conn := <-remove:
delete(srv.connections, conn)
delete(srv.idleConnections, conn)
if done != nil && len(srv.connections) == 0 {
done <- struct{}{}
return
}
case done = <-shutdown:
if len(srv.connections) == 0 && len(srv.idleConnections) == 0 {
done <- struct{}{}
return
}
// a shutdown request has been received. if we have open idle
// connections, we must close all of them now. this prevents idle
// connections from holding the server open while waiting for them to
// hit their idle timeout.
for k := range srv.idleConnections {
if err := k.Close(); err != nil {
srv.logf("[ERROR] %s", err)
}
}
case <-kill:
srv.stopLock.Lock()
defer srv.stopLock.Unlock()
srv.Server.ConnState = nil
for k := range srv.connections {
if err := k.Close(); err != nil {
srv.logf("[ERROR] %s", err)
}
}
return
}
}
}
func (srv *Server) interruptChan() chan os.Signal {
srv.chanLock.Lock()
defer srv.chanLock.Unlock()
if srv.interrupt == nil {
srv.interrupt = make(chan os.Signal, 1)
}
return srv.interrupt
}
func (srv *Server) handleInterrupt(interrupt chan os.Signal, quitting chan struct{}, listener net.Listener) {
for _ = range interrupt {
if srv.Interrupted {
srv.logf("already shutting down")
continue
}
srv.logf("shutdown initiated")
srv.Interrupted = true
if srv.BeforeShutdown != nil {
if !srv.BeforeShutdown() {
srv.Interrupted = false
continue
}
}
close(quitting)
srv.SetKeepAlivesEnabled(false)
if err := listener.Close(); err != nil {
srv.logf("[ERROR] %s", err)
}
if srv.ShutdownInitiated != nil {
srv.ShutdownInitiated()
}
}
}
func (srv *Server) logf(format string, args ...interface{}) {
if srv.LogFunc != nil {
srv.LogFunc(format, args...)
} else if srv.Logger != nil {
srv.Logger.Printf(format, args...)
}
}
func (srv *Server) shutdown(shutdown chan chan struct{}, kill chan struct{}) {
// Request done notification
done := make(chan struct{})
shutdown <- done
if srv.Timeout > 0 {
select {
case <-done:
case <-time.After(srv.Timeout):
close(kill)
}
} else {
<-done
}
// Close the stopChan to wake up any blocked goroutines.
srv.chanLock.Lock()
if srv.stopChan != nil {
close(srv.stopChan)
}
srv.chanLock.Unlock()
}
func (srv *Server) newTCPListener(addr string) (net.Listener, error) {
conn, err := net.Listen("tcp", addr)
if err != nil {
return conn, err
}
if srv.TCPKeepAlive != 0 {
conn = keepAliveListener{conn, srv.TCPKeepAlive}
}
return conn, nil
}

View File

@@ -0,0 +1,32 @@
package graceful
import (
"net"
"time"
)
type keepAliveConn interface {
SetKeepAlive(bool) error
SetKeepAlivePeriod(d time.Duration) error
}
// keepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type keepAliveListener struct {
net.Listener
keepAlivePeriod time.Duration
}
func (ln keepAliveListener) Accept() (net.Conn, error) {
c, err := ln.Listener.Accept()
if err != nil {
return nil, err
}
kac := c.(keepAliveConn)
kac.SetKeepAlive(true)
kac.SetKeepAlivePeriod(ln.keepAlivePeriod)
return c, nil
}

77
vendor/github.com/tylerb/graceful/limit_listen.go generated vendored Normal file
View File

@@ -0,0 +1,77 @@
// Copyright 2013 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package graceful
import (
"errors"
"net"
"sync"
"time"
)
// ErrNotTCP indicates that network connection is not a TCP connection.
var ErrNotTCP = errors.New("only tcp connections have keepalive")
// LimitListener returns a Listener that accepts at most n simultaneous
// connections from the provided Listener.
func LimitListener(l net.Listener, n int) net.Listener {
return &limitListener{l, make(chan struct{}, n)}
}
type limitListener struct {
net.Listener
sem chan struct{}
}
func (l *limitListener) acquire() { l.sem <- struct{}{} }
func (l *limitListener) release() { <-l.sem }
func (l *limitListener) Accept() (net.Conn, error) {
l.acquire()
c, err := l.Listener.Accept()
if err != nil {
l.release()
return nil, err
}
return &limitListenerConn{Conn: c, release: l.release}, nil
}
type limitListenerConn struct {
net.Conn
releaseOnce sync.Once
release func()
}
func (l *limitListenerConn) Close() error {
err := l.Conn.Close()
l.releaseOnce.Do(l.release)
return err
}
func (l *limitListenerConn) SetKeepAlive(doKeepAlive bool) error {
tcpc, ok := l.Conn.(*net.TCPConn)
if !ok {
return ErrNotTCP
}
return tcpc.SetKeepAlive(doKeepAlive)
}
func (l *limitListenerConn) SetKeepAlivePeriod(d time.Duration) error {
tcpc, ok := l.Conn.(*net.TCPConn)
if !ok {
return ErrNotTCP
}
return tcpc.SetKeepAlivePeriod(d)
}

40
vendor/github.com/tylerb/graceful/tests/main.go generated vendored Normal file
View File

@@ -0,0 +1,40 @@
package main
import (
"fmt"
"sync"
"github.com/urfave/negroni"
"gopkg.in/tylerb/graceful.v1"
)
func main() {
var wg sync.WaitGroup
wg.Add(3)
go func() {
n := negroni.New()
fmt.Println("Launching server on :3000")
graceful.Run(":3000", 0, n)
fmt.Println("Terminated server on :3000")
wg.Done()
}()
go func() {
n := negroni.New()
fmt.Println("Launching server on :3001")
graceful.Run(":3001", 0, n)
fmt.Println("Terminated server on :3001")
wg.Done()
}()
go func() {
n := negroni.New()
fmt.Println("Launching server on :3002")
graceful.Run(":3002", 0, n)
fmt.Println("Terminated server on :3002")
wg.Done()
}()
fmt.Println("Press ctrl+c. All servers should terminate.")
wg.Wait()
}

21
vendor/github.com/urfave/negroni/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Jeremy Saenz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

25
vendor/github.com/urfave/negroni/doc.go generated vendored Normal file
View File

@@ -0,0 +1,25 @@
// Package negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of net/http Handlers.
//
// If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit.
//
// For a full guide visit http://github.com/urfave/negroni
//
// package main
//
// import (
// "github.com/urfave/negroni"
// "net/http"
// "fmt"
// )
//
// func main() {
// mux := http.NewServeMux()
// mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
// fmt.Fprintf(w, "Welcome to the home page!")
// })
//
// n := negroni.Classic()
// n.UseHandler(mux)
// n.Run(":3000")
// }
package negroni

35
vendor/github.com/urfave/negroni/logger.go generated vendored Normal file
View File

@@ -0,0 +1,35 @@
package negroni
import (
"log"
"net/http"
"os"
"time"
)
// ALogger interface
type ALogger interface {
Println(v ...interface{})
Printf(format string, v ...interface{})
}
// Logger is a middleware handler that logs the request as it goes in and the response as it goes out.
type Logger struct {
// ALogger implements just enough log.Logger interface to be compatible with other implementations
ALogger
}
// NewLogger returns a new Logger instance
func NewLogger() *Logger {
return &Logger{log.New(os.Stdout, "[negroni] ", 0)}
}
func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
start := time.Now()
l.Printf("Started %s %s", r.Method, r.URL.Path)
next(rw, r)
res := rw.(ResponseWriter)
l.Printf("Completed %v %s in %v", res.Status(), http.StatusText(res.Status()), time.Since(start))
}

133
vendor/github.com/urfave/negroni/negroni.go generated vendored Normal file
View File

@@ -0,0 +1,133 @@
package negroni
import (
"log"
"net/http"
"os"
)
// Handler handler is an interface that objects can implement to be registered to serve as middleware
// in the Negroni middleware stack.
// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
// passed in.
//
// If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked.
type Handler interface {
ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}
// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers.
// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.
type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
h(rw, r, next)
}
type middleware struct {
handler Handler
next *middleware
}
func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
}
// Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni
// middleware. The next http.HandlerFunc is automatically called after the Handler
// is executed.
func Wrap(handler http.Handler) Handler {
return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
handler.ServeHTTP(rw, r)
next(rw, r)
})
}
// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler.
// Negroni middleware is evaluated in the order that they are added to the stack using
// the Use and UseHandler methods.
type Negroni struct {
middleware middleware
handlers []Handler
}
// New returns a new Negroni instance with no middleware preconfigured.
func New(handlers ...Handler) *Negroni {
return &Negroni{
handlers: handlers,
middleware: build(handlers),
}
}
// Classic returns a new Negroni instance with the default middleware already
// in the stack.
//
// Recovery - Panic Recovery Middleware
// Logger - Request/Response Logging
// Static - Static File Serving
func Classic() *Negroni {
return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
}
func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
n.middleware.ServeHTTP(NewResponseWriter(rw), r)
}
// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
func (n *Negroni) Use(handler Handler) {
if handler == nil {
panic("handler cannot be nil")
}
n.handlers = append(n.handlers, handler)
n.middleware = build(n.handlers)
}
// UseFunc adds a Negroni-style handler function onto the middleware stack.
func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
n.Use(HandlerFunc(handlerFunc))
}
// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
func (n *Negroni) UseHandler(handler http.Handler) {
n.Use(Wrap(handler))
}
// UseHandler adds a http.HandlerFunc-style handler function onto the middleware stack.
func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) {
n.UseHandler(http.HandlerFunc(handlerFunc))
}
// Run is a convenience function that runs the negroni stack as an HTTP
// server. The addr string takes the same format as http.ListenAndServe.
func (n *Negroni) Run(addr string) {
l := log.New(os.Stdout, "[negroni] ", 0)
l.Printf("listening on %s", addr)
l.Fatal(http.ListenAndServe(addr, n))
}
// Returns a list of all the handlers in the current Negroni middleware chain.
func (n *Negroni) Handlers() []Handler {
return n.handlers
}
func build(handlers []Handler) middleware {
var next middleware
if len(handlers) == 0 {
return voidMiddleware()
} else if len(handlers) > 1 {
next = build(handlers[1:])
} else {
next = voidMiddleware()
}
return middleware{handlers[0], &next}
}
func voidMiddleware() middleware {
return middleware{
HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}),
&middleware{},
}
}

65
vendor/github.com/urfave/negroni/recovery.go generated vendored Normal file
View File

@@ -0,0 +1,65 @@
package negroni
import (
"fmt"
"log"
"net/http"
"os"
"runtime"
"runtime/debug"
)
// Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one.
type Recovery struct {
Logger ALogger
PrintStack bool
ErrorHandlerFunc func(interface{})
StackAll bool
StackSize int
}
// NewRecovery returns a new instance of Recovery
func NewRecovery() *Recovery {
return &Recovery{
Logger: log.New(os.Stdout, "[negroni] ", 0),
PrintStack: true,
StackAll: false,
StackSize: 1024 * 8,
}
}
func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
defer func() {
if err := recover(); err != nil {
if rw.Header().Get("Content-Type") == "" {
rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
}
rw.WriteHeader(http.StatusInternalServerError)
stack := make([]byte, rec.StackSize)
stack = stack[:runtime.Stack(stack, rec.StackAll)]
f := "PANIC: %s\n%s"
rec.Logger.Printf(f, err, stack)
if rec.PrintStack {
fmt.Fprintf(rw, f, err, stack)
}
if rec.ErrorHandlerFunc != nil {
func() {
defer func() {
if err := recover(); err != nil {
rec.Logger.Printf("provided ErrorHandlerFunc panic'd: %s, trace:\n%s", err, debug.Stack())
rec.Logger.Printf("%s\n", debug.Stack())
}
}()
rec.ErrorHandlerFunc(err)
}()
}
}
}()
next(rw, r)
}

99
vendor/github.com/urfave/negroni/response_writer.go generated vendored Normal file
View File

@@ -0,0 +1,99 @@
package negroni
import (
"bufio"
"fmt"
"net"
"net/http"
)
// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about
// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter
// if the functionality calls for it.
type ResponseWriter interface {
http.ResponseWriter
http.Flusher
// Status returns the status code of the response or 200 if the response has
// not been written (as this is the default response code in net/http)
Status() int
// Written returns whether or not the ResponseWriter has been written.
Written() bool
// Size returns the size of the response body.
Size() int
// Before allows for a function to be called before the ResponseWriter has been written to. This is
// useful for setting headers or any other operations that must happen before a response has been written.
Before(func(ResponseWriter))
}
type beforeFunc func(ResponseWriter)
// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
return &responseWriter{
ResponseWriter: rw,
}
}
type responseWriter struct {
http.ResponseWriter
status int
size int
beforeFuncs []beforeFunc
}
func (rw *responseWriter) WriteHeader(s int) {
rw.status = s
rw.callBefore()
rw.ResponseWriter.WriteHeader(s)
}
func (rw *responseWriter) Write(b []byte) (int, error) {
if !rw.Written() {
// The status will be StatusOK if WriteHeader has not been called yet
rw.WriteHeader(http.StatusOK)
}
size, err := rw.ResponseWriter.Write(b)
rw.size += size
return size, err
}
func (rw *responseWriter) Status() int {
return rw.status
}
func (rw *responseWriter) Size() int {
return rw.size
}
func (rw *responseWriter) Written() bool {
return rw.status != 0
}
func (rw *responseWriter) Before(before func(ResponseWriter)) {
rw.beforeFuncs = append(rw.beforeFuncs, before)
}
func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hijacker, ok := rw.ResponseWriter.(http.Hijacker)
if !ok {
return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
}
return hijacker.Hijack()
}
func (rw *responseWriter) CloseNotify() <-chan bool {
return rw.ResponseWriter.(http.CloseNotifier).CloseNotify()
}
func (rw *responseWriter) callBefore() {
for i := len(rw.beforeFuncs) - 1; i >= 0; i-- {
rw.beforeFuncs[i](rw)
}
}
func (rw *responseWriter) Flush() {
flusher, ok := rw.ResponseWriter.(http.Flusher)
if ok {
flusher.Flush()
}
}

88
vendor/github.com/urfave/negroni/static.go generated vendored Normal file
View File

@@ -0,0 +1,88 @@
package negroni
import (
"net/http"
"path"
"strings"
)
// Static is a middleware handler that serves static files in the given
// directory/filesystem. If the file does not exist on the filesystem, it
// passes along to the next middleware in the chain. If you desire "fileserver"
// type behavior where it returns a 404 for unfound files, you should consider
// using http.FileServer from the Go stdlib.
type Static struct {
// Dir is the directory to serve static files from
Dir http.FileSystem
// Prefix is the optional prefix used to serve the static directory content
Prefix string
// IndexFile defines which file to serve as index if it exists.
IndexFile string
}
// NewStatic returns a new instance of Static
func NewStatic(directory http.FileSystem) *Static {
return &Static{
Dir: directory,
Prefix: "",
IndexFile: "index.html",
}
}
func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if r.Method != "GET" && r.Method != "HEAD" {
next(rw, r)
return
}
file := r.URL.Path
// if we have a prefix, filter requests by stripping the prefix
if s.Prefix != "" {
if !strings.HasPrefix(file, s.Prefix) {
next(rw, r)
return
}
file = file[len(s.Prefix):]
if file != "" && file[0] != '/' {
next(rw, r)
return
}
}
f, err := s.Dir.Open(file)
if err != nil {
// discard the error?
next(rw, r)
return
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
next(rw, r)
return
}
// try to serve index file
if fi.IsDir() {
// redirect if missing trailing slash
if !strings.HasSuffix(r.URL.Path, "/") {
http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound)
return
}
file = path.Join(file, s.IndexFile)
f, err = s.Dir.Open(file)
if err != nil {
next(rw, r)
return
}
defer f.Close()
fi, err = f.Stat()
if err != nil || fi.IsDir() {
next(rw, r)
return
}
}
http.ServeContent(rw, r, file, fi.ModTime(), f)
}

21
vendor/gopkg.in/tylerb/graceful.v1/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Tyler Bunnell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

487
vendor/gopkg.in/tylerb/graceful.v1/graceful.go generated vendored Normal file
View File

@@ -0,0 +1,487 @@
package graceful
import (
"crypto/tls"
"log"
"net"
"net/http"
"os"
"os/signal"
"sync"
"syscall"
"time"
)
// Server wraps an http.Server with graceful connection handling.
// It may be used directly in the same way as http.Server, or may
// be constructed with the global functions in this package.
//
// Example:
// srv := &graceful.Server{
// Timeout: 5 * time.Second,
// Server: &http.Server{Addr: ":1234", Handler: handler},
// }
// srv.ListenAndServe()
type Server struct {
*http.Server
// Timeout is the duration to allow outstanding requests to survive
// before forcefully terminating them.
Timeout time.Duration
// Limit the number of outstanding requests
ListenLimit int
// TCPKeepAlive sets the TCP keep-alive timeouts on accepted
// connections. It prunes dead TCP connections ( e.g. closing
// laptop mid-download)
TCPKeepAlive time.Duration
// ConnState specifies an optional callback function that is
// called when a client connection changes state. This is a proxy
// to the underlying http.Server's ConnState, and the original
// must not be set directly.
ConnState func(net.Conn, http.ConnState)
// BeforeShutdown is an optional callback function that is called
// before the listener is closed. Returns true if shutdown is allowed
BeforeShutdown func() bool
// ShutdownInitiated is an optional callback function that is called
// when shutdown is initiated. It can be used to notify the client
// side of long lived connections (e.g. websockets) to reconnect.
ShutdownInitiated func()
// NoSignalHandling prevents graceful from automatically shutting down
// on SIGINT and SIGTERM. If set to true, you must shut down the server
// manually with Stop().
NoSignalHandling bool
// Logger used to notify of errors on startup and on stop.
Logger *log.Logger
// LogFunc can be assigned with a logging function of your choice, allowing
// you to use whatever logging approach you would like
LogFunc func(format string, args ...interface{})
// Interrupted is true if the server is handling a SIGINT or SIGTERM
// signal and is thus shutting down.
Interrupted bool
// interrupt signals the listener to stop serving connections,
// and the server to shut down.
interrupt chan os.Signal
// stopLock is used to protect against concurrent calls to Stop
stopLock sync.Mutex
// stopChan is the channel on which callers may block while waiting for
// the server to stop.
stopChan chan struct{}
// chanLock is used to protect access to the various channel constructors.
chanLock sync.RWMutex
// connections holds all connections managed by graceful
connections map[net.Conn]struct{}
// idleConnections holds all idle connections managed by graceful
idleConnections map[net.Conn]struct{}
}
// Run serves the http.Handler with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func Run(addr string, timeout time.Duration, n http.Handler) {
srv := &Server{
Timeout: timeout,
TCPKeepAlive: 3 * time.Minute,
Server: &http.Server{Addr: addr, Handler: n},
// Logger: DefaultLogger(),
}
if err := srv.ListenAndServe(); err != nil {
if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
srv.logf("%s", err)
os.Exit(1)
}
}
}
// RunWithErr is an alternative version of Run function which can return error.
//
// Unlike Run this version will not exit the program if an error is encountered but will
// return it instead.
func RunWithErr(addr string, timeout time.Duration, n http.Handler) error {
srv := &Server{
Timeout: timeout,
TCPKeepAlive: 3 * time.Minute,
Server: &http.Server{Addr: addr, Handler: n},
Logger: DefaultLogger(),
}
return srv.ListenAndServe()
}
// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func ListenAndServe(server *http.Server, timeout time.Duration) error {
srv := &Server{Timeout: timeout, Server: server, Logger: DefaultLogger()}
return srv.ListenAndServe()
}
// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
func (srv *Server) ListenAndServe() error {
// Create the listener so we can control their lifetime
addr := srv.Addr
if addr == "" {
addr = ":http"
}
conn, err := srv.newTCPListener(addr)
if err != nil {
return err
}
return srv.Serve(conn)
}
// ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func ListenAndServeTLS(server *http.Server, certFile, keyFile string, timeout time.Duration) error {
srv := &Server{Timeout: timeout, Server: server, Logger: DefaultLogger()}
return srv.ListenAndServeTLS(certFile, keyFile)
}
// ListenTLS is a convenience method that creates an https listener using the
// provided cert and key files. Use this method if you need access to the
// listener object directly. When ready, pass it to the Serve method.
func (srv *Server) ListenTLS(certFile, keyFile string) (net.Listener, error) {
// Create the listener ourselves so we can control its lifetime
addr := srv.Addr
if addr == "" {
addr = ":https"
}
config := &tls.Config{}
if srv.TLSConfig != nil {
*config = *srv.TLSConfig
}
var err error
config.Certificates = make([]tls.Certificate, 1)
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, err
}
// Enable http2
enableHTTP2ForTLSConfig(config)
conn, err := srv.newTCPListener(addr)
if err != nil {
return nil, err
}
srv.TLSConfig = config
tlsListener := tls.NewListener(conn, config)
return tlsListener, nil
}
// Enable HTTP2ForTLSConfig explicitly enables http/2 for a TLS Config. This is due to changes in Go 1.7 where
// http servers are no longer automatically configured to enable http/2 if the server's TLSConfig is set.
// See https://github.com/golang/go/issues/15908
func enableHTTP2ForTLSConfig(t *tls.Config) {
if TLSConfigHasHTTP2Enabled(t) {
return
}
t.NextProtos = append(t.NextProtos, "h2")
}
// TLSConfigHasHTTP2Enabled checks to see if a given TLS Config has http2 enabled.
func TLSConfigHasHTTP2Enabled(t *tls.Config) bool {
for _, value := range t.NextProtos {
if value == "h2" {
return true
}
}
return false
}
// ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
l, err := srv.ListenTLS(certFile, keyFile)
if err != nil {
return err
}
return srv.Serve(l)
}
// ListenAndServeTLSConfig can be used with an existing TLS config and is equivalent to
// http.Server.ListenAndServeTLS with graceful shutdown enabled,
func (srv *Server) ListenAndServeTLSConfig(config *tls.Config) error {
addr := srv.Addr
if addr == "" {
addr = ":https"
}
conn, err := srv.newTCPListener(addr)
if err != nil {
return err
}
srv.TLSConfig = config
tlsListener := tls.NewListener(conn, config)
return srv.Serve(tlsListener)
}
// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
//
// timeout is the duration to wait until killing active requests and stopping the server.
// If timeout is 0, the server never times out. It waits for all active requests to finish.
func Serve(server *http.Server, l net.Listener, timeout time.Duration) error {
srv := &Server{Timeout: timeout, Server: server, Logger: DefaultLogger()}
return srv.Serve(l)
}
// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
func (srv *Server) Serve(listener net.Listener) error {
if srv.ListenLimit != 0 {
listener = LimitListener(listener, srv.ListenLimit)
}
// Make our stopchan
srv.StopChan()
// Track connection state
add := make(chan net.Conn)
idle := make(chan net.Conn)
active := make(chan net.Conn)
remove := make(chan net.Conn)
srv.Server.ConnState = func(conn net.Conn, state http.ConnState) {
switch state {
case http.StateNew:
add <- conn
case http.StateActive:
active <- conn
case http.StateIdle:
idle <- conn
case http.StateClosed, http.StateHijacked:
remove <- conn
}
srv.stopLock.Lock()
defer srv.stopLock.Unlock()
if srv.ConnState != nil {
srv.ConnState(conn, state)
}
}
// Manage open connections
shutdown := make(chan chan struct{})
kill := make(chan struct{})
go srv.manageConnections(add, idle, active, remove, shutdown, kill)
interrupt := srv.interruptChan()
// Set up the interrupt handler
if !srv.NoSignalHandling {
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
}
quitting := make(chan struct{})
go srv.handleInterrupt(interrupt, quitting, listener)
// Serve with graceful listener.
// Execution blocks here until listener.Close() is called, above.
err := srv.Server.Serve(listener)
if err != nil {
// If the underlying listening is closed, Serve returns an error
// complaining about listening on a closed socket. This is expected, so
// let's ignore the error if we are the ones who explicitly closed the
// socket.
select {
case <-quitting:
err = nil
default:
}
}
srv.shutdown(shutdown, kill)
return err
}
// Stop instructs the type to halt operations and close
// the stop channel when it is finished.
//
// timeout is grace period for which to wait before shutting
// down the server. The timeout value passed here will override the
// timeout given when constructing the server, as this is an explicit
// command to stop the server.
func (srv *Server) Stop(timeout time.Duration) {
srv.stopLock.Lock()
defer srv.stopLock.Unlock()
srv.Timeout = timeout
interrupt := srv.interruptChan()
interrupt <- syscall.SIGINT
}
// StopChan gets the stop channel which will block until
// stopping has completed, at which point it is closed.
// Callers should never close the stop channel.
func (srv *Server) StopChan() <-chan struct{} {
srv.chanLock.Lock()
defer srv.chanLock.Unlock()
if srv.stopChan == nil {
srv.stopChan = make(chan struct{})
}
return srv.stopChan
}
// DefaultLogger returns the logger used by Run, RunWithErr, ListenAndServe, ListenAndServeTLS and Serve.
// The logger outputs to STDERR by default.
func DefaultLogger() *log.Logger {
return log.New(os.Stderr, "[graceful] ", 0)
}
func (srv *Server) manageConnections(add, idle, active, remove chan net.Conn, shutdown chan chan struct{}, kill chan struct{}) {
var done chan struct{}
srv.connections = map[net.Conn]struct{}{}
srv.idleConnections = map[net.Conn]struct{}{}
for {
select {
case conn := <-add:
srv.connections[conn] = struct{}{}
case conn := <-idle:
srv.idleConnections[conn] = struct{}{}
case conn := <-active:
delete(srv.idleConnections, conn)
case conn := <-remove:
delete(srv.connections, conn)
delete(srv.idleConnections, conn)
if done != nil && len(srv.connections) == 0 {
done <- struct{}{}
return
}
case done = <-shutdown:
if len(srv.connections) == 0 && len(srv.idleConnections) == 0 {
done <- struct{}{}
return
}
// a shutdown request has been received. if we have open idle
// connections, we must close all of them now. this prevents idle
// connections from holding the server open while waiting for them to
// hit their idle timeout.
for k := range srv.idleConnections {
if err := k.Close(); err != nil {
srv.logf("[ERROR] %s", err)
}
}
case <-kill:
srv.stopLock.Lock()
defer srv.stopLock.Unlock()
srv.Server.ConnState = nil
for k := range srv.connections {
if err := k.Close(); err != nil {
srv.logf("[ERROR] %s", err)
}
}
return
}
}
}
func (srv *Server) interruptChan() chan os.Signal {
srv.chanLock.Lock()
defer srv.chanLock.Unlock()
if srv.interrupt == nil {
srv.interrupt = make(chan os.Signal, 1)
}
return srv.interrupt
}
func (srv *Server) handleInterrupt(interrupt chan os.Signal, quitting chan struct{}, listener net.Listener) {
for _ = range interrupt {
if srv.Interrupted {
srv.logf("already shutting down")
continue
}
srv.logf("shutdown initiated")
srv.Interrupted = true
if srv.BeforeShutdown != nil {
if !srv.BeforeShutdown() {
srv.Interrupted = false
continue
}
}
close(quitting)
srv.SetKeepAlivesEnabled(false)
if err := listener.Close(); err != nil {
srv.logf("[ERROR] %s", err)
}
if srv.ShutdownInitiated != nil {
srv.ShutdownInitiated()
}
}
}
func (srv *Server) logf(format string, args ...interface{}) {
if srv.LogFunc != nil {
srv.LogFunc(format, args...)
} else if srv.Logger != nil {
srv.Logger.Printf(format, args...)
}
}
func (srv *Server) shutdown(shutdown chan chan struct{}, kill chan struct{}) {
// Request done notification
done := make(chan struct{})
shutdown <- done
if srv.Timeout > 0 {
select {
case <-done:
case <-time.After(srv.Timeout):
close(kill)
}
} else {
<-done
}
// Close the stopChan to wake up any blocked goroutines.
srv.chanLock.Lock()
if srv.stopChan != nil {
close(srv.stopChan)
}
srv.chanLock.Unlock()
}
func (srv *Server) newTCPListener(addr string) (net.Listener, error) {
conn, err := net.Listen("tcp", addr)
if err != nil {
return conn, err
}
if srv.TCPKeepAlive != 0 {
conn = keepAliveListener{conn, srv.TCPKeepAlive}
}
return conn, nil
}

View File

@@ -0,0 +1,32 @@
package graceful
import (
"net"
"time"
)
type keepAliveConn interface {
SetKeepAlive(bool) error
SetKeepAlivePeriod(d time.Duration) error
}
// keepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type keepAliveListener struct {
net.Listener
keepAlivePeriod time.Duration
}
func (ln keepAliveListener) Accept() (net.Conn, error) {
c, err := ln.Listener.Accept()
if err != nil {
return nil, err
}
kac := c.(keepAliveConn)
kac.SetKeepAlive(true)
kac.SetKeepAlivePeriod(ln.keepAlivePeriod)
return c, nil
}

77
vendor/gopkg.in/tylerb/graceful.v1/limit_listen.go generated vendored Normal file
View File

@@ -0,0 +1,77 @@
// Copyright 2013 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package graceful
import (
"errors"
"net"
"sync"
"time"
)
// ErrNotTCP indicates that network connection is not a TCP connection.
var ErrNotTCP = errors.New("only tcp connections have keepalive")
// LimitListener returns a Listener that accepts at most n simultaneous
// connections from the provided Listener.
func LimitListener(l net.Listener, n int) net.Listener {
return &limitListener{l, make(chan struct{}, n)}
}
type limitListener struct {
net.Listener
sem chan struct{}
}
func (l *limitListener) acquire() { l.sem <- struct{}{} }
func (l *limitListener) release() { <-l.sem }
func (l *limitListener) Accept() (net.Conn, error) {
l.acquire()
c, err := l.Listener.Accept()
if err != nil {
l.release()
return nil, err
}
return &limitListenerConn{Conn: c, release: l.release}, nil
}
type limitListenerConn struct {
net.Conn
releaseOnce sync.Once
release func()
}
func (l *limitListenerConn) Close() error {
err := l.Conn.Close()
l.releaseOnce.Do(l.release)
return err
}
func (l *limitListenerConn) SetKeepAlive(doKeepAlive bool) error {
tcpc, ok := l.Conn.(*net.TCPConn)
if !ok {
return ErrNotTCP
}
return tcpc.SetKeepAlive(doKeepAlive)
}
func (l *limitListenerConn) SetKeepAlivePeriod(d time.Duration) error {
tcpc, ok := l.Conn.(*net.TCPConn)
if !ok {
return ErrNotTCP
}
return tcpc.SetKeepAlivePeriod(d)
}

40
vendor/gopkg.in/tylerb/graceful.v1/tests/main.go generated vendored Normal file
View File

@@ -0,0 +1,40 @@
package main
import (
"fmt"
"sync"
"github.com/urfave/negroni"
"gopkg.in/tylerb/graceful.v1"
)
func main() {
var wg sync.WaitGroup
wg.Add(3)
go func() {
n := negroni.New()
fmt.Println("Launching server on :3000")
graceful.Run(":3000", 0, n)
fmt.Println("Terminated server on :3000")
wg.Done()
}()
go func() {
n := negroni.New()
fmt.Println("Launching server on :3001")
graceful.Run(":3001", 0, n)
fmt.Println("Terminated server on :3001")
wg.Done()
}()
go func() {
n := negroni.New()
fmt.Println("Launching server on :3002")
graceful.Run(":3002", 0, n)
fmt.Println("Terminated server on :3002")
wg.Done()
}()
fmt.Println("Press ctrl+c. All servers should terminate.")
wg.Wait()
}

24
vendor/manifest vendored
View File

@@ -1184,6 +1184,14 @@
"branch": "master",
"path": "/assert"
},
{
"importpath": "github.com/tylerb/graceful",
"repository": "https://github.com/tylerb/graceful",
"vcs": "git",
"revision": "50a48b6e73fcc75b45e22c05b79629a67c79e938",
"branch": "master",
"notests": true
},
{
"importpath": "github.com/ugorji/go/codec",
"repository": "https://github.com/ugorji/go",
@@ -1192,6 +1200,14 @@
"branch": "master",
"path": "/codec"
},
{
"importpath": "github.com/urfave/negroni",
"repository": "https://github.com/urfave/negroni",
"vcs": "git",
"revision": "5d815f907a182b6131cc88af3f17f898b93142a5",
"branch": "master",
"notests": true
},
{
"importpath": "github.com/weaveworks/go-checkpoint",
"repository": "https://github.com/weaveworks/go-checkpoint",
@@ -1318,6 +1334,14 @@
"branch": "v1",
"notests": true
},
{
"importpath": "gopkg.in/tylerb/graceful.v1",
"repository": "https://gopkg.in/tylerb/graceful.v1",
"vcs": "git",
"revision": "50a48b6e73fcc75b45e22c05b79629a67c79e938",
"branch": "master",
"notests": true
},
{
"importpath": "gopkg.in/yaml.v1",
"repository": "https://gopkg.in/yaml.v1",