2018-11-09 00:47:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
2018-11-09 14:22:44 +00:00
|
|
|
import "bytes"
|
2018-11-09 00:47:14 +00:00
|
|
|
import "flag"
|
2018-11-09 14:22:44 +00:00
|
|
|
import "io/ioutil"
|
2018-11-09 00:47:14 +00:00
|
|
|
import "log"
|
|
|
|
import "net/http"
|
2018-11-09 14:22:44 +00:00
|
|
|
import "os"
|
2018-11-13 15:39:26 +00:00
|
|
|
import "os/signal"
|
|
|
|
import "runtime"
|
|
|
|
import "runtime/pprof"
|
|
|
|
import "syscall"
|
2018-11-09 01:26:16 +00:00
|
|
|
import "time"
|
2018-11-09 00:47:14 +00:00
|
|
|
|
2018-11-09 14:55:18 +00:00
|
|
|
// import "github.com/colinmarc/cdb"
|
|
|
|
import cdb "github.com/cipriancraciun/go-cdb-lib"
|
2018-11-09 00:47:14 +00:00
|
|
|
|
2018-11-13 01:08:51 +00:00
|
|
|
import "github.com/valyala/fasthttp"
|
|
|
|
|
2018-11-13 15:37:33 +00:00
|
|
|
import . "github.com/cipriancraciun/go-cdb-http/lib/common"
|
|
|
|
import . "github.com/cipriancraciun/go-cdb-http/lib/server"
|
2018-11-09 00:47:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-09 14:55:18 +00:00
|
|
|
|
2018-11-09 00:47:14 +00:00
|
|
|
type server struct {
|
2018-11-13 15:38:43 +00:00
|
|
|
httpServer *fasthttp.Server
|
2018-11-09 00:47:14 +00:00
|
|
|
cdbReader *cdb.CDB
|
|
|
|
debug bool
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-13 15:38:43 +00:00
|
|
|
|
|
|
|
|
2018-11-13 01:08:51 +00:00
|
|
|
func (_server *server) HandleHTTP (_context *fasthttp.RequestCtx) () {
|
|
|
|
_uri := _context.URI ()
|
2018-11-13 15:38:43 +00:00
|
|
|
// _request := &_context.Request
|
|
|
|
_requestHeaders := &_context.Request.Header
|
2018-11-13 01:08:51 +00:00
|
|
|
_response := &_context.Response
|
2018-11-13 15:38:43 +00:00
|
|
|
_responseHeaders := &_context.Response.Header
|
2018-11-09 00:47:14 +00:00
|
|
|
|
2018-11-13 10:40:26 +00:00
|
|
|
_keyBuffer := [1024]byte {}
|
|
|
|
_pathNewBuffer := [1024]byte {}
|
|
|
|
_timestampBuffer := [128]byte {}
|
|
|
|
|
2018-11-09 01:26:16 +00:00
|
|
|
_timestamp := time.Now ()
|
2018-11-13 10:40:26 +00:00
|
|
|
_timestampHttp := _timestamp.AppendFormat (_timestampBuffer[:0], http.TimeFormat)
|
2018-11-09 01:26:16 +00:00
|
|
|
|
2018-11-09 13:54:47 +00:00
|
|
|
// _responseHeaders.Set ("Content-Security-Policy", "upgrade-insecure-requests")
|
2018-11-09 00:47:14 +00:00
|
|
|
_responseHeaders.Set ("Referrer-Policy", "strict-origin-when-cross-origin")
|
|
|
|
_responseHeaders.Set ("X-Frame-Options", "SAMEORIGIN")
|
2018-11-09 13:54:47 +00:00
|
|
|
_responseHeaders.Set ("X-content-type-Options", "nosniff")
|
2018-11-09 00:47:14 +00:00
|
|
|
_responseHeaders.Set ("X-XSS-Protection", "1; mode=block")
|
|
|
|
|
2018-11-13 10:40:26 +00:00
|
|
|
_responseHeaders.SetBytesV ("date", _timestampHttp)
|
|
|
|
_responseHeaders.SetBytesV ("last-modified", _timestampHttp)
|
2018-11-09 13:54:47 +00:00
|
|
|
_responseHeaders.Set ("age", "0")
|
2018-11-09 01:26:16 +00:00
|
|
|
|
2018-11-13 10:40:26 +00:00
|
|
|
_method := _requestHeaders.Method ()
|
|
|
|
_path := _uri.Path ()
|
|
|
|
_pathLen := len (_path)
|
|
|
|
_pathIsRoot := _pathLen == 1
|
|
|
|
_pathHasSlash := !_pathIsRoot && (_path[_pathLen - 1] == '/')
|
2018-11-09 00:47:14 +00:00
|
|
|
|
2018-11-13 10:40:26 +00:00
|
|
|
if ! bytes.Equal ([]byte (http.MethodGet), _method) {
|
|
|
|
// log.Printf ("[ww] [bce7a75b] invalid method `%s` for `%s`!\n", _method, _path)
|
2018-11-13 01:08:51 +00:00
|
|
|
_server.ServeError (_context, http.StatusMethodNotAllowed, nil)
|
2018-11-09 00:47:14 +00:00
|
|
|
return
|
|
|
|
}
|
2018-11-13 10:40:26 +00:00
|
|
|
if (_pathLen == 0) || (_path[0] != '/') {
|
|
|
|
// log.Printf ("[ww] [fa6b1923] invalid path `%s`!\n", _path)
|
|
|
|
_server.ServeError (_context, http.StatusBadRequest, nil)
|
|
|
|
return
|
|
|
|
}
|
2018-11-09 00:47:14 +00:00
|
|
|
|
2018-11-13 10:40:26 +00:00
|
|
|
var _fingerprint []byte
|
2018-11-09 00:47:14 +00:00
|
|
|
{
|
|
|
|
_path_0 := _path
|
2018-11-13 10:40:26 +00:00
|
|
|
if _pathHasSlash {
|
|
|
|
_path_0 = _path[: _pathLen - 1]
|
2018-11-09 00:47:14 +00:00
|
|
|
}
|
2018-11-09 14:11:32 +00:00
|
|
|
_found : for _, _namespace := range []string {NamespaceFilesContent, NamespaceFoldersContent, NamespaceFoldersEntries} {
|
2018-11-13 10:40:26 +00:00
|
|
|
_key := _keyBuffer[:0]
|
|
|
|
_key = append (_key, _namespace ...)
|
|
|
|
_key = append (_key, ':')
|
|
|
|
_key = append (_key, _path_0 ...)
|
2018-11-13 15:38:43 +00:00
|
|
|
if _value, _error := _server.cdbReader.GetWithCdbHash (_key); _error == nil {
|
2018-11-09 00:47:14 +00:00
|
|
|
if _value != nil {
|
2018-11-13 10:40:26 +00:00
|
|
|
_fingerprint = _value
|
2018-11-09 14:11:32 +00:00
|
|
|
if (_namespace == NamespaceFoldersContent) || (_namespace == NamespaceFoldersEntries) {
|
2018-11-13 10:40:26 +00:00
|
|
|
if !_pathHasSlash {
|
|
|
|
_pathNew := _pathNewBuffer[:0]
|
|
|
|
_pathNew = append (_pathNew, _path_0 ...)
|
|
|
|
_pathNew = append (_pathNew, '/')
|
|
|
|
_server.ServeRedirect (_context, http.StatusTemporaryRedirect, _pathNew)
|
2018-11-09 14:11:32 +00:00
|
|
|
return
|
|
|
|
}
|
2018-11-09 00:47:14 +00:00
|
|
|
}
|
2018-11-09 14:11:32 +00:00
|
|
|
if _namespace == NamespaceFoldersEntries {
|
2018-11-13 10:40:26 +00:00
|
|
|
for _, _indexName := range []string {
|
2018-11-09 14:11:32 +00:00
|
|
|
"index.html", "index.htm",
|
|
|
|
"index.xhtml", "index.xht",
|
|
|
|
"index.txt",
|
|
|
|
"index.json",
|
|
|
|
"index.xml",
|
|
|
|
} {
|
2018-11-13 10:40:26 +00:00
|
|
|
_key := _keyBuffer[:0]
|
|
|
|
_key = append (_key, NamespaceFilesContent ...)
|
|
|
|
_key = append (_key, '/')
|
|
|
|
if !_pathIsRoot {
|
|
|
|
_key = append (_key, _path_0 ...)
|
2018-11-09 14:11:32 +00:00
|
|
|
}
|
2018-11-13 10:40:26 +00:00
|
|
|
_key = append (_key, '/')
|
|
|
|
_key = append (_key, _indexName ...)
|
2018-11-13 15:38:43 +00:00
|
|
|
if _value, _error := _server.cdbReader.GetWithCdbHash (_key); _error == nil {
|
2018-11-13 10:40:26 +00:00
|
|
|
_fingerprint = _value
|
2018-11-09 14:11:32 +00:00
|
|
|
break _found
|
|
|
|
} else {
|
2018-11-13 01:08:51 +00:00
|
|
|
_server.ServeError (_context, http.StatusInternalServerError, _error)
|
2018-11-09 14:11:32 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break _found
|
2018-11-09 00:47:14 +00:00
|
|
|
}
|
|
|
|
} else {
|
2018-11-13 01:08:51 +00:00
|
|
|
_server.ServeError (_context, http.StatusInternalServerError, _error)
|
2018-11-09 00:47:14 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-13 10:40:26 +00:00
|
|
|
|
|
|
|
if _fingerprint == nil {
|
|
|
|
if ! bytes.Equal ([]byte ("/favicon.ico"), _path) {
|
|
|
|
// log.Printf ("[ww] [7416f61d] not found `%s`!\n", _path)
|
2018-11-13 01:08:51 +00:00
|
|
|
_server.ServeError (_context, http.StatusNotFound, nil)
|
2018-11-09 01:12:32 +00:00
|
|
|
} else {
|
|
|
|
_data, _dataContentType := FaviconData ()
|
2018-11-09 13:54:47 +00:00
|
|
|
_responseHeaders.Set ("content-type", _dataContentType)
|
|
|
|
_responseHeaders.Set ("content-encoding", "identity")
|
|
|
|
_responseHeaders.Set ("etag", "f00f5f99bb3d45ef9806547fe5fe031a")
|
|
|
|
_responseHeaders.Set ("cache-control", "public, immutable, max-age=3600")
|
2018-11-13 01:08:51 +00:00
|
|
|
_response.SetStatusCode (http.StatusOK)
|
|
|
|
_response.SetBody (_data)
|
2018-11-09 01:12:32 +00:00
|
|
|
}
|
2018-11-09 00:47:14 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var _data []byte
|
|
|
|
{
|
2018-11-13 10:40:26 +00:00
|
|
|
_key := _keyBuffer[:0]
|
|
|
|
_key = append (_key, NamespaceDataContent ...)
|
|
|
|
_key = append (_key, ':')
|
|
|
|
_key = append (_key, _fingerprint ...)
|
2018-11-13 15:38:43 +00:00
|
|
|
if _value, _error := _server.cdbReader.GetWithCdbHash (_key); _error == nil {
|
2018-11-09 00:47:14 +00:00
|
|
|
if _value != nil {
|
|
|
|
_data = _value
|
2018-11-09 13:54:47 +00:00
|
|
|
} else {
|
2018-11-13 10:40:26 +00:00
|
|
|
// log.Printf ("[ee] [0165c193] missing data content for `%s`!\n", _fingerprint)
|
|
|
|
_server.ServeError (_context, http.StatusInternalServerError, nil)
|
2018-11-09 13:54:47 +00:00
|
|
|
return
|
2018-11-09 00:47:14 +00:00
|
|
|
}
|
|
|
|
} else {
|
2018-11-13 01:08:51 +00:00
|
|
|
_server.ServeError (_context, http.StatusInternalServerError, _error)
|
2018-11-09 00:47:14 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2018-11-13 10:40:26 +00:00
|
|
|
_key := _keyBuffer[:0]
|
|
|
|
_key = append (_key, NamespaceDataMetadata ...)
|
|
|
|
_key = append (_key, ':')
|
|
|
|
_key = append (_key, _fingerprint ...)
|
2018-11-13 15:38:43 +00:00
|
|
|
if _value, _error := _server.cdbReader.GetWithCdbHash (_key); _error == nil {
|
2018-11-09 00:47:14 +00:00
|
|
|
if _value != nil {
|
2018-11-13 15:38:43 +00:00
|
|
|
if _error := MetadataDecodeIterate (_value, _responseHeaders.SetBytesKV); _error == nil {
|
2018-11-09 13:54:47 +00:00
|
|
|
} else {
|
2018-11-13 01:08:51 +00:00
|
|
|
_server.ServeError (_context, http.StatusInternalServerError, _error)
|
2018-11-09 13:54:47 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
} else {
|
2018-11-13 10:40:26 +00:00
|
|
|
// log.Printf ("[ee] [e8702411] missing data metadata for `%s`!\n", _fingerprint)
|
|
|
|
_server.ServeError (_context, http.StatusInternalServerError, nil)
|
2018-11-09 13:54:47 +00:00
|
|
|
return
|
2018-11-09 00:47:14 +00:00
|
|
|
}
|
|
|
|
} else {
|
2018-11-13 01:08:51 +00:00
|
|
|
_server.ServeError (_context, http.StatusInternalServerError, _error)
|
2018-11-09 00:47:14 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if _server.debug {
|
2018-11-13 10:40:26 +00:00
|
|
|
// log.Printf ("[dd] [b15f3cad] serving for `%s`...\n", _path)
|
2018-11-09 00:47:14 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 13:54:47 +00:00
|
|
|
_responseHeaders.Set ("cache-control", "public, immutable, max-age=3600")
|
|
|
|
|
2018-11-13 01:08:51 +00:00
|
|
|
_response.SetStatusCode (http.StatusOK)
|
|
|
|
_response.SetBody (_data)
|
2018-11-09 00:47:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-13 10:40:26 +00:00
|
|
|
func (_server *server) ServeRedirect (_context *fasthttp.RequestCtx, _status uint, _path []byte) () {
|
2018-11-13 01:08:51 +00:00
|
|
|
_response := &_context.Response
|
2018-11-13 15:38:43 +00:00
|
|
|
_responseHeaders := &_context.Response.Header
|
2018-11-09 01:26:16 +00:00
|
|
|
|
2018-11-09 13:54:47 +00:00
|
|
|
_responseHeaders.Set ("content-type", MimeTypeText)
|
|
|
|
_responseHeaders.Set ("content-encoding", "identity")
|
|
|
|
_responseHeaders.Set ("etag", "7aa652d8d607b85808c87c1c2105fbb5")
|
|
|
|
_responseHeaders.Set ("cache-control", "public, immutable, max-age=3600")
|
2018-11-13 10:40:26 +00:00
|
|
|
_responseHeaders.SetBytesV ("location", _path)
|
2018-11-09 13:54:47 +00:00
|
|
|
|
2018-11-13 01:08:51 +00:00
|
|
|
_response.SetStatusCode (int (_status))
|
2018-11-13 10:40:26 +00:00
|
|
|
// _response.SetBody ([]byte (fmt.Sprintf ("[%d] %s", _status, _path)))
|
2018-11-09 00:47:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-13 01:08:51 +00:00
|
|
|
func (_server *server) ServeError (_context *fasthttp.RequestCtx, _status uint, _error error) () {
|
|
|
|
_response := &_context.Response
|
2018-11-13 15:38:43 +00:00
|
|
|
_responseHeaders := &_context.Response.Header
|
2018-11-09 13:54:47 +00:00
|
|
|
|
|
|
|
_responseHeaders.Set ("content-type", MimeTypeText)
|
|
|
|
_responseHeaders.Set ("content-encoding", "identity")
|
|
|
|
_responseHeaders.Set ("cache-control", "no-cache")
|
|
|
|
|
2018-11-13 01:08:51 +00:00
|
|
|
_response.SetStatusCode (int (_status))
|
2018-11-13 10:40:26 +00:00
|
|
|
// _response.SetBody ([]byte (fmt.Sprintf ("[%d]", _status)))
|
2018-11-09 13:54:47 +00:00
|
|
|
|
2018-11-09 00:47:14 +00:00
|
|
|
LogError (_error, "")
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func main () () {
|
|
|
|
Main (main_0)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func main_0 () (error) {
|
|
|
|
|
|
|
|
|
|
|
|
var _bind string
|
|
|
|
var _archive string
|
2018-11-09 14:22:44 +00:00
|
|
|
var _preload bool
|
2018-11-09 00:47:14 +00:00
|
|
|
var _debug bool
|
|
|
|
|
2018-11-13 15:39:26 +00:00
|
|
|
var _profileCpu string
|
|
|
|
var _profileMem string
|
|
|
|
|
2018-11-09 00:47:14 +00:00
|
|
|
{
|
2018-11-09 18:52:30 +00:00
|
|
|
_flags := flag.NewFlagSet ("cdb-http-server", flag.ContinueOnError)
|
2018-11-09 00:47:14 +00:00
|
|
|
|
|
|
|
_bind_0 := _flags.String ("bind", "", "<ip>:<port>")
|
|
|
|
_archive_0 := _flags.String ("archive", "", "<path>")
|
2018-11-09 14:22:44 +00:00
|
|
|
_preload_0 := _flags.Bool ("preload", false, "")
|
2018-11-09 00:47:14 +00:00
|
|
|
_debug_0 := _flags.Bool ("debug", false, "")
|
|
|
|
|
2018-11-13 15:39:26 +00:00
|
|
|
_profileCpu_0 := _flags.String ("profile-cpu", "", "<path>")
|
|
|
|
_profileMem_0 := _flags.String ("profile-mem", "", "<path>")
|
|
|
|
|
2018-11-09 00:47:14 +00:00
|
|
|
FlagsParse (_flags, 0, 0)
|
|
|
|
|
|
|
|
_bind = *_bind_0
|
|
|
|
_archive = *_archive_0
|
2018-11-09 14:22:44 +00:00
|
|
|
_preload = *_preload_0
|
2018-11-09 00:47:14 +00:00
|
|
|
_debug = *_debug_0
|
|
|
|
|
2018-11-13 15:39:26 +00:00
|
|
|
_profileCpu = *_profileCpu_0
|
|
|
|
_profileMem = *_profileMem_0
|
|
|
|
|
2018-11-09 00:47:14 +00:00
|
|
|
if _bind == "" {
|
|
|
|
AbortError (nil, "[eefe1a38] expected bind address argument!")
|
|
|
|
}
|
|
|
|
if _archive == "" {
|
|
|
|
AbortError (nil, "[eefe1a38] expected archive file argument!")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-13 15:39:26 +00:00
|
|
|
var _cdbReader *cdb.CDB
|
2018-11-09 14:22:44 +00:00
|
|
|
{
|
2018-11-13 15:39:26 +00:00
|
|
|
var _cdbFile *os.File
|
|
|
|
if _cdbFile_0, _error := os.Open (_archive); _error == nil {
|
|
|
|
_cdbFile = _cdbFile_0
|
2018-11-09 14:22:44 +00:00
|
|
|
} else {
|
|
|
|
AbortError (_error, "[9e0b5ed3] failed opening archive!")
|
|
|
|
}
|
|
|
|
|
|
|
|
if _preload {
|
2018-11-13 10:40:26 +00:00
|
|
|
log.Printf ("[ii] [922ca187] preloading archive...\n")
|
2018-11-13 15:39:26 +00:00
|
|
|
var _cdbData []byte
|
|
|
|
if _cdbData_0, _error := ioutil.ReadAll (_cdbFile); _error == nil {
|
|
|
|
_cdbData = _cdbData_0
|
2018-11-09 14:22:44 +00:00
|
|
|
} else {
|
|
|
|
AbortError (_error, "[73039784] failed preloading archive!")
|
|
|
|
}
|
2018-11-13 15:39:26 +00:00
|
|
|
if _cdbReader_0, _error := cdb.NewFromBufferWithHasher (_cdbData, nil); _error == nil {
|
|
|
|
_cdbReader = _cdbReader_0
|
|
|
|
} else {
|
|
|
|
AbortError (_error, "[85234ba0] failed opening archive!")
|
|
|
|
}
|
2018-11-09 14:22:44 +00:00
|
|
|
} else {
|
2018-11-13 15:39:26 +00:00
|
|
|
if _cdbReader_0, _error := cdb.NewFromReaderWithHasher (_cdbFile, nil); _error == nil {
|
|
|
|
_cdbReader = _cdbReader_0
|
|
|
|
} else {
|
|
|
|
AbortError (_error, "[85234ba0] failed opening archive!")
|
|
|
|
}
|
2018-11-09 14:22:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-09 00:47:14 +00:00
|
|
|
|
|
|
|
_server := & server {
|
2018-11-13 15:39:26 +00:00
|
|
|
httpServer : nil,
|
2018-11-09 00:47:14 +00:00
|
|
|
cdbReader : _cdbReader,
|
|
|
|
debug : _debug,
|
|
|
|
}
|
|
|
|
|
2018-11-13 15:39:26 +00:00
|
|
|
|
|
|
|
if _profileCpu != "" {
|
|
|
|
log.Printf ("[ii] [9196ee90] profiling CPU to `%s`...\n", _profileCpu)
|
|
|
|
_stream, _error := os.Create (_profileCpu)
|
|
|
|
if _error != nil {
|
|
|
|
AbortError (_error, "[fd4e0009] failed opening CPU profile!")
|
|
|
|
}
|
|
|
|
_error = pprof.StartCPUProfile (_stream)
|
|
|
|
if _error != nil {
|
|
|
|
AbortError (_error, "[ac721629] failed starting CPU profile!")
|
|
|
|
}
|
|
|
|
defer pprof.StopCPUProfile ()
|
|
|
|
}
|
|
|
|
if _profileMem != "" {
|
|
|
|
log.Printf ("[ii] [9196ee90] profiling MEM to `%s`...\n", _profileMem)
|
|
|
|
_stream, _error := os.Create (_profileMem)
|
|
|
|
if _error != nil {
|
|
|
|
AbortError (_error, "[907d08b5] failed opening MEM profile!")
|
|
|
|
}
|
|
|
|
_profile := pprof.Lookup ("heap")
|
|
|
|
defer func () {
|
|
|
|
runtime.GC ()
|
|
|
|
if _profile != nil {
|
|
|
|
if _error := _profile.WriteTo (_stream, 0); _error != nil {
|
|
|
|
AbortError (_error, "[4b1e5112] failed writing MEM profile!")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
AbortError (nil, "[385dc8f0] failed loading MEM profile!")
|
|
|
|
}
|
|
|
|
_stream.Close ()
|
|
|
|
} ()
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_httpServer := & fasthttp.Server {
|
|
|
|
Name : "cdb-http",
|
|
|
|
Handler : _server.HandleHTTP,
|
|
|
|
Concurrency : 4096,
|
|
|
|
MaxRequestsPerConn : 16 * 1024,
|
|
|
|
NoDefaultServerHeader : true,
|
|
|
|
NoDefaultContentType : true,
|
|
|
|
}
|
|
|
|
|
|
|
|
_server.httpServer = _httpServer
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
_signals := make (chan os.Signal, 32)
|
|
|
|
signal.Notify (_signals, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
go func () () {
|
|
|
|
<- _signals
|
|
|
|
log.Printf ("[ii] [691cb695] shutingdown...\n")
|
|
|
|
_server.httpServer.Shutdown ()
|
|
|
|
} ()
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-13 10:40:26 +00:00
|
|
|
log.Printf ("[ii] [f11e4e37] listening on `http://%s/`;\n", _bind)
|
2018-11-09 13:54:47 +00:00
|
|
|
|
2018-11-13 15:39:26 +00:00
|
|
|
if _error := _httpServer.ListenAndServe (_bind); _error != nil {
|
2018-11-09 00:47:14 +00:00
|
|
|
AbortError (_error, "[44f45c67] failed starting server!")
|
|
|
|
}
|
|
|
|
|
2018-11-13 15:39:26 +00:00
|
|
|
|
|
|
|
defer log.Printf ("[ii] [a49175db] done!\n")
|
2018-11-09 00:47:14 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|