package
0.0.0-20240614095155-da5732d4417d
Repository: https://github.com/kjk/common.git
Documentation: pkg.go.dev
# 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)
}
# Functions
No description provided by the author
IterContent calls a function for every url and its content.
IterContent calls a function for every url and (optionally) its content.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
files is: uri1, path1, uri2, path2, ...
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
# Structs
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
FileWriter implements http.ResponseWriter interface for writing to a io.Writer.
No description provided by the author
Server represents all files known to the server.
No description provided by the author
# Interfaces
Handler represents one or more urls and their content.