Fastfix for previous two commits (sorry) and chroma update.
Well, doing "git add ." not from repository's root is a bad idea. Updated chroma dependency, added more languages to syntax highlighting.
This commit is contained in:
140
internal/context/context.go
Normal file
140
internal/context/context.go
Normal file
@@ -0,0 +1,140 @@
|
||||
// Fast Paste Bin - uberfast and easy-to-use pastebin.
|
||||
//
|
||||
// Copyright (c) 2018, Stanislav N. aka pztrn and Fast Paste Bin
|
||||
// developers.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package context
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
// local
|
||||
"gitlab.com/pztrn/fastpastebin/internal/config"
|
||||
"gitlab.com/pztrn/fastpastebin/internal/database/interface"
|
||||
|
||||
// other
|
||||
"github.com/labstack/echo"
|
||||
"github.com/rs/zerolog"
|
||||
"gitlab.com/pztrn/flagger"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Context is a some sort of singleton. Basically it's a structure that
|
||||
// initialized once and then passed to all parts of application. It
|
||||
// contains everything every part of application need, like configuration
|
||||
// access, logger, etc.
|
||||
type Context struct {
|
||||
Config *config.ConfigStruct
|
||||
Database databaseinterface.Interface
|
||||
Echo *echo.Echo
|
||||
Flagger *flagger.Flagger
|
||||
Logger zerolog.Logger
|
||||
}
|
||||
|
||||
// Initialize initializes context.
|
||||
func (c *Context) Initialize() {
|
||||
c.initializeLogger()
|
||||
|
||||
c.Flagger = flagger.New("fastpastebin", nil)
|
||||
c.Flagger.Initialize()
|
||||
|
||||
c.Flagger.AddFlag(&flagger.Flag{
|
||||
Name: "config",
|
||||
Description: "Configuration file path. Can be overridded with FASTPASTEBIN_CONFIG environment variable (this is what used in tests).",
|
||||
Type: "string",
|
||||
DefaultValue: "NO_CONFIG",
|
||||
})
|
||||
}
|
||||
|
||||
// InitializePost initializes everything that needs a configuration.
|
||||
func (c *Context) InitializePost() {
|
||||
c.initializeLoggerPost()
|
||||
c.initializeHTTPServer()
|
||||
}
|
||||
|
||||
// LoadConfiguration loads configuration and executes right after Flagger
|
||||
// have parsed CLI flags, because it depends on "-config" defined in
|
||||
// Initialize().
|
||||
func (c *Context) LoadConfiguration() {
|
||||
c.Logger.Info().Msg("Loading configuration...")
|
||||
|
||||
var configPath = ""
|
||||
|
||||
// We're accepting configuration path from "-config" CLI parameter
|
||||
// and FASTPASTEBIN_CONFIG environment variable. Later have higher
|
||||
// weight and can override "-config" value.
|
||||
configPathFromCLI, err := c.Flagger.GetStringValue("config")
|
||||
configPathFromEnv, configPathFromEnvFound := os.LookupEnv("FASTPASTEBIN_CONFIG")
|
||||
|
||||
if err != nil && configPathFromEnvFound || err == nil && configPathFromEnvFound {
|
||||
configPath = configPathFromEnv
|
||||
} else if err != nil && !configPathFromEnvFound || err == nil && configPathFromCLI == "NO_CONFIG" {
|
||||
c.Logger.Panic().Msg("Configuration file path wasn't passed via '-config' or 'FASTPASTEBIN_CONFIG' environment variable. Cannot continue.")
|
||||
} else if err == nil && !configPathFromEnvFound {
|
||||
configPath = configPathFromCLI
|
||||
}
|
||||
|
||||
// Normalize file path.
|
||||
normalizedConfigPath, err1 := filepath.Abs(configPath)
|
||||
if err1 != nil {
|
||||
c.Logger.Fatal().Msgf("Failed to normalize path to configuration file: %s", err1.Error())
|
||||
}
|
||||
|
||||
c.Logger.Debug().Msgf("Configuration file path: %s", configPath)
|
||||
|
||||
c.Config = &config.ConfigStruct{}
|
||||
|
||||
// Read configuration file.
|
||||
fileData, err2 := ioutil.ReadFile(normalizedConfigPath)
|
||||
if err2 != nil {
|
||||
c.Logger.Panic().Msgf("Failed to read configuration file: %s", err2.Error())
|
||||
}
|
||||
|
||||
// Parse it into structure.
|
||||
err3 := yaml.Unmarshal(fileData, c.Config)
|
||||
if err3 != nil {
|
||||
c.Logger.Panic().Msgf("Failed to parse configuration file: %s", err3.Error())
|
||||
}
|
||||
|
||||
// Yay! See what it gets!
|
||||
c.Logger.Debug().Msgf("Parsed configuration: %+v", c.Config)
|
||||
}
|
||||
|
||||
// RegisterDatabaseInterface registers database interface for later use.
|
||||
func (c *Context) RegisterDatabaseInterface(di databaseinterface.Interface) {
|
||||
c.Database = di
|
||||
}
|
||||
|
||||
// RegisterEcho registers Echo instance for later usage.
|
||||
func (c *Context) RegisterEcho(e *echo.Echo) {
|
||||
c.Echo = e
|
||||
}
|
||||
|
||||
// Shutdown shutdowns entire application.
|
||||
func (c *Context) Shutdown() {
|
||||
c.Logger.Info().Msg("Shutting down Fast Pastebin...")
|
||||
|
||||
c.Database.Shutdown()
|
||||
}
|
35
internal/context/exported.go
Normal file
35
internal/context/exported.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// Fast Paste Bin - uberfast and easy-to-use pastebin.
|
||||
//
|
||||
// Copyright (c) 2018, Stanislav N. aka pztrn and Fast Paste Bin
|
||||
// developers.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package context
|
||||
|
||||
const (
|
||||
// Version .
|
||||
Version = "0.3.0"
|
||||
)
|
||||
|
||||
// New creates new context.
|
||||
func New() *Context {
|
||||
return &Context{}
|
||||
}
|
47
internal/context/http_server.go
Normal file
47
internal/context/http_server.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
// local
|
||||
"gitlab.com/pztrn/fastpastebin/assets/static"
|
||||
|
||||
// other
|
||||
"github.com/labstack/echo"
|
||||
"github.com/labstack/echo/middleware"
|
||||
)
|
||||
|
||||
func (c *Context) initializeHTTPServer() {
|
||||
c.Echo = echo.New()
|
||||
c.Echo.Use(c.echoReqLogger())
|
||||
c.Echo.Use(middleware.Recover())
|
||||
c.Echo.DisableHTTP2 = true
|
||||
c.Echo.HideBanner = true
|
||||
c.Echo.HidePort = true
|
||||
|
||||
// Static files.
|
||||
c.Echo.GET("/static/*", echo.WrapHandler(static.Handler))
|
||||
|
||||
listenAddress := c.Config.HTTP.Address + ":" + c.Config.HTTP.Port
|
||||
|
||||
go func() {
|
||||
c.Echo.Logger.Fatal(c.Echo.Start(listenAddress))
|
||||
}()
|
||||
c.Logger.Info().Msgf("Started HTTP server at %s", listenAddress)
|
||||
}
|
||||
|
||||
// Wrapper around previous function.
|
||||
func (c *Context) echoReqLogger() echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(ec echo.Context) error {
|
||||
c.Logger.Info().
|
||||
Str("IP", ec.RealIP()).
|
||||
Str("Host", ec.Request().Host).
|
||||
Str("Method", ec.Request().Method).
|
||||
Str("Path", ec.Request().URL.Path).
|
||||
Str("UA", ec.Request().UserAgent()).
|
||||
Msg("HTTP request")
|
||||
|
||||
next(ec)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
76
internal/context/logger.go
Normal file
76
internal/context/logger.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
// other
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// Puts memory usage into log lines.
|
||||
func (c *Context) getMemoryUsage(e *zerolog.Event, level zerolog.Level, message string) {
|
||||
var m runtime.MemStats
|
||||
runtime.ReadMemStats(&m)
|
||||
|
||||
e.Str("memalloc", fmt.Sprintf("%dMB", m.Alloc/1024/1024))
|
||||
e.Str("memsys", fmt.Sprintf("%dMB", m.Sys/1024/1024))
|
||||
e.Str("numgc", fmt.Sprintf("%d", m.NumGC))
|
||||
}
|
||||
|
||||
// Initializes logger.
|
||||
func (c *Context) initializeLogger() {
|
||||
// Устанавливаем форматирование логгера.
|
||||
output := zerolog.ConsoleWriter{Out: os.Stdout, NoColor: false, TimeFormat: time.RFC3339}
|
||||
output.FormatLevel = func(i interface{}) string {
|
||||
var v string
|
||||
if ii, ok := i.(string); ok {
|
||||
ii = strings.ToUpper(ii)
|
||||
switch ii {
|
||||
case "DEBUG":
|
||||
v = fmt.Sprintf("\x1b[30m%-5s\x1b[0m", ii)
|
||||
case "ERROR":
|
||||
v = fmt.Sprintf("\x1b[31m%-5s\x1b[0m", ii)
|
||||
case "FATAL":
|
||||
v = fmt.Sprintf("\x1b[35m%-5s\x1b[0m", ii)
|
||||
case "INFO":
|
||||
v = fmt.Sprintf("\x1b[32m%-5s\x1b[0m", ii)
|
||||
case "PANIC":
|
||||
v = fmt.Sprintf("\x1b[36m%-5s\x1b[0m", ii)
|
||||
case "WARN":
|
||||
v = fmt.Sprintf("\x1b[33m%-5s\x1b[0m", ii)
|
||||
default:
|
||||
v = ii
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("| %s |", v)
|
||||
}
|
||||
|
||||
c.Logger = zerolog.New(output).With().Timestamp().Logger()
|
||||
|
||||
c.Logger = c.Logger.Hook(zerolog.HookFunc(c.getMemoryUsage))
|
||||
}
|
||||
|
||||
// Initialize logger after configuration parse.
|
||||
func (c *Context) initializeLoggerPost() {
|
||||
// Set log level.
|
||||
c.Logger.Info().Msgf("Setting logger level: %s", c.Config.Logging.LogLevel)
|
||||
switch c.Config.Logging.LogLevel {
|
||||
case "DEBUG":
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
case "INFO":
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
case "WARN":
|
||||
zerolog.SetGlobalLevel(zerolog.WarnLevel)
|
||||
case "ERROR":
|
||||
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
|
||||
case "FATAL":
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
case "PANIC":
|
||||
zerolog.SetGlobalLevel(zerolog.PanicLevel)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user