Skip to content
This repository has been archived by the owner on Nov 5, 2019. It is now read-only.

Commit

Permalink
refactor config
Browse files Browse the repository at this point in the history
  • Loading branch information
b5 committed May 25, 2017
1 parent cd1a055 commit 81bf09d
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 82 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
config.*.json
archivers-api
gin-bin
*.env
1 change: 1 addition & 0 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
)

// Proxied User model. The real user model is in github.com/archivers-space/identity/user.go
type User struct {
Id string `json:"id" sql:"id"`
Created int64 `json:"created" sql:"created"`
Expand Down
89 changes: 18 additions & 71 deletions config.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package main

import (
"encoding/json"
"fmt"
"io/ioutil"
conf "github.com/archivers-space/config"
"os"
"path/filepath"
"strings"
)

// server modes
Expand All @@ -18,13 +16,12 @@ const (

// config holds all configuration for the server. It pulls from three places (in order):
// 1. environment variables
// 2. config.[server_mode].json <- eg: config.test.json
// 3. config.json
// 2. .[MODE].env OR .env
//
// env variables win, but can only set config who's json is ALL_CAPS
// it's totally fine to not have, say, config.develop.json defined, and just
// rely on a base config.json. But if you're in production mode & config.production.json
// exists, that will be read *instead* of config.json.
// globally-set env variables win.
// it's totally fine to not have, say, .env.develop defined, and just
// rely on a base ".env" file. But if you're in production mode & ".env.production"
// exists, that will be read *instead* of .env
//
// configuration is read at startup and cannot be alterd without restarting the server.
type config struct {
Expand Down Expand Up @@ -69,23 +66,13 @@ type config struct {
func initConfig(mode string) (cfg *config, err error) {
cfg = &config{}

if err := loadConfigFile(mode, cfg); err != nil {
return cfg, err
if path := configFilePath(mode, cfg); path != "" {
logger.Printf("loading config file: %s", filepath.Base(path))
conf.Load(cfg, path)
} else {
conf.Load(cfg)
}

// override config settings with env settings, passing in the current configuration
// as the default. This has the effect of leaving the config.json value unchanged
// if the env variable is empty
cfg.Gopath = readEnvString("GOPATH", cfg.Gopath)
cfg.Port = readEnvString("PORT", cfg.Port)
cfg.UrlRoot = readEnvString("URL_ROOT", cfg.UrlRoot)
cfg.PublicKey = readEnvString("PUBLIC_KEY", cfg.PublicKey)
cfg.TLS = readEnvBool("TLS", cfg.TLS)
cfg.AllowedOrigins = readEnvStringSlice("ALLOWED_ORIGINS", cfg.AllowedOrigins)
cfg.CertbotResponse = readEnvString("CERTBOT_RESPONSE", cfg.CertbotResponse)
cfg.AnalyticsToken = readEnvString("ANALYTICS_TOKEN", cfg.AnalyticsToken)
cfg.PostgresDbUrl = readEnvString("POSTGRES_DB_URL", cfg.PostgresDbUrl)

// make sure port is set
if cfg.Port == "" {
cfg.Port = "8080"
Expand All @@ -103,30 +90,6 @@ func packagePath(path string) string {
return filepath.Join(os.Getenv("GOPATH"), "src/github.com/archivers-space/archivers-api", path)
}

// readEnvString reads key from the environment, returns def if empty
func readEnvString(key, def string) string {
if env := os.Getenv(key); env != "" {
return env
}
return def
}

// readEnvBool read key form the env, converting to a boolean value. returns def if empty
func readEnvBool(key string, def bool) bool {
if env := os.Getenv(key); env != "" {
return env == "true" || env == "TRUE" || env == "t"
}
return def
}

// readEnvString reads a slice of strings from key environment var, returns def if empty
func readEnvStringSlice(key string, def []string) []string {
if env := os.Getenv(key); env != "" {
return strings.Split(env, ",")
}
return def
}

// requireConfigStrings panics if any of the passed in values aren't set
func requireConfigStrings(values map[string]string) error {
for key, value := range values {
Expand All @@ -138,33 +101,17 @@ func requireConfigStrings(values map[string]string) error {
return nil
}

// checks for config.[mode].json file to read configuration from if the file exists
// defaults to config.json, silently fails if no configuration file is present.
func loadConfigFile(mode string, cfg *config) (err error) {
var data []byte

fileName := packagePath(fmt.Sprintf("config.%s.json", mode))
// checks for .[mode].env file to read configuration from if the file exists
// defaults to .env, returns "" if no file is present
func configFilePath(mode string, cfg *config) string {
fileName := packagePath(fmt.Sprintf(".%s.env", mode))
if !fileExists(fileName) {
fileName = packagePath("config.json")
fileName = packagePath(".env")
if !fileExists(fileName) {
return nil
return ""
}
}

logger.Printf("reading config file: %s", fileName)
data, err = ioutil.ReadFile(fileName)
if err != nil {
err = fmt.Errorf("error reading %s: %s", fileName, err)
return
}

// unmarshal ("decode") config data into a config struct
if err = json.Unmarshal(data, cfg); err != nil {
err = fmt.Errorf("error parsing %s: %s", fileName, err)
return
}

return
return fileName
}

// Does this file exist?
Expand Down
10 changes: 0 additions & 10 deletions config.json

This file was deleted.

17 changes: 16 additions & 1 deletion server.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ var (
appDB *sql.DB
)

// NewServerRoutes returns a Muxer that has all API routes.
// This makes for easy testing using httptest, see server_test.go
func NewServerRoutes() *http.ServeMux {
m := http.NewServeMux()

Expand All @@ -27,31 +29,41 @@ func NewServerRoutes() *http.ServeMux {

// m.Handle("/v0/users", middleware(UserHandler))
// m.Handle("/v0/users/", middleware(UsersHandler))

m.Handle("/v0/primers", middleware(PrimersHandler))
m.Handle("/v0/primers/", middleware(PrimerHandler))

m.Handle("/v0/sources", middleware(SourcesHandler))
m.Handle("/v0/sources/", middleware(SourceHandler))

m.Handle("/v0/urls", middleware(UrlsHandler))
m.Handle("/v0/urls/", middleware(UrlHandler))

m.Handle("/v0/uncrawlables", middleware(UncrawlablesHandler))
m.Handle("/v0/uncrawlables/", middleware(UncrawlableHandler))

// m.Handle("/v0/links", middleware(UrlHandler))
// m.Handle("/v0/links/", middleware(UrlsHandler))

// m.Handle("/v0/snapshots", middleware())
// m.Handle("/v0/snapshots/", middleware())

// m.Handle("/v0/content", middleware())
// m.Handle("/v0/content/", middleware())

// m.Handle("/v0/metadata", middleware())
// m.Handle("/v0/metadata/", middleware())

// m.Handle("/v0/consensus", middleware())
// m.Handle("/v0/consensus/", middleware())

// m.Handle("/v0/collections", middleware())
// m.Handle("/v0/collections/", middleware())

return m
}

// main app entry point
func main() {
var err error
cfg, err = initConfig(os.Getenv("GOLANG_ENV"))
Expand All @@ -60,10 +72,13 @@ func main() {
panic(fmt.Errorf("server configuration error: %s", err.Error()))
}

// TODO - run this in a goroutine & support reporting "oh snap no DB"
// while waiting for a connection
connectToAppDb()

// base server
s := &http.Server{}
// connect mux to server
// connect mux routes to server
s.Handler = NewServerRoutes()

// print notable config settings
Expand Down
4 changes: 4 additions & 0 deletions transports.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (
"golang.org/x/crypto/acme/autocert"
)

// StartServer interprets info from config to start the server
// if config.TLS == true it'll spin up an https server using LetsEncrypt
// that should work just fine on the raw internet (ie not behind a proxy like nginx etc)
// it'll also redirect http traffic to it's https route counterpart if port 80 is open
func StartServer(c *config, s *http.Server) error {
s.Addr = fmt.Sprintf(fmt.Sprintf(":%s", c.Port))

Expand Down

0 comments on commit 81bf09d

Please sign in to comment.