Documentation ¶
Overview ¶
Package netutil contains specialty network utilities for on-prem “cloud”-like services.
Index ¶
- func AcceptedConnection(connection *os.File) (net.Listener, error)
- type IdleTracker
- func (t *IdleTracker) ConnState(conn net.Conn, state http.ConnState)
- func (t *IdleTracker) Deadline() (deadline time.Time, ok bool)
- func (t *IdleTracker) Done() <-chan struct{}
- func (t *IdleTracker) Err() error
- func (*IdleTracker) String() string
- func (t *IdleTracker) Value(key interface{}) interface{}
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AcceptedConnection ¶
AcceptedConnection wraps the connection as net.Listener.
This is meant for socekt activated services that get run for every incoming connection the caller (like systemd) has already accepted.
Unless the http.Server is meant to handle more than one request per connection, remember to have http.Server close it after the first, by setting this HTTP Header:
w.Header().Set("Connection", "close")
Passed to a http.Server, the latter will also return os.ErrClosed signalling its natural end (shutdown). Check for this wherever you expect http.ErrServerClosed to avoid that "false" error.
Example ¶
package main import ( "log" "net" "net/http" "os" "github.com/coreos/go-systemd/v22/activation" netutil "github.com/wmark/go.netutil" ) func main() { // Upgrades the connection to a net.Listener, // in case of socket- or connection-activated services. var ln net.Listener if _, acceptedConn := os.LookupEnv("LISTEN_FDS"); acceptedConn { fds := activation.Files(true) // Accept=true makes that connections. if len(fds) < 1 { log.Fatalf("Conn activated, but not been given any FD") } ln, _ = netutil.AcceptedConnection(fds[0]) } else { // Traditional standalone invocation. ln, _ = net.Listen("tcp", "localhost:0") } server := &http.Server{} server.SetKeepAlivesEnabled(false) switch err := server.Serve(ln); err { case nil, http.ErrServerClosed, os.ErrClosed: return default: log.Fatalf("server.Serve: %v", err) } }
Output:
Types ¶
type IdleTracker ¶
type IdleTracker struct {
// contains filtered or unexported fields
}
IdleTracker is done after no new connections happened for some time. This can be used to stop idle services.
It can be used in place of a context.WithDeadline to bind any lifetime/runtime of residual work to that of the server's.
Example ¶
package main import ( "context" "net" "net/http" "time" netutil "github.com/wmark/go.netutil" ) func main() { // Stops the server after 15 minutes without any connection. ctx, cancelFn := context.WithCancel(context.Background()) lingerCtx := netutil.NewIdleTracker(ctx, 15*time.Minute) server := &http.Server{ IdleTimeout: 2 * time.Minute, ConnState: lingerCtx.ConnState, } ln, _ := net.Listen("tcp", "localhost:0") go func() { <-lingerCtx.Done() server.Shutdown(ctx) }() _ = server.Serve(ln) cancelFn() }
Output:
func NewIdleTracker ¶
func NewIdleTracker(parent context.Context, patience time.Duration) *IdleTracker
NewIdleTracker returns an instance with a running deadline timer. That is, even absent any original connection, the service will have a lifetime.
Don't reuse this as its assumption is that a server that has been torn down won't be revived.
func (*IdleTracker) ConnState ¶
func (t *IdleTracker) ConnState(conn net.Conn, state http.ConnState)
ConnState implements the net/http.Server.ConnState interface.
func (*IdleTracker) Deadline ¶
func (t *IdleTracker) Deadline() (deadline time.Time, ok bool)
Deadline implements the context.Context interface but breaks the promise of always returning the same deadline.
func (*IdleTracker) Done ¶
func (t *IdleTracker) Done() <-chan struct{}
Done implements the context.Context interface.
func (*IdleTracker) Err ¶
func (t *IdleTracker) Err() error
Err implements the context.Context interface.
func (*IdleTracker) String ¶
func (*IdleTracker) String() string
String implements the fmt.Stringer interface.
func (*IdleTracker) Value ¶
func (t *IdleTracker) Value(key interface{}) interface{}
Value implements the context.Context interface.