server

package
v0.0.0-...-e463486 Latest Latest
Warning

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

Go to latest
Published: Apr 14, 2024 License: MIT Imports: 14 Imported by: 1

README

Package github.com/kjk/common/server is an abstraction over http server in Go std lib.

You won't like it, it's too different.

Those are useful snippets that use the server code for re-use. Copy & paste & modify for your purpose.

import (
	"github.com/kjk/common/server"
)
func MakeHTTPServer(srv *server.Server) *http.Server {
	panicIf(srv == nil, "must provide files")
	httpPort := 8080
	if srv.Port != 0 {
		httpPort = srv.Port
	}
	httpAddr := fmt.Sprintf(":%d", httpPort)
	if isWindows() {
		httpAddr = "localhost" + httpAddr
	}
	httpSrv := &http.Server{
		ReadTimeout:  120 * time.Second,
		WriteTimeout: 120 * time.Second,
		IdleTimeout:  120 * time.Second, // introduced in Go 1.8
		Handler:      srv,
	}
	httpSrv.Addr = httpAddr
	return httpSrv
}

// returns function that will wait for SIGTERM signal (e.g. Ctrl-C) and
// shutdown the server
func StartHTTPServer(httpSrv *http.Server) func() {
	logf(ctx(), "Starting server on http://%s'\n", httpSrv.Addr)
	if isWindows() {
		openBrowser(fmt.Sprintf("http://%s", httpSrv.Addr))
	}

	chServerClosed := make(chan bool, 1)
	go func() {
		err := httpSrv.ListenAndServe()
		// mute error caused by Shutdown()
		if err == http.ErrServerClosed {
			err = nil
		}
		must(err)
		logf(ctx(), "trying to shutdown HTTP server\n")
		chServerClosed <- true
	}()

	return func() {
		c := make(chan os.Signal, 2)
		signal.Notify(c, os.Interrupt /* SIGINT */, syscall.SIGTERM)

		sig := <-c
		logf(ctx(), "Got signal %s\n", sig)

		if httpSrv != nil {
			go func() {
				// Shutdown() needs a non-nil context
				_ = httpSrv.Shutdown(ctx())
			}()
			select {
			case <-chServerClosed:
				// do nothing
				logf(ctx(), "server shutdown cleanly\n")
			case <-time.After(time.Second * 5):
				// timeout
				logf(ctx(), "server killed due to shutdown timeout\n")
			}
		}
	}
}

func StartServer(srv *server.Server) func() {
	httpServer := MakeHTTPServer(srv)
	return StartHTTPServer(httpServer)
}

Utility functions used above:

```go
func must(err error) {
	if err != nil {
		panic(err.Error())
	}
}

func ctx() context.Context {
	return context.Background()
}

func panicIf(cond bool, arg ...interface{}) {
	if !cond {
		return
	}
	s := "condition failed"
	if len(arg) > 0 {
		s = fmt.Sprintf("%s", arg[0])
		if len(arg) > 1 {
			s = fmt.Sprintf(s, arg[1:]...)
		}
	}
	panic(s)
}

func isWindows() bool {
	return strings.Contains(runtime.GOOS, "windows")
}

func openBrowser(url string) {
	var err error

	switch runtime.GOOS {
	case "linux":
		err = exec.Command("xdg-open", url).Start()
	case "windows":
		err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
	case "darwin":
		err = exec.Command("open", url).Start()
	default:
		err = fmt.Errorf("unsupported platform")
	}
	if err != nil {
		log.Fatal(err)
	}
}

func isWindows() bool {
	return strings.Contains(runtime.GOOS, "windows")
}

func formatSize(n int64) string {
	sizes := []int64{1024 * 1024 * 1024, 1024 * 1024, 1024}
	suffixes := []string{"GB", "MB", "kB"}

	for i, size := range sizes {
		if n >= size {
			s := fmt.Sprintf("%.2f", float64(n)/float64(size))
			return strings.TrimSuffix(s, ".00") + " " + suffixes[i]
		}
	}
	return fmt.Sprintf("%d bytes", n)
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Gen404Candidates

func Gen404Candidates(uri string) []string

func IterContent

func IterContent(handlers []Handler, fn func(uri string, d []byte))

IterContent calls a function for every url and its content

func IterURLS

func IterURLS(handlers []Handler, withContent bool, fn func(uri string, d []byte))

IterContent calls a function for every url and (optionally) its content

func MakeServeContent

func MakeServeContent(uri string, d []byte, code int, modTime time.Time) func(w http.ResponseWriter, r *http.Request)

func WriteServerFilesToDir

func WriteServerFilesToDir(dir string, handlers []Handler, onWritten func(path string, d []byte)) error

func WriteServerFilesToZip

func WriteServerFilesToZip(handlers []Handler, onWritten func(path string, d []byte)) ([]byte, error)

Types

type DirHandler

type DirHandler struct {
	Dir                string
	URLPrefix          string
	TryServeCompressed bool

	URL []string
	// contains filtered or unexported fields
}

func NewDirHandler

func NewDirHandler(dir string, urlPrefix string, acceptFile func(string) bool) *DirHandler

func (*DirHandler) Get

func (h *DirHandler) Get(url string) func(w http.ResponseWriter, r *http.Request)

func (*DirHandler) URLS

func (h *DirHandler) URLS() []string

type DynamicHandler

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

func NewDynamicHandler

func NewDynamicHandler(get GetHandlerFunc, urls func() []string) *DynamicHandler

func (*DynamicHandler) Get

func (h *DynamicHandler) Get(uri string) func(http.ResponseWriter, *http.Request)

func (*DynamicHandler) URLS

func (h *DynamicHandler) URLS() []string

type EmbedFSHandler

type EmbedFSHandler struct {
	URLPrefix string
	// contains filtered or unexported fields
}

func NewEmbedFSHandler

func NewEmbedFSHandler(fsys embed.FS, dirPrefix, urlPrefix string) *EmbedFSHandler

func (*EmbedFSHandler) Get

func (h *EmbedFSHandler) Get(uri string) func(w http.ResponseWriter, r *http.Request)

func (*EmbedFSHandler) URLS

func (h *EmbedFSHandler) URLS() []string

type FileWriter

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

FileWriter implements http.ResponseWriter interface for writing to a io.Writer

func (*FileWriter) Header

func (w *FileWriter) Header() http.Header

func (*FileWriter) Write

func (w *FileWriter) Write(p []byte) (int, error)

func (*FileWriter) WriteHeader

func (w *FileWriter) WriteHeader(statusCode int)

type FilesHandler

type FilesHandler struct {
	TryServeCompressed bool
	// contains filtered or unexported fields
}

func NewFilesHandler

func NewFilesHandler(files ...string) *FilesHandler

files is: uri1, path1, uri2, path2, ...

func (*FilesHandler) AddFile

func (h *FilesHandler) AddFile(uri, path string)

func (*FilesHandler) AddFilesInDir

func (h *FilesHandler) AddFilesInDir(dir string, uriPrefix string, files []string)

func (*FilesHandler) Get

func (h *FilesHandler) Get(url string) func(w http.ResponseWriter, r *http.Request)

func (*FilesHandler) URLS

func (h *FilesHandler) URLS() []string

type GetHandlerFunc

type GetHandlerFunc = func(string) func(w http.ResponseWriter, r *http.Request)

type Handler

type Handler interface {
	// returns a handler for this url
	// if nil, doesn't handle this url
	Get(url string) HandlerFunc
	// get all urls handled by this Handler
	// useful for e.g. saving a static copy to disk
	URLS() []string
}

Handler represents one or more urls and their content

type HandlerFunc

type HandlerFunc = func(w http.ResponseWriter, r *http.Request)

type InMemoryFilesHandler

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

func NewInMemoryFilesHandler

func NewInMemoryFilesHandler(uri string, d []byte) *InMemoryFilesHandler

func (*InMemoryFilesHandler) Add

func (h *InMemoryFilesHandler) Add(uri string, body []byte)

func (*InMemoryFilesHandler) Get

func (*InMemoryFilesHandler) URLS

func (h *InMemoryFilesHandler) URLS() []string

type Server

type Server struct {
	Port     int
	Handlers []Handler
	// if true supports clean urls i.e. /foo will match /foo.html URL
	CleanURLS bool
	// if true forces clean urls i.e. /foo.html will redirect to /foo
	ForceCleanURLS bool
}

Server represents all files known to the server

func (*Server) FindHandler

func (s *Server) FindHandler(uri string) (h HandlerFunc, is404 bool)

func (*Server) FindHandlerExact

func (s *Server) FindHandlerExact(uri string) HandlerFunc

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

don't really use it

type ZipHandler

type ZipHandler struct {
	URLPrefix string

	URL []string
	// contains filtered or unexported fields
}

func NewZipHandler

func NewZipHandler(zipData []byte, urlPrefix string) (*ZipHandler, error)

func (*ZipHandler) Get

func (h *ZipHandler) Get(uri string) func(w http.ResponseWriter, r *http.Request)

func (*ZipHandler) URLS

func (h *ZipHandler) URLS() []string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL