Restructured project
- backend moved to backend directory - added and initialized frontend with vue - moved infrastructure files to infra directory
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
RunMode RunMode
|
||||
DebugMode bool
|
||||
BotToken string
|
||||
|
||||
DBConnectionString string
|
||||
|
||||
OCRTokenPath string
|
||||
|
||||
TelegramApi string
|
||||
|
||||
APIPort string
|
||||
APIHost string
|
||||
APISecret string
|
||||
OpenAPIEnabled bool
|
||||
OpenAPIEndpoint string
|
||||
}
|
||||
|
||||
func Load() (Config, error) {
|
||||
_ = godotenv.Load()
|
||||
var warnings []string
|
||||
|
||||
mode := os.Getenv("RUN_MODE")
|
||||
debugMode := os.Getenv("DEBUG_MODE") == "true"
|
||||
botToken := os.Getenv("BOT_TOKEN")
|
||||
dbConnectionString := os.Getenv("DB_PATH")
|
||||
ocrTokenPath := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
|
||||
apiPort := os.Getenv("API_PORT")
|
||||
apiHost := os.Getenv("API_HOST")
|
||||
apiSecret := os.Getenv("API_SECRET")
|
||||
openAPIEnabled := os.Getenv("OPEN_API_ENABLED") == "true"
|
||||
openAPIEndpoint := os.Getenv("OPEN_API_ENDPOINT")
|
||||
|
||||
runMode, err := ParseRunMode(mode)
|
||||
if err != nil {
|
||||
warnings = append(warnings, err.Error())
|
||||
}
|
||||
|
||||
if runMode == Bot || runMode == Standalone {
|
||||
if ocrTokenPath == "" {
|
||||
warnings = append(warnings, "Missing required environment variable: GOOGLE_APPLICATION_CREDENTIALS")
|
||||
}
|
||||
if botToken == "" {
|
||||
warnings = append(warnings, "Missing required environment variable: BOT_TOKEN")
|
||||
}
|
||||
}
|
||||
if runMode == API || runMode == Standalone {
|
||||
if apiSecret == "" {
|
||||
warnings = append(warnings, "Missing required environment variable: API_SECRET")
|
||||
}
|
||||
if dbConnectionString == "" {
|
||||
dbConnectionString = "sqlite://data/app.db"
|
||||
}
|
||||
if apiHost == "" {
|
||||
apiHost = "localhost"
|
||||
}
|
||||
if apiPort == "" {
|
||||
apiPort = "8000"
|
||||
}
|
||||
if openAPIEndpoint == "" {
|
||||
openAPIEndpoint = "/docs"
|
||||
}
|
||||
}
|
||||
|
||||
if len(warnings) > 0 {
|
||||
return Config{}, errors.New(strings.Join(warnings, "\n"))
|
||||
}
|
||||
return Config{
|
||||
BotToken: botToken,
|
||||
DBConnectionString: dbConnectionString,
|
||||
OCRTokenPath: ocrTokenPath,
|
||||
DebugMode: debugMode,
|
||||
RunMode: runMode,
|
||||
APIPort: apiPort,
|
||||
APIHost: apiHost,
|
||||
APISecret: apiSecret,
|
||||
OpenAPIEnabled: openAPIEnabled,
|
||||
OpenAPIEndpoint: openAPIEndpoint,
|
||||
TelegramApi: "https://api.telegram.org",
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package config_test
|
||||
|
||||
import (
|
||||
"FamilyHub/src/config"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type EnvFixture struct {
|
||||
backup map[string]string
|
||||
}
|
||||
|
||||
func NewEnvFixture() *EnvFixture {
|
||||
env := make(map[string]string)
|
||||
|
||||
for _, e := range os.Environ() {
|
||||
pair := split(e)
|
||||
env[pair[0]] = pair[1]
|
||||
}
|
||||
|
||||
// полностью чистое окружение
|
||||
os.Clearenv()
|
||||
return &EnvFixture{backup: env}
|
||||
}
|
||||
|
||||
func (e *EnvFixture) Restore() {
|
||||
os.Clearenv()
|
||||
for key, val := range e.backup {
|
||||
_ = os.Setenv(key, val)
|
||||
}
|
||||
}
|
||||
|
||||
func split(s string) [2]string {
|
||||
var p [2]string
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == '=' {
|
||||
p[0] = s[:i]
|
||||
p[1] = s[i+1:]
|
||||
return p
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func MustSet(env map[string]string) {
|
||||
for k, v := range env {
|
||||
_ = os.Setenv(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func MustUnset(keys ...string) {
|
||||
for _, k := range keys {
|
||||
_ = os.Unsetenv(k)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigLoad_Table(t *testing.T) {
|
||||
env := NewEnvFixture()
|
||||
defer env.Restore()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
env map[string]string
|
||||
want config.Config
|
||||
error bool
|
||||
}{
|
||||
{
|
||||
name: "ok - values set",
|
||||
env: map[string]string{"BOT_TOKEN": "abc", "DB_PATH": "db.sqlite"},
|
||||
want: config.Config{BotToken: "abc", DBConnectionString: "db.sqlite"},
|
||||
},
|
||||
{
|
||||
name: "fail - missing token",
|
||||
env: map[string]string{}, // ничего нет
|
||||
error: true,
|
||||
},
|
||||
{
|
||||
name: "default DB path applied",
|
||||
env: map[string]string{"BOT_TOKEN": "xyz"},
|
||||
error: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
testCase := tc
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
os.Clearenv()
|
||||
MustSet(testCase.env)
|
||||
|
||||
cfg, err := config.Load()
|
||||
|
||||
if testCase.error {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, testCase.want.BotToken, cfg.BotToken)
|
||||
assert.Equal(t, testCase.want.DBConnectionString, cfg.DBConnectionString)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RunMode string
|
||||
|
||||
const (
|
||||
Bot RunMode = "bot"
|
||||
API RunMode = "api"
|
||||
Standalone RunMode = "standalone"
|
||||
Unknown RunMode = "unknown"
|
||||
)
|
||||
|
||||
func ParseRunMode(s string) (RunMode, error) {
|
||||
switch strings.ToLower(s) {
|
||||
case "bot":
|
||||
return Bot, nil
|
||||
case "api":
|
||||
return API, nil
|
||||
case "standalone":
|
||||
return Standalone, nil
|
||||
default:
|
||||
return Unknown, fmt.Errorf("invalid run mode: %s", s)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user