change up database configuration to use discrete values for parameters, rather than the raw DSN (database/base.go computes the DSN)

This commit is contained in:
2026-03-12 16:59:19 -06:00
parent 2cc0d0f94d
commit a91202a57e
6 changed files with 54 additions and 42 deletions
+13 -3
View File
@@ -71,6 +71,16 @@ MySQL server, use that.)
Ensure a user in your database is granted SELECT, INSERT, UPDATE, and DELETE privileges to all tables in your new database.
The database URL for this database can be specified on the Amsterdam command line with the `-d` or `--database` parameters,
or with the `AMSTERDAM_DATABASE_URL` environment variable. The URL is specified as `mysql:dsn`, where "dsn" is the complete
datasource name (`user:password@tcp(hostname)/amsterdam?parseTime=true&loc=UTC`).
The database may be specified to Amsterdam with the following command line options or environment variables:
* Host name: Command line options `-t` or `--database-host`, or environment variable `AMSTERDAM_DATABASE_HOST`
* User name: Command line options `-u` or `--database-user`, or environment variable `AMSTERDAM_DATABASE_USER`
* Password: Command line options `-p` or `--database-password`, or environment variable `AMSTERDAM_DATABASE_PASSWORD`
* Database name: Command line options `-d` or `--database-name`, or environment variable `AMSTERDAM_DATABASE_NAME`
All these options may also be specified via the configuration file (see below).
Amsterdam also requires access to a local SMTP server, as it sends out E-mail messages such as account verification,
password reminders, subscribed posts, and messages from conference or community hosts. It may be specified to Amsterdam
with the following command line options or environment variables:
+22 -27
View File
@@ -19,8 +19,8 @@ import (
"os"
"path/filepath"
"reflect"
"strings"
"git.erbosoft.com/amy/amsterdam/util"
argparse "github.com/alexflint/go-arg"
"github.com/dustin/go-humanize"
log "github.com/sirupsen/logrus"
@@ -45,8 +45,11 @@ type AmCLI struct {
Debug bool `arg:"-D,--debug,env:AMSTERDAM_DEBUG" help:"Force Amsterdam to run in debug mode."`
LogLevel string `arg:"-L,--level,--loglevel,env:AMSTERDAM_LOG_LEVEL" help:"Set the log level for the server."`
Production bool `arg:"-P,--production,env:AMSTERDAM_PROD" help:"Force Amsterdam to run in production mode."`
DatabaseURL string `arg:"-d,--database,env:AMSTERDAM_DATABASE_URL" help:"Database URL for Amsterdam to connect to."`
Listen string `arg:"-l,--listen,env:AMSTERDAM_LISTEN" help:"Specifies the local address and port for Amsterdam to listen on."`
DatabaseName string `arg:"-d,--database-name,env:AMSTERDAM_DATABASE_NAME" help:"Database name to use on the database server."`
Listen string `arg:"-l,--listen,env:AMSTERDAM_LISTEN" help:"The local address and port for Amsterdam to listen on."`
DatabasePassword string `arg:"-p,--database-password,env:AMSTERDAM_DATABASE_PASSWORD" help:"Password for the database server."`
DatabaseHost string `arg:"-t,--database-host,env:AMSTERDAM_DATABASE_HOST" help:"Hostname for the database server."`
DatabaseUser string `arg:"-u,--database-user,env:AMSTERDAM_DATABASE_USER" help:"User name for the database server."`
DebugPanic bool `arg:"--debug-panic" help:"Development Only - disable Echo panic recovery"`
BuggyAttachments bool `arg:"--buggy-attachments" help:"Some attachments may be buggy - truncate data if necessary"`
}
@@ -101,8 +104,11 @@ type AmConfig struct {
} `yaml:"rateLimit"`
} `yaml:"site"`
Database struct {
Driver string `yaml:"driver"`
Dsn string `yaml:"dsn"`
Driver string `yaml:"driver"`
HostName string `yaml:"hostName"`
User string `yaml:"user"`
Password string `yaml:"password"`
DatabaseName string `yaml:"databaseName"`
} `yaml:"database"`
Defaults struct {
Language string `yaml:"language"`
@@ -191,7 +197,10 @@ type AmConfigComputed struct {
LogLevel string // the logging level
Listen string // listen address
DatabaseDriver string // name of database driver
DatabaseDSN string // DSN for the database
DatabaseHost string // hostname for database
DatabaseUser string // user name for database
DatabasePassword string // password for database
DatabaseName string // database name
UploadMaxSize int32 // maximum upload size in bytes
UploadNoCompress map[string]bool // which upload types are not compressed?
}
@@ -361,27 +370,13 @@ func SetupConfig() {
} else {
GlobalComputedConfig.DebugMode = !GlobalConfig.Site.Production
}
if CommandLine.LogLevel != "" {
GlobalComputedConfig.LogLevel = CommandLine.LogLevel
} else {
GlobalComputedConfig.LogLevel = GlobalConfig.Logging.LogLevel
}
if CommandLine.Listen != "" {
GlobalComputedConfig.Listen = CommandLine.Listen
} else {
GlobalComputedConfig.Listen = GlobalConfig.Site.Listen
}
if CommandLine.DatabaseURL != "" {
p := strings.Index(CommandLine.DatabaseURL, ":")
if p < 0 {
panic("Invalid database URL on command line")
}
GlobalComputedConfig.DatabaseDriver = CommandLine.DatabaseURL[:p]
GlobalComputedConfig.DatabaseDSN = CommandLine.DatabaseURL[p+1:]
} else {
GlobalComputedConfig.DatabaseDriver = GlobalConfig.Database.Driver
GlobalComputedConfig.DatabaseDSN = GlobalConfig.Database.Dsn
}
GlobalComputedConfig.LogLevel = util.IIF(CommandLine.LogLevel != "", CommandLine.LogLevel, GlobalConfig.Logging.LogLevel)
GlobalComputedConfig.Listen = util.IIF(CommandLine.Listen != "", CommandLine.Listen, GlobalConfig.Site.Listen)
GlobalComputedConfig.DatabaseDriver = GlobalConfig.Database.Driver // FUTURE: allow configuration
GlobalComputedConfig.DatabaseHost = util.IIF(CommandLine.DatabaseHost != "", CommandLine.DatabaseHost, GlobalConfig.Database.HostName)
GlobalComputedConfig.DatabaseUser = util.IIF(CommandLine.DatabaseUser != "", CommandLine.DatabaseUser, GlobalConfig.Database.User)
GlobalComputedConfig.DatabasePassword = util.IIF(CommandLine.DatabasePassword != "", CommandLine.DatabasePassword, GlobalConfig.Database.Password)
GlobalComputedConfig.DatabaseName = util.IIF(CommandLine.DatabaseName != "", CommandLine.DatabaseName, GlobalConfig.Database.DatabaseName)
tmp, err := humanize.ParseBytes(GlobalConfig.Posting.Uploads.MaxSize)
if err != nil {
panic(err.Error())
+4 -1
View File
@@ -36,7 +36,10 @@ site:
expireMinutes: 3
database:
driver: "mysql"
dsn: "amsdb:x00yes2k@tcp(localhost)/amsterdam?parseTime=true&loc=UTC"
hostName: "localhost"
user: "amsdb"
password: "x00yes2k"
databaseName: "amsterdam"
defaults:
language: "en-US"
timezone: "America/Denver"
+11 -1
View File
@@ -11,6 +11,7 @@ package database
import (
"context"
"fmt"
"slices"
"git.erbosoft.com/amy/amsterdam/config"
@@ -22,10 +23,19 @@ import (
// amdb is the reference to the Amsterdam database.
var amdb *sqlx.DB
// buildMysqlDSN builds the MySQL DSN for the driver.
func buildMysqlDSN() string {
return fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true&loc=UTC",
config.GlobalComputedConfig.DatabaseUser,
config.GlobalComputedConfig.DatabasePassword,
config.GlobalComputedConfig.DatabaseHost,
config.GlobalComputedConfig.DatabaseName)
}
// SetupDb sets up the database and associated items.
func SetupDb() (func(), error) {
exitfns := make([]func(), 0, 2)
db, err := sqlx.Connect(config.GlobalComputedConfig.DatabaseDriver, config.GlobalComputedConfig.DatabaseDSN)
db, err := sqlx.Connect(config.GlobalComputedConfig.DatabaseDriver, buildMysqlDSN())
if err == nil {
amdb = db
g, err := AmGlobals(context.Background())
+1 -1
View File
@@ -321,7 +321,7 @@ func setupTemplates() {
views.AddGlobalFunc("DisplayExpandCat", displayExpandCat)
views.AddGlobalFunc("GetCountryList", func(jet.Arguments) reflect.Value {
return reflect.ValueOf(util.AmCountryList())
return reflect.ValueOf(util.AmCountryList(config.GlobalConfig.Rendering.CountryList.Prioritize))
})
views.AddGlobalFunc("GetLanguageList", func(jet.Arguments) reflect.Value {
return reflect.ValueOf(util.AmLanguageList())
+3 -9
View File
@@ -15,7 +15,6 @@ import (
"strings"
"sync"
"git.erbosoft.com/amy/amsterdam/config"
"github.com/biter777/countries"
)
@@ -26,7 +25,7 @@ var cachedCountryList []countries.CountryCode = nil
var countryListMutex sync.Mutex
// AmCountryList is a wrapper around countries.All() that sorts it by country name.
func AmCountryList() []countries.CountryCode {
func AmCountryList(prioritize string) []countries.CountryCode {
countryListMutex.Lock()
defer countryListMutex.Unlock()
if cachedCountryList == nil {
@@ -34,9 +33,9 @@ func AmCountryList() []countries.CountryCode {
slices.SortFunc(countryList, func(a countries.CountryCode, b countries.CountryCode) int {
return strings.Compare(a.Info().Name, b.Info().Name)
})
if config.GlobalConfig.Rendering.CountryList.Prioritize != "" {
if prioritize != "" {
for i, c := range countryList {
if c.Info().Alpha2 == config.GlobalConfig.Rendering.CountryList.Prioritize {
if c.Info().Alpha2 == prioritize {
newList := make([]countries.CountryCode, len(countryList))
newList[0] = c
copy(newList[1:], countryList[:i])
@@ -49,8 +48,3 @@ func AmCountryList() []countries.CountryCode {
}
return cachedCountryList
}
// init preloads the country list.
func init() {
go AmCountryList()
}