DDD (Domain Design) partially implemented, added comments everywhere.
This commit is contained in:
parent
3456ecd312
commit
242fb3d361
@ -5,6 +5,7 @@ import (
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
// Logs Echo requests.
|
||||
func echoReqLog(ec echo.Context, next echo.HandlerFunc) error {
|
||||
c.Logger.Info().
|
||||
Str("IP", ec.RealIP()).
|
||||
@ -18,6 +19,7 @@ func echoReqLog(ec echo.Context, next echo.HandlerFunc) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wrapper around previous function.
|
||||
func echoReqLogger() echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
|
@ -16,10 +16,12 @@ var (
|
||||
e *echo.Echo
|
||||
)
|
||||
|
||||
// New initializes variables for api package.
|
||||
func New(cc *context.Context) {
|
||||
c = cc
|
||||
}
|
||||
|
||||
// InitializeAPI initializes HTTP API and starts web server.
|
||||
func InitializeAPI() {
|
||||
c.Logger.Info().Msg("Initializing HTTP server...")
|
||||
|
||||
|
@ -13,6 +13,8 @@ var (
|
||||
c *context.Context
|
||||
)
|
||||
|
||||
// New initializes basic HTTP API, which shows only index page and serves
|
||||
// static files.
|
||||
func New(cc *context.Context) {
|
||||
c = cc
|
||||
c.Logger.Info().Msg("Initializing HTTP API...")
|
||||
@ -22,14 +24,4 @@ func New(cc *context.Context) {
|
||||
|
||||
// Index.
|
||||
c.Echo.GET("/", indexGet)
|
||||
|
||||
// New paste.
|
||||
c.Echo.POST("/paste/", pastePOST)
|
||||
|
||||
// Show paste.
|
||||
c.Echo.GET("/paste/:id", pasteGET)
|
||||
|
||||
// Pastes list.
|
||||
c.Echo.GET("/pastes/", pastesGET)
|
||||
c.Echo.GET("/pastes/:page", pastesGET)
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
// Index of this site.
|
||||
func indexGet(ec echo.Context) error {
|
||||
html, err := static.ReadFile("index.html")
|
||||
if err != nil {
|
||||
|
@ -9,6 +9,7 @@ var (
|
||||
c *context.Context
|
||||
)
|
||||
|
||||
// New initializes basic JSON API.
|
||||
func New(cc *context.Context) {
|
||||
c = cc
|
||||
c.Logger.Info().Msg("Initializing JSON API...")
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/pztrn/fastpastebin/context"
|
||||
"github.com/pztrn/fastpastebin/database"
|
||||
"github.com/pztrn/fastpastebin/database/migrations"
|
||||
"github.com/pztrn/fastpastebin/pastes"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -34,6 +35,8 @@ func main() {
|
||||
api.New(c)
|
||||
api.InitializeAPI()
|
||||
|
||||
pastes.New(c)
|
||||
|
||||
// CTRL+C handler.
|
||||
signalHandler := make(chan os.Signal, 1)
|
||||
shutdownDone := make(chan bool, 1)
|
||||
|
@ -1,5 +1,6 @@
|
||||
package config
|
||||
|
||||
// ConfigDatabase describes database configuration.
|
||||
type ConfigDatabase struct {
|
||||
Address string `yaml:"address"`
|
||||
Port string `yaml:"port"`
|
||||
|
@ -1,5 +1,6 @@
|
||||
package config
|
||||
|
||||
// ConfigHTTP describes HTTP server configuration.
|
||||
type ConfigHTTP struct {
|
||||
Address string `yaml:"address"`
|
||||
Port string `yaml:"port"`
|
||||
|
@ -1,5 +1,6 @@
|
||||
package config
|
||||
|
||||
// ConfigLogging describes logger configuration.
|
||||
type ConfigLogging struct {
|
||||
LogToFile bool `yaml:"log_to_file"`
|
||||
FileName string `yaml:"filename"`
|
||||
|
@ -1,5 +1,6 @@
|
||||
package config
|
||||
|
||||
// ConfigStruct describes whole configuration.
|
||||
type ConfigStruct struct {
|
||||
Database ConfigDatabase `yaml:"database"`
|
||||
Logging ConfigLogging `yaml:"logging"`
|
||||
|
@ -17,6 +17,10 @@ import (
|
||||
"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
|
||||
@ -25,6 +29,7 @@ type Context struct {
|
||||
Logger zerolog.Logger
|
||||
}
|
||||
|
||||
// Initialize initializes context.
|
||||
func (c *Context) Initialize() {
|
||||
c.Logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Caller().Logger()
|
||||
|
||||
@ -39,11 +44,17 @@ func (c *Context) Initialize() {
|
||||
})
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
@ -65,27 +76,33 @@ func (c *Context) LoadConfiguration() {
|
||||
|
||||
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...")
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package context
|
||||
|
||||
// New creates new context.
|
||||
func New() *Context {
|
||||
return &Context{}
|
||||
}
|
||||
|
@ -9,17 +9,22 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// Database represents control structure for database connection.
|
||||
type Database struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
// GetDatabaseConnection returns current database connection.
|
||||
func (db *Database) GetDatabaseConnection() *sqlx.DB {
|
||||
return db.db
|
||||
}
|
||||
|
||||
// Initialize initializes connection to database.
|
||||
func (db *Database) Initialize() {
|
||||
c.Logger.Info().Msg("Initializing database connection...")
|
||||
|
||||
// There might be only user, without password. MySQL/MariaDB driver
|
||||
// in DSN wants "user" or "user:password", "user:" is invalid.
|
||||
var userpass = ""
|
||||
if c.Config.Database.Password == "" {
|
||||
userpass = c.Config.Database.Username
|
||||
|
@ -11,6 +11,7 @@ var (
|
||||
d *Database
|
||||
)
|
||||
|
||||
// New initializes database structure.
|
||||
func New(cc *context.Context) {
|
||||
c = cc
|
||||
d = &Database{}
|
||||
|
@ -5,12 +5,16 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// Handler is an interfaceable structure that proxifies calls from anyone
|
||||
// to Database structure.
|
||||
type Handler struct{}
|
||||
|
||||
// GetDatabaseConnection returns current database connection.
|
||||
func (dbh Handler) GetDatabaseConnection() *sqlx.DB {
|
||||
return d.GetDatabaseConnection()
|
||||
}
|
||||
|
||||
// Initialize initializes connection to database.
|
||||
func (dbh Handler) Initialize() {
|
||||
d.Initialize()
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// Interface represents database interface which is available to all
|
||||
// parts of application and registers with context.Context.
|
||||
type Interface interface {
|
||||
GetDatabaseConnection() *sqlx.DB
|
||||
Initialize()
|
||||
|
@ -13,15 +13,18 @@ var (
|
||||
c *context.Context
|
||||
)
|
||||
|
||||
// New initializes migrations.
|
||||
func New(cc *context.Context) {
|
||||
c = cc
|
||||
}
|
||||
|
||||
// Migrate launching migrations.
|
||||
func Migrate() {
|
||||
c.Logger.Info().Msg("Migrating database...")
|
||||
|
||||
goose.SetDialect("mysql")
|
||||
goose.AddNamedMigration("1_initial.go", InitialUp, nil)
|
||||
// Add new migrations BEFORE this message.
|
||||
|
||||
dbConn := c.Database.GetDatabaseConnection()
|
||||
err := goose.Up(dbConn.DB, ".")
|
||||
|
@ -1,4 +1,4 @@
|
||||
package http
|
||||
package pastes
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
@ -10,7 +10,6 @@ import (
|
||||
|
||||
// local
|
||||
"github.com/pztrn/fastpastebin/api/http/static"
|
||||
"github.com/pztrn/fastpastebin/models"
|
||||
|
||||
// other
|
||||
"github.com/labstack/echo"
|
||||
@ -20,6 +19,7 @@ var (
|
||||
regexInts = regexp.MustCompile("[0-9]+")
|
||||
)
|
||||
|
||||
// GET for "/paste/PASTE_ID".
|
||||
func pasteGET(ec echo.Context) error {
|
||||
errhtml, err := static.ReadFile("error.html")
|
||||
if err != nil {
|
||||
@ -33,7 +33,7 @@ func pasteGET(ec echo.Context) error {
|
||||
c.Logger.Debug().Msgf("Requesting paste #%+v", pasteID)
|
||||
|
||||
// Get paste.
|
||||
paste := &models.Paste{ID: pasteID}
|
||||
paste := &Paste{ID: pasteID}
|
||||
err1 := paste.GetByID(c.Database.GetDatabaseConnection())
|
||||
if err1 != nil {
|
||||
c.Logger.Error().Msgf("Failed to get paste #%d from database: %s", pasteID, err1.Error())
|
||||
@ -50,6 +50,8 @@ func pasteGET(ec echo.Context) error {
|
||||
return ec.HTML(http.StatusOK, string(pasteHTMLAsString))
|
||||
}
|
||||
|
||||
// POST for "/paste/" which will create new paste and redirect to
|
||||
// "/pastes/CREATED_PASTE_ID".
|
||||
func pastePOST(ec echo.Context) error {
|
||||
errhtml, err := static.ReadFile("error.html")
|
||||
if err != nil {
|
||||
@ -68,7 +70,7 @@ func pastePOST(ec echo.Context) error {
|
||||
return ec.HTML(http.StatusBadRequest, string(errhtml))
|
||||
}
|
||||
|
||||
paste := &models.Paste{
|
||||
paste := &Paste{
|
||||
Title: params["paste-title"][0],
|
||||
Data: params["paste-contents"][0],
|
||||
}
|
||||
@ -91,7 +93,7 @@ func pastePOST(ec echo.Context) error {
|
||||
paste.KeepFor = keepFor
|
||||
|
||||
keepForUnitRaw := keepForUnitRegex.FindAllString(params["paste-keep-for"][0], 1)[0]
|
||||
keepForUnit := models.PASTE_KEEPS_CORELLATION[keepForUnitRaw]
|
||||
keepForUnit := PASTE_KEEPS_CORELLATION[keepForUnitRaw]
|
||||
paste.KeepForUnitType = keepForUnit
|
||||
|
||||
id, err2 := paste.Save(c.Database.GetDatabaseConnection())
|
||||
@ -105,6 +107,7 @@ func pastePOST(ec echo.Context) error {
|
||||
return ec.Redirect(http.StatusFound, "/paste/"+newPasteIDAsString)
|
||||
}
|
||||
|
||||
// GET for "/pastes/", a list of publicly available pastes.
|
||||
func pastesGET(ec echo.Context) error {
|
||||
pasteListHTML, err1 := static.ReadFile("pastelist_list.html")
|
||||
if err1 != nil {
|
||||
@ -125,7 +128,7 @@ func pastesGET(ec echo.Context) error {
|
||||
|
||||
c.Logger.Debug().Msgf("Requested page #%d", page)
|
||||
|
||||
p := &models.Paste{}
|
||||
p := &Paste{}
|
||||
// Get pastes IDs.
|
||||
pastes, err3 := p.GetPagedPastes(c.Database.GetDatabaseConnection(), page)
|
||||
c.Logger.Debug().Msgf("Got %d pastes", len(pastes))
|
26
pastes/exported.go
Normal file
26
pastes/exported.go
Normal file
@ -0,0 +1,26 @@
|
||||
package pastes
|
||||
|
||||
import (
|
||||
// local
|
||||
"github.com/pztrn/fastpastebin/context"
|
||||
)
|
||||
|
||||
var (
|
||||
c *context.Context
|
||||
)
|
||||
|
||||
// New initializes pastes package and adds neccessary HTTP and API
|
||||
// endpoints.
|
||||
func New(cc *context.Context) {
|
||||
c = cc
|
||||
|
||||
// New paste.
|
||||
c.Echo.POST("/paste/", pastePOST)
|
||||
|
||||
// Show paste.
|
||||
c.Echo.GET("/paste/:id", pasteGET)
|
||||
|
||||
// Pastes list.
|
||||
c.Echo.GET("/pastes/", pastesGET)
|
||||
c.Echo.GET("/pastes/:page", pastesGET)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package models
|
||||
package pastes
|
||||
|
||||
import (
|
||||
// stdlib
|
||||
@ -24,6 +24,7 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Paste represents paste itself.
|
||||
type Paste struct {
|
||||
ID int `db:"id"`
|
||||
Title string `db:"title"`
|
Loading…
Reference in New Issue
Block a user