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}
- },
- )
- }
|