| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 | 
							- package bootstrap
 
- import (
 
- 	"context"
 
- 	"crypto/md5"
 
- 	"encoding/hex"
 
- 	"fmt"
 
- 	"net/http"
 
- 	"os"
 
- 	"time"
 
- 	"github.com/vladimirok5959/golang-ctrlc/ctrlc"
 
- )
 
- type Handler func(h http.Handler) http.Handler
 
- type CBServer func(s *http.Server)
 
- type Iface interface{}
 
- type BeforeAfter func(
 
- 	ctx context.Context,
 
- 	w http.ResponseWriter,
 
- 	r *http.Request,
 
- 	o *[]Iface,
 
- )
 
- type ShutdownFunc func(ctx context.Context, o *[]Iface) error
 
- type Opts struct {
 
- 	Handle   Handler
 
- 	Host     string
 
- 	Path     string
 
- 	Cbserv   CBServer
 
- 	Before   BeforeAfter
 
- 	After    BeforeAfter
 
- 	Objects  *[]Iface
 
- 	Timeout  time.Duration
 
- 	Shutdown ShutdownFunc
 
- }
 
- type bootstrap struct {
 
- 	ctx  context.Context
 
- 	opts *Opts
 
- }
 
- func new(ctx context.Context, opts *Opts) *bootstrap {
 
- 	return &bootstrap{ctx: ctx, opts: opts}
 
- }
 
- func etag(str string) string {
 
- 	hasher := md5.New()
 
- 	hasher.Write([]byte(str))
 
- 	return hex.EncodeToString(hasher.Sum(nil))
 
- }
 
- func modified(p string, s int, v int64, w http.ResponseWriter, r *http.Request) bool {
 
- 	w.Header().Set("Content-Length", fmt.Sprintf("%d", s))
 
- 	w.Header().Set("Cache-Control", "no-cache")
 
- 	// Set: ETag
 
- 	ehash := etag(fmt.Sprintf("%s-%d-%d", p, s, v))
 
- 	w.Header().Set("ETag", fmt.Sprintf("%s", ehash))
 
- 	// Set: Last-Modified
 
- 	w.Header().Set(
 
- 		"Last-Modified",
 
- 		time.Unix(v, 0).In(time.FixedZone("GMT", 0)).Format("Wed, 01 Oct 2006 15:04:05 GMT"),
 
- 	)
 
- 	// Check: ETag
 
- 	if cc := r.Header.Get("Cache-Control"); cc != "no-cache" {
 
- 		if inm := r.Header.Get("If-None-Match"); inm == ehash {
 
- 			w.WriteHeader(http.StatusNotModified)
 
- 			return false
 
- 		}
 
- 	}
 
- 	// Check: Last-Modified
 
- 	if cc := r.Header.Get("Cache-Control"); cc != "no-cache" {
 
- 		if ims := r.Header.Get("If-Modified-Since"); ims != "" {
 
- 			if t, err := time.Parse("Wed, 01 Oct 2006 15:04:05 GMT", ims); err == nil {
 
- 				if time.Unix(v, 0).In(time.FixedZone("GMT", 0)).Unix() <= t.In(time.FixedZone("GMT", 0)).Unix() {
 
- 					w.WriteHeader(http.StatusNotModified)
 
- 					return false
 
- 				}
 
- 			}
 
- 		}
 
- 	}
 
- 	return true
 
- }
 
- func (this *bootstrap) handler(w http.ResponseWriter, r *http.Request) {
 
- 	if this.opts.Before != nil {
 
- 		this.opts.Before(this.ctx, w, r, this.opts.Objects)
 
- 	}
 
- 	if r.URL.Path == "/"+this.opts.Path+"/bootstrap.css" {
 
- 		w.Header().Set("Content-Type", "text/css")
 
- 		if !modified(r.URL.Path, len(rbc), rbcm, w, r) {
 
- 			return
 
- 		}
 
- 		w.Write(rbc)
 
- 		return
 
- 	} else if r.URL.Path == "/"+this.opts.Path+"/bootstrap.js" {
 
- 		w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
 
- 		if !modified(r.URL.Path, len(rbj), rbjm, w, r) {
 
- 			return
 
- 		}
 
- 		w.Write(rbj)
 
- 		return
 
- 	} else if r.URL.Path == "/"+this.opts.Path+"/jquery.js" {
 
- 		w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
 
- 		if !modified(r.URL.Path, len(rjj), rjjm, w, r) {
 
- 			return
 
- 		}
 
- 		w.Write(rjj)
 
- 		return
 
- 	} else if r.URL.Path == "/"+this.opts.Path+"/popper.js" {
 
- 		w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
 
- 		if !modified(r.URL.Path, len(rpj), rpjm, w, r) {
 
- 			return
 
- 		}
 
- 		w.Write(rpj)
 
- 		return
 
- 	}
 
- 	if this.opts.After != nil {
 
- 		this.opts.After(this.ctx, w, r, this.opts.Objects)
 
- 	}
 
- }
 
- func (this *bootstrap) Shutdown(ctx context.Context) error {
 
- 	if this.opts.Shutdown != nil {
 
- 		return this.opts.Shutdown(ctx, this.opts.Objects)
 
- 	}
 
- 	return nil
 
- }
 
- func Start(opts *Opts) {
 
- 	if opts == nil {
 
- 		fmt.Println("Start: options is not defined")
 
- 		os.Exit(1)
 
- 	}
 
- 	ctrlc.App(
 
- 		opts.Timeout,
 
- 		func(ctx context.Context, shutdown context.CancelFunc) *[]ctrlc.Iface {
 
- 			bt := new(ctx, opts)
 
- 			mux := http.NewServeMux()
 
- 			mux.HandleFunc("/", bt.handler)
 
- 			var srv *http.Server
 
- 			if opts.Handle == nil {
 
- 				srv = &http.Server{
 
- 					Addr:    opts.Host,
 
- 					Handler: mux,
 
- 				}
 
- 			} else {
 
- 				srv = &http.Server{
 
- 					Addr:    opts.Host,
 
- 					Handler: opts.Handle(mux),
 
- 				}
 
- 			}
 
- 			if opts.Cbserv != nil {
 
- 				opts.Cbserv(srv)
 
- 			}
 
- 			go func() {
 
- 				fmt.Printf("Starting server at http://%s/\n", opts.Host)
 
- 				if err := srv.ListenAndServe(); err != nil {
 
- 					if err != http.ErrServerClosed {
 
- 						fmt.Printf("Web server startup error: %s\n", err.Error())
 
- 						shutdown()
 
- 						return
 
- 					}
 
- 				}
 
- 			}()
 
- 			return &[]ctrlc.Iface{bt, srv}
 
- 		},
 
- 	)
 
- }
 
 
  |