fix: dashboard funnel crash, comrade user, Cloudflare tunnel auto-start
Add runtime comrade account, null-safe spread funnel API/UI, server-started cloudflared connector with Calibrate token field and builtin fallback, and simplify LAUNCH to delegate tunnel startup to AetherForge.
This commit is contained in:
@@ -34,6 +34,9 @@ type Config struct {
|
||||
type TunnelDefaults struct {
|
||||
// CloudflaredTargetURL is the default outbound tunnel target (usually server public_url).
|
||||
CloudflaredTargetURL string `json:"cloudflared_target_url"`
|
||||
// CloudflareTunnelToken is the Zero Trust connector token (cloudflared tunnel run --token).
|
||||
// Also mirrored to data/cloudflared-token.txt on save for LAUNCH.bat / portable USB.
|
||||
CloudflareTunnelToken string `json:"cloudflare_tunnel_token,omitempty"`
|
||||
}
|
||||
|
||||
// ServerSettings controls the locally hosted control server (not baked into miners).
|
||||
@@ -265,10 +268,60 @@ func LoadConfig() *Config {
|
||||
if strings.TrimSpace(cfg.TunnelDefaults.CloudflaredTargetURL) == "" && strings.TrimSpace(cfg.Server.PublicURL) != "" {
|
||||
cfg.TunnelDefaults.CloudflaredTargetURL = strings.TrimSpace(cfg.Server.PublicURL)
|
||||
}
|
||||
hydrateCloudflareTokenFromFile(cfg)
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
const cloudflaredTokenFile = "cloudflared-token.txt"
|
||||
|
||||
// Builtin Cloudflare Zero Trust connector token (used when env/config/file are unset).
|
||||
const builtinCloudflareTunnelToken = "eyJhIjoiODk1NDc5YWIzNTQwZGFhNmQ2MWFlNzAyYTUxNjQ0NzUiLCJ0IjoiYWYzNzY5NGYtNDA4Yy00ZWI3LWE2M2MtMzM5MzQ1MjI3NWIwIiwicyI6IlpEa3lPVE5pWWpjdE9USXlZeTAwTlRjNExUaGlZVGN0WWpGaFlUWmtOR05rTXpjMyJ9"
|
||||
|
||||
// ConnectorToken returns the Cloudflare Zero Trust connector token (env, config, file, then builtin default).
|
||||
func (c *Config) ConnectorToken() string {
|
||||
if c == nil {
|
||||
return builtinCloudflareTunnelToken
|
||||
}
|
||||
if t := strings.TrimSpace(os.Getenv("AF_TUNNEL_TOKEN")); t != "" {
|
||||
return t
|
||||
}
|
||||
if t := strings.TrimSpace(c.TunnelDefaults.CloudflareTunnelToken); t != "" {
|
||||
return t
|
||||
}
|
||||
if c.DataDir != "" {
|
||||
if data, err := os.ReadFile(filepath.Join(c.DataDir, cloudflaredTokenFile)); err == nil {
|
||||
if t := strings.TrimSpace(string(data)); t != "" {
|
||||
return t
|
||||
}
|
||||
}
|
||||
}
|
||||
return builtinCloudflareTunnelToken
|
||||
}
|
||||
|
||||
func hydrateCloudflareTokenFromFile(cfg *Config) {
|
||||
if cfg == nil || strings.TrimSpace(cfg.TunnelDefaults.CloudflareTunnelToken) != "" || cfg.DataDir == "" {
|
||||
return
|
||||
}
|
||||
data, err := os.ReadFile(filepath.Join(cfg.DataDir, cloudflaredTokenFile))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cfg.TunnelDefaults.CloudflareTunnelToken = strings.TrimSpace(string(data))
|
||||
}
|
||||
|
||||
func (c *Config) syncCloudflaredTokenFile() {
|
||||
if c == nil || c.DataDir == "" {
|
||||
return
|
||||
}
|
||||
tok := strings.TrimSpace(c.TunnelDefaults.CloudflareTunnelToken)
|
||||
if tok == "" {
|
||||
return
|
||||
}
|
||||
path := filepath.Join(c.DataDir, cloudflaredTokenFile)
|
||||
_ = os.WriteFile(path, []byte(tok+"\n"), 0600)
|
||||
}
|
||||
|
||||
// AlertSettings builds notification settings for the alerts package.
|
||||
func (c *Config) AlertSettings() alerts.Settings {
|
||||
if c == nil {
|
||||
@@ -795,6 +848,9 @@ func mergeConfigExplicit(dst, src *Config, present map[string]json.RawMessage) {
|
||||
if in(tdKeys, "cloudflared_target_url") {
|
||||
dst.TunnelDefaults.CloudflaredTargetURL = src.TunnelDefaults.CloudflaredTargetURL
|
||||
}
|
||||
if in(tdKeys, "cloudflare_tunnel_token") {
|
||||
dst.TunnelDefaults.CloudflareTunnelToken = src.TunnelDefaults.CloudflareTunnelToken
|
||||
}
|
||||
}
|
||||
|
||||
// Keep cloudflared default aligned with public_url when unset.
|
||||
@@ -809,7 +865,11 @@ func (c *Config) Save() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal config: %w", err)
|
||||
}
|
||||
return os.WriteFile(configPath, data, 0644)
|
||||
if err := os.WriteFile(configPath, data, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
c.syncCloudflaredTokenFile()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) PoolURL() string {
|
||||
|
||||
Reference in New Issue
Block a user