feat(backend): implement task creation and admin web
This commit is contained in:
@@ -10,11 +10,13 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
HTTPAddressEnvironment = "CMROUBAO_HTTP_ADDR"
|
||||
DatabasePathEnvironment = "CMROUBAO_DATABASE_PATH"
|
||||
HTTPAddressEnvironment = "CMROUBAO_HTTP_ADDR"
|
||||
DatabasePathEnvironment = "CMROUBAO_DATABASE_PATH"
|
||||
AssetDirectoryEnvironment = "CMROUBAO_ASSET_DIR"
|
||||
|
||||
defaultHTTPAddress = "127.0.0.1:8080"
|
||||
defaultDatabasePath = "var/cmroubao.db"
|
||||
defaultHTTPAddress = "127.0.0.1:8080"
|
||||
defaultDatabasePath = "var/cmroubao.db"
|
||||
defaultAssetDirectory = "var/assets"
|
||||
)
|
||||
|
||||
type LookupEnvironment func(string) (string, bool)
|
||||
@@ -22,6 +24,7 @@ type LookupEnvironment func(string) (string, bool)
|
||||
type Config struct {
|
||||
HTTPAddress string
|
||||
DatabasePath string
|
||||
AssetDirectory string
|
||||
ReadHeaderTimeout time.Duration
|
||||
ReadTimeout time.Duration
|
||||
WriteTimeout time.Duration
|
||||
@@ -53,9 +56,23 @@ func Load(lookup LookupEnvironment) (Config, error) {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
assetDirectory, err := environmentValue(
|
||||
lookup,
|
||||
AssetDirectoryEnvironment,
|
||||
defaultAssetDirectory,
|
||||
)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
assetDirectory, err = validatedAssetDirectory(assetDirectory)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
return Config{
|
||||
HTTPAddress: httpAddress,
|
||||
DatabasePath: filepath.Clean(databasePath),
|
||||
AssetDirectory: assetDirectory,
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: 30 * time.Second,
|
||||
@@ -65,6 +82,24 @@ func Load(lookup LookupEnvironment) (Config, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func validatedAssetDirectory(path string) (string, error) {
|
||||
if strings.ContainsRune(path, '\x00') {
|
||||
return "", errors.New(
|
||||
AssetDirectoryEnvironment + " contains an invalid character",
|
||||
)
|
||||
}
|
||||
cleanPath := filepath.Clean(path)
|
||||
volumeRoot := filepath.VolumeName(cleanPath) + string(filepath.Separator)
|
||||
if cleanPath == "." ||
|
||||
cleanPath == string(filepath.Separator) ||
|
||||
cleanPath == volumeRoot {
|
||||
return "", errors.New(
|
||||
AssetDirectoryEnvironment + " must be a dedicated directory",
|
||||
)
|
||||
}
|
||||
return cleanPath, nil
|
||||
}
|
||||
|
||||
func LoadDatabasePath(lookup LookupEnvironment) (string, error) {
|
||||
databasePath, err := environmentValue(
|
||||
lookup,
|
||||
|
||||
@@ -18,6 +18,9 @@ func TestLoadUsesSafeDefaults(t *testing.T) {
|
||||
if cfg.DatabasePath != filepath.FromSlash("var/cmroubao.db") {
|
||||
t.Fatalf("DatabasePath = %q", cfg.DatabasePath)
|
||||
}
|
||||
if cfg.AssetDirectory != filepath.FromSlash("var/assets") {
|
||||
t.Fatalf("AssetDirectory = %q", cfg.AssetDirectory)
|
||||
}
|
||||
if cfg.ReadHeaderTimeout <= 0 ||
|
||||
cfg.ReadTimeout <= 0 ||
|
||||
cfg.WriteTimeout <= 0 ||
|
||||
@@ -33,8 +36,9 @@ func TestLoadUsesSafeDefaults(t *testing.T) {
|
||||
|
||||
func TestLoadAcceptsExplicitConfiguration(t *testing.T) {
|
||||
values := map[string]string{
|
||||
HTTPAddressEnvironment: "192.0.2.10:9090",
|
||||
DatabasePathEnvironment: "tmp/test.db",
|
||||
HTTPAddressEnvironment: "192.0.2.10:9090",
|
||||
DatabasePathEnvironment: "tmp/test.db",
|
||||
AssetDirectoryEnvironment: "tmp/assets",
|
||||
}
|
||||
|
||||
cfg, err := Load(mapEnvironment(values))
|
||||
@@ -48,6 +52,9 @@ func TestLoadAcceptsExplicitConfiguration(t *testing.T) {
|
||||
if cfg.DatabasePath != filepath.Clean(values[DatabasePathEnvironment]) {
|
||||
t.Fatalf("DatabasePath = %q", cfg.DatabasePath)
|
||||
}
|
||||
if cfg.AssetDirectory != filepath.Clean(values[AssetDirectoryEnvironment]) {
|
||||
t.Fatalf("AssetDirectory = %q", cfg.AssetDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadRejectsUnsafeOrInvalidValues(t *testing.T) {
|
||||
@@ -97,6 +104,18 @@ func TestLoadRejectsUnsafeOrInvalidValues(t *testing.T) {
|
||||
DatabasePathEnvironment: "var/database.txt",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "asset root directory",
|
||||
values: map[string]string{
|
||||
AssetDirectoryEnvironment: string(filepath.Separator),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "asset current directory",
|
||||
values: map[string]string{
|
||||
AssetDirectoryEnvironment: ".",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
Reference in New Issue
Block a user