Files
cftunnel/cmd/add.go
T
晴天 4f36ea0942 fix: ingress 推送失败不再静默吞掉,up 启动前自动同步 ingress
- add 命令 ingress 推送失败改为 error 中断,避免用户无感知丢失配置
- up 命令启动 cloudflared 前自动同步本地 Routes 到远端 ingress
- 修复用户反馈的 Win10 下先 add 再 up 路由不生效的问题
2026-02-23 23:24:36 +08:00

102 lines
2.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cmd
import (
"context"
"fmt"
"strings"
"github.com/qingchencloud/cftunnel/internal/cfapi"
"github.com/qingchencloud/cftunnel/internal/config"
"github.com/spf13/cobra"
)
var addDomain string
func init() {
addCmd.Flags().StringVar(&addDomain, "domain", "", "完整域名 (如 webhook.example.com)")
addCmd.MarkFlagRequired("domain")
rootCmd.AddCommand(addCmd)
}
// pushIngress 推送当前所有路由的 ingress 配置到远端
func pushIngress(client *cfapi.Client, ctx context.Context, cfg *config.Config) error {
var rules []cfapi.IngressRule
for _, r := range cfg.Routes {
rules = append(rules, cfapi.IngressRule{Hostname: r.Hostname, Service: r.Service})
}
return client.PushIngressConfig(ctx, cfg.Tunnel.ID, rules)
}
// findZoneForDomain 通过遍历账户 Zone 列表匹配域名(支持多级 TLD)
func findZoneForDomain(client *cfapi.Client, ctx context.Context, domain string) (*cfapi.ZoneInfo, error) {
zoneList, err := client.ListZones(ctx)
if err != nil {
return nil, err
}
for _, z := range zoneList {
if domain == z.Name || strings.HasSuffix(domain, "."+z.Name) {
return &cfapi.ZoneInfo{ID: z.ID, Name: z.Name}, nil
}
}
return nil, fmt.Errorf("未找到域名 %s 对应的 Zone,请确认域名已添加到 Cloudflare", domain)
}
var addCmd = &cobra.Command{
Use: "add <名称> <端口>",
Short: "添加路由(自动创建 CNAME + 更新 ingress",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
name, port := args[0], args[1]
service := "http://localhost:" + port
cfg, err := config.Load()
if err != nil {
return err
}
if cfg.Tunnel.ID == "" {
return fmt.Errorf("请先运行 cftunnel init && cftunnel create <名称>")
}
if cfg.FindRoute(name) != nil {
return fmt.Errorf("路由 %s 已存在", name)
}
client := cfapi.New(cfg.Auth.APIToken, cfg.Auth.AccountID)
ctx := context.Background()
// 查找域名对应的 Zone(支持多级 TLD)
zone, err := findZoneForDomain(client, ctx, addDomain)
if err != nil {
return err
}
// 创建 CNAME
target := cfg.Tunnel.ID + ".cfargotunnel.com"
fmt.Printf("正在创建 DNS 记录 %s → %s\n", addDomain, target)
recordID, err := client.CreateCNAME(ctx, zone.ID, addDomain, target)
if err != nil {
return err
}
// 保存路由
cfg.Routes = append(cfg.Routes, config.RouteConfig{
Name: name,
Hostname: addDomain,
Service: service,
ZoneID: zone.ID,
DNSRecordID: recordID,
})
if err := cfg.Save(); err != nil {
return err
}
// 推送 ingress 配置到远端
fmt.Println("正在同步 ingress 配置...")
if err := pushIngress(client, ctx, cfg); err != nil {
return fmt.Errorf("推送 ingress 失败: %wDNS 记录已创建,请排查后重试 add 或手动删除 DNS 记录)", err)
}
fmt.Printf("路由已添加: %s → %s (%s)\n", addDomain, service, name)
return nil
},
}