package nodes import ( "errors" "log" "net" "os" "os/exec" "runtime" "sync" "time" teaconst "github.com/TeaOSLab/EdgeHttpDNS/internal/const" "github.com/TeaOSLab/EdgeHttpDNS/internal/utils" "github.com/iwind/TeaGo/maps" "github.com/iwind/gosock/pkg/gosock" ) type HTTPDNSNode struct { sock *gosock.Sock quitOnce sync.Once quitCh chan struct{} } func NewHTTPDNSNode() *HTTPDNSNode { return &HTTPDNSNode{ sock: gosock.NewTmpSock(teaconst.ProcessName), quitCh: make(chan struct{}), } } func (n *HTTPDNSNode) Run() { err := n.listenSock() if err != nil { log.Println("[HTTPDNS_NODE]" + err.Error()) return } go n.start() select {} } func (n *HTTPDNSNode) Daemon() { path := os.TempDir() + "/" + teaconst.ProcessName + ".sock" for { conn, err := net.DialTimeout("unix", path, 1*time.Second) if err != nil { exe, exeErr := os.Executable() if exeErr != nil { log.Println("[DAEMON]", exeErr) time.Sleep(1 * time.Second) continue } cmd := exec.Command(exe) cmd.Env = append(os.Environ(), "EdgeBackground=on") if runtime.GOOS != "windows" { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr } startErr := cmd.Start() if startErr != nil { log.Println("[DAEMON]", startErr) time.Sleep(1 * time.Second) continue } _ = cmd.Wait() time.Sleep(5 * time.Second) continue } _ = conn.Close() time.Sleep(5 * time.Second) } } func (n *HTTPDNSNode) InstallSystemService() error { exe, err := os.Executable() if err != nil { return err } manager := utils.NewServiceManager(teaconst.SystemdServiceName, teaconst.ProductName) return manager.Install(exe, []string{}) } func (n *HTTPDNSNode) listenSock() error { if runtime.GOOS == "windows" { return nil } if n.sock.IsListening() { reply, err := n.sock.Send(&gosock.Command{Code: "pid"}) if err == nil { return errors.New("the process is already running, pid: " + maps.NewMap(reply.Params).GetString("pid")) } return errors.New("the process is already running") } go func() { n.sock.OnCommand(func(cmd *gosock.Command) { switch cmd.Code { case "pid": _ = cmd.Reply(&gosock.Command{ Code: "pid", Params: map[string]interface{}{ "pid": os.Getpid(), }, }) case "info": exePath, _ := os.Executable() _ = cmd.Reply(&gosock.Command{ Code: "info", Params: map[string]interface{}{ "pid": os.Getpid(), "version": teaconst.Version, "path": exePath, }, }) case "stop": _ = cmd.ReplyOk() n.stop() time.Sleep(100 * time.Millisecond) os.Exit(0) } }) err := n.sock.Listen() if err != nil { log.Println("[HTTPDNS_NODE][sock]", err.Error()) } }() return nil } func (n *HTTPDNSNode) start() { log.Println("[HTTPDNS_NODE]started") snapshotManager := NewSnapshotManager(n.quitCh) statusManager := NewStatusManager(n.quitCh) taskManager := NewTaskManager(n.quitCh, snapshotManager) resolveServer := NewResolveServer(n.quitCh, snapshotManager) go snapshotManager.Start() go statusManager.Start() go taskManager.Start() go resolveServer.Start() } func (n *HTTPDNSNode) stop() { n.quitOnce.Do(func() { close(n.quitCh) _ = n.sock.Close() }) }