Browse Source

Upgrade bootstrap

Vova Tkach 5 years ago
parent
commit
665448614b

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module golang-fave
 require (
 require (
 	github.com/disintegration/imaging v1.6.1
 	github.com/disintegration/imaging v1.6.1
 	github.com/go-sql-driver/mysql v1.4.1
 	github.com/go-sql-driver/mysql v1.4.1
-	github.com/vladimirok5959/golang-server-bootstrap v1.0.6
+	github.com/vladimirok5959/golang-server-bootstrap v1.0.8
 	github.com/vladimirok5959/golang-server-resources v1.0.4
 	github.com/vladimirok5959/golang-server-resources v1.0.4
 	github.com/vladimirok5959/golang-server-sessions v1.0.6
 	github.com/vladimirok5959/golang-server-sessions v1.0.6
 	github.com/vladimirok5959/golang-server-static v1.0.2
 	github.com/vladimirok5959/golang-server-static v1.0.2

+ 6 - 0
go.sum

@@ -5,12 +5,18 @@ github.com/disintegration/imaging v1.6.1/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7
 github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
 github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
 github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/vladimirok5959/golang-ctrlc v1.0.1 h1:ahZFNSw01qxKeIyO8PscOsE1Z10aJomprONkxwvZTn4=
+github.com/vladimirok5959/golang-ctrlc v1.0.1/go.mod h1:fIz52p0IMNedUfGBoT82xKAuFGfFMeQhYp+ne0FIKwU=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.4 h1:+Su6EAc5ZXntjEOkYKVZUJ8pRVrh7GIvqrkmeMS48Vo=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.4 h1:+Su6EAc5ZXntjEOkYKVZUJ8pRVrh7GIvqrkmeMS48Vo=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.4/go.mod h1:R5PGBuqlupYd0evIXoi81plWH/HpNQO2V/jHxZzg2y0=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.4/go.mod h1:R5PGBuqlupYd0evIXoi81plWH/HpNQO2V/jHxZzg2y0=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.5 h1:+7MfVJCh/c5LcDV9xCWeXSE3KVDSP5EiQPddkccznV8=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.5 h1:+7MfVJCh/c5LcDV9xCWeXSE3KVDSP5EiQPddkccznV8=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.5/go.mod h1:R5PGBuqlupYd0evIXoi81plWH/HpNQO2V/jHxZzg2y0=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.5/go.mod h1:R5PGBuqlupYd0evIXoi81plWH/HpNQO2V/jHxZzg2y0=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.6 h1:KN8hK5ej9W0037Dq4+kWNaB5PRcOcuNX5Hf2HEuSAeQ=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.6 h1:KN8hK5ej9W0037Dq4+kWNaB5PRcOcuNX5Hf2HEuSAeQ=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.6/go.mod h1:TxfWNSKqZetbZMaActi8hGcMrxLwjMNNQzCjIxzr9ZY=
 github.com/vladimirok5959/golang-server-bootstrap v1.0.6/go.mod h1:TxfWNSKqZetbZMaActi8hGcMrxLwjMNNQzCjIxzr9ZY=
+github.com/vladimirok5959/golang-server-bootstrap v1.0.7 h1:k8Rfcl7AufIQGzrqsEmmnirI6bddArC8iO+wP07y7eA=
+github.com/vladimirok5959/golang-server-bootstrap v1.0.7/go.mod h1:IDc3Spk1slgsj1bMYDpx/W6rtci60YDDA4y0uRNSWds=
+github.com/vladimirok5959/golang-server-bootstrap v1.0.8 h1:jLvoOKPawnwjMITiLMJ0+2ihIhx1ChS9GCbt4Fm3t+M=
+github.com/vladimirok5959/golang-server-bootstrap v1.0.8/go.mod h1:IDc3Spk1slgsj1bMYDpx/W6rtci60YDDA4y0uRNSWds=
 github.com/vladimirok5959/golang-server-resources v1.0.2 h1:XwxFXyaOtfDGRmYp8P9q4P4gx4YK8NiYacpHe9V8Lck=
 github.com/vladimirok5959/golang-server-resources v1.0.2 h1:XwxFXyaOtfDGRmYp8P9q4P4gx4YK8NiYacpHe9V8Lck=
 github.com/vladimirok5959/golang-server-resources v1.0.2/go.mod h1:tsf2oAEf3E3ukiQSCO7dstl0IXbEXec68UUIiMWysBc=
 github.com/vladimirok5959/golang-server-resources v1.0.2/go.mod h1:tsf2oAEf3E3ukiQSCO7dstl0IXbEXec68UUIiMWysBc=
 github.com/vladimirok5959/golang-server-resources v1.0.3 h1:kQLQZe2BGucs95J1A4J5pNYwscR9N65oitZib4uEw34=
 github.com/vladimirok5959/golang-server-resources v1.0.3 h1:kQLQZe2BGucs95J1A4J5pNYwscR9N65oitZib4uEw34=

+ 118 - 104
main.go

@@ -1,11 +1,13 @@
 package main
 package main
 
 
 import (
 import (
+	"context"
 	"errors"
 	"errors"
 	"flag"
 	"flag"
 	"fmt"
 	"fmt"
 	"net/http"
 	"net/http"
 	"os"
 	"os"
+	"time"
 
 
 	"golang-fave/assets"
 	"golang-fave/assets"
 	"golang-fave/cblocks"
 	"golang-fave/cblocks"
@@ -121,120 +123,132 @@ func main() {
 
 
 	// Init and start web server
 	// Init and start web server
 	server_address := fmt.Sprintf("%s:%d", consts.ParamHost, consts.ParamPort)
 	server_address := fmt.Sprintf("%s:%d", consts.ParamHost, consts.ParamPort)
-	bootstrap.Start(lg.Handler, server_address, 9, consts.AssetsPath, func(w http.ResponseWriter, r *http.Request, o interface{}) {
-		w.Header().Set("Server", "fave.pro/"+consts.ServerVersion)
-	}, func(w http.ResponseWriter, r *http.Request, o interface{}) {
-		// Schema
-		r.URL.Scheme = "http"
-
-		// Mounted assets
-		if res.Response(w, r, func(w http.ResponseWriter, r *http.Request, i *resource.OneResource) {
-			w.Header().Set("Cache-Control", "public, max-age=31536000")
-			if consts.ParamDebug && i.Path == "assets/cp/scripts.js" {
-				w.Write([]byte("window.fave_debug=true;"))
-			}
-		}, nil) {
-			return
-		}
 
 
-		// Host and port
-		host, port := utils.ExtractHostPort(r.Host, false)
-		curr_host := host
+	bootstrap.Start(
+		&bootstrap.Opts{
+			Timeout: 8 * time.Second,
+			Handle:  lg.Handler,
+			Host:    server_address,
+			Path:    consts.AssetsPath,
+			Object:  mpool,
+			Cbserv: func(s *http.Server) {
+				s.SetKeepAlivesEnabled(consts.ParamKeepAlive)
+			},
+			Before: func(ctx context.Context, w http.ResponseWriter, r *http.Request, o interface{}) {
+				w.Header().Set("Server", "fave.pro/"+consts.ServerVersion)
+			},
+			After: func(ctx context.Context, w http.ResponseWriter, r *http.Request, o interface{}) {
+				// Schema
+				r.URL.Scheme = "http"
+
+				// Mounted assets
+				if res.Response(w, r, func(w http.ResponseWriter, r *http.Request, i *resource.OneResource) {
+					w.Header().Set("Cache-Control", "public, max-age=31536000")
+					if consts.ParamDebug && i.Path == "assets/cp/scripts.js" {
+						w.Write([]byte("window.fave_debug=true;"))
+					}
+				}, nil) {
+					return
+				}
 
 
-		// Domain bindings
-		doms := domains.New(consts.ParamWwwDir)
-		if mhost := doms.GetHost(host); mhost != "" {
-			curr_host = mhost
-		}
+				// Host and port
+				host, port := utils.ExtractHostPort(r.Host, false)
+				curr_host := host
 
 
-		vhost_dir := consts.ParamWwwDir + string(os.PathSeparator) + curr_host
-		if !utils.IsDirExists(vhost_dir) {
-			curr_host = "localhost"
-			vhost_dir = consts.ParamWwwDir + string(os.PathSeparator) + "localhost"
-		}
+				// Domain bindings
+				doms := domains.New(consts.ParamWwwDir)
+				if mhost := doms.GetHost(host); mhost != "" {
+					curr_host = mhost
+				}
 
 
-		// Check for minimal dir structure
-		vhost_dir_config := vhost_dir + string(os.PathSeparator) + "config"
-		vhost_dir_htdocs := vhost_dir + string(os.PathSeparator) + "htdocs"
-		vhost_dir_logs := vhost_dir + string(os.PathSeparator) + "logs"
-		vhost_dir_template := vhost_dir + string(os.PathSeparator) + "template"
-		vhost_dir_tmp := vhost_dir + string(os.PathSeparator) + "tmp"
-		if !utils.IsDirExists(vhost_dir_config) {
-			utils.SystemErrorPageEngine(w, errors.New("Folder "+vhost_dir_config+" is not found"))
-			return
-		}
-		if !utils.IsDirExists(vhost_dir_htdocs) {
-			utils.SystemErrorPageEngine(w, errors.New("Folder "+vhost_dir_htdocs+" is not found"))
-			return
-		}
-		if !utils.IsDirExists(vhost_dir_logs) {
-			utils.SystemErrorPageEngine(w, errors.New("Folder "+vhost_dir_logs+" is not found"))
-			return
-		}
-		if !utils.IsDirExists(vhost_dir_template) {
-			utils.SystemErrorPageEngine(w, errors.New("Folder "+vhost_dir_template+" is not found"))
-			return
-		}
-		if !utils.IsDirExists(vhost_dir_tmp) {
-			utils.SystemErrorPageEngine(w, errors.New("Folder "+vhost_dir_tmp+" is not found"))
-			return
-		}
+				vhost_dir := consts.ParamWwwDir + string(os.PathSeparator) + curr_host
+				if !utils.IsDirExists(vhost_dir) {
+					curr_host = "localhost"
+					vhost_dir = consts.ParamWwwDir + string(os.PathSeparator) + "localhost"
+				}
 
 
-		// Static files
-		if stat.Response(vhost_dir_htdocs, w, r, nil, nil) {
-			return
-		}
+				// Check for minimal dir structure
+				vhost_dir_config := vhost_dir + string(os.PathSeparator) + "config"
+				vhost_dir_htdocs := vhost_dir + string(os.PathSeparator) + "htdocs"
+				vhost_dir_logs := vhost_dir + string(os.PathSeparator) + "logs"
+				vhost_dir_template := vhost_dir + string(os.PathSeparator) + "template"
+				vhost_dir_tmp := vhost_dir + string(os.PathSeparator) + "tmp"
+				if !utils.IsDirExists(vhost_dir_config) {
+					utils.SystemErrorPageEngine(w, errors.New("Folder "+vhost_dir_config+" is not found"))
+					return
+				}
+				if !utils.IsDirExists(vhost_dir_htdocs) {
+					utils.SystemErrorPageEngine(w, errors.New("Folder "+vhost_dir_htdocs+" is not found"))
+					return
+				}
+				if !utils.IsDirExists(vhost_dir_logs) {
+					utils.SystemErrorPageEngine(w, errors.New("Folder "+vhost_dir_logs+" is not found"))
+					return
+				}
+				if !utils.IsDirExists(vhost_dir_template) {
+					utils.SystemErrorPageEngine(w, errors.New("Folder "+vhost_dir_template+" is not found"))
+					return
+				}
+				if !utils.IsDirExists(vhost_dir_tmp) {
+					utils.SystemErrorPageEngine(w, errors.New("Folder "+vhost_dir_tmp+" is not found"))
+					return
+				}
 
 
-		// Robots.txt and styles.css from template dir
-		if ServeTemplateFile(w, r, "robots.txt", "", vhost_dir_template) {
-			return
-		}
-		if ServeTemplateFile(w, r, "styles.css", "assets/theme/", vhost_dir_template) {
-			return
-		}
-		if ServeTemplateFile(w, r, "scripts.js", "assets/theme/", vhost_dir_template) {
-			return
-		}
+				// Static files
+				if stat.Response(vhost_dir_htdocs, w, r, nil, nil) {
+					return
+				}
 
 
-		// Session
-		sess := session.New(w, r, vhost_dir_tmp)
-		defer sess.Close()
+				// Robots.txt and styles.css from template dir
+				if ServeTemplateFile(w, r, "robots.txt", "", vhost_dir_template) {
+					return
+				}
+				if ServeTemplateFile(w, r, "styles.css", "assets/theme/", vhost_dir_template) {
+					return
+				}
+				if ServeTemplateFile(w, r, "scripts.js", "assets/theme/", vhost_dir_template) {
+					return
+				}
 
 
-		// Convert
-		var mp *mysqlpool.MySqlPool
-		if mpool, ok := o.(*mysqlpool.MySqlPool); ok {
-			mp = mpool
-		}
+				// Session
+				sess := session.New(w, r, vhost_dir_tmp)
+				defer sess.Close()
 
 
-		// Logic
-		if mp != nil {
-			if engine.Response(
-				mp,
-				sb,
-				lg,
-				mods,
-				w,
-				r,
-				sess,
-				cbs,
-				host,
-				port,
-				curr_host,
-				vhost_dir_config,
-				vhost_dir_htdocs,
-				vhost_dir_logs,
-				vhost_dir_template,
-				vhost_dir_tmp,
-			) {
-				return
-			}
-		}
+				// Convert
+				var mp *mysqlpool.MySqlPool
+				if mpool, ok := o.(*mysqlpool.MySqlPool); ok {
+					mp = mpool
+				}
+
+				// Logic
+				if mp != nil {
+					if engine.Response(
+						mp,
+						sb,
+						lg,
+						mods,
+						w,
+						r,
+						sess,
+						cbs,
+						host,
+						port,
+						curr_host,
+						vhost_dir_config,
+						vhost_dir_htdocs,
+						vhost_dir_logs,
+						vhost_dir_template,
+						vhost_dir_tmp,
+					) {
+						return
+					}
+				}
 
 
-		// Error 404
-		utils.SystemErrorPage404(w)
-	}, func(s *http.Server) {
-		s.SetKeepAlivesEnabled(consts.ParamKeepAlive)
-	}, mpool)
+				// Error 404
+				utils.SystemErrorPage404(w)
+			},
+		},
+	)
 
 
 	// Close MySQL
 	// Close MySQL
 	mpool.CloseAll()
 	mpool.CloseAll()

+ 1 - 3
vendor/github.com/disintegration/imaging/.travis.yml

@@ -1,10 +1,8 @@
 language: go
 language: go
 go:
 go:
-  - "1.7.x"
-  - "1.8.x"
-  - "1.9.x"
   - "1.10.x"
   - "1.10.x"
   - "1.11.x"
   - "1.11.x"
+  - "1.12.x"
 
 
 before_install:
 before_install:
   - go get github.com/mattn/goveralls
   - go get github.com/mattn/goveralls

+ 29 - 0
vendor/github.com/disintegration/imaging/README.md

@@ -129,6 +129,35 @@ Original image                     | Saturation = 30
 -----------------------------------|----------------------------------------------|---------------------------------------------
 -----------------------------------|----------------------------------------------|---------------------------------------------
 ![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_saturation_p30.png) | ![dstImage](testdata/out_saturation_m30.png)
 ![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_saturation_p30.png) | ![dstImage](testdata/out_saturation_m30.png)
 
 
+## FAQ
+
+### Incorrect image orientation after processing (e.g. an image appears rotated after resizing)
+
+Most probably, the given image contains the EXIF orientation tag.
+The stadard `image/*` packages do not support loading and saving
+this kind of information. To fix the issue, try opening images with
+the `AutoOrientation` decode option. If this option is set to `true`,
+the image orientation is changed after decoding, according to the
+orientation tag (if present). Here's the example:
+
+```go
+img, err := imaging.Open("test.jpg", imaging.AutoOrientation(true))
+```
+
+### What's the difference between `imaging` and `gift` packages?
+
+[imaging](https://github.com/disintegration/imaging)
+is designed to be a lightweight and simple image manipulation package.
+It provides basic image processing functions and a few helper functions
+such as `Open` and `Save`. It consistently returns *image.NRGBA image 
+type (8 bits per channel, RGBA).
+
+[gift](https://github.com/disintegration/gift)
+supports more advanced image processing, for example, sRGB/Linear color
+space conversions. It also supports different output image types
+(e.g. 16 bits per channel) and provides easy-to-use API for chaining
+multiple processing steps together.
+
 ## Example code
 ## Example code
 
 
 ```go
 ```go

+ 4 - 3
vendor/github.com/disintegration/imaging/adjust.go

@@ -91,11 +91,12 @@ func AdjustContrast(img image.Image, percentage float64) *image.NRGBA {
 
 
 	v := (100.0 + percentage) / 100.0
 	v := (100.0 + percentage) / 100.0
 	for i := 0; i < 256; i++ {
 	for i := 0; i < 256; i++ {
-		if 0 <= v && v <= 1 {
+		switch {
+		case 0 <= v && v <= 1:
 			lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*v) * 255.0)
 			lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*v) * 255.0)
-		} else if 1 < v && v < 2 {
+		case 1 < v && v < 2:
 			lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*(1/(2.0-v))) * 255.0)
 			lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*(1/(2.0-v))) * 255.0)
-		} else {
+		default:
 			lut[i] = uint8(float64(i)/255.0+0.5) * 255
 			lut[i] = uint8(float64(i)/255.0+0.5) * 255
 		}
 		}
 	}
 	}

+ 21 - 0
vendor/github.com/vladimirok5959/golang-ctrlc/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Vova Tkach
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 26 - 0
vendor/github.com/vladimirok5959/golang-ctrlc/ctrlc/colors.go

@@ -0,0 +1,26 @@
+package ctrlc
+
+import (
+	"fmt"
+)
+
+func clr(use bool, str string) string {
+	if !IS_WIN_PLATFORM && use {
+		return fmt.Sprintf("\033[1;31m%s\033[0m", str)
+	}
+	return str
+}
+
+func clg(use bool, str string) string {
+	if !IS_WIN_PLATFORM && use {
+		return fmt.Sprintf("\033[1;32m%s\033[0m", str)
+	}
+	return str
+}
+
+func cly(use bool, str string) string {
+	if !IS_WIN_PLATFORM && use {
+		return fmt.Sprintf("\033[1;33m%s\033[0m", str)
+	}
+	return str
+}

+ 146 - 0
vendor/github.com/vladimirok5959/golang-ctrlc/ctrlc/ctrlc.go

@@ -0,0 +1,146 @@
+package ctrlc
+
+import (
+	"context"
+	"flag"
+	"fmt"
+	"os"
+	"os/signal"
+	"syscall"
+	"time"
+)
+
+const C_ICON_START = "🌟"
+const C_ICON_WARN = "⚡️"
+const C_ICON_HOT = "🔥"
+const C_ICON_MAG = "✨"
+const C_ICON_SC = "🌳"
+
+type Iface interface {
+	Shutdown(ctx context.Context) error
+}
+
+type CallbackFunc func(ctx context.Context, shutdown context.CancelFunc) *[]Iface
+
+func App(t time.Duration, f CallbackFunc) {
+	var ParamColor string
+	flag.StringVar(&ParamColor, "color", "auto", "color output (auto/always/never)")
+	flag.Parse()
+
+	useColors := !IS_WIN_PLATFORM && ParamColor == "always"
+
+	stop := make(chan os.Signal)
+	signal.Notify(stop, syscall.SIGTERM)
+	signal.Notify(stop, syscall.SIGINT)
+
+	fmt.Printf(
+		icon_start(useColors)+"%s\n",
+		cly(
+			useColors,
+			fmt.Sprintf(
+				"Application started (%d sec)",
+				t/time.Second,
+			),
+		),
+	)
+
+	sctx, shutdown := context.WithCancel(context.Background())
+	ifaces := f(sctx, shutdown)
+
+	select {
+	case <-sctx.Done():
+		fmt.Printf(
+			"\r"+icon_warn(useColors)+"%s\n",
+			cly(
+				useColors,
+				fmt.Sprintf(
+					"Shutting down (application) (%d sec)",
+					t/time.Second,
+				),
+			),
+		)
+	case val := <-stop:
+		switch val {
+		case syscall.SIGINT:
+			fmt.Printf(
+				"\r"+icon_warn(useColors)+"%s\n",
+				cly(
+					useColors,
+					fmt.Sprintf(
+						"Shutting down (interrupt) (%d sec)",
+						t/time.Second,
+					),
+				),
+			)
+		case syscall.SIGTERM:
+			fmt.Printf(
+				icon_warn(useColors)+"%s\n",
+				cly(
+					useColors,
+					fmt.Sprintf(
+						"Shutting down (terminate) (%d sec)",
+						t/time.Second,
+					),
+				),
+			)
+		default:
+			fmt.Printf(
+				icon_warn(useColors)+"%s\n",
+				cly(
+					useColors,
+					fmt.Sprintf(
+						"Shutting down (%d sec)",
+						t/time.Second,
+					),
+				),
+			)
+		}
+	}
+
+	shutdown()
+
+	errors := false
+	ctx, cancel := context.WithTimeout(context.Background(), t)
+	for _, iface := range *ifaces {
+		if err := iface.Shutdown(ctx); err != nil {
+			errors = true
+			fmt.Printf(
+				icon_hot(useColors)+"%s\n",
+				clr(
+					useColors,
+					fmt.Sprintf(
+						"Shutdown error (%T): %s",
+						iface,
+						err.Error(),
+					),
+				),
+			)
+		}
+	}
+	cancel()
+
+	if errors {
+		fmt.Printf(
+			icon_mag(useColors)+"%s\n",
+			cly(
+				useColors,
+				fmt.Sprintf(
+					"Application exited with errors (%d sec)",
+					t/time.Second,
+				),
+			),
+		)
+		os.Exit(1)
+	} else {
+		fmt.Printf(
+			icon_sc(useColors)+"%s\n",
+			clg(
+				useColors,
+				fmt.Sprintf(
+					"Application exited successfully (%d sec)",
+					t/time.Second,
+				),
+			),
+		)
+	}
+}

+ 36 - 0
vendor/github.com/vladimirok5959/golang-ctrlc/ctrlc/icons.go

@@ -0,0 +1,36 @@
+package ctrlc
+
+func icon_start(use bool) string {
+	if use {
+		return C_ICON_START + " "
+	}
+	return ""
+}
+
+func icon_warn(use bool) string {
+	if use {
+		return C_ICON_WARN + " "
+	}
+	return ""
+}
+
+func icon_hot(use bool) string {
+	if use {
+		return C_ICON_HOT + " "
+	}
+	return ""
+}
+
+func icon_mag(use bool) string {
+	if use {
+		return C_ICON_MAG + " "
+	}
+	return ""
+}
+
+func icon_sc(use bool) string {
+	if use {
+		return C_ICON_SC + " "
+	}
+	return ""
+}

+ 5 - 0
vendor/github.com/vladimirok5959/golang-ctrlc/ctrlc/platform.go

@@ -0,0 +1,5 @@
+package ctrlc
+
+func IsWinPlatform() bool {
+	return IS_WIN_PLATFORM
+}

+ 5 - 0
vendor/github.com/vladimirok5959/golang-ctrlc/ctrlc/platform_other.go

@@ -0,0 +1,5 @@
+// +build !windows
+
+package ctrlc
+
+const IS_WIN_PLATFORM = false

+ 5 - 0
vendor/github.com/vladimirok5959/golang-ctrlc/ctrlc/platform_windows.go

@@ -0,0 +1,5 @@
+// +build windows
+
+package ctrlc
+
+const IS_WIN_PLATFORM = true

+ 63 - 61
vendor/github.com/vladimirok5959/golang-server-bootstrap/bootstrap/bootstrap.go

@@ -5,104 +5,106 @@ import (
 	"fmt"
 	"fmt"
 	"net/http"
 	"net/http"
 	"os"
 	"os"
-	"os/signal"
-	"syscall"
 	"time"
 	"time"
+
+	"github.com/vladimirok5959/golang-ctrlc/ctrlc"
 )
 )
 
 
 type customHandler func(h http.Handler) http.Handler
 type customHandler func(h http.Handler) http.Handler
-type callbackBeforeAfter func(w http.ResponseWriter, r *http.Request, o interface{})
+type callbackBeforeAfter func(ctx context.Context, w http.ResponseWriter, r *http.Request, o interface{})
 type callbackServer func(s *http.Server)
 type callbackServer func(s *http.Server)
 
 
+type Opts struct {
+	Handle  customHandler
+	Host    string
+	Timeout time.Duration
+	Path    string
+	Before  callbackBeforeAfter
+	After   callbackBeforeAfter
+	Cbserv  callbackServer
+	Object  interface{}
+}
+
 type bootstrap struct {
 type bootstrap struct {
-	path   string
-	before callbackBeforeAfter
-	after  callbackBeforeAfter
-	object interface{}
+	ctx  context.Context
+	opts *Opts
 }
 }
 
 
-func new(path string, before callbackBeforeAfter, after callbackBeforeAfter, object interface{}) *bootstrap {
-	return &bootstrap{path, before, after, object}
+func new(ctx context.Context, opts *Opts) *bootstrap {
+	return &bootstrap{ctx: ctx, opts: opts}
 }
 }
 
 
 func (this *bootstrap) handler(w http.ResponseWriter, r *http.Request) {
 func (this *bootstrap) handler(w http.ResponseWriter, r *http.Request) {
-	if this.before != nil {
-		this.before(w, r, this.object)
+	if this.opts.Before != nil {
+		this.opts.Before(this.ctx, w, r, this.opts.Object)
 	}
 	}
-	if r.URL.Path == "/"+this.path+"/bootstrap.css" {
+	if r.URL.Path == "/"+this.opts.Path+"/bootstrap.css" {
 		w.Header().Set("Cache-Control", "public, max-age=31536000")
 		w.Header().Set("Cache-Control", "public, max-age=31536000")
 		w.Header().Set("Content-Type", "text/css")
 		w.Header().Set("Content-Type", "text/css")
 		w.Write(resource_bootstrap_css)
 		w.Write(resource_bootstrap_css)
 		return
 		return
-	} else if r.URL.Path == "/"+this.path+"/bootstrap.js" {
+	} else if r.URL.Path == "/"+this.opts.Path+"/bootstrap.js" {
 		w.Header().Set("Cache-Control", "public, max-age=31536000")
 		w.Header().Set("Cache-Control", "public, max-age=31536000")
 		w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
 		w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
 		w.Write(resource_bootstrap_js)
 		w.Write(resource_bootstrap_js)
 		return
 		return
-	} else if r.URL.Path == "/"+this.path+"/jquery.js" {
+	} else if r.URL.Path == "/"+this.opts.Path+"/jquery.js" {
 		w.Header().Set("Cache-Control", "public, max-age=31536000")
 		w.Header().Set("Cache-Control", "public, max-age=31536000")
 		w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
 		w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
 		w.Write(resource_jquery_js)
 		w.Write(resource_jquery_js)
 		return
 		return
-	} else if r.URL.Path == "/"+this.path+"/popper.js" {
+	} else if r.URL.Path == "/"+this.opts.Path+"/popper.js" {
 		w.Header().Set("Cache-Control", "public, max-age=31536000")
 		w.Header().Set("Cache-Control", "public, max-age=31536000")
 		w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
 		w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
 		w.Write(resource_popper_js)
 		w.Write(resource_popper_js)
 		return
 		return
 	}
 	}
-	if this.after != nil {
-		this.after(w, r, this.object)
+	if this.opts.After != nil {
+		this.opts.After(this.ctx, w, r, this.opts.Object)
 	}
 	}
 }
 }
 
 
-func Start(h customHandler, host string, timeout time.Duration, path string, before callbackBeforeAfter, after callbackBeforeAfter, cbserv callbackServer, object interface{}) {
-	mux := http.NewServeMux()
-	mux.HandleFunc("/", new(path, before, after, object).handler)
-
-	var srv *http.Server
-	if h == nil {
-		srv = &http.Server{
-			Addr:    host,
-			Handler: mux,
-		}
-	} else {
-		srv = &http.Server{
-			Addr:    host,
-			Handler: h(mux),
-		}
+func Start(opts *Opts) {
+	if opts == nil {
+		fmt.Println("Start: options is not defined")
+		os.Exit(1)
 	}
 	}
 
 
-	if cbserv != nil {
-		cbserv(srv)
-	}
+	ctrlc.App(
+		opts.Timeout,
+		func(ctx context.Context, shutdown context.CancelFunc) *[]ctrlc.Iface {
+			mux := http.NewServeMux()
+			mux.HandleFunc("/", new(ctx, opts).handler)
 
 
-	stop := make(chan os.Signal)
-	signal.Notify(stop, syscall.SIGTERM)
-	signal.Notify(stop, syscall.SIGINT)
-	go func() {
-		fmt.Printf("Starting server at http://%s/\n", host)
-		if err := srv.ListenAndServe(); err != nil {
-			if err != http.ErrServerClosed {
-				fmt.Println(err)
-				stop <- os.Interrupt
-				os.Exit(1)
+			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),
+				}
 			}
 			}
-		}
-	}()
 
 
-	switch val := <-stop; val {
-	case syscall.SIGTERM:
-		fmt.Println("Shutting down server (terminate)...")
-	case syscall.SIGINT:
-		fmt.Println("Shutting down server (interrupt)...")
-	default:
-		fmt.Println("Shutting down server...")
-	}
+			if opts.Cbserv != nil {
+				opts.Cbserv(srv)
+			}
 
 
-	ctx, cancel := context.WithTimeout(context.Background(), timeout*time.Second)
-	defer cancel()
-	if err := srv.Shutdown(ctx); err != nil {
-		fmt.Println(err)
-		os.Exit(1)
-	}
+			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{srv}
+		},
+	)
 }
 }

+ 7 - 5
vendor/modules.txt

@@ -1,14 +1,16 @@
-# github.com/disintegration/imaging v1.6.0
+# github.com/disintegration/imaging v1.6.1
 github.com/disintegration/imaging
 github.com/disintegration/imaging
 # github.com/go-sql-driver/mysql v1.4.1
 # github.com/go-sql-driver/mysql v1.4.1
 github.com/go-sql-driver/mysql
 github.com/go-sql-driver/mysql
-# github.com/vladimirok5959/golang-server-bootstrap v1.0.5
+# github.com/vladimirok5959/golang-ctrlc v1.0.1
+github.com/vladimirok5959/golang-ctrlc/ctrlc
+# github.com/vladimirok5959/golang-server-bootstrap v1.0.8
 github.com/vladimirok5959/golang-server-bootstrap/bootstrap
 github.com/vladimirok5959/golang-server-bootstrap/bootstrap
-# github.com/vladimirok5959/golang-server-resources v1.0.3
+# github.com/vladimirok5959/golang-server-resources v1.0.4
 github.com/vladimirok5959/golang-server-resources/resource
 github.com/vladimirok5959/golang-server-resources/resource
-# github.com/vladimirok5959/golang-server-sessions v1.0.5
+# github.com/vladimirok5959/golang-server-sessions v1.0.6
 github.com/vladimirok5959/golang-server-sessions/session
 github.com/vladimirok5959/golang-server-sessions/session
-# github.com/vladimirok5959/golang-server-static v1.0.0
+# github.com/vladimirok5959/golang-server-static v1.0.2
 github.com/vladimirok5959/golang-server-static/static
 github.com/vladimirok5959/golang-server-static/static
 # golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81
 # golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81
 golang.org/x/image/bmp
 golang.org/x/image/bmp