Skip to content

Commit bfb6cd7

Browse files
committed
fix: correct lock order doc, sendMsg typo, unused parentCtx, Stop goroutine overlap, variable shadowing, duplicate time.Since, ffmpeg stderr capture, base64 threshold comment
1 parent 24faf9b commit bfb6cd7

File tree

2 files changed

+19
-21
lines changed

2 files changed

+19
-21
lines changed

server/lib/cdpmonitor/monitor.go

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ const wsReadLimit = 8 * 1024 * 1024
2828
//
2929
// Lock ordering (outer → inner):
3030
//
31-
// lifeMurestartMu → pendReqMu → computed.mu → pendMu → sessionsMu
31+
// restartMulifeMu → pendReqMu → computed.mu → pendMu → sessionsMu
3232
//
3333
// Never acquire a lock that appears later in this order while holding an
3434
// earlier one, to prevent deadlock.
3535
//
3636
// WebSocket concurrency: coder/websocket guarantees that one concurrent Read
3737
// and one concurrent Write are safe. The readLoop holds the sole Read; all
38-
// writes go through sendMsg, which serialises them with conn.Write's internal
38+
// writes go through send, which serialises them with conn.Write's internal
3939
// lock. No external write mutex is needed.
4040
type Monitor struct {
4141
upstreamMgr UpstreamProvider
@@ -69,8 +69,9 @@ type Monitor struct {
6969
bindingRateMu sync.Mutex
7070
bindingLastSeen map[string]time.Time // sessionID → last accepted binding event time
7171

72-
// asyncWg tracks short-lived goroutines only (fetchResponseBody, enableDomains,
73-
// initSession). readLoop and subscribeToUpstream are not tracked; they exit via context.
72+
// asyncWg tracks all goroutines except readLoop (which is tracked via done).
73+
// subscribeToUpstream and sweepPendingRequests are included so Stop() can
74+
// wait for them to exit before returning.
7475
asyncWg sync.WaitGroup
7576
restartMu sync.Mutex // serializes handleUpstreamRestart to prevent overlapping reconnects
7677

@@ -138,7 +139,7 @@ func (m *Monitor) getLifecycleCtx() context.Context {
138139

139140
// Start begins CDP capture. Restarts if already running.
140141
// Not concurrency-safe; callers must serialize Start calls.
141-
func (m *Monitor) Start(parentCtx context.Context) error {
142+
func (m *Monitor) Start(_ context.Context) error {
142143
m.Stop() // no-op if not running
143144

144145
devtoolsURL := m.upstreamMgr.Current()
@@ -168,8 +169,8 @@ func (m *Monitor) Start(parentCtx context.Context) error {
168169
m.log.Info("cdpmonitor: started", "url", devtoolsURL)
169170

170171
go m.readLoop(ctx)
171-
go m.subscribeToUpstream(ctx)
172-
go m.sweepPendingRequests(ctx)
172+
m.asyncWg.Go(func() { m.subscribeToUpstream(ctx) })
173+
m.asyncWg.Go(func() { m.sweepPendingRequests(ctx) })
173174
m.asyncWg.Go(func() { m.initSession(ctx) })
174175

175176
return nil
@@ -452,12 +453,12 @@ func (m *Monitor) attachExistingTargets(ctx context.Context) {
452453
if err != nil {
453454
return
454455
}
455-
var attached struct {
456+
var attachResp struct {
456457
SessionID string `json:"sessionId"`
457458
}
458-
if json.Unmarshal(res, &attached) == nil && attached.SessionID != "" {
459-
m.enableDomains(ctx, attached.SessionID, targetTypePage)
460-
_ = m.injectScript(ctx, attached.SessionID)
459+
if json.Unmarshal(res, &attachResp) == nil && attachResp.SessionID != "" {
460+
m.enableDomains(ctx, attachResp.SessionID, targetTypePage)
461+
_ = m.injectScript(ctx, attachResp.SessionID)
461462
}
462463
})
463464
}
@@ -554,17 +555,15 @@ func (m *Monitor) handleUpstreamRestart(ctx context.Context, newURL string) {
554555
m.clearState()
555556

556557
m.asyncWg.Go(func() { m.initSession(ctx) })
557-
m.log.Info("cdpmonitor: reconnected", "url", newURL, "duration_ms", time.Since(startReconnect).Milliseconds())
558+
reconnectDurationMs := time.Since(startReconnect).Milliseconds()
559+
m.log.Info("cdpmonitor: reconnected", "url", newURL, "duration_ms", reconnectDurationMs)
558560

559561
m.publish(events.Event{
560562
Ts: time.Now().UnixMilli(),
561563
Type: EventMonitorReconnected,
562564
Category: events.CategorySystem,
563565
Source: events.Source{Kind: events.KindLocalProcess},
564-
Data: json.RawMessage(fmt.Sprintf(
565-
`{"reconnect_duration_ms":%d}`,
566-
time.Since(startReconnect).Milliseconds(),
567-
)),
566+
Data: json.RawMessage(fmt.Sprintf(`{"reconnect_duration_ms":%d}`, reconnectDurationMs)),
568567
})
569568
}
570569

server/lib/cdpmonitor/screenshot.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"encoding/base64"
77
"encoding/json"
88
"fmt"
9-
"io"
109
"os/exec"
1110
"time"
1211

@@ -54,7 +53,7 @@ func (m *Monitor) captureScreenshot(parentCtx context.Context) {
5453
return
5554
}
5655

57-
// Downscale if base64 output would exceed 950KB (~729KB raw).
56+
// Downscale if base64 output would exceed ~972KB (~729KB raw × 4/3 base64 inflation).
5857
const rawThreshold = 729 * 1024
5958
for scale := 2; len(pngBytes) > rawThreshold && scale <= 16 && m.screenshotFn == nil; scale *= 2 {
6059
pngBytes, err = captureViaFFmpeg(ctx, m.displayNum, scale)
@@ -89,12 +88,12 @@ func captureViaFFmpeg(ctx context.Context, displayNum, divisor int) ([]byte, err
8988
}
9089
args = append(args, "-f", "image2", "pipe:1")
9190

92-
var out bytes.Buffer
91+
var out, stderr bytes.Buffer
9392
cmd := exec.CommandContext(ctx, "ffmpeg", args...)
9493
cmd.Stdout = &out
95-
cmd.Stderr = io.Discard
94+
cmd.Stderr = &stderr
9695
if err := cmd.Run(); err != nil {
97-
return nil, err
96+
return nil, fmt.Errorf("%w: %s", err, stderr.String())
9897
}
9998
return out.Bytes(), nil
10099
}

0 commit comments

Comments
 (0)