Compare commits

...

9 commits

Author SHA1 Message Date
tsmethurst 1f38b68ad9 don't leave double newlines at end of generated file 2022-12-13 13:20:25 +01:00
tsmethurst 70f50383fe fix import 2022-12-13 13:20:14 +01:00
tsmethurst 2c3b79ac7a Merge branch 'main' into feature/sqlite-optimizations 2022-12-13 13:17:02 +01:00
kim 201a82e652 move database configs to separate namespaces, add sql pragma tuning
Signed-off-by: kim <grufwub@gmail.com>
2022-12-10 11:53:25 +00:00
kim 2a2c7e3978 move caches to sub-cache "gts" namespace, update envparsing, add cache config docs to example config
Signed-off-by: kim <grufwub@gmail.com>
2022-12-10 10:47:48 +00:00
kim d49e0a2ca6 set cache configuration in testrig
Signed-off-by: kim <grufwub@gmail.com>
2022-12-10 09:55:57 +00:00
kim 3091d4608d add cache configuration to config parse tests
Signed-off-by: kim <grufwub@gmail.com>
2022-12-09 22:10:15 +00:00
kim 9083772d03 update envparsing test
Signed-off-by: kim <grufwub@gmail.com>
2022-12-09 21:48:46 +00:00
kim d155c50491 update config generator to support nested structs, add cache configuration options
Signed-off-by: kim <grufwub@gmail.com>
2022-12-09 21:45:59 +00:00
10 changed files with 424 additions and 392 deletions

View file

@ -103,66 +103,136 @@ trusted-proxies:
- "127.0.0.1/32"
- "::1"
############################
##### DATABASE CONFIG ######
############################
database:
############################
##### DATABASE CONFIG ######
############################
# Config pertaining to the Gotosocial database connection
# Config pertaining to the Gotosocial database connection
# String. Database type.
# Options: ["postgres","sqlite"]
# Default: "postgres"
db-type: "postgres"
# String. Database type.
# Options: ["postgres","sqlite"]
# Default: "postgres"
type: "postgres"
# String. Database address or parameters.
#
# For Postgres, this should be the address or socket at which the database can be reached.
#
# For Sqlite, this should be the path to your sqlite database file. Eg., /opt/gotosocial/sqlite.db.
# If the file doesn't exist at the specified path, it will be created.
# If just a filename is provided (no directory) then the database will be created in the same directory
# as the GoToSocial binary.
# If address is set to :memory: then an in-memory database will be used (no file).
# WARNING: :memory: should NOT BE USED except for testing purposes.
#
# Examples: ["localhost","my.db.host","127.0.0.1","192.111.39.110",":memory:", "sqlite.db"]
# Default: ""
db-address: ""
# String. Database address or parameters.
#
# For Postgres, this should be the address or socket at which the database can be reached.
#
# For Sqlite, this should be the path to your sqlite database file. Eg., /opt/gotosocial/sqlite.db.
# If the file doesn't exist at the specified path, it will be created.
# If just a filename is provided (no directory) then the database will be created in the same directory
# as the GoToSocial binary.
# If address is set to :memory: then an in-memory database will be used (no file).
# WARNING: :memory: should NOT BE USED except for testing purposes.
#
# Examples: ["localhost","my.db.host","127.0.0.1","192.111.39.110",":memory:", "sqlite.db"]
# Default: ""
address: ""
# Int. Port for database connection.
# Examples: [5432, 1234, 6969]
# Default: 5432
db-port: 5432
postgres:
# Int. Port for database connection.
# Examples: [5432, 1234, 6969]
# Default: 5432
port: 5432
# String. Username for the database connection.
# Examples: ["mydbuser","postgres","gotosocial"]
# Default: ""
db-user: ""
# String. Username for the database connection.
# Examples: ["mydbuser","postgres","gotosocial"]
# Default: ""
duser: ""
# String. Password to use for the database connection
# Examples: ["password123","verysafepassword","postgres"]
# Default: ""
db-password: ""
# String. Password to use for the database connection
# Examples: ["password123","verysafepassword","postgres"]
# Default: ""
password: ""
# String. Name of the database to use within the provided database type.
# Examples: ["mydb","postgres","gotosocial"]
# Default: "gotosocial"
db-database: "gotosocial"
# String. Name of the database to use within the provided database type.
# Examples: ["mydb","postgres","gotosocial"]
# Default: "gotosocial"
database: "gotosocial"
# String. Disable, enable, or require SSL/TLS connection to the database.
# If "disable" then no TLS connection will be attempted.
# If "enable" then TLS will be tried, but the database certificate won't be checked (for self-signed certs).
# If "require" then TLS will be required to make a connection, and a valid certificate must be presented.
# Options: ["disable", "enable", "require"]
# Default: "disable"
db-tls-mode: "disable"
# String. Disable, enable, or require SSL/TLS connection to the database.
# If "disable" then no TLS connection will be attempted.
# If "enable" then TLS will be tried, but the database certificate won't be checked (for self-signed certs).
# If "require" then TLS will be required to make a connection, and a valid certificate must be presented.
# Options: ["disable", "enable", "require"]
# Default: "disable"
tls-mode: "disable"
# String. Path to a CA certificate on the host machine for db certificate validation.
# If this is left empty, just the host certificates will be used.
# If filled in, the certificate will be loaded and added to host certificates.
# Examples: ["/path/to/some/cert.crt"]
# Default: ""
db-tls-ca-cert: ""
# String. Path to a CA certificate on the host machine for db certificate validation.
# If this is left empty, just the host certificates will be used.
# If filled in, the certificate will be loaded and added to host certificates.
# Examples: ["/path/to/some/cert.crt"]
# Default: ""
tls-ca-cert: ""
sqlite:
# String. SQLite journaling mode.
# See: https://www.sqlite.org/pragma.html#pragma_journal_mode
journal-mode: "WAL"
# String. SQLite synchronous mode.
# See: https://www.sqlite.org/pragma.html#pragma_synchronous
synchronous: "FULL"
# Byte size. SQlite cache size.
# See: https://www.sqlite.org/pragma.html#pragma_cache_size
cache-size: "64MiB"
cache:
gts:
###########################
#### DATABASE CACHES ######
###########################
#
# Database cache configuration:
#
# Allows configuration of caches used
# when loading GTS models from the database.
#
# max-size = maximum cached objects count
# ttl = cached object lifetime
# sweep-freq = frequency to look for stale cache objects
account-max-size: 100
account-ttl: "5m"
account-sweep-freq: "10s"
block-max-size: 100
block-ttl: "5m"
block-sweep-freq: "10s"
domain-block-max-size: 1000
domain-block-ttl: "24h"
domain-block-sweep-freq: "1m"
emoji-max-size: 500
emoji-ttl: "5m"
emoji-sweep-freq: "10s"
emoji-category-max-size: 100
emoji-category-ttl: "5m"
emoji-category-sweep-freq: "10s"
mention-max-size: 500
mention-ttl: "5m"
mention-sweep-freq: "10s"
notification-max-size: 500
notification-ttl: "5m"
notification-sweep-freq: "10s"
status-max-size: 500
status-ttl: "5m"
status-sweep-freq: "10s"
tombstone-max-size: 100
tombstone-ttl: "5m"
tombstone-sweep-freq: "10s"
user-max-size: 100
user-ttl: "5m"
user-sweep-freq: "10s"
cache:
gts:

View file

@ -58,14 +58,8 @@ type Configuration struct {
TrustedProxies []string `name:"trusted-proxies" usage:"Proxies to trust when parsing x-forwarded headers into real IPs."`
SoftwareVersion string `name:"software-version" usage:""`
DbType string `name:"db-type" usage:"Database type: eg., postgres"`
DbAddress string `name:"db-address" usage:"Database ipv4 address, hostname, or filename"`
DbPort int `name:"db-port" usage:"Database port"`
DbUser string `name:"db-user" usage:"Database username"`
DbPassword string `name:"db-password" usage:"Database password"`
DbDatabase string `name:"db-database" usage:"Database name"`
DbTLSMode string `name:"db-tls-mode" usage:"Database tls mode"`
DbTLSCACert string `name:"db-tls-ca-cert" usage:"Path to CA cert for db tls connection"`
// Database configuration vars.
Database DatabaseConfiguration `name:"database"`
WebTemplateBaseDir string `name:"web-template-base-dir" usage:"Basedir for html templating files for rendering pages and composing emails."`
WebAssetBaseDir string `name:"web-asset-base-dir" usage:"Directory to serve static assets from, accessible at example.org/assets/"`
@ -141,6 +135,32 @@ type Configuration struct {
AdminMediaPruneDryRun bool `name:"dry-run" usage:"perform a dry run and only log number of items eligible for pruning"`
}
type DatabaseConfiguration struct {
Type string `name:"type"`
Address string `name:"address"`
// Postgres specific configuration vars.
Postgres PostgresConfiguration `name:"postgres"`
// SQLite specific configuration vars.
SQLite SQLiteConfiguration `name:"sqlite"`
}
type PostgresConfiguration struct {
Port int `name:"port"`
User string `name:"user"`
Password string `name:"password"`
Database string `name:"database"`
TLSMode string `name:"tls-mode"`
TLSCACert string `name:"tls-ca-cert"`
}
type SQLiteConfiguration struct {
JournalMode string `name:"journal-mode"`
Synchronous string `name:"synchronous"`
CacheSize bytesize.Size `name:"cache-size"`
}
type CacheConfiguration struct {
GTS GTSCacheConfiguration `name:"gts"`
}

View file

@ -40,14 +40,25 @@ var Defaults = Configuration{
Port: 8080,
TrustedProxies: []string{"127.0.0.1/32", "::1"}, // localhost
DbType: "postgres",
DbAddress: "",
DbPort: 5432,
DbUser: "",
DbPassword: "",
DbDatabase: "gotosocial",
DbTLSMode: "disable",
DbTLSCACert: "",
Database: DatabaseConfiguration{
Type: "postgres",
Address: "",
Postgres: PostgresConfiguration{
Port: 5432,
User: "",
Password: "",
Database: "gotosocial",
TLSMode: "disable",
TLSCACert: "",
},
SQLite: SQLiteConfiguration{
JournalMode: "WAL",
Synchronous: "FULL",
CacheSize: 32 * bytesize.MiB,
},
},
WebTemplateBaseDir: "./web/template/",
WebAssetBaseDir: "./web/assets/",

View file

@ -43,14 +43,14 @@ func (s *ConfigState) AddGlobalFlags(cmd *cobra.Command) {
cmd.PersistentFlags().String(ConfigPathFlag(), cfg.ConfigPath, fieldtag("ConfigPath", "usage"))
// Database
cmd.PersistentFlags().String(DbTypeFlag(), cfg.DbType, fieldtag("DbType", "usage"))
cmd.PersistentFlags().String(DbAddressFlag(), cfg.DbAddress, fieldtag("DbAddress", "usage"))
cmd.PersistentFlags().Int(DbPortFlag(), cfg.DbPort, fieldtag("DbPort", "usage"))
cmd.PersistentFlags().String(DbUserFlag(), cfg.DbUser, fieldtag("DbUser", "usage"))
cmd.PersistentFlags().String(DbPasswordFlag(), cfg.DbPassword, fieldtag("DbPassword", "usage"))
cmd.PersistentFlags().String(DbDatabaseFlag(), cfg.DbDatabase, fieldtag("DbDatabase", "usage"))
cmd.PersistentFlags().String(DbTLSModeFlag(), cfg.DbTLSMode, fieldtag("DbTLSMode", "usage"))
cmd.PersistentFlags().String(DbTLSCACertFlag(), cfg.DbTLSCACert, fieldtag("DbTLSCACert", "usage"))
cmd.PersistentFlags().String(DatabaseTypeFlag(), cfg.Database.Type, "Database type: eg., postgres")
cmd.PersistentFlags().String(DatabaseAddressFlag(), cfg.Database.Address, "Database ipv4 address, hostname, or filename")
cmd.PersistentFlags().Int(DatabasePostgresPortFlag(), cfg.Database.Postgres.Port, "Database port")
cmd.PersistentFlags().String(DatabasePostgresUserFlag(), cfg.Database.Postgres.User, "Database username")
cmd.PersistentFlags().String(DatabasePostgresPasswordFlag(), cfg.Database.Postgres.Password, "Database password")
cmd.PersistentFlags().String(DatabasePostgresDatabaseFlag(), cfg.Database.Postgres.Database, "Database name")
cmd.PersistentFlags().String(DatabasePostgresTLSModeFlag(), cfg.Database.Postgres.TLSMode, "Database tls mode")
cmd.PersistentFlags().String(DatabasePostgresTLSCACertFlag(), cfg.Database.Postgres.TLSCACert, "Path to CA cert for db tls connection")
})
}

View file

@ -26,9 +26,8 @@ import (
"os/exec"
"reflect"
"strings"
"time"
"codeberg.org/gruf/go-bytesize"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
const license = `/*
@ -50,149 +49,6 @@ const license = `/*
*/
`
type Configuration struct {
LogLevel string `name:"log-level" usage:"Log level to run at: [trace, debug, info, warn, fatal]"`
LogDbQueries bool `name:"log-db-queries" usage:"Log database queries verbosely when log-level is trace or debug"`
ApplicationName string `name:"application-name" usage:"Name of the application, used in various places internally"`
LandingPageUser string `name:"landing-page-user" usage:"the user that should be shown on the instance's landing page"`
ConfigPath string `name:"config-path" usage:"Path to a file containing gotosocial configuration. Values set in this file will be overwritten by values set as env vars or arguments"`
Host string `name:"host" usage:"Hostname to use for the server (eg., example.org, gotosocial.whatever.com). DO NOT change this on a server that's already run!"`
AccountDomain string `name:"account-domain" usage:"Domain to use in account names (eg., example.org, whatever.com). If not set, will default to the setting for host. DO NOT change this on a server that's already run!"`
Protocol string `name:"protocol" usage:"Protocol to use for the REST api of the server (only use http if you are debugging or behind a reverse proxy!)"`
BindAddress string `name:"bind-address" usage:"Bind address to use for the GoToSocial server (eg., 0.0.0.0, 172.138.0.9, [::], localhost). For ipv6, enclose the address in square brackets, eg [2001:db8::fed1]. Default binds to all interfaces."`
Port int `name:"port" usage:"Port to use for GoToSocial. Change this to 443 if you're running the binary directly on the host machine."`
TrustedProxies []string `name:"trusted-proxies" usage:"Proxies to trust when parsing x-forwarded headers into real IPs."`
SoftwareVersion string `name:"software-version" usage:""`
DbType string `name:"db-type" usage:"Database type: eg., postgres"`
DbAddress string `name:"db-address" usage:"Database ipv4 address, hostname, or filename"`
DbPort int `name:"db-port" usage:"Database port"`
DbUser string `name:"db-user" usage:"Database username"`
DbPassword string `name:"db-password" usage:"Database password"`
DbDatabase string `name:"db-database" usage:"Database name"`
DbTLSMode string `name:"db-tls-mode" usage:"Database tls mode"`
DbTLSCACert string `name:"db-tls-ca-cert" usage:"Path to CA cert for db tls connection"`
WebTemplateBaseDir string `name:"web-template-base-dir" usage:"Basedir for html templating files for rendering pages and composing emails."`
WebAssetBaseDir string `name:"web-asset-base-dir" usage:"Directory to serve static assets from, accessible at example.org/assets/"`
InstanceExposePeers bool `name:"instance-expose-peers" usage:"Allow unauthenticated users to query /api/v1/instance/peers?filter=open"`
InstanceExposeSuspended bool `name:"instance-expose-suspended" usage:"Expose suspended instances via web UI, and allow unauthenticated users to query /api/v1/instance/peers?filter=suspended"`
InstanceExposePublicTimeline bool `name:"instance-expose-public-timeline" usage:"Allow unauthenticated users to query /api/v1/timelines/public"`
InstanceDeliverToSharedInboxes bool `name:"instance-deliver-to-shared-inboxes" usage:"Deliver federated messages to shared inboxes, if they're available."`
AccountsRegistrationOpen bool `name:"accounts-registration-open" usage:"Allow anyone to submit an account signup request. If false, server will be invite-only."`
AccountsApprovalRequired bool `name:"accounts-approval-required" usage:"Do account signups require approval by an admin or moderator before user can log in? If false, new registrations will be automatically approved."`
AccountsReasonRequired bool `name:"accounts-reason-required" usage:"Do new account signups require a reason to be submitted on registration?"`
AccountsAllowCustomCSS bool `name:"accounts-allow-custom-css" usage:"Allow accounts to enable custom CSS for their profile pages and statuses."`
MediaImageMaxSize bytesize.Size `name:"media-image-max-size" usage:"Max size of accepted images in bytes"`
MediaVideoMaxSize bytesize.Size `name:"media-video-max-size" usage:"Max size of accepted videos in bytes"`
MediaDescriptionMinChars int `name:"media-description-min-chars" usage:"Min required chars for an image description"`
MediaDescriptionMaxChars int `name:"media-description-max-chars" usage:"Max permitted chars for an image description"`
MediaRemoteCacheDays int `name:"media-remote-cache-days" usage:"Number of days to locally cache media from remote instances. If set to 0, remote media will be kept indefinitely."`
MediaEmojiLocalMaxSize bytesize.Size `name:"media-emoji-local-max-size" usage:"Max size in bytes of emojis uploaded to this instance via the admin API."`
MediaEmojiRemoteMaxSize bytesize.Size `name:"media-emoji-remote-max-size" usage:"Max size in bytes of emojis to download from other instances."`
StorageBackend string `name:"storage-backend" usage:"Storage backend to use for media attachments"`
StorageLocalBasePath string `name:"storage-local-base-path" usage:"Full path to an already-created directory where gts should store/retrieve media files. Subfolders will be created within this dir."`
StorageS3Endpoint string `name:"storage-s3-endpoint" usage:"S3 Endpoint URL (e.g 'minio.example.org:9000')"`
StorageS3AccessKey string `name:"storage-s3-access-key" usage:"S3 Access Key"`
StorageS3SecretKey string `name:"storage-s3-secret-key" usage:"S3 Secret Key"`
StorageS3UseSSL bool `name:"storage-s3-use-ssl" usage:"Use SSL for S3 connections. Only set this to 'false' when testing locally"`
StorageS3BucketName string `name:"storage-s3-bucket" usage:"Place blobs in this bucket"`
StorageS3Proxy bool `name:"storage-s3-proxy" usage:"Proxy S3 contents through GoToSocial instead of redirecting to a presigned URL"`
StatusesMaxChars int `name:"statuses-max-chars" usage:"Max permitted characters for posted statuses"`
StatusesCWMaxChars int `name:"statuses-cw-max-chars" usage:"Max permitted characters for content/spoiler warnings on statuses"`
StatusesPollMaxOptions int `name:"statuses-poll-max-options" usage:"Max amount of options permitted on a poll"`
StatusesPollOptionMaxChars int `name:"statuses-poll-option-max-chars" usage:"Max amount of characters for a poll option"`
StatusesMediaMaxFiles int `name:"statuses-media-max-files" usage:"Maximum number of media files/attachments per status"`
LetsEncryptEnabled bool `name:"letsencrypt-enabled" usage:"Enable letsencrypt TLS certs for this server. If set to true, then cert dir also needs to be set (or take the default)."`
LetsEncryptPort int `name:"letsencrypt-port" usage:"Port to listen on for letsencrypt certificate challenges. Must not be the same as the GtS webserver/API port."`
LetsEncryptCertDir string `name:"letsencrypt-cert-dir" usage:"Directory to store acquired letsencrypt certificates."`
LetsEncryptEmailAddress string `name:"letsencrypt-email-address" usage:"Email address to use when requesting letsencrypt certs. Will receive updates on cert expiry etc."`
OIDCEnabled bool `name:"oidc-enabled" usage:"Enabled OIDC authorization for this instance. If set to true, then the other OIDC flags must also be set."`
OIDCIdpName string `name:"oidc-idp-name" usage:"Name of the OIDC identity provider. Will be shown to the user when logging in."`
OIDCSkipVerification bool `name:"oidc-skip-verification" usage:"Skip verification of tokens returned by the OIDC provider. Should only be set to 'true' for testing purposes, never in a production environment!"`
OIDCIssuer string `name:"oidc-issuer" usage:"Address of the OIDC issuer. Should be the web address, including protocol, at which the issuer can be reached. Eg., 'https://example.org/auth'"`
OIDCClientID string `name:"oidc-client-id" usage:"ClientID of GoToSocial, as registered with the OIDC provider."`
OIDCClientSecret string `name:"oidc-client-secret" usage:"ClientSecret of GoToSocial, as registered with the OIDC provider."`
OIDCScopes []string `name:"oidc-scopes" usage:"OIDC scopes."`
OIDCLinkExisting bool `name:"oidc-link-existing" usage:"link existing user accounts to OIDC logins based on the stored email value"`
SMTPHost string `name:"smtp-host" usage:"Host of the smtp server. Eg., 'smtp.eu.mailgun.org'"`
SMTPPort int `name:"smtp-port" usage:"Port of the smtp server. Eg., 587"`
SMTPUsername string `name:"smtp-username" usage:"Username to authenticate with the smtp server as. Eg., 'postmaster@mail.example.org'"`
SMTPPassword string `name:"smtp-password" usage:"Password to pass to the smtp server."`
SMTPFrom string `name:"smtp-from" usage:"Address to use as the 'from' field of the email. Eg., 'gotosocial@example.org'"`
SyslogEnabled bool `name:"syslog-enabled" usage:"Enable the syslog logging hook. Logs will be mirrored to the configured destination."`
SyslogProtocol string `name:"syslog-protocol" usage:"Protocol to use when directing logs to syslog. Leave empty to connect to local syslog."`
SyslogAddress string `name:"syslog-address" usage:"Address:port to send syslog logs to. Leave empty to connect to local syslog."`
AdvancedCookiesSamesite string `name:"advanced-cookies-samesite" usage:"'strict' or 'lax', see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite"`
AdvancedRateLimitRequests int `name:"advanced-rate-limit-requests" usage:"Amount of HTTP requests to permit within a 5 minute window. 0 or less turns rate limiting off."`
// Cache configuration vars.
Cache CacheConfiguration `name:"cache"`
// TODO: move these elsewhere, these are more ephemeral vs long-running flags like above
AdminAccountUsername string `name:"username" usage:"the username to create/delete/etc"`
AdminAccountEmail string `name:"email" usage:"the email address of this account"`
AdminAccountPassword string `name:"password" usage:"the password to set for this account"`
AdminTransPath string `name:"path" usage:"the path of the file to import from/export to"`
AdminMediaPruneDryRun bool `name:"dry-run" usage:"perform a dry run and only log number of items eligible for pruning"`
}
type CacheConfiguration struct {
GTS GTSCacheConfiguration `name:"gts"`
}
type GTSCacheConfiguration struct {
AccountMaxSize int `name:"account-max-size"`
AccountTTL time.Duration `name:"account-ttl"`
AccountSweepFreq time.Duration `name:"account-sweep-freq"`
BlockMaxSize int `name:"block-max-size"`
BlockTTL time.Duration `name:"block-ttl"`
BlockSweepFreq time.Duration `name:"block-sweep-freq"`
DomainBlockMaxSize int `name:"domain-block-max-size"`
DomainBlockTTL time.Duration `name:"domain-block-ttl"`
DomainBlockSweepFreq time.Duration `name:"domain-block-sweep-freq"`
EmojiMaxSize int `name:"emoji-max-size"`
EmojiTTL time.Duration `name:"emoji-ttl"`
EmojiSweepFreq time.Duration `name:"emoji-sweep-freq"`
EmojiCategoryMaxSize int `name:"emoji-category-max-size"`
EmojiCategoryTTL time.Duration `name:"emoji-category-ttl"`
EmojiCategorySweepFreq time.Duration `name:"emoji-category-sweep-freq"`
MentionMaxSize int `name:"mention-max-size"`
MentionTTL time.Duration `name:"mention-ttl"`
MentionSweepFreq time.Duration `name:"mention-sweep-freq"`
NotificationMaxSize int `name:"notification-max-size"`
NotificationTTL time.Duration `name:"notification-ttl"`
NotificationSweepFreq time.Duration `name:"notification-sweep-freq"`
StatusMaxSize int `name:"status-max-size"`
StatusTTL time.Duration `name:"status-ttl"`
StatusSweepFreq time.Duration `name:"status-sweep-freq"`
TombstoneMaxSize int `name:"tombstone-max-size"`
TombstoneTTL time.Duration `name:"tombstone-ttl"`
TombstoneSweepFreq time.Duration `name:"tombstone-sweep-freq"`
UserMaxSize int `name:"user-max-size"`
UserTTL time.Duration `name:"user-ttl"`
UserSweepFreq time.Duration `name:"user-sweep-freq"`
}
func main() {
var out string
@ -209,8 +65,12 @@ func main() {
fmt.Fprint(output, "// THIS IS A GENERATED FILE, DO NOT EDIT BY HAND\n")
fmt.Fprint(output, license)
fmt.Fprint(output, "package config\n\n")
fmt.Fprint(output, "import \"codeberg.org/gruf/go-bytesize\"\n\n")
generateFields(output, nil, reflect.TypeOf(Configuration{}))
fmt.Fprint(output, "import (\n")
fmt.Fprint(output, "\t\"time\"\n")
fmt.Fprint(output, "\n")
fmt.Fprint(output, "\t\"codeberg.org/gruf/go-bytesize\"\n")
fmt.Fprint(output, ")\n")
generateFields(output, nil, reflect.TypeOf(config.Configuration{}))
_ = output.Close()
_ = exec.Command("gofumports", "-w", out).Run()
@ -239,7 +99,7 @@ func generateFields(output io.Writer, prefixes []string, t reflect.Type) {
flagPath = strings.ToLower(flagPath)
// ConfigState structure helper methods
fmt.Fprintf(output, "// Get%s safely fetches the Configuration value for state's '%s' field\n", name, fieldPath)
fmt.Fprintf(output, "\n// Get%s safely fetches the Configuration value for state's '%s' field\n", name, fieldPath)
fmt.Fprintf(output, "func (st *ConfigState) Get%s() (v %s) {\n", name, field.Type.String())
fmt.Fprintf(output, "\tst.mutex.Lock()\n")
fmt.Fprintf(output, "\tv = st.config.%s\n", fieldPath)
@ -261,6 +121,6 @@ func generateFields(output io.Writer, prefixes []string, t reflect.Type) {
fmt.Fprintf(output, "// Get%s safely fetches the value for global configuration '%s' field\n", name, fieldPath)
fmt.Fprintf(output, "func Get%[1]s() %[2]s { return global.Get%[1]s() }\n\n", name, field.Type.String())
fmt.Fprintf(output, "// Set%s safely sets the value for global configuration '%s' field\n", name, fieldPath)
fmt.Fprintf(output, "func Set%[1]s(v %[2]s) { global.Set%[1]s(v) }\n\n", name, field.Type.String())
fmt.Fprintf(output, "func Set%[1]s(v %[2]s) { global.Set%[1]s(v) }\n", name, field.Type.String())
}
}

View file

@ -324,205 +324,280 @@ func GetSoftwareVersion() string { return global.GetSoftwareVersion() }
// SetSoftwareVersion safely sets the value for global configuration 'SoftwareVersion' field
func SetSoftwareVersion(v string) { global.SetSoftwareVersion(v) }
// GetDbType safely fetches the Configuration value for state's 'DbType' field
func (st *ConfigState) GetDbType() (v string) {
// GetDatabaseType safely fetches the Configuration value for state's 'Database.Type' field
func (st *ConfigState) GetDatabaseType() (v string) {
st.mutex.Lock()
v = st.config.DbType
v = st.config.Database.Type
st.mutex.Unlock()
return
}
// SetDbType safely sets the Configuration value for state's 'DbType' field
func (st *ConfigState) SetDbType(v string) {
// SetDatabaseType safely sets the Configuration value for state's 'Database.Type' field
func (st *ConfigState) SetDatabaseType(v string) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.DbType = v
st.config.Database.Type = v
st.reloadToViper()
}
// DbTypeFlag returns the flag name for the 'DbType' field
func DbTypeFlag() string { return "db-type" }
// DatabaseTypeFlag returns the flag name for the 'Database.Type' field
func DatabaseTypeFlag() string { return "database-type" }
// GetDbType safely fetches the value for global configuration 'DbType' field
func GetDbType() string { return global.GetDbType() }
// GetDatabaseType safely fetches the value for global configuration 'Database.Type' field
func GetDatabaseType() string { return global.GetDatabaseType() }
// SetDbType safely sets the value for global configuration 'DbType' field
func SetDbType(v string) { global.SetDbType(v) }
// SetDatabaseType safely sets the value for global configuration 'Database.Type' field
func SetDatabaseType(v string) { global.SetDatabaseType(v) }
// GetDbAddress safely fetches the Configuration value for state's 'DbAddress' field
func (st *ConfigState) GetDbAddress() (v string) {
// GetDatabaseAddress safely fetches the Configuration value for state's 'Database.Address' field
func (st *ConfigState) GetDatabaseAddress() (v string) {
st.mutex.Lock()
v = st.config.DbAddress
v = st.config.Database.Address
st.mutex.Unlock()
return
}
// SetDbAddress safely sets the Configuration value for state's 'DbAddress' field
func (st *ConfigState) SetDbAddress(v string) {
// SetDatabaseAddress safely sets the Configuration value for state's 'Database.Address' field
func (st *ConfigState) SetDatabaseAddress(v string) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.DbAddress = v
st.config.Database.Address = v
st.reloadToViper()
}
// DbAddressFlag returns the flag name for the 'DbAddress' field
func DbAddressFlag() string { return "db-address" }
// DatabaseAddressFlag returns the flag name for the 'Database.Address' field
func DatabaseAddressFlag() string { return "database-address" }
// GetDbAddress safely fetches the value for global configuration 'DbAddress' field
func GetDbAddress() string { return global.GetDbAddress() }
// GetDatabaseAddress safely fetches the value for global configuration 'Database.Address' field
func GetDatabaseAddress() string { return global.GetDatabaseAddress() }
// SetDbAddress safely sets the value for global configuration 'DbAddress' field
func SetDbAddress(v string) { global.SetDbAddress(v) }
// SetDatabaseAddress safely sets the value for global configuration 'Database.Address' field
func SetDatabaseAddress(v string) { global.SetDatabaseAddress(v) }
// GetDbPort safely fetches the Configuration value for state's 'DbPort' field
func (st *ConfigState) GetDbPort() (v int) {
// GetDatabasePostgresPort safely fetches the Configuration value for state's 'Database.Postgres.Port' field
func (st *ConfigState) GetDatabasePostgresPort() (v int) {
st.mutex.Lock()
v = st.config.DbPort
v = st.config.Database.Postgres.Port
st.mutex.Unlock()
return
}
// SetDbPort safely sets the Configuration value for state's 'DbPort' field
func (st *ConfigState) SetDbPort(v int) {
// SetDatabasePostgresPort safely sets the Configuration value for state's 'Database.Postgres.Port' field
func (st *ConfigState) SetDatabasePostgresPort(v int) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.DbPort = v
st.config.Database.Postgres.Port = v
st.reloadToViper()
}
// DbPortFlag returns the flag name for the 'DbPort' field
func DbPortFlag() string { return "db-port" }
// DatabasePostgresPortFlag returns the flag name for the 'Database.Postgres.Port' field
func DatabasePostgresPortFlag() string { return "database-postgres-port" }
// GetDbPort safely fetches the value for global configuration 'DbPort' field
func GetDbPort() int { return global.GetDbPort() }
// GetDatabasePostgresPort safely fetches the value for global configuration 'Database.Postgres.Port' field
func GetDatabasePostgresPort() int { return global.GetDatabasePostgresPort() }
// SetDbPort safely sets the value for global configuration 'DbPort' field
func SetDbPort(v int) { global.SetDbPort(v) }
// SetDatabasePostgresPort safely sets the value for global configuration 'Database.Postgres.Port' field
func SetDatabasePostgresPort(v int) { global.SetDatabasePostgresPort(v) }
// GetDbUser safely fetches the Configuration value for state's 'DbUser' field
func (st *ConfigState) GetDbUser() (v string) {
// GetDatabasePostgresUser safely fetches the Configuration value for state's 'Database.Postgres.User' field
func (st *ConfigState) GetDatabasePostgresUser() (v string) {
st.mutex.Lock()
v = st.config.DbUser
v = st.config.Database.Postgres.User
st.mutex.Unlock()
return
}
// SetDbUser safely sets the Configuration value for state's 'DbUser' field
func (st *ConfigState) SetDbUser(v string) {
// SetDatabasePostgresUser safely sets the Configuration value for state's 'Database.Postgres.User' field
func (st *ConfigState) SetDatabasePostgresUser(v string) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.DbUser = v
st.config.Database.Postgres.User = v
st.reloadToViper()
}
// DbUserFlag returns the flag name for the 'DbUser' field
func DbUserFlag() string { return "db-user" }
// DatabasePostgresUserFlag returns the flag name for the 'Database.Postgres.User' field
func DatabasePostgresUserFlag() string { return "database-postgres-user" }
// GetDbUser safely fetches the value for global configuration 'DbUser' field
func GetDbUser() string { return global.GetDbUser() }
// GetDatabasePostgresUser safely fetches the value for global configuration 'Database.Postgres.User' field
func GetDatabasePostgresUser() string { return global.GetDatabasePostgresUser() }
// SetDbUser safely sets the value for global configuration 'DbUser' field
func SetDbUser(v string) { global.SetDbUser(v) }
// SetDatabasePostgresUser safely sets the value for global configuration 'Database.Postgres.User' field
func SetDatabasePostgresUser(v string) { global.SetDatabasePostgresUser(v) }
// GetDbPassword safely fetches the Configuration value for state's 'DbPassword' field
func (st *ConfigState) GetDbPassword() (v string) {
// GetDatabasePostgresPassword safely fetches the Configuration value for state's 'Database.Postgres.Password' field
func (st *ConfigState) GetDatabasePostgresPassword() (v string) {
st.mutex.Lock()
v = st.config.DbPassword
v = st.config.Database.Postgres.Password
st.mutex.Unlock()
return
}
// SetDbPassword safely sets the Configuration value for state's 'DbPassword' field
func (st *ConfigState) SetDbPassword(v string) {
// SetDatabasePostgresPassword safely sets the Configuration value for state's 'Database.Postgres.Password' field
func (st *ConfigState) SetDatabasePostgresPassword(v string) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.DbPassword = v
st.config.Database.Postgres.Password = v
st.reloadToViper()
}
// DbPasswordFlag returns the flag name for the 'DbPassword' field
func DbPasswordFlag() string { return "db-password" }
// DatabasePostgresPasswordFlag returns the flag name for the 'Database.Postgres.Password' field
func DatabasePostgresPasswordFlag() string { return "database-postgres-password" }
// GetDbPassword safely fetches the value for global configuration 'DbPassword' field
func GetDbPassword() string { return global.GetDbPassword() }
// GetDatabasePostgresPassword safely fetches the value for global configuration 'Database.Postgres.Password' field
func GetDatabasePostgresPassword() string { return global.GetDatabasePostgresPassword() }
// SetDbPassword safely sets the value for global configuration 'DbPassword' field
func SetDbPassword(v string) { global.SetDbPassword(v) }
// SetDatabasePostgresPassword safely sets the value for global configuration 'Database.Postgres.Password' field
func SetDatabasePostgresPassword(v string) { global.SetDatabasePostgresPassword(v) }
// GetDbDatabase safely fetches the Configuration value for state's 'DbDatabase' field
func (st *ConfigState) GetDbDatabase() (v string) {
// GetDatabasePostgresDatabase safely fetches the Configuration value for state's 'Database.Postgres.Database' field
func (st *ConfigState) GetDatabasePostgresDatabase() (v string) {
st.mutex.Lock()
v = st.config.DbDatabase
v = st.config.Database.Postgres.Database
st.mutex.Unlock()
return
}
// SetDbDatabase safely sets the Configuration value for state's 'DbDatabase' field
func (st *ConfigState) SetDbDatabase(v string) {
// SetDatabasePostgresDatabase safely sets the Configuration value for state's 'Database.Postgres.Database' field
func (st *ConfigState) SetDatabasePostgresDatabase(v string) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.DbDatabase = v
st.config.Database.Postgres.Database = v
st.reloadToViper()
}
// DbDatabaseFlag returns the flag name for the 'DbDatabase' field
func DbDatabaseFlag() string { return "db-database" }
// DatabasePostgresDatabaseFlag returns the flag name for the 'Database.Postgres.Database' field
func DatabasePostgresDatabaseFlag() string { return "database-postgres-database" }
// GetDbDatabase safely fetches the value for global configuration 'DbDatabase' field
func GetDbDatabase() string { return global.GetDbDatabase() }
// GetDatabasePostgresDatabase safely fetches the value for global configuration 'Database.Postgres.Database' field
func GetDatabasePostgresDatabase() string { return global.GetDatabasePostgresDatabase() }
// SetDbDatabase safely sets the value for global configuration 'DbDatabase' field
func SetDbDatabase(v string) { global.SetDbDatabase(v) }
// SetDatabasePostgresDatabase safely sets the value for global configuration 'Database.Postgres.Database' field
func SetDatabasePostgresDatabase(v string) { global.SetDatabasePostgresDatabase(v) }
// GetDbTLSMode safely fetches the Configuration value for state's 'DbTLSMode' field
func (st *ConfigState) GetDbTLSMode() (v string) {
// GetDatabasePostgresTLSMode safely fetches the Configuration value for state's 'Database.Postgres.TLSMode' field
func (st *ConfigState) GetDatabasePostgresTLSMode() (v string) {
st.mutex.Lock()
v = st.config.DbTLSMode
v = st.config.Database.Postgres.TLSMode
st.mutex.Unlock()
return
}
// SetDbTLSMode safely sets the Configuration value for state's 'DbTLSMode' field
func (st *ConfigState) SetDbTLSMode(v string) {
// SetDatabasePostgresTLSMode safely sets the Configuration value for state's 'Database.Postgres.TLSMode' field
func (st *ConfigState) SetDatabasePostgresTLSMode(v string) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.DbTLSMode = v
st.config.Database.Postgres.TLSMode = v
st.reloadToViper()
}
// DbTLSModeFlag returns the flag name for the 'DbTLSMode' field
func DbTLSModeFlag() string { return "db-tls-mode" }
// DatabasePostgresTLSModeFlag returns the flag name for the 'Database.Postgres.TLSMode' field
func DatabasePostgresTLSModeFlag() string { return "database-postgres-tls-mode" }
// GetDbTLSMode safely fetches the value for global configuration 'DbTLSMode' field
func GetDbTLSMode() string { return global.GetDbTLSMode() }
// GetDatabasePostgresTLSMode safely fetches the value for global configuration 'Database.Postgres.TLSMode' field
func GetDatabasePostgresTLSMode() string { return global.GetDatabasePostgresTLSMode() }
// SetDbTLSMode safely sets the value for global configuration 'DbTLSMode' field
func SetDbTLSMode(v string) { global.SetDbTLSMode(v) }
// SetDatabasePostgresTLSMode safely sets the value for global configuration 'Database.Postgres.TLSMode' field
func SetDatabasePostgresTLSMode(v string) { global.SetDatabasePostgresTLSMode(v) }
// GetDbTLSCACert safely fetches the Configuration value for state's 'DbTLSCACert' field
func (st *ConfigState) GetDbTLSCACert() (v string) {
// GetDatabasePostgresTLSCACert safely fetches the Configuration value for state's 'Database.Postgres.TLSCACert' field
func (st *ConfigState) GetDatabasePostgresTLSCACert() (v string) {
st.mutex.Lock()
v = st.config.DbTLSCACert
v = st.config.Database.Postgres.TLSCACert
st.mutex.Unlock()
return
}
// SetDbTLSCACert safely sets the Configuration value for state's 'DbTLSCACert' field
func (st *ConfigState) SetDbTLSCACert(v string) {
// SetDatabasePostgresTLSCACert safely sets the Configuration value for state's 'Database.Postgres.TLSCACert' field
func (st *ConfigState) SetDatabasePostgresTLSCACert(v string) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.DbTLSCACert = v
st.config.Database.Postgres.TLSCACert = v
st.reloadToViper()
}
// DbTLSCACertFlag returns the flag name for the 'DbTLSCACert' field
func DbTLSCACertFlag() string { return "db-tls-ca-cert" }
// DatabasePostgresTLSCACertFlag returns the flag name for the 'Database.Postgres.TLSCACert' field
func DatabasePostgresTLSCACertFlag() string { return "database-postgres-tls-ca-cert" }
// GetDbTLSCACert safely fetches the value for global configuration 'DbTLSCACert' field
func GetDbTLSCACert() string { return global.GetDbTLSCACert() }
// GetDatabasePostgresTLSCACert safely fetches the value for global configuration 'Database.Postgres.TLSCACert' field
func GetDatabasePostgresTLSCACert() string { return global.GetDatabasePostgresTLSCACert() }
// SetDbTLSCACert safely sets the value for global configuration 'DbTLSCACert' field
func SetDbTLSCACert(v string) { global.SetDbTLSCACert(v) }
// SetDatabasePostgresTLSCACert safely sets the value for global configuration 'Database.Postgres.TLSCACert' field
func SetDatabasePostgresTLSCACert(v string) { global.SetDatabasePostgresTLSCACert(v) }
// GetDatabaseSQLiteJournalMode safely fetches the Configuration value for state's 'Database.SQLite.JournalMode' field
func (st *ConfigState) GetDatabaseSQLiteJournalMode() (v string) {
st.mutex.Lock()
v = st.config.Database.SQLite.JournalMode
st.mutex.Unlock()
return
}
// SetDatabaseSQLiteJournalMode safely sets the Configuration value for state's 'Database.SQLite.JournalMode' field
func (st *ConfigState) SetDatabaseSQLiteJournalMode(v string) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.Database.SQLite.JournalMode = v
st.reloadToViper()
}
// DatabaseSQLiteJournalModeFlag returns the flag name for the 'Database.SQLite.JournalMode' field
func DatabaseSQLiteJournalModeFlag() string { return "database-sqlite-journal-mode" }
// GetDatabaseSQLiteJournalMode safely fetches the value for global configuration 'Database.SQLite.JournalMode' field
func GetDatabaseSQLiteJournalMode() string { return global.GetDatabaseSQLiteJournalMode() }
// SetDatabaseSQLiteJournalMode safely sets the value for global configuration 'Database.SQLite.JournalMode' field
func SetDatabaseSQLiteJournalMode(v string) { global.SetDatabaseSQLiteJournalMode(v) }
// GetDatabaseSQLiteSynchronous safely fetches the Configuration value for state's 'Database.SQLite.Synchronous' field
func (st *ConfigState) GetDatabaseSQLiteSynchronous() (v string) {
st.mutex.Lock()
v = st.config.Database.SQLite.Synchronous
st.mutex.Unlock()
return
}
// SetDatabaseSQLiteSynchronous safely sets the Configuration value for state's 'Database.SQLite.Synchronous' field
func (st *ConfigState) SetDatabaseSQLiteSynchronous(v string) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.Database.SQLite.Synchronous = v
st.reloadToViper()
}
// DatabaseSQLiteSynchronousFlag returns the flag name for the 'Database.SQLite.Synchronous' field
func DatabaseSQLiteSynchronousFlag() string { return "database-sqlite-synchronous" }
// GetDatabaseSQLiteSynchronous safely fetches the value for global configuration 'Database.SQLite.Synchronous' field
func GetDatabaseSQLiteSynchronous() string { return global.GetDatabaseSQLiteSynchronous() }
// SetDatabaseSQLiteSynchronous safely sets the value for global configuration 'Database.SQLite.Synchronous' field
func SetDatabaseSQLiteSynchronous(v string) { global.SetDatabaseSQLiteSynchronous(v) }
// GetDatabaseSQLiteCacheSize safely fetches the Configuration value for state's 'Database.SQLite.CacheSize' field
func (st *ConfigState) GetDatabaseSQLiteCacheSize() (v bytesize.Size) {
st.mutex.Lock()
v = st.config.Database.SQLite.CacheSize
st.mutex.Unlock()
return
}
// SetDatabaseSQLiteCacheSize safely sets the Configuration value for state's 'Database.SQLite.CacheSize' field
func (st *ConfigState) SetDatabaseSQLiteCacheSize(v bytesize.Size) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.Database.SQLite.CacheSize = v
st.reloadToViper()
}
// DatabaseSQLiteCacheSizeFlag returns the flag name for the 'Database.SQLite.CacheSize' field
func DatabaseSQLiteCacheSizeFlag() string { return "database-sqlite-cache-size" }
// GetDatabaseSQLiteCacheSize safely fetches the value for global configuration 'Database.SQLite.CacheSize' field
func GetDatabaseSQLiteCacheSize() bytesize.Size { return global.GetDatabaseSQLiteCacheSize() }
// SetDatabaseSQLiteCacheSize safely sets the value for global configuration 'Database.SQLite.CacheSize' field
func SetDatabaseSQLiteCacheSize(v bytesize.Size) { global.SetDatabaseSQLiteCacheSize(v) }
// GetWebTemplateBaseDir safely fetches the Configuration value for state's 'WebTemplateBaseDir' field
func (st *ConfigState) GetWebTemplateBaseDir() (v string) {

View file

@ -31,6 +31,7 @@ import (
"strings"
"time"
"codeberg.org/gruf/go-bytesize"
"github.com/google/uuid"
"github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/stdlib"
@ -49,22 +50,6 @@ import (
"modernc.org/sqlite"
)
const (
dbTypePostgres = "postgres"
dbTypeSqlite = "sqlite"
// dbTLSModeDisable does not attempt to make a TLS connection to the database.
dbTLSModeDisable = "disable"
// dbTLSModeEnable attempts to make a TLS connection to the database, but doesn't fail if
// the certificate passed by the database isn't verified.
dbTLSModeEnable = "enable"
// dbTLSModeRequire attempts to make a TLS connection to the database, and requires
// that the certificate presented by the database is valid.
dbTLSModeRequire = "require"
// dbTLSModeUnset means that the TLS mode has not been set.
dbTLSModeUnset = ""
)
var registerTables = []interface{}{
&gtsmodel.AccountToEmoji{},
&gtsmodel.StatusToEmoji{},
@ -126,21 +111,20 @@ func doMigration(ctx context.Context, db *bun.DB) error {
func NewBunDBService(ctx context.Context, state *state.State) (db.DB, error) {
var conn *DBConn
var err error
dbType := strings.ToLower(config.GetDbType())
switch dbType {
case dbTypePostgres:
switch t := strings.ToLower(config.GetDatabaseType()); t {
case "postgres":
conn, err = pgConn(ctx)
if err != nil {
return nil, err
}
case dbTypeSqlite:
case "sqlite":
conn, err = sqliteConn(ctx)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("database type %s not supported for bundb", dbType)
return nil, fmt.Errorf("database type %s not supported for bundb", t)
}
// Add database query hook
@ -225,29 +209,29 @@ func NewBunDBService(ctx context.Context, state *state.State) (db.DB, error) {
func sqliteConn(ctx context.Context) (*DBConn, error) {
// validate db address has actually been set
dbAddress := config.GetDbAddress()
if dbAddress == "" {
return nil, fmt.Errorf("'%s' was not set when attempting to start sqlite", config.DbAddressFlag())
address := config.GetDatabaseAddress()
if address == "" {
return nil, fmt.Errorf("'%s' was not set when attempting to start sqlite", config.DatabaseAddressFlag())
}
// Drop anything fancy from DB address
dbAddress = strings.Split(dbAddress, "?")[0]
dbAddress = strings.TrimPrefix(dbAddress, "file:")
address = strings.Split(address, "?")[0]
address = strings.TrimPrefix(address, "file:")
// Append our own SQLite preferences
dbAddress = "file:" + dbAddress + "?cache=shared"
address = "file:" + address + "?cache=shared"
var inMem bool
if dbAddress == "file::memory:?cache=shared" {
dbAddress = fmt.Sprintf("file:%s?mode=memory&cache=shared", uuid.NewString())
log.Infof("using in-memory database address " + dbAddress)
if address == "file::memory:?cache=shared" {
address = fmt.Sprintf("file:%s?mode=memory&cache=shared", uuid.NewString())
log.Infof("using in-memory database address " + address)
log.Warn("sqlite in-memory database should only be used for debugging")
inMem = true
}
// Open new DB instance
sqldb, err := sql.Open("sqlite", dbAddress)
sqldb, err := sql.Open("sqlite", address)
if err != nil {
if errWithCode, ok := err.(*sqlite.Error); ok {
err = errors.New(sqlite.ErrorCodeString[errWithCode.Code()])
@ -255,8 +239,6 @@ func sqliteConn(ctx context.Context) (*DBConn, error) {
return nil, fmt.Errorf("could not open sqlite db: %s", err)
}
tweakConnectionValues(sqldb)
if inMem {
// don't close connections on disconnect -- otherwise
// the SQLite database will be deleted when there
@ -264,8 +246,31 @@ func sqliteConn(ctx context.Context) (*DBConn, error) {
sqldb.SetConnMaxLifetime(0)
}
// Wrap Bun database conn in our own wrapper
conn := WrapDBConn(bun.NewDB(sqldb, sqlitedialect.New()))
var pragmas []string
if mode := config.GetDatabaseSQLiteJournalMode(); mode != "" {
// Set the user provided SQLite journal mode
pragmas = append(pragmas, fmt.Sprintf("PRAGMA journal_mode = %s;", mode))
}
if mode := config.GetDatabaseSQLiteSynchronous(); mode != "" {
// Set the user provided SQLite synchronous mode
pragmas = append(pragmas, fmt.Sprintf("PRAGMA synchronous = %s;", mode))
}
if size := config.GetDatabaseSQLiteCacheSize(); size > 0 {
// Set the user provided SQLite cache size (in kibibytes)
pragmas = append(pragmas, fmt.Sprintf("PRAGMA cache_size = %d;", size/bytesize.KiB))
}
// Executed the collected pragma statements (this may be a no-op).
if _, err := conn.Exec(strings.Join(pragmas, "\n")); err != nil {
return nil, fmt.Errorf("error executing sqlite pragmas: %w", err)
}
// ping to check the db is there and listening
if err := conn.PingContext(ctx); err != nil {
if errWithCode, ok := err.(*sqlite.Error); ok {
@ -286,7 +291,10 @@ func pgConn(ctx context.Context) (*DBConn, error) {
sqldb := stdlib.OpenDB(*opts)
tweakConnectionValues(sqldb)
// https://bun.uptrace.dev/postgres/running-bun-in-production.html#database-sql
maxOpenConns := 4 * runtime.GOMAXPROCS(0)
sqldb.SetMaxOpenConns(maxOpenConns)
sqldb.SetMaxIdleConns(maxOpenConns)
conn := WrapDBConn(bun.NewDB(sqldb, pgdialect.New()))
@ -306,29 +314,25 @@ func pgConn(ctx context.Context) (*DBConn, error) {
// deriveBunDBPGOptions takes an application config and returns either a ready-to-use set of options
// with sensible defaults, or an error if it's not satisfied by the provided config.
func deriveBunDBPGOptions() (*pgx.ConnConfig, error) {
if strings.ToUpper(config.GetDbType()) != db.DBTypePostgres {
return nil, fmt.Errorf("expected db type of %s but got %s", db.DBTypePostgres, config.DbTypeFlag())
}
// these are all optional, the db adapter figures out defaults
address := config.GetDbAddress()
address := config.GetDatabaseAddress()
// validate database
database := config.GetDbDatabase()
database := config.GetDatabasePostgresDatabase()
if database == "" {
return nil, errors.New("no database set")
}
var tlsConfig *tls.Config
switch config.GetDbTLSMode() {
case dbTLSModeDisable, dbTLSModeUnset:
switch config.GetDatabasePostgresTLSMode() {
case "", "disable":
break // nothing to do
case dbTLSModeEnable:
case "enable":
/* #nosec G402 */
tlsConfig = &tls.Config{
InsecureSkipVerify: true,
}
case dbTLSModeRequire:
case "require":
tlsConfig = &tls.Config{
InsecureSkipVerify: false,
ServerName: address,
@ -336,7 +340,7 @@ func deriveBunDBPGOptions() (*pgx.ConnConfig, error) {
}
}
if certPath := config.GetDbTLSCACert(); tlsConfig != nil && certPath != "" {
if certPath := config.GetDatabasePostgresTLSCACert(); tlsConfig != nil && certPath != "" {
// load the system cert pool first -- we'll append the given CA cert to this
certPool, err := x509.SystemCertPool()
if err != nil {
@ -373,13 +377,13 @@ func deriveBunDBPGOptions() (*pgx.ConnConfig, error) {
if address != "" {
cfg.Host = address
}
if port := config.GetDbPort(); port > 0 {
if port := config.GetDatabasePostgresPort(); port > 0 {
cfg.Port = uint16(port)
}
if u := config.GetDbUser(); u != "" {
if u := config.GetDatabasePostgresUser(); u != "" {
cfg.User = u
}
if p := config.GetDbPassword(); p != "" {
if p := config.GetDatabasePostgresPassword(); p != "" {
cfg.Password = p
}
if tlsConfig != nil {
@ -392,13 +396,6 @@ func deriveBunDBPGOptions() (*pgx.ConnConfig, error) {
return cfg, nil
}
// https://bun.uptrace.dev/postgres/running-bun-in-production.html#database-sql
func tweakConnectionValues(sqldb *sql.DB) {
maxOpenConns := 4 * runtime.GOMAXPROCS(0)
sqldb.SetMaxOpenConns(maxOpenConns)
sqldb.SetMaxIdleConns(maxOpenConns)
}
/*
CONVERSION FUNCTIONS
*/

View file

@ -40,8 +40,8 @@ func (suite *BundbNewTestSuite) TestCreateNewDB() {
func (suite *BundbNewTestSuite) TestCreateNewSqliteDBNoAddress() {
// create a new db with no address specified
config.SetDbAddress("")
config.SetDbType("sqlite")
config.SetDatabaseAddress("")
config.SetDatabaseType("sqlite")
db, err := bundb.NewBunDBService(context.Background(), nil)
suite.EqualError(err, "'db-address' was not set when attempting to start sqlite")
suite.Nil(db)

View file

@ -43,12 +43,17 @@ var testDefaults = config.Configuration{
Port: 8080,
TrustedProxies: []string{"127.0.0.1/32", "::1"},
DbType: "sqlite",
DbAddress: ":memory:",
DbPort: 5432,
DbUser: "postgres",
DbPassword: "postgres",
DbDatabase: "postgres",
Database: config.DatabaseConfiguration{
Type: "sqlite",
Address: ":memory:",
Postgres: config.PostgresConfiguration{
Port: 5432,
User: "postgres",
Password: "postgres",
Database: "postgres",
},
SQLite: config.Defaults.Database.SQLite,
},
WebTemplateBaseDir: "./web/template/",
WebAssetBaseDir: "./web/assets/",

View file

@ -72,15 +72,11 @@ var testModels = []interface{}{
// value as the port instead.
func NewTestDB() db.DB {
if alternateAddress := os.Getenv("GTS_DB_ADDRESS"); alternateAddress != "" {
config.Config(func(cfg *config.Configuration) {
cfg.DbAddress = alternateAddress
})
config.SetDatabaseAddress(alternateAddress)
}
if alternateDBType := os.Getenv("GTS_DB_TYPE"); alternateDBType != "" {
config.Config(func(cfg *config.Configuration) {
cfg.DbType = alternateDBType
})
config.SetDatabaseType(alternateDBType)
}
if alternateDBPort := os.Getenv("GTS_DB_PORT"); alternateDBPort != "" {
@ -88,9 +84,7 @@ func NewTestDB() db.DB {
if err != nil {
panic(err)
}
config.Config(func(cfg *config.Configuration) {
cfg.DbPort = int(port)
})
config.SetDatabasePostgresPort(int(port))
}
var state state.State