From 47d517c91385a2b7c52f1af845c5f8a3c2fc090b Mon Sep 17 00:00:00 2001 From: Anibal Angulo Date: Mon, 2 Mar 2026 01:30:48 +0000 Subject: [PATCH] Add SQL Store --- cmd/gateway/main.go | 13 +++++++++---- config.example.yaml | 12 ++++++++++++ go.mod | 7 +++++++ go.sum | 16 ++++++++++++++++ internal/config/config.go | 23 +++++++++++++++++++---- 5 files changed, 63 insertions(+), 8 deletions(-) diff --git a/cmd/gateway/main.go b/cmd/gateway/main.go index 4dfb56e..0613492 100644 --- a/cmd/gateway/main.go +++ b/cmd/gateway/main.go @@ -9,6 +9,10 @@ import ( "os" "time" + _ "github.com/go-sql-driver/mysql" + _ "github.com/jackc/pgx/v5/stdlib" + _ "github.com/mattn/go-sqlite3" + "github.com/yourusername/go-llm-gateway/internal/auth" "github.com/yourusername/go-llm-gateway/internal/config" "github.com/yourusername/go-llm-gateway/internal/conversation" @@ -50,9 +54,11 @@ func main() { logger.Printf("Authentication disabled - WARNING: API is publicly accessible") } - // Initialize conversation store (1 hour TTL) - convStore := conversation.NewMemoryStore(1 * time.Hour) - logger.Printf("Conversation store initialized (TTL: 1h)") + // Initialize conversation store + convStore, err := initConversationStore(cfg.Conversations, logger) + if err != nil { + log.Fatalf("init conversation store: %v", err) + } gatewayServer := server.New(registry, convStore, logger) mux := http.NewServeMux() @@ -111,7 +117,6 @@ func initConversationStore(cfg config.ConversationConfig, logger *log.Logger) (c return conversation.NewMemoryStore(ttl), nil } } - func loggingMiddleware(next http.Handler, logger *log.Logger) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() diff --git a/config.example.yaml b/config.example.yaml index 5a12e1e..895b52f 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -26,6 +26,18 @@ providers: # api_key: "YOUR_AZURE_ANTHROPIC_API_KEY" # endpoint: "https://your-resource.services.ai.azure.com/anthropic" +# conversations: +# store: "sql" # "memory" (default) or "sql" +# ttl: "1h" # conversation expiration (default: 1h) +# driver: "sqlite3" # SQL driver: "sqlite3", "mysql", "pgx" +# dsn: "conversations.db" # connection string +# # MySQL example: +# # driver: "mysql" +# # dsn: "user:password@tcp(localhost:3306)/dbname?parseTime=true" +# # PostgreSQL example: +# # driver: "pgx" +# # dsn: "postgres://user:password@localhost:5432/dbname?sslmode=disable" + models: - name: "gemini-1.5-flash" provider: "google" diff --git a/go.mod b/go.mod index 4f8ed23..702dd68 100644 --- a/go.mod +++ b/go.mod @@ -14,15 +14,22 @@ require ( cloud.google.com/go v0.116.0 // indirect cloud.google.com/go/auth v0.9.3 // indirect cloud.google.com/go/compute/metadata v0.5.0 // indirect + filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai v0.9.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect + github.com/go-sql-driver/mysql v1.9.3 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.8.0 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/mattn/go-sqlite3 v1.14.34 // indirect github.com/openai/openai-go/v3 v3.2.0 // indirect github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect diff --git a/go.sum b/go.sum index be24977..79d78bc 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U= cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk= cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai v0.9.0 h1:t/DLMixbb8ygU11RAHJ8quXwJD7FwlC7+u6XodmSi1w= github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai v0.9.0/go.mod h1:Bb4vy1c7tXIqFrypNxCO7I5xlDSbpQiOWu/XvF5htP8= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= @@ -26,6 +28,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -59,6 +63,16 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gT github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= +github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk= +github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/openai/openai-go v1.12.0 h1:NBQCnXzqOTv5wsgNC36PrFEiskGfO5wccfCWDo9S1U0= github.com/openai/openai-go v1.12.0/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y= github.com/openai/openai-go/v3 v3.2.0 h1:2AbqFUCsoW2pm/2pUtPRuwK89dnoGHaQokzWsfoQO/U= @@ -69,6 +83,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= diff --git a/internal/config/config.go b/internal/config/config.go index 2d30632..18bca49 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -9,10 +9,25 @@ import ( // Config describes the full gateway configuration file. type Config struct { - Server ServerConfig `yaml:"server"` - Providers map[string]ProviderEntry `yaml:"providers"` - Models []ModelEntry `yaml:"models"` - Auth AuthConfig `yaml:"auth"` + Server ServerConfig `yaml:"server"` + Providers map[string]ProviderEntry `yaml:"providers"` + Models []ModelEntry `yaml:"models"` + Auth AuthConfig `yaml:"auth"` + Conversations ConversationConfig `yaml:"conversations"` +} + +// ConversationConfig controls conversation storage. +type ConversationConfig struct { + // Store is the storage backend: "memory" (default) or "sql". + Store string `yaml:"store"` + // TTL is the conversation expiration duration (e.g. "1h", "30m"). Defaults to "1h". + TTL string `yaml:"ttl"` + // DSN is the database connection string, required when store is "sql". + // Examples: "conversations.db" (SQLite), "postgres://user:pass@host/db". + DSN string `yaml:"dsn"` + // Driver is the SQL driver name, required when store is "sql". + // Examples: "sqlite3", "postgres", "mysql". + Driver string `yaml:"driver"` } // AuthConfig holds OIDC authentication settings.