feat(backend): establish gin sqlite service skeleton
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
HTTPAddressEnvironment = "CMROUBAO_HTTP_ADDR"
|
||||
DatabasePathEnvironment = "CMROUBAO_DATABASE_PATH"
|
||||
|
||||
defaultHTTPAddress = "127.0.0.1:8080"
|
||||
defaultDatabasePath = "var/cmroubao.db"
|
||||
)
|
||||
|
||||
type LookupEnvironment func(string) (string, bool)
|
||||
|
||||
type Config struct {
|
||||
HTTPAddress string
|
||||
DatabasePath string
|
||||
ReadHeaderTimeout time.Duration
|
||||
ReadTimeout time.Duration
|
||||
WriteTimeout time.Duration
|
||||
IdleTimeout time.Duration
|
||||
ShutdownTimeout time.Duration
|
||||
MaxHeaderBytes int
|
||||
}
|
||||
|
||||
func Load(lookup LookupEnvironment) (Config, error) {
|
||||
httpAddress, err := environmentValue(
|
||||
lookup,
|
||||
HTTPAddressEnvironment,
|
||||
defaultHTTPAddress,
|
||||
)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
if err := validateHTTPAddress(httpAddress); err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
databasePath, err := environmentValue(
|
||||
lookup,
|
||||
DatabasePathEnvironment,
|
||||
defaultDatabasePath,
|
||||
)
|
||||
databasePath, err = validatedDatabasePath(databasePath, err)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
return Config{
|
||||
HTTPAddress: httpAddress,
|
||||
DatabasePath: filepath.Clean(databasePath),
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: 30 * time.Second,
|
||||
IdleTimeout: 60 * time.Second,
|
||||
ShutdownTimeout: 10 * time.Second,
|
||||
MaxHeaderBytes: 1 << 20,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func LoadDatabasePath(lookup LookupEnvironment) (string, error) {
|
||||
databasePath, err := environmentValue(
|
||||
lookup,
|
||||
DatabasePathEnvironment,
|
||||
defaultDatabasePath,
|
||||
)
|
||||
return validatedDatabasePath(databasePath, err)
|
||||
}
|
||||
|
||||
func environmentValue(
|
||||
lookup LookupEnvironment,
|
||||
name string,
|
||||
defaultValue string,
|
||||
) (string, error) {
|
||||
value, exists := lookup(name)
|
||||
if !exists {
|
||||
return defaultValue, nil
|
||||
}
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return "", errors.New(name + " must not be blank")
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func validateHTTPAddress(address string) error {
|
||||
host, portValue, err := net.SplitHostPort(address)
|
||||
if err != nil || strings.TrimSpace(host) == "" {
|
||||
return errors.New(HTTPAddressEnvironment + " must include a host and port")
|
||||
}
|
||||
port, err := strconv.Atoi(portValue)
|
||||
if err != nil || port < 1 || port > 65535 {
|
||||
return errors.New(HTTPAddressEnvironment + " port must be between 1 and 65535")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatedDatabasePath(path string, previousError error) (string, error) {
|
||||
if previousError != nil {
|
||||
return "", previousError
|
||||
}
|
||||
if strings.ContainsRune(path, '\x00') {
|
||||
return "", errors.New(
|
||||
DatabasePathEnvironment + " contains an invalid character",
|
||||
)
|
||||
}
|
||||
lowerPath := strings.ToLower(path)
|
||||
cleanPath := filepath.Clean(path)
|
||||
extension := strings.ToLower(filepath.Ext(cleanPath))
|
||||
if cleanPath == "." ||
|
||||
cleanPath == string(filepath.Separator) ||
|
||||
lowerPath == ":memory:" ||
|
||||
strings.HasPrefix(lowerPath, "file:") ||
|
||||
(extension != ".db" && extension != ".sqlite" && extension != ".sqlite3") {
|
||||
return "", errors.New(
|
||||
DatabasePathEnvironment + " must be a SQLite file path",
|
||||
)
|
||||
}
|
||||
return cleanPath, nil
|
||||
}
|
||||
Reference in New Issue
Block a user