Skip to content

Commit bbe6dab

Browse files
committed
Idk maybe this will work...
1 parent 446327e commit bbe6dab

7 files changed

Lines changed: 156 additions & 15 deletions

File tree

cmd/meshexec/config.go

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ package main
33
import (
44
"fmt"
55
"os"
6+
"os/exec"
7+
"path/filepath"
8+
"runtime"
9+
"strings"
610

711
"github.com/monster0506/meshexec/internal"
812
"github.com/monster0506/meshexec/internal/config"
@@ -83,8 +87,95 @@ var configEditCmd = &cobra.Command{
8387
Use: "edit",
8488
Short: "Open configuration in default editor",
8589
Run: func(cmd *cobra.Command, args []string) {
86-
// Stub implementation
87-
fmt.Fprintln(os.Stderr, "Config edit is not implemented yet.")
90+
logLevel, _ := cmd.Root().PersistentFlags().GetString("log-level")
91+
verbose, _ := cmd.Root().PersistentFlags().GetBool("verbose")
92+
if verbose {
93+
logLevel = "debug"
94+
}
95+
manager := config.NewManagerWithLevel(logLevel)
96+
97+
// Respect global --config path
98+
if configPath, _ := cmd.Root().PersistentFlags().GetString("config"); configPath != "" {
99+
manager.SetConfigPath(configPath)
100+
}
101+
102+
cfgPath := manager.GetConfigPath()
103+
104+
// Ensure the config file exists
105+
if _, err := os.Stat(cfgPath); os.IsNotExist(err) {
106+
if logger != nil {
107+
logger.Info("config edit: creating default config as it does not exist", map[string]interface{}{"path": cfgPath})
108+
}
109+
if mkErr := manager.CreateDefaultConfig(); mkErr != nil {
110+
me := internal.NewConfigError("create_failed", "failed to create default configuration", map[string]interface{}{"error": mkErr.Error()})
111+
fmt.Fprintln(os.Stderr, internal.FormatUserError(me))
112+
os.Exit(1)
113+
}
114+
}
115+
116+
// Determine editor
117+
editorSpec := os.Getenv("EDITOR")
118+
if editorSpec == "" {
119+
editorSpec = os.Getenv("VISUAL")
120+
}
121+
var editor string
122+
var editorArgs []string
123+
if strings.TrimSpace(editorSpec) != "" {
124+
parts := strings.Fields(editorSpec)
125+
editor = parts[0]
126+
if len(parts) > 1 {
127+
editorArgs = parts[1:]
128+
}
129+
} else {
130+
switch runtime.GOOS {
131+
case "windows":
132+
editor = "notepad"
133+
case "darwin":
134+
// Prefer a terminal editor; if unavailable, fall back to open -W -t
135+
if p, err := exec.LookPath("nano"); err == nil {
136+
editor = p
137+
} else if p, err := exec.LookPath("vi"); err == nil {
138+
editor = p
139+
} else {
140+
editor = "open"
141+
editorArgs = append(editorArgs, "-W", "-t")
142+
}
143+
default:
144+
if p, err := exec.LookPath("nano"); err == nil {
145+
editor = p
146+
} else if p, err := exec.LookPath("vi"); err == nil {
147+
editor = p
148+
} else {
149+
editor = "vi"
150+
}
151+
}
152+
}
153+
154+
// Prepare command
155+
argsWithFile := append(editorArgs, cfgPath)
156+
if logger != nil {
157+
logger.Info("config edit: opening editor", map[string]interface{}{"editor": editor, "args": strings.Join(editorArgs, " "), "path": cfgPath})
158+
}
159+
160+
c := exec.Command(editor, argsWithFile...)
161+
c.Stdin = os.Stdin
162+
c.Stdout = os.Stdout
163+
c.Stderr = os.Stderr
164+
if err := c.Run(); err != nil {
165+
me := internal.NewConfigError("editor_failed", "failed to open editor", map[string]interface{}{"editor": editor, "error": err.Error()})
166+
fmt.Fprintln(os.Stderr, internal.FormatUserError(me))
167+
os.Exit(1)
168+
}
169+
170+
// Validate resulting configuration
171+
if _, err := manager.Load(); err != nil {
172+
me := internal.NewConfigError("invalid_config", "configuration invalid after edit", map[string]interface{}{"error": err.Error()})
173+
fmt.Fprintln(os.Stderr, internal.FormatUserError(me))
174+
os.Exit(1)
175+
}
176+
177+
// Success message
178+
fmt.Printf("Configuration saved to: %s\n", filepath.Clean(cfgPath))
88179
},
89180
}
90181

cmd/meshexec/daemon.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ func runDaemon(cmd *cobra.Command) error {
121121
}()
122122
// Start simple TCP listener for POC/discovery port and mDNS advertise
123123
go func(port int) {
124+
// Normalize port; 0 means ephemeral. We'll advertise the actual bound port below.
125+
if port < 0 {
126+
port = 0
127+
}
124128
addr := fmt.Sprintf(":%d", port)
125129
if logger != nil {
126130
logger.Info("daemon: starting tcp listener", map[string]interface{}{"addr": addr})
@@ -132,11 +136,16 @@ func runDaemon(cmd *cobra.Command) error {
132136
}
133137
return
134138
}
139+
// Resolve actual port in case of :0
140+
actualPort := port
141+
if ta, ok := ln.Addr().(*net.TCPAddr); ok {
142+
actualPort = ta.Port
143+
}
135144
if logger != nil {
136-
logger.Info("daemon: tcp listener ready", map[string]interface{}{"addr": addr})
145+
logger.Info("daemon: tcp listener ready", map[string]interface{}{"addr": ln.Addr().String(), "port": actualPort})
137146
}
138147
// mDNS advertise
139-
adv, err := discovery.StartAdvertiser(cfg.Device.Name, port, map[string]string{
148+
adv, err := discovery.StartAdvertiser(cfg.Device.Name, actualPort, map[string]string{
140149
"role": cfg.Device.Role,
141150
"os": cfg.Device.OS,
142151
"arch": cfg.Device.Arch,

cmd/meshexec/network.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ var joinCmd = &cobra.Command{
2828
}
2929
for {
3030
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
31+
if logger != nil {
32+
discovery.SetLogger(logger)
33+
}
3134
if logger != nil {
3235
logger.Debug("join: discovering peers", map[string]interface{}{"timeout_ms": 3000})
3336
}
@@ -54,6 +57,9 @@ var discoverCmd = &cobra.Command{
5457
timeout = 2000 * time.Millisecond
5558
}
5659
ctx, cancel := context.WithTimeout(context.Background(), timeout)
60+
if logger != nil {
61+
discovery.SetLogger(logger)
62+
}
5763
defer cancel()
5864
if logger != nil {
5965
logger.Debug("list: mDNS discover", map[string]interface{}{"timeout_ms": timeout.Milliseconds()})

cmd/meshexec/run.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ var runCmd = &cobra.Command{
182182

183183
// Non-dry-run: mDNS discover peers and send over TCP
184184
if logger != nil {
185+
discovery.SetLogger(logger)
185186
logger.Debug("run: starting mDNS discovery", map[string]interface{}{"timeout_ms": 5000})
186187
}
187188
dctx, dcancel := context.WithTimeout(context.Background(), 5*time.Second)

internal/config/manager.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ func (m *Manager) Load() (*internal.Config, error) {
6767
return nil, fmt.Errorf("failed to read config file: %w", err)
6868
}
6969

70-
var config internal.Config
70+
// Start from defaults and overlay file values so missing fields keep defaults
71+
config := *internal.DefaultConfig()
7172
if err := toml.Unmarshal(data, &config); err != nil {
7273
m.logger.Error("Failed to unmarshal config", err, map[string]interface{}{
7374
"path": m.configPath,
@@ -122,7 +123,8 @@ func (m *Manager) Load() (*internal.Config, error) {
122123
return nil, fmt.Errorf("failed to read config file: %w", err)
123124
}
124125

125-
var config internal.Config
126+
// Start from defaults and overlay file values so missing fields keep defaults
127+
config := *internal.DefaultConfig()
126128
if err := toml.Unmarshal(data, &config); err != nil {
127129
m.logger.Error("Failed to unmarshal config", err, map[string]interface{}{
128130
"path": configFile,

internal/discovery/mdns.go

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ import (
1212

1313
const serviceType = "_meshexec._tcp"
1414

15+
// package logger (default disabled); can be set via SetLogger
16+
var pkgLogger *logging.Logger = logging.NewLogger("none")
17+
18+
// SetLogger sets discovery package logger
19+
func SetLogger(l *logging.Logger) {
20+
if l != nil {
21+
pkgLogger = l
22+
}
23+
}
24+
1525
// Advertiser wraps a zeroconf server
1626
type Advertiser struct {
1727
server *zeroconf.Server
@@ -27,13 +37,20 @@ func StartAdvertiser(instance string, port int, meta map[string]string) (*Advert
2737
for k, v := range meta {
2838
txt = append(txt, fmt.Sprintf("%s=%s", k, v))
2939
}
40+
if pkgLogger != nil {
41+
pkgLogger.Debug("mdns: registering service", map[string]interface{}{"instance": instance, "port": port, "txt_len": len(txt)})
42+
}
3043
srv, err := zeroconf.Register(instance, serviceType, "local.", port, txt, nil)
3144
if err != nil {
45+
if pkgLogger != nil {
46+
pkgLogger.Warn("mdns: register failed", map[string]interface{}{"error": err.Error()})
47+
}
3248
return nil, err
3349
}
34-
lg := logging.NewLogger("none")
35-
lg.Debug("mdns: advertiser started", map[string]interface{}{"instance": instance, "port": port, "meta_keys": len(meta)})
36-
return &Advertiser{server: srv, logger: lg}, nil
50+
if pkgLogger != nil {
51+
pkgLogger.Debug("mdns: advertiser started", map[string]interface{}{"instance": instance, "port": port, "meta_keys": len(meta)})
52+
}
53+
return &Advertiser{server: srv, logger: pkgLogger}, nil
3754
}
3855

3956
// Stop stops the advertiser
@@ -48,9 +65,15 @@ func (a *Advertiser) Stop() {
4865

4966
// Discover finds peers advertising the service within the timeout
5067
func Discover(ctx context.Context, timeout time.Duration) ([]core.PeerInfo, error) {
51-
lg := logging.NewLogger("none")
68+
lg := pkgLogger
69+
if lg != nil {
70+
lg.Debug("mdns: discover begin", map[string]interface{}{"timeout_ms": timeout.Milliseconds(), "service": serviceType})
71+
}
5272
r, err := zeroconf.NewResolver(nil)
5373
if err != nil {
74+
if lg != nil {
75+
lg.Warn("mdns: resolver create failed", map[string]interface{}{"error": err.Error()})
76+
}
5477
return nil, err
5578
}
5679
entries := make(chan *zeroconf.ServiceEntry, 32)
@@ -78,10 +101,19 @@ func Discover(ctx context.Context, timeout time.Duration) ([]core.PeerInfo, erro
78101
LastSeen: time.Now(),
79102
})
80103
}
104+
if lg != nil {
105+
lg.Debug("mdns: entries channel closed", nil)
106+
}
81107
}()
82108
qctx, cancel := context.WithTimeout(ctx, timeout)
83109
defer cancel()
110+
if lg != nil {
111+
lg.Debug("mdns: browse start", nil)
112+
}
84113
if err := r.Browse(qctx, serviceType, "local.", entries); err != nil {
114+
if lg != nil {
115+
lg.Warn("mdns: browse failed", map[string]interface{}{"error": err.Error()})
116+
}
85117
return nil, err
86118
}
87119
<-qctx.Done()

internal/mesh/node.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,10 @@ func (n *Node) Start(ctx context.Context) error {
7272
n.started = true
7373
n.startedMu.Unlock()
7474

75-
// In TCP-only builds, transport is nil; treat Start as a no-op
76-
if n.transport == nil {
77-
return nil
78-
}
75+
// In TCP-only builds, transport is nil; treat Start as a no-op
76+
if n.transport == nil {
77+
return nil
78+
}
7979

8080
// Try to create GATT service; if unsupported on this platform/transport, continue without it
8181
if _, err := n.transport.CreateGATTService(); err != nil {
@@ -95,7 +95,7 @@ func (n *Node) Start(ctx context.Context) error {
9595
// Start discovery
9696
// BLE manager disabled in TCP-only build
9797

98-
// Start BLE notification receiver if transport supports it
98+
// Start BLE notification receiver if transport supports it
9999
if sub, ok := n.transport.(interface {
100100
SubscribeWriteNotifications(ctx context.Context) (<-chan []byte, func(), error)
101101
}); ok {

0 commit comments

Comments
 (0)