From 238bf4784427a9bc4af570439c4e778b1f245906 Mon Sep 17 00:00:00 2001 From: "Billy D." Date: Sat, 21 Feb 2026 15:30:51 -0500 Subject: [PATCH] feat: migrate from msgpack to protobuf (handler-base v1.0.0) - Replace msgpack encoding with protobuf wire format - Update field names to proto convention (SessionId) - Cast int fields to int32 (ChunkIndex, TotalChunks, SampleRate, Count) - Use pointer slices for repeated messages ([]*TTSVoiceInfo) - Rewrite tests for proto round-trips --- e2e_test.go | 24 ++++++++++++------------ go.mod | 6 ++---- go.sum | 8 ++------ main.go | 32 ++++++++++++++++---------------- main_test.go | 20 ++++++++++---------- 5 files changed, 42 insertions(+), 48 deletions(-) diff --git a/e2e_test.go b/e2e_test.go index 79a7390..f640ce3 100644 --- a/e2e_test.go +++ b/e2e_test.go @@ -12,7 +12,7 @@ import ( "testing" "git.daviestechlabs.io/daviestechlabs/handler-base/messages" - "github.com/vmihailenco/msgpack/v5" + "google.golang.org/protobuf/proto" ) // ──────────────────────────────────────────────────────────────────────────── @@ -67,21 +67,21 @@ func TestSynthesisE2E_StreamChunks(t *testing.T) { // Verify typed chunk struct msg := messages.TTSAudioChunk{ - SessionID: "test-session", - ChunkIndex: chunkIdx, - TotalChunks: totalChunks, + SessionId: "test-session", + ChunkIndex: int32(chunkIdx), + TotalChunks: int32(totalChunks), Audio: chunk, IsLast: isLast, SampleRate: 24000, } // Round-trip through msgpack - data, _ := msgpack.Marshal(&msg) + data, _ := proto.Marshal(&msg) var decoded messages.TTSAudioChunk - _ = msgpack.Unmarshal(data, &decoded) + _ = proto.Unmarshal(data, &decoded) - if decoded.SessionID != "test-session" { - t.Errorf("chunk %d: session = %v", chunkIdx, decoded.SessionID) + if decoded.SessionId != "test-session" { + t.Errorf("chunk %d: session = %v", chunkIdx, decoded.SessionId) } if decoded.IsLast != isLast { t.Errorf("chunk %d: is_last = %v, want %v", chunkIdx, decoded.IsLast, isLast) @@ -266,13 +266,13 @@ func BenchmarkAudioChunking(b *testing.B) { } chunk := audioBytes[i:end] msg := &messages.TTSAudioChunk{ - SessionID: "bench", - ChunkIndex: i / chunkSize, - TotalChunks: totalChunks, + SessionId: "bench", + ChunkIndex: int32(i / chunkSize), + TotalChunks: int32(totalChunks), Audio: chunk, SampleRate: 24000, } - _, _ = msgpack.Marshal(msg) + _, _ = proto.Marshal(msg) } } } diff --git a/go.mod b/go.mod index b6efc01..bf4fb94 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module git.daviestechlabs.io/daviestechlabs/tts-module go 1.25.1 require ( - git.daviestechlabs.io/daviestechlabs/handler-base v0.1.5 + git.daviestechlabs.io/daviestechlabs/handler-base v1.0.0 github.com/nats-io/nats.go v1.48.0 - github.com/vmihailenco/msgpack/v5 v5.4.1 + google.golang.org/protobuf v1.36.11 ) require ( @@ -19,7 +19,6 @@ require ( github.com/klauspost/compress v1.18.0 // indirect github.com/nats-io/nkeys v0.4.11 // indirect github.com/nats-io/nuid v1.0.1 // indirect - github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel v1.40.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 // indirect @@ -37,5 +36,4 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect google.golang.org/grpc v1.78.0 // indirect - google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/go.sum b/go.sum index efceef0..5d7dfc1 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -git.daviestechlabs.io/daviestechlabs/handler-base v0.1.5 h1:DqYZpeluTXh5QKqdVFgN8YIMh4Ycqzw5E9+5FTNDFCA= -git.daviestechlabs.io/daviestechlabs/handler-base v0.1.5/go.mod h1:M3HgvUDWnRn7cX3BE8l+HvoCUYtmRr5OoumB+hnRHoE= +git.daviestechlabs.io/daviestechlabs/handler-base v1.0.0 h1:pB3ehOKaDYQfbyRBKQXrB9curqSFteLrDveoElRKnBY= +git.daviestechlabs.io/daviestechlabs/handler-base v1.0.0/go.mod h1:zocOHFt8yY3cW4+Xi37sNr5Tw7KcjGFSZqgWYxPWyqA= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -33,10 +33,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= -github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= -github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= -github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= diff --git a/main.go b/main.go index f35038a..5e68bb6 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,7 @@ import ( "time" "github.com/nats-io/nats.go" - "github.com/vmihailenco/msgpack/v5" + "google.golang.org/protobuf/proto" "git.daviestechlabs.io/daviestechlabs/handler-base/config" "git.daviestechlabs.io/daviestechlabs/handler-base/health" @@ -128,12 +128,12 @@ func (vr *VoiceRegistry) get(name string) *CustomVoice { return vr.voices[name] } -func (vr *VoiceRegistry) listVoices() []messages.TTSVoiceInfo { +func (vr *VoiceRegistry) listVoices() []*messages.TTSVoiceInfo { vr.mu.RLock() defer vr.mu.RUnlock() - result := make([]messages.TTSVoiceInfo, 0, len(vr.voices)) + result := make([]*messages.TTSVoiceInfo, 0, len(vr.voices)) for _, v := range vr.voices { - result = append(result, messages.TTSVoiceInfo{ + result = append(result, &messages.TTSVoiceInfo{ Name: v.Name, Language: v.Language, ModelType: v.ModelType, @@ -223,7 +223,7 @@ func main() { // Helper: publish status publishStatus := func(sessionID, status, message string) { statusMsg := &messages.TTSStatus{ - SessionID: sessionID, + SessionId: sessionID, Status: status, Message: message, Timestamp: time.Now().Unix(), @@ -285,13 +285,13 @@ func main() { isLast := end >= len(audioBytes) msg := &messages.TTSAudioChunk{ - SessionID: sessionID, - ChunkIndex: chunkIndex, - TotalChunks: totalChunks, + SessionId: sessionID, + ChunkIndex: int32(chunkIndex), + TotalChunks: int32(totalChunks), Audio: chunk, IsLast: isLast, Timestamp: time.Now().Unix(), - SampleRate: sampleRate, + SampleRate: int32(sampleRate), } _ = nc.Publish(fmt.Sprintf("%s.%s", audioSubjectPrefix, sessionID), msg) } @@ -307,8 +307,8 @@ func main() { } sessionID := parts[4] - req, err := natsutil.Decode[messages.TTSRequest](natMsg.Data) - if err != nil { + var req messages.TTSRequest + if err := natsutil.Decode(natMsg.Data, &req); err != nil { slog.Error("decode error", "error", err) return } @@ -343,10 +343,10 @@ func main() { streamAudio(sessionID, audioBytes) } else { msg := &messages.TTSFullResponse{ - SessionID: sessionID, + SessionId: sessionID, Audio: audioBytes, Timestamp: time.Now().Unix(), - SampleRate: sampleRate, + SampleRate: int32(sampleRate), } _ = nc.Publish(fmt.Sprintf("%s.%s", audioSubjectPrefix, sessionID), msg) } @@ -368,7 +368,7 @@ func main() { LastRefresh: registry.lastRefresh.Unix(), Timestamp: time.Now().Unix(), } - packed, _ := msgpack.Marshal(resp) + packed, _ := proto.Marshal(resp) if msg.Reply != "" { _ = msg.Respond(packed) } @@ -380,11 +380,11 @@ func main() { if _, err := nc.Conn().Subscribe(voicesRefreshSubject, func(msg *nats.Msg) { count := registry.refresh() resp := &messages.TTSVoiceRefreshResponse{ - Count: count, + Count: int32(count), CustomVoices: registry.listVoices(), Timestamp: time.Now().Unix(), } - packed, _ := msgpack.Marshal(resp) + packed, _ := proto.Marshal(resp) if msg.Reply != "" { _ = msg.Respond(packed) } diff --git a/main_test.go b/main_test.go index a521774..7dc4961 100644 --- a/main_test.go +++ b/main_test.go @@ -11,7 +11,7 @@ import ( "git.daviestechlabs.io/daviestechlabs/handler-base/messages" "git.daviestechlabs.io/daviestechlabs/handler-base/natsutil" - "github.com/vmihailenco/msgpack/v5" + "google.golang.org/protobuf/proto" ) func TestVoiceRegistryRefresh(t *testing.T) { @@ -105,18 +105,18 @@ func TestSynthesizeHTTP(t *testing.T) { } func TestTTSRequestDecode(t *testing.T) { - req := messages.TTSRequest{ + req := &messages.TTSRequest{ Text: "hello world", Speaker: "custom-en", Language: "en", Stream: true, } - data, err := msgpack.Marshal(&req) + data, err := proto.Marshal(req) if err != nil { t.Fatal(err) } - decoded, err := natsutil.Decode[messages.TTSRequest](data) - if err != nil { + var decoded messages.TTSRequest + if err := natsutil.Decode(data, &decoded); err != nil { t.Fatal(err) } if decoded.Text != "hello world" { @@ -132,7 +132,7 @@ func TestTTSRequestDecode(t *testing.T) { func TestTTSAudioChunkRoundtrip(t *testing.T) { chunk := messages.TTSAudioChunk{ - SessionID: "sess-001", + SessionId: "sess-001", ChunkIndex: 0, TotalChunks: 2, Audio: make([]byte, 32768), @@ -140,16 +140,16 @@ func TestTTSAudioChunkRoundtrip(t *testing.T) { Timestamp: 1234567890, SampleRate: 24000, } - data, err := msgpack.Marshal(&chunk) + data, err := proto.Marshal(&chunk) if err != nil { t.Fatal(err) } var got messages.TTSAudioChunk - if err := msgpack.Unmarshal(data, &got); err != nil { + if err := proto.Unmarshal(data, &got); err != nil { t.Fatal(err) } - if got.SessionID != "sess-001" { - t.Errorf("SessionID = %q", got.SessionID) + if got.SessionId != "sess-001" { + t.Errorf("SessionID = %q", got.SessionId) } if len(got.Audio) != 32768 { t.Errorf("Audio len = %d", len(got.Audio))