mirror of
https://github.com/openlibrecommunity/olcrtc.git
synced 2026-06-02 10:29:45 +00:00
videochannel, seichannel and vp8channel each carried independent copies of randomID(), fragmentPayload(), inboundMessage + upsertInbound + assembleMessage + ackWaiters/ackMu. The reassembly logic was almost byte-identical across videochannel and seichannel; vp8channel only needed randomID. Three copies of the same idea. Add internal/transport/common with: - RandomID(): 8-char hex per-peer ID (Jitsi msid uniqueness requirement). - FragmentPayload(): split bytes into max-size chunks. - Reassembler: stores in-flight messages keyed by Seq, validates CRC, and reports Partial / Delivered / Duplicate / Ignore via a Result enum. - AckRegistry: Register/Unregister/Resolve for ack waiters. videochannel and seichannel now hold *common.AckRegistry and *common.Reassembler instead of raw maps + mutexes. Their Send paths route through acks.Register/Unregister; their handleInboundFrame is a 20-line switch over reassembler.Push. vp8channel keeps its KCP framing but reuses common.RandomID. Tests that constructed raw streamTransport with inbound/delivered/ackWaiters maps are updated to instantiate the new common types instead. Two now- redundant low-level tests (upsertInbound out-of-range, assembleMessage) collapse into the new TestInboundRejectsBadCRC. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
77 lines
1.9 KiB
Go
77 lines
1.9 KiB
Go
package videochannel
|
|
|
|
import (
|
|
"bytes"
|
|
"hash/crc32"
|
|
"testing"
|
|
|
|
"github.com/openlibrecommunity/olcrtc/internal/transport/common"
|
|
)
|
|
|
|
func TestInboundAssemblyAndAck(t *testing.T) {
|
|
var got []byte
|
|
tr := &streamTransport{
|
|
onData: func(data []byte) { got = append([]byte(nil), data...) },
|
|
outboundAck: make(chan []byte, 4),
|
|
reassembler: common.NewReassembler(256),
|
|
}
|
|
|
|
payload := []byte("hello video")
|
|
crc := crc32.ChecksumIEEE(payload)
|
|
tr.handleInboundFrame(transportFrame{
|
|
typ: frameTypeData,
|
|
seq: 1,
|
|
crc: crc,
|
|
totalLen: uint32(len(payload)), //nolint:gosec // G115: bounded conversion verified by surrounding logic
|
|
fragIdx: 1,
|
|
fragTotal: 2,
|
|
payload: []byte(" video"),
|
|
})
|
|
if len(got) != 0 {
|
|
t.Fatalf("onData called before message complete: %q", got)
|
|
}
|
|
|
|
tr.handleInboundFrame(transportFrame{
|
|
typ: frameTypeData,
|
|
seq: 1,
|
|
crc: crc,
|
|
totalLen: uint32(len(payload)), //nolint:gosec // G115: bounded conversion verified by surrounding logic
|
|
fragIdx: 0,
|
|
fragTotal: 2,
|
|
payload: []byte("hello"),
|
|
})
|
|
if !bytes.Equal(got, payload) {
|
|
t.Fatalf("assembled payload = %q, want %q", got, payload)
|
|
}
|
|
select {
|
|
case ack := <-tr.outboundAck:
|
|
frame, err := decodeTransportFrame(ack)
|
|
if err != nil || frame.typ != frameTypeAck || frame.seq != 1 || frame.crc != crc {
|
|
t.Fatalf("ack frame = %+v err=%v", frame, err)
|
|
}
|
|
default:
|
|
t.Fatal("handleInboundFrame() did not enqueue ack")
|
|
}
|
|
}
|
|
|
|
func TestInboundRejectsBadCRC(t *testing.T) {
|
|
tr := &streamTransport{
|
|
outboundAck: make(chan []byte, 2),
|
|
reassembler: common.NewReassembler(256),
|
|
}
|
|
|
|
called := false
|
|
tr.onData = func([]byte) { called = true }
|
|
tr.handleInboundFrame(transportFrame{
|
|
seq: 2,
|
|
crc: 123,
|
|
totalLen: 3,
|
|
fragIdx: 0,
|
|
fragTotal: 1,
|
|
payload: []byte("abc"),
|
|
})
|
|
if called {
|
|
t.Fatal("handleInboundFrame() delivered payload with bad crc")
|
|
}
|
|
}
|