Skip to content

Commit 5123cfd

Browse files
committed
feat(store): add PostgreSQL-backed config store with env selection
1 parent 32a8102 commit 5123cfd

File tree

6 files changed

+755
-28
lines changed

6 files changed

+755
-28
lines changed

cmd/server/main.go

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"os"
1313
"path/filepath"
1414
"strings"
15+
"time"
1516

1617
configaccess "github.com/router-for-me/CLIProxyAPI/v6/internal/access/config_access"
1718
"github.com/router-for-me/CLIProxyAPI/v6/internal/cmd"
@@ -101,6 +102,12 @@ func main() {
101102
var cfg *config.Config
102103
var isCloudDeploy bool
103104
var (
105+
usePostgresStore bool
106+
pgStoreDSN string
107+
pgStoreSchema string
108+
pgStoreConfigKey string
109+
pgStoreCacheDir string
110+
pgStoreInst *store.PostgresStore
104111
gitStoreLocalPath string
105112
useGitStore bool
106113
gitStoreRemoteURL string
@@ -125,6 +132,22 @@ func main() {
125132
}
126133
return "", false
127134
}
135+
if value, ok := lookupEnv("PGSTORE_DSN", "pgstore_dsn"); ok {
136+
usePostgresStore = true
137+
pgStoreDSN = value
138+
}
139+
if usePostgresStore {
140+
if value, ok := lookupEnv("PGSTORE_SCHEMA", "pgstore_schema"); ok {
141+
pgStoreSchema = value
142+
}
143+
if value, ok := lookupEnv("PGSTORE_CONFIG_KEY", "pgstore_config_key"); ok {
144+
pgStoreConfigKey = value
145+
}
146+
if value, ok := lookupEnv("PGSTORE_CACHE_DIR", "pgstore_cache_dir"); ok {
147+
pgStoreCacheDir = value
148+
}
149+
useGitStore = false
150+
}
128151
if value, ok := lookupEnv("GITSTORE_GIT_URL", "gitstore_git_url"); ok {
129152
useGitStore = true
130153
gitStoreRemoteURL = value
@@ -147,13 +170,42 @@ func main() {
147170
}
148171

149172
// Determine and load the configuration file.
150-
// If gitstore is configured, load from the cloned repository; otherwise use the provided path or default.
173+
// Prefer the Postgres store when configured, otherwise fallback to git or local files.
151174
var configFilePath string
152-
if useGitStore {
175+
if usePostgresStore {
176+
if pgStoreCacheDir == "" {
177+
pgStoreCacheDir = wd
178+
}
179+
pgStoreCacheDir = filepath.Join(pgStoreCacheDir, "pgstore")
180+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
181+
pgStoreInst, err = store.NewPostgresStore(ctx, store.PostgresStoreConfig{
182+
DSN: pgStoreDSN,
183+
Schema: pgStoreSchema,
184+
ConfigKey: pgStoreConfigKey,
185+
SpoolDir: pgStoreCacheDir,
186+
})
187+
cancel()
188+
if err != nil {
189+
log.Fatalf("failed to initialize postgres token store: %v", err)
190+
}
191+
examplePath := filepath.Join(wd, "config.example.yaml")
192+
ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
193+
if errBootstrap := pgStoreInst.Bootstrap(ctx, examplePath); errBootstrap != nil {
194+
cancel()
195+
log.Fatalf("failed to bootstrap postgres-backed config: %v", errBootstrap)
196+
}
197+
cancel()
198+
configFilePath = pgStoreInst.ConfigPath()
199+
cfg, err = config.LoadConfigOptional(configFilePath, isCloudDeploy)
200+
if err == nil {
201+
cfg.AuthDir = pgStoreInst.AuthDir()
202+
log.Infof("postgres-backed token store enabled, workspace path: %s", pgStoreInst.WorkDir())
203+
}
204+
} else if useGitStore {
153205
if gitStoreLocalPath == "" {
154206
gitStoreLocalPath = wd
155207
}
156-
gitStoreRoot = filepath.Join(gitStoreLocalPath, "remote")
208+
gitStoreRoot = filepath.Join(gitStoreLocalPath, "gitstore")
157209
authDir := filepath.Join(gitStoreRoot, "auths")
158210
gitStoreInst = store.NewGitTokenStore(gitStoreRemoteURL, gitStoreUser, gitStorePassword)
159211
gitStoreInst.SetBaseDir(authDir)
@@ -172,7 +224,7 @@ func main() {
172224
if errCopy := misc.CopyConfigTemplate(examplePath, configFilePath); errCopy != nil {
173225
log.Fatalf("failed to bootstrap git-backed config: %v", errCopy)
174226
}
175-
if errCommit := gitStoreInst.CommitConfig(context.Background()); errCommit != nil {
227+
if errCommit := gitStoreInst.PersistConfig(context.Background()); errCommit != nil {
176228
log.Fatalf("failed to commit initial git-backed config: %v", errCommit)
177229
}
178230
log.Infof("git-backed config initialized from template: %s", configFilePath)
@@ -245,7 +297,9 @@ func main() {
245297
}
246298

247299
// Register the shared token store once so all components use the same persistence backend.
248-
if useGitStore {
300+
if usePostgresStore {
301+
sdkAuth.RegisterTokenStore(pgStoreInst)
302+
} else if useGitStore {
249303
sdkAuth.RegisterTokenStore(gitStoreInst)
250304
} else {
251305
sdkAuth.RegisterTokenStore(sdkAuth.NewFileTokenStore())

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/gin-gonic/gin v1.10.1
88
github.com/go-git/go-git/v6 v6.0.0-20251009132922-75a182125145
99
github.com/google/uuid v1.6.0
10+
github.com/jackc/pgx/v5 v5.7.6
1011
github.com/klauspost/compress v1.17.3
1112
github.com/sirupsen/logrus v1.9.3
1213
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
@@ -39,6 +40,9 @@ require (
3940
github.com/go-playground/validator/v10 v10.20.0 // indirect
4041
github.com/goccy/go-json v0.10.2 // indirect
4142
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
43+
github.com/jackc/pgpassfile v1.0.0 // indirect
44+
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
45+
github.com/jackc/puddle/v2 v2.2.2 // indirect
4246
github.com/json-iterator/go v1.1.12 // indirect
4347
github.com/kevinburke/ssh_config v1.4.0 // indirect
4448
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
@@ -54,6 +58,7 @@ require (
5458
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
5559
github.com/ugorji/go/codec v1.2.12 // indirect
5660
golang.org/x/arch v0.8.0 // indirect
61+
golang.org/x/sync v0.17.0 // indirect
5762
golang.org/x/sys v0.37.0 // indirect
5863
golang.org/x/text v0.30.0 // indirect
5964
google.golang.org/protobuf v1.34.1 // indirect

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
6262
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
6363
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
6464
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
65+
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
66+
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
67+
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
68+
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
69+
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
70+
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
71+
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
72+
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
6573
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
6674
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
6775
github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
@@ -137,6 +145,8 @@ golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
137145
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
138146
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
139147
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
148+
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
149+
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
140150
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
141151
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
142152
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=

internal/store/gitstore.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,9 @@ func (s *GitTokenStore) Delete(_ context.Context, id string) error {
359359
return nil
360360
}
361361

362-
// CommitPaths commits and pushes the provided paths to the remote repository.
362+
// PersistAuthFiles commits and pushes the provided paths to the remote repository.
363363
// It no-ops when the store is not fully configured or when there are no paths.
364-
func (s *GitTokenStore) CommitPaths(_ context.Context, message string, paths ...string) error {
364+
func (s *GitTokenStore) PersistAuthFiles(_ context.Context, message string, paths ...string) error {
365365
if len(paths) == 0 {
366366
return nil
367367
}
@@ -652,8 +652,8 @@ func (s *GitTokenStore) rewriteHeadAsSingleCommit(repo *git.Repository, branch p
652652
return nil
653653
}
654654

655-
// CommitConfig commits and pushes configuration changes to git.
656-
func (s *GitTokenStore) CommitConfig(_ context.Context) error {
655+
// PersistConfig commits and pushes configuration changes to git.
656+
func (s *GitTokenStore) PersistConfig(_ context.Context) error {
657657
if err := s.EnsureRepository(); err != nil {
658658
return err
659659
}

0 commit comments

Comments
 (0)