()
| 46 | } |
| 47 | |
| 48 | func Run() error { |
| 49 | cfg := config.Load() |
| 50 | |
| 51 | if cfg.NodeID == "" { |
| 52 | return errors.New("PULSE_NODE_ID is required (run `pulse-node enroll ...` first)") |
| 53 | } |
| 54 | serverAddr := cfg.NodeServerAddr |
| 55 | if serverAddr == "" { |
| 56 | return errors.New("PULSE_NODE_SERVER_ADDR is required (host:port of control-plane gRPC)") |
| 57 | } |
| 58 | |
| 59 | if err := os.MkdirAll(stateDir(cfg), 0o700); err != nil { |
| 60 | return err |
| 61 | } |
| 62 | |
| 63 | xrManager := xray.NewManager(xrayConfigPath(cfg)) |
| 64 | |
| 65 | xrInfo := xrManager.RuntimeInfo(context.Background()) |
| 66 | if xrInfo.Available { |
| 67 | log.Printf("pulse-node xray: %s %s", xrInfo.Module, xrInfo.Version) |
| 68 | } |
| 69 | |
| 70 | sniMgr := sniproxy.NewManager(sniproxyStatePath(cfg)) |
| 71 | if err := sniMgr.Restore(); err != nil { |
| 72 | log.Printf("pulse-node sniproxy restore: %v", err) |
| 73 | } else if restored := sniMgr.Config(); restored.Listen != "" { |
| 74 | log.Printf("pulse-node sniproxy restored: listen=%s routes=%d", restored.Listen, len(restored.Routes)) |
| 75 | } |
| 76 | |
| 77 | api := nodeapi.New(xrManager).WithSNIManager(sniMgr) |
| 78 | |
| 79 | ipsentinelHandler := ipsentinel.NewNodeHandler(cfg.DataDir) |
| 80 | |
| 81 | dispatcher := nodeagent.NewAPIDispatcher(api, ipsentinelHandler) |
| 82 | |
| 83 | if saved := xrManager.SavedConfig(); saved != "" { |
| 84 | log.Printf("pulse-node restoring xray from saved config") |
| 85 | if err := xrManager.Start(saved); err != nil { |
| 86 | log.Printf("pulse-node restore xray failed: %v", err) |
| 87 | } else { |
| 88 | log.Printf("pulse-node xray auto-started") |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) |
| 93 | defer stop() |
| 94 | |
| 95 | usagePusher := nodeagent.NewUsagePusher(api, 30*time.Second) |
| 96 | var pusherStart sync.Once |
| 97 | |
| 98 | agentCfg := nodeagent.Config{ |
| 99 | NodeID: cfg.NodeID, |
| 100 | ServerAddr: serverAddr, |
| 101 | CertFile: cfg.NodeClientCert, |
| 102 | KeyFile: cfg.NodeClientKey, |
| 103 | CAFile: cfg.NodeServerCAFile, |
| 104 | ServerName: cfg.NodeServerName, |
| 105 | Dispatcher: dispatcher, |
no test coverage detected