Skip to content
This repository has been archived by the owner on Aug 28, 2023. It is now read-only.

Commit

Permalink
TOML config (#29)
Browse files Browse the repository at this point in the history
Implement TOML-based configuration
Resolves #22
  • Loading branch information
romshark authored May 29, 2019
1 parent ee091ed commit d97b721
Show file tree
Hide file tree
Showing 52 changed files with 4,347 additions and 369 deletions.
12 changes: 12 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 22 additions & 22 deletions api/apiServer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"sync"

"github.com/pkg/errors"
"github.com/romshark/dgraph_graphql_go/api/config"
"github.com/romshark/dgraph_graphql_go/api/graph"
"github.com/romshark/dgraph_graphql_go/api/options"
"github.com/romshark/dgraph_graphql_go/api/transport"
"github.com/romshark/dgraph_graphql_go/api/validator"
"github.com/romshark/dgraph_graphql_go/store"
Expand All @@ -29,7 +29,7 @@ type Server interface {
}

type server struct {
opts options.ServerOptions
conf *config.ServerConfig
store store.Store
graph *graph.Graph
debugSessionKey []byte
Expand All @@ -38,15 +38,15 @@ type server struct {
}

// NewServer creates a new API server instance
func NewServer(opts options.ServerOptions) (Server, error) {
if err := opts.Prepare(); err != nil {
return nil, fmt.Errorf("options: %s", err)
func NewServer(conf *config.ServerConfig) (Server, error) {
if err := conf.Prepare(); err != nil {
return nil, fmt.Errorf("config: %s", err)
}

// Initialize validator
validator, err := validator.NewValidator(
opts.Mode == options.ModeProduction,
validator.Options{
conf.Mode == config.ModeProduction,
validator.Config{
PasswordLenMin: 6,
PasswordLenMax: 256,
EmailLenMax: 96,
Expand All @@ -66,22 +66,22 @@ func NewServer(opts options.ServerOptions) (Server, error) {

// Initialize store instance
store := dgraph.NewStore(
opts.DBHost,
conf.DBHost,

// Compare password
func(hash, password string) bool {
return opts.PasswordHasher.Compare([]byte(hash), []byte(password))
return conf.PasswordHasher.Compare([]byte(hash), []byte(password))
},

opts.DebugLog,
opts.ErrorLog,
conf.DebugLog,
conf.ErrorLog,
)

graph, err := graph.New(
store,
validator,
opts.SessionKeyGenerator,
opts.PasswordHasher,
conf.SessionKeyGenerator,
conf.PasswordHasher,
)
if err != nil {
return nil, errors.Wrap(err, "graph init")
Expand All @@ -90,37 +90,37 @@ func NewServer(opts options.ServerOptions) (Server, error) {
// Initialize API server instance
newSrv := &server{
store: store,
opts: opts,
conf: conf,
graph: graph,
transports: opts.Transport,
transports: conf.Transport,
shutdownAwaitBlocker: &sync.WaitGroup{},
}

// Initialize transports
for _, transport := range opts.Transport {
for _, transport := range conf.Transport {
if err := transport.Init(
newSrv.onGraphQuery,
newSrv.onAuth,
newSrv.onDebugAuth,
newSrv.onDebugSess,
opts.DebugLog,
opts.ErrorLog,
conf.DebugLog,
conf.ErrorLog,
); err != nil {
return nil, err
}
}
opts.DebugLog.Print("all transports initialized")
conf.DebugLog.Print("all transports initialized")

// Generate the debug user session key if the debug user is enabled
if opts.DebugUser.Status != options.DebugUserDisabled {
newSrv.debugSessionKey = []byte(opts.SessionKeyGenerator.Generate())
if conf.DebugUser.Mode != config.DebugUserDisabled {
newSrv.debugSessionKey = []byte(conf.SessionKeyGenerator.Generate())
}

return newSrv, nil
}

func (srv *server) logErrf(format string, v ...interface{}) {
srv.opts.ErrorLog.Printf(format, v...)
srv.conf.ErrorLog.Printf(format, v...)
}

// Launch implements the Server interface
Expand Down
40 changes: 20 additions & 20 deletions api/options/options_test.go → api/config/config_test.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
package options_test
package config_test

import (
"testing"

"github.com/romshark/dgraph_graphql_go/api/options"
"github.com/romshark/dgraph_graphql_go/api/config"
"github.com/romshark/dgraph_graphql_go/api/transport"
thttp "github.com/romshark/dgraph_graphql_go/api/transport/http"
"github.com/stretchr/testify/require"
)

func TestOptionsInvalid(t *testing.T) {
assumeErr := func(t *testing.T, opts options.ServerOptions) {
require.Error(t, opts.Prepare())
func TestConfigInvalid(t *testing.T) {
assumeErr := func(t *testing.T, conf config.ServerConfig) {
require.Error(t, conf.Prepare())
}

t.Run("noTransport", func(t *testing.T) {
assumeErr(t, options.ServerOptions{
Mode: options.ModeProduction,
assumeErr(t, config.ServerConfig{
Mode: config.ModeProduction,
Transport: []transport.Server{},
})
})

t.Run("production/debugUserEnabled", func(t *testing.T) {
debugUsrOptions := []options.DebugUserStatus{
options.DebugUserRW,
options.DebugUserReadOnly,
debugUserModes := []config.DebugUserMode{
config.DebugUserRW,
config.DebugUserReadOnly,
}
for _, debugUsrOption := range debugUsrOptions {
t.Run(string(debugUsrOption), func(t *testing.T) {
serverHTTP, err := thttp.NewServer(thttp.ServerOptions{
for _, debugUserMode := range debugUserModes {
t.Run(string(debugUserMode), func(t *testing.T) {
serverHTTP, err := thttp.NewServer(thttp.ServerConfig{
Host: "localhost:80",
TLS: &thttp.ServerTLS{
CertificateFilePath: "certfile",
Expand All @@ -39,28 +39,28 @@ func TestOptionsInvalid(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, serverHTTP)

assumeErr(t, options.ServerOptions{
Mode: options.ModeProduction,
assumeErr(t, config.ServerConfig{
Mode: config.ModeProduction,
Transport: []transport.Server{serverHTTP},
DebugUser: options.DebugUserOptions{
Status: debugUsrOption,
DebugUser: config.DebugUserConfig{
Mode: debugUserMode,
},
})
})
}
})

t.Run("production/nonTLSTransport", func(t *testing.T) {
serverHTTP, err := thttp.NewServer(thttp.ServerOptions{
serverHTTP, err := thttp.NewServer(thttp.ServerConfig{
Host: "localhost:80",
TLS: nil,
Playground: true,
})
require.NoError(t, err)
require.NotNil(t, serverHTTP)

assumeErr(t, options.ServerOptions{
Mode: options.ModeProduction,
assumeErr(t, config.ServerConfig{
Mode: config.ModeProduction,
Transport: []transport.Server{serverHTTP},
})
})
Expand Down
46 changes: 46 additions & 0 deletions api/config/debugUserConfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package config

import "errors"

// DebugUserConfig defines the API debug user configurations
type DebugUserConfig struct {
Mode DebugUserMode
Username string
Password string
}

// Prepares sets defaults and validates the configurations
func (conf *DebugUserConfig) Prepares(mode Mode) error {
// Set default debug user mode
if conf.Mode == DebugUserUnset {
switch mode {
case ModeProduction:
conf.Mode = DebugUserDisabled
case ModeBeta:
conf.Mode = DebugUserReadOnly
default:
conf.Mode = DebugUserRW
}
}

// Use "debug" as the default debug username
if conf.Username == "" {
conf.Username = "debug"
}

// Use "debug" as the default debug password
if conf.Password == "" {
conf.Password = "debug"
}

// VALIDATE

// Ensure the debug user isn't enabled in production mode
if mode == ModeProduction {
if conf.Mode != DebugUserDisabled {
return errors.New("debug user must be disabled in production mode")
}
}

return nil
}
35 changes: 35 additions & 0 deletions api/config/debugUserMode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package config

import "fmt"

// DebugUserMode represents a debug user mode
type DebugUserMode string

const (
// DebugUserUnset represents the default unset option value
DebugUserUnset DebugUserMode = ""

// DebugUserDisabled disables the debug user
DebugUserDisabled DebugUserMode = "disabled"

// DebugUserReadOnly enables the debug user in a read-only mode
DebugUserReadOnly DebugUserMode = "read-only"

// DebugUserRW enables the debug user in a read-write mode
DebugUserRW DebugUserMode = "read-write"
)

// Validate returns an error if the value is invalid
func (md DebugUserMode) Validate() error {
switch md {
case DebugUserUnset:
fallthrough
case DebugUserDisabled:
fallthrough
case DebugUserRW:
fallthrough
case DebugUserReadOnly:
return nil
}
return fmt.Errorf("invalid debug user mode: '%s'", md)
}
26 changes: 26 additions & 0 deletions api/config/duration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package config

import (
"fmt"
"reflect"
"time"
)

// Duration represents a duration
type Duration time.Duration

// UnmarshalTOML implements the TOML unmarshaler interface
func (v *Duration) UnmarshalTOML(val interface{}) error {
if str, isString := val.(string); isString {
dur, err := time.ParseDuration(str)
if err != nil {
return err
}
*v = Duration(dur)
return nil
}
return fmt.Errorf(
"unexpected duration value type: %s",
reflect.TypeOf(val),
)
}
Loading

0 comments on commit d97b721

Please sign in to comment.