Skip to content

Commit

Permalink
initial commit. config structs for application info, database, queue …
Browse files Browse the repository at this point in the history
…and webserver. Some interfaces and validation. default yaml config for them.
  • Loading branch information
smgladkovskiy committed Oct 27, 2021
0 parents commit 7b19788
Show file tree
Hide file tree
Showing 12 changed files with 388 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.DS_Store
.idea
.git
.golangci*.yml
c.out
coverage.html
vendor
bin
linter.mk
tests.mk
29 changes: 29 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# ----
## LINTER stuff start

linter_include_check:
@[ -f linter.mk ] && echo "linter.mk include exists" || (echo "getting linter.mk from github.com" && curl -sO https://raw.githubusercontent.com/spacetab-io/makefiles/master/golang/linter.mk)

.PHONY: lint
lint: linter_include_check
@make -f linter.mk go_lint

## LINTER stuff end
# ----

# ----
## TESTS stuff start

tests_include_check:
@[ -f tests.mk ] && echo "tests.mk include exists" || (echo "getting tests.mk from github.com" && curl -sO https://raw.githubusercontent.com/spacetab-io/makefiles/master/golang/tests.mk)

tests: tests_include_check
@make -f tests.mk go_tests
.PHONY: tests

tests_html: tests_include_check
@make -f tests.mk go_tests_html
.PHONY: tests_html

## TESTS stuff end
# ----
28 changes: 28 additions & 0 deletions application_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cfgstructs

import (
"fmt"
)

type ApplicationInfo struct {
ID int64 `json:"id,omitempty"`
Alias string `json:"alias"`
Name string `json:"name"`
About string `json:"about"`
Version string `json:"version"`
Docs string `json:"docs"`
Contacts string `json:"contacts"`
Copyright string `json:"copyright"`
}

func (i ApplicationInfo) GetString() string {
return fmt.Sprintf("%s %s [%s] %s", i.Name, i.Version, i.Alias, i.Copyright)
}

func (i ApplicationInfo) GetAlias() string {
return i.Alias
}

func (i ApplicationInfo) GetVersion() string {
return i.Version
}
20 changes: 20 additions & 0 deletions configuration/defaults/database.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
defaults:
database:
driver: postgres
host: 127.0.0.1
port: 5432
schema: public
user: postgres
pass: ""
database: ""
ssl_mode: disable
log_level: error
migrations:
run_on_start: false
path: ./migrations/
seeding:
run_on_start: false
seeds: [ ]
max_open_connections: 10
max_idle_connections: 0
connection_lifetime: 30m
12 changes: 12 additions & 0 deletions configuration/defaults/logs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defaults:
logs:
type: zerolog
format: text
level: trace
no_color: false
caller:
hide_caller: false
skip_frames: 2
sentry:
enable: false
dsn: ""
22 changes: 22 additions & 0 deletions configuration/defaults/webserver.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defaults:
webserver:
host: 0.0.0.0 # The host ip that webserver is listening to. By default - all.
port: 8080 # The port that webserver is listening to
cors:
enabled: false
allow_all_origins: true # allow *
lifetime: 12h
allow_methods: [ "GET", "POST", "PUT", "PATCH", "DELETE" ]
allow_headers: [ "Origin", "Content-Length", "Content-Type", "Authorization" ]
allow_credentials: false
timeouts:
read_header: 10s
read_request: 10s
write_response: 60s
idle: 60s
shutdown: 5s
requests_and_connections:
max_conn_per_ip: 200
max_req_per_conn: 500
compress: true
debug: true
162 changes: 162 additions & 0 deletions database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package cfgstructs

import (
"errors"
"fmt"
"net"
"strings"
"time"
)

const (
connMaxLifeTime = 30 * time.Minute
maxOpenConn = 4
defaultSchema = "public"
cfgDBPrefix = "[config/database]"
cfgValidationErrorFormat = "%s: %w - %s"
)

type SeedingCfg struct {
RunOnStart bool `yaml:"run_on_start"`
Seeds []string `yaml:"seeds"`
}

type MigrationCfg struct {
RunOnStart bool `yaml:"run_on_start"`
TableName string `yaml:"table_name"`
Path string `yaml:"path"`
}

type Database struct {
Driver string `yaml:"driver"`
Host string `yaml:"host"`
Port uint `yaml:"port"`
User string `yaml:"user"`
Pass string `yaml:"pass"`
Schema string `yaml:"schema"`
Name string `yaml:"database"`
SSLMode string `yaml:"ssl_mode"`
LogLevel string `yaml:"log_level"`
Seeding SeedingCfg `yaml:"seeding"`
Migrations MigrationCfg `yaml:"migrations"`
MaxOpenConnections int `yaml:"max_open_connections"`
MaxIdleConnections int `yaml:"max_idle_connections"`
ConnectionLifeTime time.Duration `yaml:"connection_lifetime"`
}

func (d *Database) GetConnectionURL() string {
return fmt.Sprintf(
"%s://%s:%s@%s:%d/%s?search_path=%s&sslmode=%s",
d.Driver,
d.User,
d.Pass,
d.Host,
d.Port,
d.Name,
d.Schema,
d.SSLMode,
)
}

func (d *Database) GetDSN() string {
if d.Driver != "postgres" {
return d.GetConnectionURL()
}

return fmt.Sprintf(
"host=%s port=%d search_path=%s dbname=%s user=%s password=%s sslmode=%s",
d.Host,
d.Port,
d.Schema,
d.Name,
d.User,
d.Pass,
d.SSLMode,
)
}

func (d *Database) GetMigrationDSN() string {
return fmt.Sprintf("%s&x-migrations-table=migrations", d.GetDSN())
}

func (d *Database) GetMigrationsPath() string {
return fmt.Sprintf("file://%s", d.Migrations.Path)
}

func (d Database) GetMigrationsTableName() string {
return d.Migrations.TableName
}

func (d Database) GetSchema() string {
return d.Schema
}

var (
ErrDataIsEmpty = errors.New("data is empty")
ErrDataIsInvalid = errors.New("data is invalid")
)

func (d *Database) Validate() []error {
errList := make([]error, 0)

d.Driver = strings.TrimSpace(d.Driver)
switch d.Driver {
case "postgres", "mysql":
break
case "":
errList = append(errList, fmt.Errorf(cfgValidationErrorFormat, cfgDBPrefix, ErrDataIsEmpty, "driver"))
default:
errList = append(errList, fmt.Errorf(
cfgValidationErrorFormat,
cfgDBPrefix,
ErrDataIsEmpty,
"driver is unknown. only 'postgres' and 'mysql' are well-known",
))
}

d.User = strings.TrimSpace(d.User)
if d.User == "" {
errList = append(errList, fmt.Errorf(cfgValidationErrorFormat, cfgDBPrefix, ErrDataIsEmpty, "user"))
}

// d.Password = strings.TrimSpace(d.Password)
// if d.Password == "" {
// errList = append(errList, fmt.Errorf(cfgDBPrefix, "password is empty"))
// }

d.Host = strings.TrimSpace(d.Host)
if d.Host == "" {
errList = append(errList, fmt.Errorf(cfgValidationErrorFormat, cfgDBPrefix, ErrDataIsEmpty, "host"))
} else if _, err := net.LookupHost(d.Host); err != nil {
errList = append(errList, fmt.Errorf(cfgValidationErrorFormat, cfgDBPrefix, err, "host resolve error"))
}

if d.Port == 0 || d.Port > 70000 {
errList = append(errList, fmt.Errorf(cfgValidationErrorFormat, cfgDBPrefix, ErrDataIsInvalid, "port"))
}

d.Schema = strings.TrimSpace(d.Schema)
if d.Schema == "" {
d.Schema = defaultSchema
}

d.Name = strings.TrimSpace(d.Name)
if d.Name == "" {
errList = append(errList, fmt.Errorf(cfgValidationErrorFormat, cfgDBPrefix, ErrDataIsEmpty, "db name"))
}

if d.ConnectionLifeTime == 0 {
d.ConnectionLifeTime = connMaxLifeTime
}

if d.MaxOpenConnections == 0 {
d.MaxOpenConnections = maxOpenConn
}

d.Migrations.Path = strings.TrimSpace(d.Migrations.Path)
if len(d.Migrations.Path) == 0 {
errList = append(errList, fmt.Errorf(cfgValidationErrorFormat, cfgDBPrefix, ErrDataIsEmpty, "migrations_path"))
}

return errList
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/spacetab-io/configuration-structs-go

go 1.16
30 changes: 30 additions & 0 deletions interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cfgstructs

type Config interface {
ValidateAll() []error
}

type Configurator interface {
Validate() []error
}

type ApplicationInfoCfgInterface interface {
GetString() string
GetAlias() string
GetVersion() string
}

type DatabaseCfgInterface interface {
GetConnectionURL() string
GetDSN() string
GetMigrationDSN() string
GetMigrationsPath() string

GetSchema() string
GetMigrationsTableName() string
}

type NSQQueueCfgInterface interface {
GetNSQLookupdPath() string
GetNSQdPath() string
}
28 changes: 28 additions & 0 deletions queue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cfgstructs

import (
"fmt"
)

type NSQQueue struct {
Enable bool `yaml:"enable"`
LogLevel string `yaml:"log_level"`
LookupdHost string `yaml:"lookupd_host"`
LookupdPort int `yaml:"lookupd_port"`
NsqdPort int `yaml:"nsqd_port"`
NsqdHost string `yaml:"nsqd_host"`
MaxInFlight int `yaml:"max_in_flight"`
MaxAttempts *uint16 `yaml:"max_attempts"`
}

type MessageQueue struct {
Nsq NSQQueue `yaml:"nsq"`
}

func (s NSQQueue) GetNSQLookupdPath() string {
return fmt.Sprintf("%s:%v", s.LookupdHost, s.LookupdPort)
}

func (s NSQQueue) GetNSQdPath() string {
return fmt.Sprintf("%s:%v", s.NsqdHost, s.NsqdPort)
}
7 changes: 7 additions & 0 deletions service_name.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package cfgstructs

type ServiceName string

func (n ServiceName) String() string {
return string(n)
}
Loading

0 comments on commit 7b19788

Please sign in to comment.