Skip to content

Commit e02004a

Browse files
committed
TCP is just so much easier.
1 parent b59bd46 commit e02004a

18 files changed

Lines changed: 574 additions & 219 deletions

cmd/meshexec/daemon.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
package main
22

33
import (
4+
"bufio"
45
"context"
6+
"encoding/json"
57
"fmt"
8+
"net"
69
"os"
710
"os/signal"
811
"runtime"
12+
"strings"
913
"syscall"
1014
"time"
1115

1216
core "github.com/monster0506/meshexec/internal"
1317
"github.com/monster0506/meshexec/internal/agent"
1418
"github.com/monster0506/meshexec/internal/config"
19+
"github.com/monster0506/meshexec/internal/discovery"
1520
"github.com/monster0506/meshexec/internal/executor"
1621
"github.com/monster0506/meshexec/internal/mesh"
1722
"github.com/monster0506/meshexec/internal/targeting"
@@ -55,9 +60,15 @@ func runDaemon(cmd *cobra.Command) error {
5560
_ = os.Setenv("MESHEXEC_BLE_IMPL", "sidecar")
5661
}
5762

63+
if logger != nil {
64+
logger.Info("daemon: building mesh node", nil)
65+
}
5866
// Build mesh node
5967
node, err := newMeshNodeForDaemon(cfg)
6068
if err != nil {
69+
if logger != nil {
70+
logger.Error("daemon: mesh init failed", err, nil)
71+
}
6172
return fmt.Errorf("mesh init: %w", err)
6273
}
6374

@@ -76,11 +87,20 @@ func runDaemon(cmd *cobra.Command) error {
7687
// Start services
7788
ctx, cancel := context.WithCancel(context.Background())
7889
defer cancel()
90+
if logger != nil {
91+
logger.Info("daemon: starting node and agent", nil)
92+
}
7993
if err := node.Start(ctx); err != nil {
94+
if logger != nil {
95+
logger.Error("daemon: mesh start failed", err, nil)
96+
}
8097
return fmt.Errorf("mesh start: %w", err)
8198
}
8299
if err := ag.Start(ctx); err != nil {
83100
_ = node.Stop()
101+
if logger != nil {
102+
logger.Error("daemon: agent start failed", err, nil)
103+
}
84104
return fmt.Errorf("agent start: %w", err)
85105
}
86106

@@ -99,6 +119,103 @@ func runDaemon(cmd *cobra.Command) error {
99119
logger.Info("daemon: received result", map[string]interface{}{"id": m.ID, "from": m.Sender, "ttl": m.TTL})
100120
}
101121
}()
122+
// Start simple TCP listener for POC/discovery port and mDNS advertise
123+
go func(port int) {
124+
addr := fmt.Sprintf(":%d", port)
125+
if logger != nil {
126+
logger.Info("daemon: starting tcp listener", map[string]interface{}{"addr": addr})
127+
}
128+
ln, err := net.Listen("tcp", addr)
129+
if err != nil {
130+
if logger != nil {
131+
logger.Warn("tcp listen failed", map[string]interface{}{"addr": addr, "error": err.Error()})
132+
}
133+
return
134+
}
135+
if logger != nil {
136+
logger.Info("daemon: tcp listener ready", map[string]interface{}{"addr": addr})
137+
}
138+
// mDNS advertise
139+
adv, err := discovery.StartAdvertiser(cfg.Device.Name, port, map[string]string{
140+
"role": cfg.Device.Role,
141+
"os": cfg.Device.OS,
142+
"arch": cfg.Device.Arch,
143+
})
144+
if err == nil {
145+
if logger != nil {
146+
logger.Info("daemon: mdns advertiser started", map[string]interface{}{"name": cfg.Device.Name, "port": port})
147+
}
148+
go func() { <-ctx.Done(); adv.Stop() }()
149+
}
150+
go func() { <-ctx.Done(); _ = ln.Close() }()
151+
for {
152+
c, err := ln.Accept()
153+
if err != nil {
154+
select {
155+
case <-ctx.Done():
156+
return
157+
default:
158+
}
159+
if logger != nil {
160+
logger.Warn("daemon: accept error", map[string]interface{}{"error": err.Error()})
161+
}
162+
continue
163+
}
164+
go func(conn net.Conn) {
165+
if logger != nil {
166+
logger.Info("daemon: connection accepted", map[string]interface{}{"remote": conn.RemoteAddr().String()})
167+
}
168+
defer func() { _ = conn.Close() }()
169+
// Read one line; support raw text or JSON {"cmd":"..."}
170+
r := bufio.NewReader(conn)
171+
line, _ := r.ReadString('\n')
172+
if logger != nil {
173+
logger.Debug("daemon: received line", map[string]interface{}{"bytes": len(line)})
174+
}
175+
cmdStr := ""
176+
var payload struct {
177+
Cmd string `json:"cmd"`
178+
}
179+
if json.Unmarshal([]byte(line), &payload) == nil && payload.Cmd != "" {
180+
cmdStr = payload.Cmd
181+
} else {
182+
cmdStr = line
183+
}
184+
cmdStr = strings.TrimSpace(cmdStr)
185+
if cmdStr == "" {
186+
return
187+
}
188+
if logger != nil {
189+
logger.Info("daemon: executing", map[string]interface{}{"cmd": cmdStr})
190+
}
191+
// Execute command via executor
192+
ctxExec, cancel := context.WithTimeout(context.Background(), 30*time.Second)
193+
defer cancel()
194+
res, err := exec.Execute(ctxExec, cmdStr)
195+
if err != nil && res != nil && res.Stderr == "" {
196+
res.Stderr = err.Error()
197+
}
198+
if res != nil && logger != nil {
199+
logger.Debug("daemon: exec result", map[string]interface{}{"code": res.ExitCode, "stdout_len": len(res.Stdout), "stderr_len": len(res.Stderr)})
200+
}
201+
if res != nil {
202+
if res.ExitCode == 0 && res.Status == "" {
203+
res.Status = "success"
204+
}
205+
if res.ExitCode != 0 && res.Status == "" {
206+
res.Status = "failed"
207+
}
208+
}
209+
_ = json.NewEncoder(conn).Encode(map[string]interface{}{
210+
"ok": true,
211+
"result": res,
212+
})
213+
if logger != nil {
214+
logger.Info("daemon: response sent", map[string]interface{}{"remote": conn.RemoteAddr().String()})
215+
}
216+
}(c)
217+
}
218+
}(cfg.Network.TCPPort)
102219
}
103220

104221
// Wait for termination signal (test seam)

0 commit comments

Comments
 (0)