mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
162 lines
4.9 KiB
Go
162 lines
4.9 KiB
Go
package host
|
|
|
|
// the 24hour name was "Supervisor" but it's not cover its usage
|
|
// 100%, best name is Task or Thead, I'll chouse Task.
|
|
// and re-name the host to "Supervisor" because that is the really
|
|
// supervisor.
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/kataras/iris/v12/core/netutil"
|
|
)
|
|
|
|
// WriteStartupLogOnServe is a task which accepts a logger(io.Writer)
|
|
// and logs the listening address
|
|
// by a generated message based on the host supervisor's server and writes it to the "w".
|
|
// This function should be registered on Serve.
|
|
func WriteStartupLogOnServe(w io.Writer) func(TaskHost) {
|
|
return func(h TaskHost) {
|
|
guessScheme := netutil.ResolveScheme(h.Supervisor.autoTLS || h.Supervisor.manuallyTLS || h.Supervisor.Fallback != nil)
|
|
addr := h.Supervisor.FriendlyAddr
|
|
if addr == "" {
|
|
addr = h.Supervisor.Server.Addr
|
|
}
|
|
|
|
var listeningURIs = make([]string, 0, 1)
|
|
|
|
if host, port, err := net.SplitHostPort(addr); err == nil { // Improve for the issue #2175.
|
|
if host == "" || host == "0.0.0.0" {
|
|
if ifaces, err := net.Interfaces(); err == nil {
|
|
var ips []string
|
|
for _, i := range ifaces {
|
|
addrs, err := i.Addrs()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, localAddr := range addrs {
|
|
var ip net.IP
|
|
switch v := localAddr.(type) {
|
|
case *net.IPNet:
|
|
ip = v.IP
|
|
case *net.IPAddr:
|
|
ip = v.IP
|
|
}
|
|
if ip != nil && ip.To4() != nil {
|
|
if !ip.IsPrivate() {
|
|
// let's don't print ips that are not accessible through browser.
|
|
continue
|
|
}
|
|
ips = append(ips, ip.String())
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, ip := range ips {
|
|
listeningURI := netutil.ResolveURL(guessScheme, fmt.Sprintf("%s:%s", ip, port))
|
|
|
|
listeningURI = "> Network: " + listeningURI
|
|
listeningURIs = append(listeningURIs, listeningURI)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if len(listeningURIs) == 0 {
|
|
// ^ check no need, we want to print the virtual addr too.
|
|
listeningURI := netutil.ResolveURL(guessScheme, addr)
|
|
if len(listeningURIs) > 0 {
|
|
listeningURIs[0] = "\n" + listeningURIs[0]
|
|
listeningURI = "> Local: " + listeningURI
|
|
}
|
|
listeningURIs = append(listeningURIs, listeningURI)
|
|
/*
|
|
Now listening on:
|
|
> Network: http://192.168.1.109:8080
|
|
> Network: http://172.25.224.1:8080
|
|
> Local: http://localhost:8080
|
|
|
|
Otherwise:
|
|
Now listening on: http://192.168.1.109:8080
|
|
*/
|
|
_, _ = fmt.Fprintf(w, "Now listening on: %s\nApplication started. Press CTRL+C to shut down.\n",
|
|
strings.Join(listeningURIs, "\n"))
|
|
}
|
|
}
|
|
|
|
// ShutdownOnInterrupt terminates the supervisor and its underline server when CMD+C/CTRL+C pressed.
|
|
// This function should be registered on Interrupt.
|
|
func ShutdownOnInterrupt(su *Supervisor, shutdownTimeout time.Duration) func() {
|
|
return func() {
|
|
ctx, cancel := context.WithTimeout(context.TODO(), shutdownTimeout)
|
|
defer cancel()
|
|
su.shutdownOnInterrupt(ctx)
|
|
su.RestoreFlow()
|
|
}
|
|
}
|
|
|
|
// TaskHost contains all the necessary information
|
|
// about the host supervisor, its server
|
|
// and the exports the whole flow controller of it.
|
|
type TaskHost struct {
|
|
Supervisor *Supervisor
|
|
}
|
|
|
|
// Serve can (re)run the server with the latest known configuration.
|
|
func (h TaskHost) Serve() error {
|
|
// the underline server's serve, using the "latest known" listener from the supervisor.
|
|
l, err := h.Supervisor.newListener()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// if http.serverclosed ignore the error, it will have this error
|
|
// from the previous close
|
|
if err := h.Supervisor.Server.Serve(l); !errors.Is(err, http.ErrServerClosed) {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// HostURL returns the listening full url (scheme+host)
|
|
// based on the supervisor's server's address.
|
|
func (h TaskHost) HostURL() string {
|
|
return netutil.ResolveURLFromServer(h.Supervisor.Server)
|
|
}
|
|
|
|
// Hostname returns the underline server's hostname.
|
|
func (h TaskHost) Hostname() string {
|
|
return netutil.ResolveHostname(h.Supervisor.Server.Addr)
|
|
}
|
|
|
|
// Shutdown gracefully shuts down the server without interrupting any
|
|
// active connections. Shutdown works by first closing all open
|
|
// listeners, then closing all idle connections, and then waiting
|
|
// indefinitely for connections to return to idle and then shut down.
|
|
// If the provided context expires before the shutdown is complete,
|
|
// then the context's error is returned.
|
|
//
|
|
// Shutdown does not attempt to close nor wait for hijacked
|
|
// connections such as WebSockets. The caller of Shutdown should
|
|
// separately notify such long-lived connections of shutdown and wait
|
|
// for them to close, if desired.
|
|
//
|
|
// This Shutdown calls the underline's Server's Shutdown, in order to be able to re-start the server
|
|
// from a task.
|
|
func (h TaskHost) Shutdown(ctx context.Context) error {
|
|
// the underline server's Shutdown (otherwise we will cancel all tasks and do cycles)
|
|
return h.Supervisor.Server.Shutdown(ctx)
|
|
}
|
|
|
|
func createTaskHost(su *Supervisor) TaskHost {
|
|
return TaskHost{
|
|
Supervisor: su,
|
|
}
|
|
}
|