Skip to content

Commit 2e6fc19

Browse files
committed
Try to fix showing output for commands, idk if this will work.
1 parent ff8d548 commit 2e6fc19

9 files changed

Lines changed: 120 additions & 27 deletions

File tree

cmd/meshexec/daemon.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ func runDaemon(cmd *cobra.Command) error {
8686

8787
if logger != nil {
8888
logger.Info("daemon started", map[string]interface{}{"device": cfg.Device.Name})
89+
// Add subscriptions to log inbound command/result messages for observability
90+
cmdCh := node.Subscribe(core.MessageTypeCommand)
91+
resCh := node.Subscribe(core.MessageTypeResult)
92+
go func() {
93+
for m := range cmdCh {
94+
logger.Info("daemon: received command", map[string]interface{}{"id": m.ID, "from": m.Sender, "ttl": m.TTL, "cmd": m.Command})
95+
}
96+
}()
97+
go func() {
98+
for m := range resCh {
99+
logger.Info("daemon: received result", map[string]interface{}{"id": m.ID, "from": m.Sender, "ttl": m.TTL})
100+
}
101+
}()
89102
}
90103

91104
// Wait for termination signal (test seam)

cmd/meshexec/run.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,30 @@ var runCmd = &cobra.Command{
215215
select {
216216
case rm := <-resCh:
217217
if rm != nil {
218-
fmt.Printf("Received a result message (id=%s, sender=%s)\n", rm.ID, rm.Sender)
218+
// If payload contains the raw JSON, try to deserialize ResultMessage for rich output
219+
printed := false
220+
if len(rm.Payload) > 0 {
221+
var full messages.MessageHandler
222+
// Use handler to deserialize based on embedded type
223+
if v, err := full.DeserializeMessage(rm.Payload); err == nil {
224+
if res, ok := v.(*core.ResultMessage); ok {
225+
r := res.Result
226+
fmt.Printf("Result: status=%s code=%d device=%s\n", r.Status, r.ExitCode, r.Device)
227+
if s := strings.TrimSpace(r.Stdout); s != "" {
228+
fmt.Println("stdout:")
229+
fmt.Println(s)
230+
}
231+
if s := strings.TrimSpace(r.Stderr); s != "" {
232+
fmt.Println("stderr:")
233+
fmt.Println(s)
234+
}
235+
printed = true
236+
}
237+
}
238+
}
239+
if !printed {
240+
fmt.Printf("Received a result message (id=%s, sender=%s)\n", rm.ID, rm.Sender)
241+
}
219242
} else {
220243
fmt.Println("Result channel closed without message")
221244
}

cmd/meshexec/smoke.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"os"
99
"runtime"
10+
"strings"
1011
"time"
1112

1213
core "github.com/monster0506/meshexec/internal"
@@ -131,10 +132,29 @@ var smokeCmd = &cobra.Command{
131132
os.Exit(6)
132133
}
133134

134-
// Print result summary
135-
fmt.Printf("Result received: id=%s type=%s sender=%s ttl=%d\n", got.ID, got.Type, got.Sender, got.TTL)
136-
// In this smoke path, stdout/stderr/exitcode are carried inside ResultMessage payload (handled by higher layers),
137-
// but MeshMessage schema does not include them; we just confirm receipt.
135+
// Print rich result if payload contains a serialized ResultMessage
136+
printed := false
137+
if len(got.Payload) > 0 {
138+
mh := messages.NewMessageHandlerWithLevel(logLevel)
139+
if v, err := mh.DeserializeMessage(got.Payload); err == nil {
140+
if res, ok := v.(*core.ResultMessage); ok {
141+
r := res.Result
142+
fmt.Printf("Result: status=%s code=%d device=%s\n", r.Status, r.ExitCode, r.Device)
143+
if s := strings.TrimSpace(r.Stdout); s != "" {
144+
fmt.Println("stdout:")
145+
fmt.Println(s)
146+
}
147+
if s := strings.TrimSpace(r.Stderr); s != "" {
148+
fmt.Println("stderr:")
149+
fmt.Println(s)
150+
}
151+
printed = true
152+
}
153+
}
154+
}
155+
if !printed {
156+
fmt.Printf("Result received: id=%s type=%s sender=%s ttl=%d\n", got.ID, got.Type, got.Sender, got.TTL)
157+
}
138158

139159
// Cleanup
140160
_ = ag.Stop()

internal/agent/agent.go

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package agent
22

33
import (
44
"context"
5+
"strings"
56
"sync"
67
"time"
78

@@ -119,7 +120,7 @@ func (a *Agent) ProcessCommand(msg *core.MeshMessage) error {
119120
var execRes *core.ExecutionResult
120121
var execErr error
121122
if a.exec != nil {
122-
cmdLine := buildCommandLine(msg.Command, msg.Payload)
123+
cmdLine := commandLineFromMessage(msg)
123124
if err := a.exec.ValidateCommand(cmdLine); err != nil {
124125
return err
125126
}
@@ -145,7 +146,16 @@ func (a *Agent) ProcessCommand(msg *core.MeshMessage) error {
145146
}
146147
}
147148
}
149+
// Ensure required fields are populated for downstream validation/printing
148150
execRes.Device = a.device.Name
151+
if execRes.ID == "" {
152+
mhTmp := messages.NewMessageHandlerWithLevel("none")
153+
gen := mhTmp.CreateExecutionResult(msg.Command, execRes.Status, execRes.Stdout, execRes.Stderr, execRes.ExitCode, execRes.Device, time.Duration(execRes.Duration)*time.Millisecond)
154+
execRes.ID = gen.ID
155+
if execRes.Type == "" {
156+
execRes.Type = gen.Type
157+
}
158+
}
149159

150160
// Create and sign result
151161
mh := messages.NewMessageHandlerWithLevel("none")
@@ -170,13 +180,26 @@ func (a *Agent) ValidateCommand(msg *core.MeshMessage) error {
170180
if a.exec == nil {
171181
return nil
172182
}
173-
cmdLine := buildCommandLine(msg.Command, msg.Payload)
183+
cmdLine := commandLineFromMessage(msg)
174184
return a.exec.ValidateCommand(cmdLine)
175185
}
176186

177-
func buildCommandLine(command string, payload []byte) string {
178-
if command == "" {
187+
// commandLineFromMessage reconstructs the intended command line from a possibly down-cast MeshMessage.
188+
// If the raw JSON payload is present and represents a CommandMessage, we include arguments.
189+
func commandLineFromMessage(msg *core.MeshMessage) string {
190+
if msg == nil {
179191
return ""
180192
}
181-
return command
193+
if len(msg.Payload) > 0 {
194+
mh := messages.NewMessageHandlerWithLevel("none")
195+
if v, err := mh.DeserializeMessage(msg.Payload); err == nil {
196+
if cm, ok := v.(*core.CommandMessage); ok {
197+
if len(cm.Arguments) > 0 {
198+
return cm.Command + " " + strings.Join(cm.Arguments, " ")
199+
}
200+
return cm.Command
201+
}
202+
}
203+
}
204+
return msg.Command
182205
}

internal/ble/transport_sidecar_windows.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,8 @@ func (t *SidecarTransport) Advertise(ctx context.Context, serviceData []byte) er
118118
if t.logger != nil {
119119
t.logger.Info("Sidecar: starting advertise", map[string]interface{}{"len": len(serviceData)})
120120
}
121-
cfg := core.DefaultConfig()
122121
params := map[string]interface{}{
123-
"service_uuid": cfg.Network.ServiceUUID,
122+
"service_uuid": t.serviceUUID,
124123
"local_name": "meshexec",
125124
"service_data_b64": base64.StdEncoding.EncodeToString(serviceData),
126125
}
@@ -154,16 +153,15 @@ func (t *SidecarTransport) CreateGATTService() (*core.GATTService, error) {
154153
if t.logger != nil {
155154
t.logger.Info("Sidecar: creating GATT service", nil)
156155
}
157-
cfg := core.DefaultConfig()
158156
params := map[string]interface{}{
159-
"service_uuid": cfg.Network.ServiceUUID,
160-
"characteristic_uuid": cfg.Network.CharacteristicUUID,
157+
"service_uuid": t.serviceUUID,
158+
"characteristic_uuid": t.charUUID,
161159
"properties": "read,write,notify",
162160
}
163161
if _, err := t.do("gatt_create", params); err != nil {
164162
return nil, err
165163
}
166-
return &core.GATTService{UUID: cfg.Network.ServiceUUID, Characteristics: []core.GATTCharacteristic{{UUID: cfg.Network.CharacteristicUUID, Writable: true}}}, nil
164+
return &core.GATTService{UUID: t.serviceUUID, Characteristics: []core.GATTCharacteristic{{UUID: t.charUUID, Writable: true}}}, nil
167165
}
168166

169167
// SubscribeWriteNotifications subscribes to incoming GATT write events from sidecar and streams payloads.
@@ -285,7 +283,7 @@ func (t *SidecarTransport) CentralBroadcast(ctx context.Context, data []byte) er
285283
"service_uuid": t.serviceUUID,
286284
"characteristic_uuid": t.charUUID,
287285
"value_b64": base64.StdEncoding.EncodeToString(data),
288-
"scan_ms": 800,
286+
"scan_ms": 2000,
289287
}
290288
// Best-effort: make a short-lived request; sidecar performs scan/connect/write internally
291289
if _, err := t.do("central_broadcast", p); err != nil {

internal/mesh/node.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ func (n *Node) Start(ctx context.Context) error {
133133
if full := n.tryReassemble(b); full != nil {
134134
var m core.MeshMessage
135135
if err := json.Unmarshal(full, &m); err == nil {
136+
// Preserve raw JSON payload so subscribers can deserialize full message (e.g., results)
137+
m.Payload = append([]byte(nil), full...)
136138
n.publishLocal(&m)
137139
}
138140
}

internal/messages/messages.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ func (h *MessageHandler) CreateCommandMessage(
5454
Timeout: timeout,
5555
}
5656

57+
// Embed a raw JSON representation (without payload) for local delivery convenience
58+
// to allow receivers to deserialize the full typed message from MeshMessage.Payload.
59+
// Avoid recursion by marshaling a copy with empty payload.
60+
{
61+
tmp := *msg
62+
tmp.Payload = nil
63+
if b, err := json.Marshal(&tmp); err == nil {
64+
msg.Payload = b
65+
}
66+
}
67+
5768
h.logger.Debug("Created command message", map[string]interface{}{
5869
"message_id": msg.ID,
5970
"command": command,
@@ -83,6 +94,14 @@ func (h *MessageHandler) CreateResultMessage(
8394
CommandID: commandID,
8495
Result: result,
8596
}
97+
// Embed raw JSON (without payload) for local delivery convenience
98+
{
99+
tmp := *msg
100+
tmp.Payload = nil
101+
if b, err := json.Marshal(&tmp); err == nil {
102+
msg.Payload = b
103+
}
104+
}
86105
return msg
87106
}
88107

sidecar/WinBLE/Program.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ async Task<JsonElement> HandleAsync(JsonElement req)
282282
{
283283
var req2 = await e.GetRequestAsync();
284284
var len = req2.Value?.Length ?? 0;
285-
Log("DEBUG", "gatt write request", new Dictionary<string, object?> { { "len", len } });
285+
Log("INFO", "gatt write request", new Dictionary<string, object?> { { "len", len }, { "session", e.Session.SessionId } });
286286
if (req2.Value != null)
287287
{
288288
var bytes = new byte[req2.Value.Length];
@@ -341,6 +341,7 @@ async Task<JsonElement> HandleAsync(JsonElement req)
341341
try
342342
{
343343
if (!e.Advertisement.ServiceUuids.Contains(svc)) return;
344+
Log("INFO", "central match", new Dictionary<string, object?> { { "addr", e.BluetoothAddress }, { "rssi", e.RawSignalStrengthInDBm } });
344345
var dev = await BluetoothLEDevice.FromBluetoothAddressAsync(e.BluetoothAddress);
345346
if (dev == null) return;
346347
var result = await dev.GetGattServicesForUuidAsync(svc);
@@ -369,9 +370,11 @@ async Task<JsonElement> HandleAsync(JsonElement req)
369370
Log("ERROR", "central write failed", new Dictionary<string, object?> { { "error", ex.Message } });
370371
}
371372
};
373+
Log("INFO", "central_broadcast start", new Dictionary<string, object?> { { "scan_ms", scanMs } });
372374
watcher.Start();
373375
await Task.Delay(scanMs);
374376
watcher.Stop();
377+
Log("INFO", "central_broadcast stop", null);
375378
return JsonDocument.Parse("{\"ok\":true}").RootElement;
376379
}
377380
// gatt_subscribe / gatt_unsubscribe are handled in ServeAsync where writer is in scope

sidecar/WinBLE/packages.lock.json

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
{
22
"version": 1,
33
"dependencies": {
4-
"net8.0-windows10.0.19041": {
5-
"Microsoft.NET.ILLink.Tasks": {
6-
"type": "Direct",
7-
"requested": "[8.0.19, )",
8-
"resolved": "8.0.19",
9-
"contentHash": "IhHf+zeZiaE5EXRyxILd4qM+Hj9cxV3sa8MpzZgeEhpvaG3a1VEGF6UCaPFLO44Kua3JkLKluE0SWVamS50PlA=="
10-
}
11-
},
12-
"net8.0-windows10.0.19041/win-x64": {}
4+
"net8.0-windows10.0.19041": {}
135
}
146
}

0 commit comments

Comments
 (0)