Skip to content

Commit e3392ac

Browse files
committed
Fix ready channel race condition and implement Neko heartbeat protocol
Bug 1: In Start(), only replace the ready channel if the previous one was already closed (reconnection case). Previously, Start() always created a new channel, orphaning the one from NewRelay() and causing the first client to always time out with a 503. Bug 2: Extract heartbeat_interval from system/init payload and start a periodic client/heartbeat sender. Remove dead system/heartbeat handler (Neko never sends this event; it sends system/pong in response to client-initiated heartbeats).
1 parent 6e0ae57 commit e3392ac

1 file changed

Lines changed: 36 additions & 7 deletions

File tree

‎server/lib/webrtcscreen/relay.go‎

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,13 @@ func (r *Relay) ensureRunning() {
9494
// Start in a loop for automatic reconnection.
9595
func (r*Relay) Start(ctx context.Context) error {
9696
r.mu.Lock()
97-
r.ready=make(chanstruct{})
97+
select {
98+
case<-r.ready:
99+
// Previous connection closed the channel; create a fresh one.
100+
r.ready=make(chanstruct{})
101+
default:
102+
// Channel is still open (first call), keep it.
103+
}
98104
r.mu.Unlock()
99105

100106
token, err:=r.nekoLogin(ctx)
@@ -124,10 +130,35 @@ func (r *Relay) Start(ctx context.Context) error {
124130
r.mu.Unlock()
125131
}()
126132

127-
iferr:=r.waitForEvent(ctx, ws, "system/init"); err!=nil {
133+
initPayload, err:=r.waitForEvent(ctx, ws, "system/init")
134+
iferr!=nil {
128135
returnfmt.Errorf("waiting for system/init: %w", err)
129136
}
130137

138+
varinitDatastruct {
139+
HeartbeatIntervalfloat64`json:"heartbeat_interval"`
140+
}
141+
ifinitPayload!=nil {
142+
_=json.Unmarshal(initPayload, &initData)
143+
}
144+
145+
ifinitData.HeartbeatInterval>0 {
146+
gofunc() {
147+
ticker:=time.NewTicker(time.Duration(initData.HeartbeatInterval*float64(time.Second)))
148+
deferticker.Stop()
149+
for {
150+
select {
151+
case<-ctx.Done():
152+
return
153+
case<-ticker.C:
154+
iferr:=sendWSMsg(ctx, ws, "client/heartbeat", nil); err!=nil {
155+
return
156+
}
157+
}
158+
}
159+
}()
160+
}
161+
131162
pc, err:=webrtc.NewPeerConnection(webrtc.Configuration{})
132163
iferr!=nil {
133164
returnfmt.Errorf("creating neko peer connection: %w", err)
@@ -502,15 +533,15 @@ func sendWSMsg(ctx context.Context, ws *cws.Conn, event string, payload json.Raw
502533
returnws.Write(ctx, cws.MessageText, data)
503534
}
504535

505-
func (r*Relay) waitForEvent(ctx context.Context, ws*cws.Conn, eventstring) error {
536+
func (r*Relay) waitForEvent(ctx context.Context, ws*cws.Conn, eventstring) (json.RawMessage, error) {
506537
for {
507538
_, data, err:=ws.Read(ctx)
508539
iferr!=nil {
509-
returnerr
540+
returnnil, err
510541
}
511542
varmsgnekoMsg
512543
ifjson.Unmarshal(data, &msg) ==nil&&msg.Event==event {
513-
returnnil
544+
returnmsg.Payload, nil
514545
}
515546
}
516547
}
@@ -545,8 +576,6 @@ func (r *Relay) nekoWSLoop(ctx context.Context, ws *cws.Conn, pc *webrtc.PeerCon
545576
continue
546577
}
547578
switchmsg.Event {
548-
case"system/heartbeat":
549-
_=sendWSMsg(ctx, ws, "client/heartbeat", nil)
550579
case"signal/candidate":
551580
varcandidate webrtc.ICECandidateInit
552581
ifjson.Unmarshal(msg.Payload, &candidate) ==nil {

0 commit comments

Comments
 (0)