client: chirp offer every 5s while unpaired
Solves the late-subscriber problem — browsers that load the page after the peer's startup offer would never see one. Now the peer re-broadcasts the offer every 5 seconds until the DataChannel opens, then stops. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/atotto/clipboard"
|
"github.com/atotto/clipboard"
|
||||||
@@ -179,7 +180,10 @@ func handleMessage(ev string, m Message) {
|
|||||||
|
|
||||||
// ── WebRTC ────────────────────────────────────────────────────────────────
|
// ── WebRTC ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
var incomingSignal = make(chan Message, 16)
|
var (
|
||||||
|
incomingSignal = make(chan Message, 16)
|
||||||
|
rtcConnected = make(chan struct{})
|
||||||
|
)
|
||||||
|
|
||||||
func runRTCPeer(server string) {
|
func runRTCPeer(server string) {
|
||||||
api := webrtc.NewAPI()
|
api := webrtc.NewAPI()
|
||||||
@@ -200,8 +204,10 @@ func runRTCPeer(server string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var once sync.Once
|
||||||
dc.OnOpen(func() {
|
dc.OnOpen(func() {
|
||||||
fmt.Fprintln(os.Stderr, "rtc: DataChannel OPEN — P2P live")
|
fmt.Fprintln(os.Stderr, "rtc: DataChannel OPEN — P2P live")
|
||||||
|
once.Do(func() { close(rtcConnected) })
|
||||||
})
|
})
|
||||||
dc.OnMessage(func(msg webrtc.DataChannelMessage) {
|
dc.OnMessage(func(msg webrtc.DataChannelMessage) {
|
||||||
text := string(msg.Data)
|
text := string(msg.Data)
|
||||||
@@ -225,7 +231,7 @@ func runRTCPeer(server string) {
|
|||||||
fmt.Fprintf(os.Stderr, "rtc: state=%s\n", s)
|
fmt.Fprintf(os.Stderr, "rtc: state=%s\n", s)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create offer + post via signaling bus
|
// Create offer + post once immediately
|
||||||
offer, err := pc.CreateOffer(nil)
|
offer, err := pc.CreateOffer(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("rtc: create offer: %v", err)
|
log.Printf("rtc: create offer: %v", err)
|
||||||
@@ -237,7 +243,24 @@ func runRTCPeer(server string) {
|
|||||||
}
|
}
|
||||||
payload, _ := json.Marshal(SignalPayload{Kind: "offer", SDP: &offer})
|
payload, _ := json.Marshal(SignalPayload{Kind: "offer", SDP: &offer})
|
||||||
send(server, myLabel, "", "signal", payload)
|
send(server, myLabel, "", "signal", payload)
|
||||||
fmt.Fprintln(os.Stderr, "rtc: offer posted, waiting for answer...")
|
fmt.Fprintln(os.Stderr, "rtc: offer posted, will chirp every 5s until paired...")
|
||||||
|
|
||||||
|
// "Chirp": re-post the offer every 5s until DataChannel opens. Catches
|
||||||
|
// late-joining browsers without needing server-side history of signals.
|
||||||
|
go func() {
|
||||||
|
t := time.NewTicker(5 * time.Second)
|
||||||
|
defer t.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-rtcConnected:
|
||||||
|
fmt.Fprintln(os.Stderr, "rtc: paired — chirping stopped")
|
||||||
|
return
|
||||||
|
case <-t.C:
|
||||||
|
p, _ := json.Marshal(SignalPayload{Kind: "offer", SDP: &offer})
|
||||||
|
send(server, myLabel, "", "signal", p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Process incoming signals
|
// Process incoming signals
|
||||||
for {
|
for {
|
||||||
|
|||||||
Reference in New Issue
Block a user