Merge Go frontend (apiserver + xcecli) into meson build
This commit is contained in:
parent
43dc12a36c
commit
c9dc8c4676
205 changed files with 30793 additions and 328 deletions
293
src/frontend/apiserver/utils/config.go
Normal file
293
src/frontend/apiserver/utils/config.go
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type BackendConfig struct {
|
||||
Address string `yaml:"address"`
|
||||
Port int `yaml:"port"`
|
||||
From string `yaml:"from"`
|
||||
Key string `yaml:"key"`
|
||||
}
|
||||
|
||||
type AppServerConfig struct {
|
||||
AppConfig AppConfig `yaml:"app"`
|
||||
Security Security `yaml:"security"`
|
||||
RateLimit RateLimitConfig `yaml:"rate_limit"`
|
||||
Authentication Authentication `yaml:"authentication"`
|
||||
JobConfig JobConfig `yaml:"job"`
|
||||
CacheConfig CacheConfig `yaml:"cache"`
|
||||
Backend BackendConfig `yaml:"backend"`
|
||||
}
|
||||
|
||||
type AppConfig struct {
|
||||
AppName string `yaml:"name"`
|
||||
AppMode string `yaml:"mode"`
|
||||
HTTPPort string `yaml:"http_port"`
|
||||
AppVersion string `yaml:"version"`
|
||||
}
|
||||
|
||||
// TokenConfig is the configuration for the token
|
||||
type TokenConfig struct {
|
||||
Type string `yaml:"type"`
|
||||
SecretKey string `yaml:"secret_key"`
|
||||
TokenExpireTime int `yaml:"token_expire_time"`
|
||||
}
|
||||
|
||||
// Authentication is the configuration for the authentication
|
||||
type Authentication struct {
|
||||
Token TokenConfig
|
||||
}
|
||||
|
||||
type Security struct {
|
||||
HTTPS HTTPSConfig `yaml:"https"`
|
||||
}
|
||||
type HTTPSConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Port string `yaml:"port"`
|
||||
CertFile string `yaml:"cert_file"`
|
||||
KeyFile string `yaml:"key_file"`
|
||||
}
|
||||
|
||||
type RateLimitConfig struct {
|
||||
Global EndpointLimit `yaml:"global"`
|
||||
Endpoints map[string]EndpointLimit `yaml:"endpoints"`
|
||||
}
|
||||
|
||||
type EndpointLimit struct {
|
||||
Rate int `yaml:"rate"` // requests per second
|
||||
Burst int `yaml:"burst"` // requests per minute
|
||||
Window string `yaml:"window"` // Time window (second, minute)
|
||||
}
|
||||
|
||||
type WhitelistConfig struct {
|
||||
Whitelist []string `yaml:"whitelist"`
|
||||
}
|
||||
|
||||
type FileUploadConfig struct {
|
||||
MaxSize string `yaml:"max_size"` // maximum file size in MB
|
||||
AllowedTypes []string `yaml:"allowed_types"` // allowed file types
|
||||
DisallowedTypes []string `yaml:"disallowed_types"` // disallowed file types
|
||||
}
|
||||
|
||||
type JobConfig struct {
|
||||
MaxArraySize int `yaml:"max_array_size"`
|
||||
}
|
||||
|
||||
type CORSConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
AllowedOrigins []string `yaml:"allowed_origins"`
|
||||
}
|
||||
|
||||
type CacheConfig struct {
|
||||
RefreshInterval int `yaml:"refresh_interval"`
|
||||
}
|
||||
|
||||
var DirPerm os.FileMode
|
||||
|
||||
// Add global variables to store configs
|
||||
var (
|
||||
AppYamlConfig *AppConfig
|
||||
AuthenticationYamlConfig *Authentication
|
||||
HttpsYamlConfig *HTTPSConfig
|
||||
RateLimitYamlConfig *RateLimitConfig
|
||||
WhitelistYamlConfig *WhitelistConfig
|
||||
FileUploadYamlConfig *FileUploadConfig
|
||||
JobYamlConfig *JobConfig
|
||||
CacheYamlConfig *CacheConfig
|
||||
CORSYamlConfig *CORSConfig
|
||||
BackendYamlConfig *BackendConfig
|
||||
)
|
||||
|
||||
func init() {
|
||||
if runtime.GOOS == "windows" {
|
||||
DirPerm = 0666
|
||||
} else {
|
||||
DirPerm = 0700
|
||||
}
|
||||
}
|
||||
|
||||
func InitConf() error {
|
||||
Debug("Enter InitConf() function")
|
||||
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AddConfigPath(Global_TopDir + "/config")
|
||||
viper.SetConfigName("app")
|
||||
// validate the app.yaml file whether is validate
|
||||
data, err := ValidateYamlFormat(Global_TopDir + "/config/app.yaml")
|
||||
if err != nil {
|
||||
Error("Fail to call DiagnoseLogCreationError with error")
|
||||
return err
|
||||
}
|
||||
if data == nil {
|
||||
Error("Fail to call ValidateYamlFormat and data is nil")
|
||||
return err
|
||||
}
|
||||
|
||||
err1 := viper.ReadInConfig()
|
||||
if err1 != nil {
|
||||
_, ok := err1.(viper.ConfigFileNotFoundError)
|
||||
if ok {
|
||||
Error("Can't find the configuration files of app.yaml")
|
||||
return err1
|
||||
} else {
|
||||
log.Println("The configuration file of app.yaml with some error")
|
||||
return err1
|
||||
}
|
||||
}
|
||||
// parse app section
|
||||
AppYamlConfig = &AppConfig{
|
||||
AppName: viper.GetString("app.name"),
|
||||
AppMode: viper.GetString("app.runmode"),
|
||||
HTTPPort: viper.GetString("app.http_port"),
|
||||
AppVersion: viper.GetString("app.version"),
|
||||
}
|
||||
// parse authentication section
|
||||
AuthenticationYamlConfig = &Authentication{
|
||||
Token: TokenConfig{
|
||||
Type: viper.GetString("authentication.token.type"),
|
||||
SecretKey: resolveJWTSecret(viper.GetString("authentication.token.secretKey")),
|
||||
TokenExpireTime: int(viper.GetFloat64("authentication.token.token_expire_time")),
|
||||
},
|
||||
}
|
||||
// parse security section
|
||||
HttpsYamlConfig = &HTTPSConfig{
|
||||
Enabled: viper.GetBool("security.https.enabled"),
|
||||
Port: viper.GetString("security.https.port"),
|
||||
CertFile: viper.GetString("security.https.cert_file"),
|
||||
KeyFile: viper.GetString("security.https.key_file"),
|
||||
}
|
||||
|
||||
// parse rate limit section
|
||||
RateLimitYamlConfig = &RateLimitConfig{
|
||||
Global: EndpointLimit{
|
||||
Rate: viper.GetInt("rate_limit.global.rate"),
|
||||
Burst: viper.GetInt("rate_limit.global.burst"),
|
||||
Window: viper.GetString("rate_limit.global.window"),
|
||||
},
|
||||
Endpoints: make(map[string]EndpointLimit),
|
||||
}
|
||||
// parse endpoints
|
||||
endpoints := viper.GetStringMap("rate_limit.endpoints")
|
||||
for path := range endpoints {
|
||||
RateLimitYamlConfig.Endpoints[path] = EndpointLimit{
|
||||
Rate: viper.GetInt("rate_limit.endpoints." + path + ".rate"),
|
||||
Burst: viper.GetInt("rate_limit.endpoints." + path + ".burst"),
|
||||
Window: viper.GetString("rate_limit.endpoints." + path + ".window"),
|
||||
}
|
||||
}
|
||||
|
||||
WhitelistYamlConfig = &WhitelistConfig{
|
||||
Whitelist: viper.GetStringSlice("whitelist"),
|
||||
}
|
||||
// parse file upload section
|
||||
rawMaxSize := viper.GetString("file_upload.max_size")
|
||||
fileMaxSizeMB, err := ParseMaxSize(rawMaxSize)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse max_size: %v", err)
|
||||
}
|
||||
FileUploadYamlConfig = &FileUploadConfig{
|
||||
MaxSize: strconv.FormatInt(fileMaxSizeMB, 10) + " MB",
|
||||
AllowedTypes: viper.GetStringSlice("file_upload.allowed_types"),
|
||||
DisallowedTypes: viper.GetStringSlice("file_upload.disallowed_types"),
|
||||
}
|
||||
|
||||
// parse job config section
|
||||
// parse job config section
|
||||
if !viper.IsSet("job") {
|
||||
// if job section is not set, use default values
|
||||
JobYamlConfig = &JobConfig{
|
||||
MaxArraySize: 1000,
|
||||
}
|
||||
} else {
|
||||
maxArraySize := viper.GetInt("job.max_array_size")
|
||||
if maxArraySize == 0 {
|
||||
maxArraySize = 1000
|
||||
}
|
||||
if maxArraySize < 1 || maxArraySize > 2147483646 {
|
||||
return fmt.Errorf("invalid job.max_array_size value: %d, must be between 1 and 2147483646", maxArraySize)
|
||||
}
|
||||
JobYamlConfig = &JobConfig{
|
||||
MaxArraySize: maxArraySize,
|
||||
}
|
||||
}
|
||||
|
||||
// parse cache config section
|
||||
if !viper.IsSet("cache") {
|
||||
// if cache section is not set, use default values
|
||||
CacheYamlConfig = &CacheConfig{
|
||||
RefreshInterval: 300,
|
||||
}
|
||||
} else {
|
||||
refreshInterval := viper.GetInt("cache.refresh_interval")
|
||||
if refreshInterval == 0 {
|
||||
refreshInterval = 300
|
||||
}
|
||||
if refreshInterval < 1 || refreshInterval > 300 {
|
||||
return fmt.Errorf("invalid cache.refresh_interval value: %d, must be between 1 and 300", refreshInterval)
|
||||
}
|
||||
CacheYamlConfig = &CacheConfig{
|
||||
RefreshInterval: refreshInterval,
|
||||
}
|
||||
}
|
||||
|
||||
CORSYamlConfig = &CORSConfig{
|
||||
Enabled: viper.GetBool("cors.enabled"),
|
||||
AllowedOrigins: viper.GetStringSlice("cors.allowed_origins"),
|
||||
}
|
||||
|
||||
BackendYamlConfig = &BackendConfig{
|
||||
Address: viper.GetString("backend.address"),
|
||||
Port: viper.GetInt("backend.port"),
|
||||
From: viper.GetString("backend.from"),
|
||||
Key: viper.GetString("backend.key"),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseMaxSize(maxSize string) (int64, error) {
|
||||
parts := strings.Fields(maxSize)
|
||||
if len(parts) != 2 {
|
||||
return 0, errors.New("invalid max_size format, expected '<number> <unit>'")
|
||||
}
|
||||
|
||||
size, err := strconv.ParseInt(parts[0], 10, 64)
|
||||
if err != nil {
|
||||
return 0, errors.New("invalid number in max_size")
|
||||
}
|
||||
|
||||
unit := strings.ToUpper(parts[1])
|
||||
switch unit {
|
||||
case "MB":
|
||||
size *= 1 // MB remains as is
|
||||
case "GB":
|
||||
size *= 1024 // convert GB to MB
|
||||
default:
|
||||
return 0, errors.New("unsupported unit in max_size, use MB or GB")
|
||||
}
|
||||
|
||||
if size > 10240 {
|
||||
return 0, errors.New("max_size cannot exceed 10GB (10240 MB)")
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// resolveJWTSecret returns the JWT secret from XCE_JWT_SECRET env var if set and non-empty,
|
||||
// otherwise falls back to the value from config file.
|
||||
func resolveJWTSecret(configValue string) string {
|
||||
if env := os.Getenv("XCE_JWT_SECRET"); env != "" {
|
||||
return env
|
||||
}
|
||||
return configValue
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue