2021-12-04 16:42:11 +00:00

74 lines
1.8 KiB
Go

// Package wspb provides helpers for reading and writing protobuf messages.
package wspb // import "nhooyr.io/websocket/wspb"
import (
"bytes"
"context"
"fmt"
"github.com/golang/protobuf/proto"
"nhooyr.io/websocket"
"nhooyr.io/websocket/internal/bpool"
"nhooyr.io/websocket/internal/errd"
)
// Read reads a protobuf message from c into v.
// It will reuse buffers in between calls to avoid allocations.
func Read(ctx context.Context, c *websocket.Conn, v proto.Message) error {
return read(ctx, c, v)
}
func read(ctx context.Context, c *websocket.Conn, v proto.Message) (err error) {
defer errd.Wrap(&err, "failed to read protobuf message")
typ, r, err := c.Reader(ctx)
if err != nil {
return err
}
if typ != websocket.MessageBinary {
c.Close(websocket.StatusUnsupportedData, "expected binary message")
return fmt.Errorf("expected binary message for protobuf but got: %v", typ)
}
b := bpool.Get()
defer bpool.Put(b)
_, err = b.ReadFrom(r)
if err != nil {
return err
}
err = proto.Unmarshal(b.Bytes(), v)
if err != nil {
c.Close(websocket.StatusInvalidFramePayloadData, "failed to unmarshal protobuf")
return fmt.Errorf("failed to unmarshal protobuf: %w", err)
}
return nil
}
// Write writes the protobuf message v to c.
// It will reuse buffers in between calls to avoid allocations.
func Write(ctx context.Context, c *websocket.Conn, v proto.Message) error {
return write(ctx, c, v)
}
func write(ctx context.Context, c *websocket.Conn, v proto.Message) (err error) {
defer errd.Wrap(&err, "failed to write protobuf message")
b := bpool.Get()
pb := proto.NewBuffer(b.Bytes())
defer func() {
bpool.Put(bytes.NewBuffer(pb.Bytes()))
}()
err = pb.Marshal(v)
if err != nil {
return fmt.Errorf("failed to marshal protobuf: %w", err)
}
return c.Write(ctx, websocket.MessageBinary, pb.Bytes())
}