luispater commited on
Commit
b08747e
·
unverified ·
2 Parent(s): 41682377ad4c22

Merge pull request #104 from router-for-me/cloud

Browse files
cmd/server/main.go CHANGED
@@ -96,6 +96,14 @@ func main() {
96
  var err error
97
  var cfg *config.Config
98
  var wd string
 
 
 
 
 
 
 
 
99
 
100
  // Determine and load the configuration file.
101
  // If a config path is provided via flags, it is used directly.
@@ -103,18 +111,34 @@ func main() {
103
  var configFilePath string
104
  if configPath != "" {
105
  configFilePath = configPath
106
- cfg, err = config.LoadConfig(configPath)
107
  } else {
108
  wd, err = os.Getwd()
109
  if err != nil {
110
  log.Fatalf("failed to get working directory: %v", err)
111
  }
112
  configFilePath = filepath.Join(wd, "config.yaml")
113
- cfg, err = config.LoadConfig(configFilePath)
114
  }
115
  if err != nil {
116
  log.Fatalf("failed to load config: %v", err)
117
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  usage.SetStatisticsEnabled(cfg.UsageStatisticsEnabled)
119
 
120
  if err = logging.ConfigureLogOutput(cfg.LoggingToFile); err != nil {
@@ -161,6 +185,12 @@ func main() {
161
  } else if geminiWebAuth {
162
  cmd.DoGeminiWebAuth(cfg)
163
  } else {
 
 
 
 
 
 
164
  // Start the main proxy service
165
  cmd.StartService(cfg, configFilePath, password)
166
  }
 
96
  var err error
97
  var cfg *config.Config
98
  var wd string
99
+ var isCloudDeploy bool
100
+
101
+ // Check for cloud deploy mode only on first execution
102
+ // Read env var name in uppercase: DEPLOY
103
+ deployEnv := os.Getenv("DEPLOY")
104
+ if deployEnv == "cloud" {
105
+ isCloudDeploy = true
106
+ }
107
 
108
  // Determine and load the configuration file.
109
  // If a config path is provided via flags, it is used directly.
 
111
  var configFilePath string
112
  if configPath != "" {
113
  configFilePath = configPath
114
+ cfg, err = config.LoadConfigOptional(configPath, isCloudDeploy)
115
  } else {
116
  wd, err = os.Getwd()
117
  if err != nil {
118
  log.Fatalf("failed to get working directory: %v", err)
119
  }
120
  configFilePath = filepath.Join(wd, "config.yaml")
121
+ cfg, err = config.LoadConfigOptional(configFilePath, isCloudDeploy)
122
  }
123
  if err != nil {
124
  log.Fatalf("failed to load config: %v", err)
125
  }
126
+
127
+ // Log if we're running without a config file in cloud deploy mode
128
+ var configFileExists bool
129
+ if isCloudDeploy {
130
+ if info, errStat := os.Stat(configFilePath); errStat != nil {
131
+ // Don't mislead: API server will not start until configuration is provided.
132
+ log.Info("Cloud deploy mode: No configuration file detected; standing by for configuration (API server not started)")
133
+ configFileExists = false
134
+ } else if info.IsDir() {
135
+ log.Info("Cloud deploy mode: Config path is a directory; standing by for configuration (API server not started)")
136
+ configFileExists = false
137
+ } else {
138
+ log.Info("Cloud deploy mode: Configuration file detected; starting service")
139
+ configFileExists = true
140
+ }
141
+ }
142
  usage.SetStatisticsEnabled(cfg.UsageStatisticsEnabled)
143
 
144
  if err = logging.ConfigureLogOutput(cfg.LoggingToFile); err != nil {
 
185
  } else if geminiWebAuth {
186
  cmd.DoGeminiWebAuth(cfg)
187
  } else {
188
+ // In cloud deploy mode without config file, just wait for shutdown signals
189
+ if isCloudDeploy && !configFileExists {
190
+ // No config file available, just wait for shutdown
191
+ cmd.WaitForCloudDeploy()
192
+ return
193
+ }
194
  // Start the main proxy service
195
  cmd.StartService(cfg, configFilePath, password)
196
  }
docker-compose.yml CHANGED
@@ -10,6 +10,8 @@ services:
10
  COMMIT: ${COMMIT:-none}
11
  BUILD_DATE: ${BUILD_DATE:-unknown}
12
  container_name: cli-proxy-api
 
 
13
  ports:
14
  - "8317:8317"
15
  - "8085:8085"
 
10
  COMMIT: ${COMMIT:-none}
11
  BUILD_DATE: ${BUILD_DATE:-unknown}
12
  container_name: cli-proxy-api
13
+ environment:
14
+ DEPLOY: ${DEPLOY:-}
15
  ports:
16
  - "8317:8317"
17
  - "8085:8085"
internal/cmd/run.go CHANGED
@@ -53,3 +53,17 @@ func StartService(cfg *config.Config, configPath string, localPassword string) {
53
  log.Fatalf("proxy service exited with error: %v", err)
54
  }
55
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  log.Fatalf("proxy service exited with error: %v", err)
54
  }
55
  }
56
+
57
+ // WaitForCloudDeploy waits indefinitely for shutdown signals in cloud deploy mode
58
+ // when no configuration file is available.
59
+ func WaitForCloudDeploy() {
60
+ // Clarify that we are intentionally idle for configuration and not running the API server.
61
+ log.Info("Cloud deploy mode: No config found; standing by for configuration. API server is not started. Press Ctrl+C to exit.")
62
+
63
+ ctxSignal, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
64
+ defer cancel()
65
+
66
+ // Block until shutdown signal is received
67
+ <-ctxSignal.Done()
68
+ log.Info("Cloud deploy mode: Shutdown signal received; exiting")
69
+ }
internal/config/config.go CHANGED
@@ -5,8 +5,10 @@
5
  package config
6
 
7
  import (
 
8
  "fmt"
9
  "os"
 
10
 
11
  "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
12
  "golang.org/x/crypto/bcrypt"
@@ -187,9 +189,21 @@ type OpenAICompatibilityModel struct {
187
  // - *Config: The loaded configuration
188
  // - error: An error if the configuration could not be loaded
189
  func LoadConfig(configFile string) (*Config, error) {
 
 
 
 
 
 
190
  // Read the entire configuration file into memory.
191
  data, err := os.ReadFile(configFile)
192
  if err != nil {
 
 
 
 
 
 
193
  return nil, fmt.Errorf("failed to read config file: %w", err)
194
  }
195
 
 
5
  package config
6
 
7
  import (
8
+ "errors"
9
  "fmt"
10
  "os"
11
+ "syscall"
12
 
13
  "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
14
  "golang.org/x/crypto/bcrypt"
 
189
  // - *Config: The loaded configuration
190
  // - error: An error if the configuration could not be loaded
191
  func LoadConfig(configFile string) (*Config, error) {
192
+ return LoadConfigOptional(configFile, false)
193
+ }
194
+
195
+ // LoadConfigOptional reads YAML from configFile.
196
+ // If optional is true and the file is missing, it returns an empty Config.
197
+ func LoadConfigOptional(configFile string, optional bool) (*Config, error) {
198
  // Read the entire configuration file into memory.
199
  data, err := os.ReadFile(configFile)
200
  if err != nil {
201
+ if optional {
202
+ if os.IsNotExist(err) || errors.Is(err, syscall.EISDIR) {
203
+ // Missing and optional: return empty config (cloud deploy standby).
204
+ return &Config{}, nil
205
+ }
206
+ }
207
  return nil, fmt.Errorf("failed to read config file: %w", err)
208
  }
209