forked from templates/template-go-backend
- Приоритетная очередь для контроля параллельных запросов - Аутентификация по API-ключу из URL (/auth/<key>/v1/...) - Роли пользователей с белым списком моделей и ограничением контекста (num_ctx) - Sliding window rate limiting - Admin API для горячей перезагрузки users.json без перезапуска прокси - Graceful shutdown с таймаутом завершения активных запросов - Маскировка API-ключа в логах - Подробная инструкция по установке для Windows и Linux (SETUP_WIN_SERVER.md)
85 lines
2.8 KiB
Go
85 lines
2.8 KiB
Go
package config
|
||
|
||
import (
|
||
"fmt"
|
||
"log/slog"
|
||
"net/url"
|
||
"os"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// GetEnvAs загружает переменную окружения key, парсит её функцией parse
|
||
// и возвращает результат. При отсутствии переменной или ошибке парсинга
|
||
// возвращает defaultVal.
|
||
func GetEnvAs[T any](key string, defaultVal T, parse func(string) (T, error)) T {
|
||
raw, ok := os.LookupEnv(key)
|
||
if !ok || strings.TrimSpace(raw) == "" {
|
||
return defaultVal
|
||
}
|
||
v, err := parse(raw)
|
||
if err != nil {
|
||
slog.Warn(fmt.Sprintf("Некорректное значение переменной %q, используется значение по умолчанию", key),
|
||
"key", key, "raw", raw, "default", defaultVal, "error", err)
|
||
return defaultVal
|
||
}
|
||
return v
|
||
}
|
||
|
||
// --- Парсеры для базовых типов ---
|
||
|
||
func ParseString(s string) (string, error) { return strings.TrimSpace(s), nil }
|
||
func ParseBool(s string) (bool, error) { return strconv.ParseBool(strings.TrimSpace(s)) }
|
||
func ParseFloat64(s string) (float64, error) { return strconv.ParseFloat(strings.TrimSpace(s), 64) }
|
||
func ParseURL(s string) (*url.URL, error) { return url.Parse(strings.TrimSpace(s)) }
|
||
func ParseTimeRFC3339(s string) (time.Time, error) { return time.Parse(time.RFC3339, strings.TrimSpace(s)) }
|
||
|
||
func ParseInt(s string) (int, error) {
|
||
i64, err := strconv.ParseInt(strings.TrimSpace(s), 10, 0)
|
||
return int(i64), err
|
||
}
|
||
|
||
func ParseInt64(s string) (int64, error) {
|
||
return strconv.ParseInt(strings.TrimSpace(s), 10, 64)
|
||
}
|
||
|
||
func ParseUint(s string) (uint, error) {
|
||
u64, err := strconv.ParseUint(strings.TrimSpace(s), 10, 0)
|
||
return uint(u64), err
|
||
}
|
||
|
||
// ParseDuration парсит строку длительности ("150ms", "2s", "1m", "24h").
|
||
func ParseDuration(s string) (time.Duration, error) {
|
||
return time.ParseDuration(strings.TrimSpace(s))
|
||
}
|
||
|
||
// --- Парсеры для списков ---
|
||
|
||
// MakeListParser создаёт парсер для строки-списка с заданным разделителем.
|
||
func MakeListParser[T any](sep string, itemParser func(string) (T, error)) func(string) ([]T, error) {
|
||
return func(s string) ([]T, error) {
|
||
s = strings.TrimSpace(s)
|
||
if s == "" {
|
||
var zero []T
|
||
return zero, nil
|
||
}
|
||
parts := strings.Split(s, sep)
|
||
out := make([]T, 0, len(parts))
|
||
for _, p := range parts {
|
||
v, err := itemParser(p)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("ошибка парсинга элемента %q: %w", p, err)
|
||
}
|
||
out = append(out, v)
|
||
}
|
||
return out, nil
|
||
}
|
||
}
|
||
|
||
var (
|
||
ParseCSVStrings = MakeListParser[string](",", ParseString)
|
||
ParseCSVInts = MakeListParser[int](",", ParseInt)
|
||
ParseCSVFloat64 = MakeListParser[float64](",", ParseFloat64)
|
||
)
|