refactor(core): разбить client.go (1678 строк) на 15 мелких модулей по зонам ответственности
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ===== Логирование и debug-утилиты =====
|
||||
//
|
||||
// - ctxKeyLogLevel / CtxWithLogLevel — переопределение LogLevel на уровне ресурса
|
||||
// - debugLogPath / isHTTPDebugEnabled — файловый debug HTTP (NUBES_DEBUG_HTTP=1)
|
||||
// - sanitizeAuthHeader — маскирование Authorization в дампах
|
||||
// - formatStageMsg — форматирование stageMsg операции
|
||||
|
||||
// ctxKeyLogLevel — ключ для переопределения LogLevel на уровне ресурса через context.WithValue.
|
||||
type ctxKeyLogLevelType struct{}
|
||||
|
||||
var ctxKeyLogLevel = ctxKeyLogLevelType{}
|
||||
|
||||
func debugLogPath(fileName string) string {
|
||||
if dir := strings.TrimSpace(os.Getenv("NUBES_DEBUG_DIR")); dir != "" {
|
||||
return filepath.Join(dir, fileName)
|
||||
}
|
||||
return filepath.Join(os.TempDir(), fileName)
|
||||
}
|
||||
|
||||
func isHTTPDebugEnabled() bool {
|
||||
return os.Getenv("NUBES_DEBUG_HTTP") == "1"
|
||||
}
|
||||
|
||||
func sanitizeAuthHeader(h http.Header) http.Header {
|
||||
cloned := h.Clone()
|
||||
if cloned.Get("Authorization") != "" {
|
||||
cloned.Set("Authorization", "Bearer [REDACTED]")
|
||||
}
|
||||
return cloned
|
||||
}
|
||||
|
||||
// CtxWithLogLevel возвращает ctx с переопределённым уровнем логирования.
|
||||
func CtxWithLogLevel(ctx context.Context, level string) context.Context {
|
||||
return context.WithValue(ctx, ctxKeyLogLevel, level)
|
||||
}
|
||||
|
||||
// reTimestamp удаляет временны́е метки вида [2026-03-24T05:07:47.716Z +0.860s] из строк.
|
||||
var reTimestamp = regexp.MustCompile(`\[[0-9]{4}-[0-9]{2}-[0-9]{2}T[^\]]+\]\s*`)
|
||||
|
||||
// formatStageMsg парсит stageMsg (JSON-массив пар [имя, текст]) и возвращает
|
||||
// отформатированные строки для вывода. Временны́е метки убираются.
|
||||
func formatStageMsg(raw string) []string {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return nil
|
||||
}
|
||||
// Пытаемся распарсить как [["name","text"],...]
|
||||
var pairs [][]string
|
||||
if err := json.Unmarshal([]byte(raw), &pairs); err != nil || len(pairs) == 0 {
|
||||
return nil
|
||||
}
|
||||
// Вычисляем максимальную ширину имени для выравнивания
|
||||
maxLen := 0
|
||||
for _, p := range pairs {
|
||||
if len(p) >= 1 && len(p[0]) > maxLen {
|
||||
maxLen = len(p[0])
|
||||
}
|
||||
}
|
||||
var result []string
|
||||
for _, p := range pairs {
|
||||
if len(p) < 2 {
|
||||
continue
|
||||
}
|
||||
name := p[0]
|
||||
text := reTimestamp.ReplaceAllString(p[1], "")
|
||||
lines := strings.Split(strings.TrimSpace(text), "\n")
|
||||
padding := strings.Repeat(" ", maxLen-len(name))
|
||||
for i, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
if i == 0 {
|
||||
result = append(result, fmt.Sprintf(" %s:%s %s", name, padding, line))
|
||||
} else {
|
||||
result = append(result, fmt.Sprintf(" %s %s", strings.Repeat(" ", maxLen), line))
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user