Skip to content

Commit

Permalink
add a configuration struct for runtime config options
Browse files Browse the repository at this point in the history
  • Loading branch information
lsymds committed May 13, 2024
1 parent e60cc6b commit a4ba0ff
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 30 deletions.
Binary file added file=shareasecret.db
Binary file not shown.
Binary file added file=shareasecret.db-shm
Binary file not shown.
Binary file added file=shareasecret.db-wal
Binary file not shown.
50 changes: 47 additions & 3 deletions internal/shareasecret/shareasecret.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package shareasecret

import (
"errors"
"fmt"
"io/fs"
"net/http"
"os"

"github.com/joho/godotenv"
)

// deletionReasonExpired is a deletion reason used when secrets have exceeded their TTL (time to live)
Expand All @@ -16,6 +20,46 @@ const deletionReasonUserDeleted = "user_deleted"
// hit or exceeded
const deletionReasonMaximumViewCountHit = "maximum_view_count_hit"

// Configuration contains all of the possible configuration options for the application.
type Configuration struct {
Database struct {
Path string
}
Server struct {
BaseUrl string
ListeningAddr string
}
SecretCreationRestrictions struct {
IPAddresses []string
}
}

// PopulateFromEnv populates all of the configuration values from environment variables, returning errors if this
// cannot be achieved.
func (c *Configuration) PopulateFromEnv() error {
err := godotenv.Load()
if err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("loading env file: %w", err)
}

c.Database.Path = os.Getenv("SHAREASECRET_DB_PATH")
if c.Database.Path == "" {
return fmt.Errorf("SHAREASECRET_DB_PATH not set")
}

c.Server.BaseUrl = os.Getenv("SHAREASECRET_BASE_URL")
if c.Server.BaseUrl == "" {
return fmt.Errorf("SHAREASECRET_BASE_URL not set")
}

c.Server.ListeningAddr = os.Getenv("SHAREASECRET_LISTENING_ADDR")
if c.Server.ListeningAddr == "" {
c.Server.ListeningAddr = "127.0.0.1:8994"
}

return nil
}

// Application is a wrapper/container for the "ShareASecret" project. All jobs and entry points hang off of this
// struct.
type Application struct {
Expand All @@ -26,16 +70,16 @@ type Application struct {
}

// NewApplication initializes the Application struct which provides access to all available components of the project.
func NewApplication(connectionString string, baseURL string, webAssets fs.FS) (*Application, error) {
db, err := newDatabase(connectionString)
func NewApplication(config *Configuration, webAssets fs.FS) (*Application, error) {
db, err := newDatabase("file:" + config.Database.Path)
if err != nil {
return nil, fmt.Errorf("new db: %w", err)
}

application := &Application{
db: db,
router: http.NewServeMux(),
baseURL: baseURL,
baseURL: config.Server.BaseUrl,
webAssets: webAssets,
}
application.mapRoutes()
Expand Down
6 changes: 5 additions & 1 deletion internal/shareasecret/shareasecret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import (
var app *Application

func TestMain(m *testing.M) {
a, err := NewApplication("file:shareasecret_test.db", "http://127.0.0.1:8999", os.DirFS("../web/"))
config := &Configuration{}
config.Database.Path = "shareasecret_test.db"
config.Server.BaseUrl = "http://127.0.0.1:8999"

a, err := NewApplication(config, os.DirFS("../web/"))
if err != nil {
panic(err)
}
Expand Down
33 changes: 7 additions & 26 deletions shareasecret.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ package main

import (
"embed"
"errors"
"io/fs"
"net/http"
"os"

"github.com/joho/godotenv"
"github.com/lsymds/shareasecret/internal/shareasecret"
"github.com/rs/zerolog/log"
)
Expand All @@ -23,28 +21,11 @@ var version string = "0.0.1"
func main() {
log.Info().Str("version", version).Msg("starting shareasecret")

// extract any required environment variables
err := godotenv.Load()
if err != nil && !errors.Is(err, os.ErrNotExist) {
log.Error().Err(err).Msg("loading .env file")
os.Exit(1)
}

dbPath := os.Getenv("SHAREASECRET_DB_PATH")
if dbPath == "" {
log.Error().Msg("SHAREASECRET_DB_PATH not set")
os.Exit(1)
}
config := &shareasecret.Configuration{}

baseUrl := os.Getenv("SHAREASECRET_BASE_URL")
if baseUrl == "" {
log.Error().Msg("SHAREASECRET_BASE_URL not set")
os.Exit(1)
}

listeningAddr := os.Getenv("SHAREASECRET_LISTENING_ADDR")
if listeningAddr == "" {
listeningAddr = "127.0.0.1:8994"
err := config.PopulateFromEnv()
if err != nil {
log.Error().Err(err).Msg("populating configuration")
}

webAssets, err := fs.Sub(embeddedWebAssets, "web")
Expand All @@ -54,7 +35,7 @@ func main() {
}

// initialize the wrapper application
application, err := shareasecret.NewApplication("file:"+dbPath, baseUrl, webAssets)
application, err := shareasecret.NewApplication(config, webAssets)
if err != nil {
log.Error().Err(err).Msg("initializing application")
os.Exit(1)
Expand All @@ -64,8 +45,8 @@ func main() {
application.RunDeleteExpiredSecretsJob()

// serve all HTTP endpoints
log.Info().Str("addr", listeningAddr).Msg("booting HTTP server")
err = http.ListenAndServe(listeningAddr, application)
log.Info().Str("addr", config.Server.ListeningAddr).Msg("booting HTTP server")
err = http.ListenAndServe(config.Server.ListeningAddr, application)
if err != nil {
log.Error().Err(err).Msg("listen and serve")
os.Exit(1)
Expand Down

0 comments on commit a4ba0ff

Please sign in to comment.