// agent-core 客户端核心:设备身份 + 凭据保险库 + WSS 长连接 + 平台执行器。 // 常驻模型:WinUI 壳 spawn 本进程 → 壳读 data/local.json(随机端口+token)→ // 经 localhost HTTP 控制(状态/配对/挑战)。CLI 亦可独立运行(-user/-pass 自动配对)。 package main import ( "context" "errors" "flag" "log" "os" "os/signal" "path/filepath" "strings" "sync" "syscall" "everypublish/agentcore/internal/config" "everypublish/agentcore/internal/device" "everypublish/agentcore/internal/exec" "everypublish/agentcore/internal/exec/bilibili" "everypublish/agentcore/internal/exec/douyin" "everypublish/agentcore/internal/exec/fake" "everypublish/agentcore/internal/exec/kuaishou" "everypublish/agentcore/internal/exec/xiaohongshu" "everypublish/agentcore/internal/localserver" "everypublish/agentcore/internal/pairing" "everypublish/agentcore/internal/vault" "everypublish/agentcore/internal/wsclient" ) func main() { var ( server = flag.String("server", "", "服务器地址(默认取配置)") dir = flag.String("dir", "./data", "数据目录(设备密钥/保险库/配置)") name = flag.String("name", "", "设备名") user = flag.String("user", "", "开发便利:自动配对登录邮箱") password = flag.String("pass", "", "开发便利:自动配对登录密码") simMS = flag.Int("sim", 0, "假执行器模拟耗时 ms(0 用配置值)") token = flag.String("local-token", "", "本机控制服务 token(默认随机)") ) flag.Parse() cfg, err := config.Load(*dir) if err != nil { log.Fatalf("config: %v", err) } if *server != "" { cfg.Server = *server } if *name != "" { cfg.Name = *name } if *simMS > 0 { cfg.SimMS = *simMS } _ = cfg.Save(*dir) // 设备身份(私钥本机持久化 0600) id, err := device.LoadOrCreate(*dir, cfg.Name) if err != nil { log.Fatalf("device: %v", err) } cfg.Name = id.Name // 凭据保险库(平台 cookie/token 加密落盘) v, err := vault.Open(*dir) if err != nil { log.Fatalf("vault: %v", err) } // 执行器注册:B站无浏览器投稿 + 抖音/快手/小红书 CDP(D10/D11); // fakeAll=true 时全部走假执行器(无真实账号的安装联调)。 registry := exec.NewRegistry() if !cfg.FakeAll { browserRoot := filepath.Join(*dir, "browser") // 每账号独立档案 registry.Register(bilibili.New(v)) registry.Register(douyin.New(v, browserRoot, cfg.Proxy, "", false)) registry.Register(kuaishou.New(v, browserRoot, cfg.Proxy, "", false)) registry.Register(xiaohongshu.New(v, browserRoot, cfg.Proxy, "", false)) } registry.SetFallback(fake.Executor{SimMS: cfg.SimMS}) // WSS 客户端(重连/幂等/心跳) client := wsclient.New(cfg.Server, id, registry) ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() // 连接启动(配对后;未配对时等壳调 /pair) var runOnce sync.Once startConn := func() { if id.DeviceID == 0 { return } runOnce.Do(func() { go func() { _ = client.Run(ctx) }() }) } // 配对回调(本机控制服务 /pair 触发) pairFn := func(code, name string) error { if id.DeviceID > 0 { return errors.New("设备已配对") } name = strings.TrimSpace(name) if name == "" { name = cfg.Name } if name == "" { name, _ = os.Hostname() } if name == "" { name = "macOS Agent" } did, err := pairing.PairWithCode(cfg.Server, code, name, "core", "0.2.0", id.PublicKey) if err != nil { return err } id.DeviceID = did if name != "" { id.Name = name cfg.Name = name } if err = id.Save(*dir); err != nil { return err } log.Printf("paired device %d (name %s)", id.DeviceID, id.Name) startConn() return nil } // 开发便利:CLI 自动配对 if id.DeviceID == 0 && *user != "" && *password != "" { did, err := pairing.AutoPair(cfg.Server, *user, *password, cfg.Name, id.PublicKey) if err != nil { log.Fatalf("auto pair: %v", err) } id.DeviceID = did if err = id.Save(*dir); err != nil { log.Fatalf("save identity: %v", err) } log.Printf("auto paired device %d", id.DeviceID) } startConn() // 本机控制服务(WinUI 壳入口) localToken := *token if localToken == "" { localToken = localserver.RandToken() } ls := localserver.New(client, pairFn, localToken, *dir, func() map[string]interface{} { return map[string]interface{}{ "server": cfg.Server, "deviceId": id.DeviceID, "name": id.Name, } }) go func() { if err = ls.Listen(); err != nil { log.Fatalf("local server: %v", err) } }() if id.DeviceID == 0 { log.Printf("agent-core started UNPAIRED: server=%s(请在客户端输入网页端配对码)", cfg.Server) } else { log.Printf("agent-core started: server=%s device=%d", cfg.Server, id.DeviceID) } <-ctx.Done() log.Println("agent-core stopped") }