Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
128
backend/internal/util/util.go
Normal file
128
backend/internal/util/util.go
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
// Package util provides utility functions for the CLI Proxy API server.
|
||||
// It includes helper functions for logging configuration, file system operations,
|
||||
// and other common utilities used throughout the application.
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var functionNameSanitizer = regexp.MustCompile(`[^a-zA-Z0-9_.:-]`)
|
||||
|
||||
// SanitizeFunctionName ensures a function name matches the requirements for Gemini/Vertex AI.
|
||||
// It replaces invalid characters with underscores, ensures it starts with a letter or underscore,
|
||||
// and truncates it to 64 characters if necessary.
|
||||
// Regex Rule: [^a-zA-Z0-9_.:-] replaced with _.
|
||||
func SanitizeFunctionName(name string) string {
|
||||
if name == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Replace invalid characters with underscore
|
||||
sanitized := functionNameSanitizer.ReplaceAllString(name, "_")
|
||||
|
||||
// Ensure it starts with a letter or underscore
|
||||
// Re-reading requirements: Must start with a letter or an underscore.
|
||||
if len(sanitized) > 0 {
|
||||
first := sanitized[0]
|
||||
if !((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z') || first == '_') {
|
||||
// If it starts with an allowed character but not allowed at the beginning (digit, dot, colon, dash),
|
||||
// we must prepend an underscore.
|
||||
|
||||
// To stay within the 64-character limit while prepending, we must truncate first.
|
||||
if len(sanitized) >= 64 {
|
||||
sanitized = sanitized[:63]
|
||||
}
|
||||
sanitized = "_" + sanitized
|
||||
}
|
||||
} else {
|
||||
sanitized = "_"
|
||||
}
|
||||
|
||||
// Truncate to 64 characters
|
||||
if len(sanitized) > 64 {
|
||||
sanitized = sanitized[:64]
|
||||
}
|
||||
return sanitized
|
||||
}
|
||||
|
||||
// SetLogLevel configures the logrus log level based on the configuration.
|
||||
// It sets the log level to DebugLevel if debug mode is enabled, otherwise to InfoLevel.
|
||||
func SetLogLevel(cfg *config.Config) {
|
||||
currentLevel := log.GetLevel()
|
||||
var newLevel log.Level
|
||||
if cfg.Debug {
|
||||
newLevel = log.DebugLevel
|
||||
} else {
|
||||
newLevel = log.InfoLevel
|
||||
}
|
||||
|
||||
if currentLevel != newLevel {
|
||||
log.SetLevel(newLevel)
|
||||
log.Infof("log level changed from %s to %s (debug=%t)", currentLevel, newLevel, cfg.Debug)
|
||||
}
|
||||
}
|
||||
|
||||
// ResolveAuthDir normalizes the auth directory path for consistent reuse throughout the app.
|
||||
// It expands a leading tilde (~) to the user's home directory and returns a cleaned path.
|
||||
// If authDir is empty, it defaults to ~/.cli-proxy-api.
|
||||
func ResolveAuthDir(authDir string) (string, error) {
|
||||
if authDir == "" {
|
||||
authDir = config.DefaultAuthDir
|
||||
}
|
||||
if strings.HasPrefix(authDir, "~") {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("resolve auth dir: %w", err)
|
||||
}
|
||||
remainder := strings.TrimPrefix(authDir, "~")
|
||||
remainder = strings.TrimLeft(remainder, "/\\")
|
||||
if remainder == "" {
|
||||
return filepath.Clean(home), nil
|
||||
}
|
||||
normalized := strings.ReplaceAll(remainder, "\\", "/")
|
||||
return filepath.Clean(filepath.Join(home, filepath.FromSlash(normalized))), nil
|
||||
}
|
||||
return filepath.Clean(authDir), nil
|
||||
}
|
||||
|
||||
// CountAuthFiles returns the number of auth records available through the provided Store.
|
||||
// For filesystem-backed stores, this reflects the number of JSON auth files under the configured directory.
|
||||
func CountAuthFiles[T any](ctx context.Context, store interface {
|
||||
List(context.Context) ([]T, error)
|
||||
}) int {
|
||||
if store == nil {
|
||||
return 0
|
||||
}
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
entries, err := store.List(ctx)
|
||||
if err != nil {
|
||||
log.Debugf("countAuthFiles: failed to list auth records: %v", err)
|
||||
return 0
|
||||
}
|
||||
return len(entries)
|
||||
}
|
||||
|
||||
// WritablePath returns the cleaned WRITABLE_PATH environment variable when it is set.
|
||||
// It accepts both uppercase and lowercase variants for compatibility with existing conventions.
|
||||
func WritablePath() string {
|
||||
for _, key := range []string{"WRITABLE_PATH", "writable_path"} {
|
||||
if value, ok := os.LookupEnv(key); ok {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
if trimmed != "" {
|
||||
return filepath.Clean(trimmed)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Loading…
Reference in a new issue