ably-go icon indicating copy to clipboard operation
ably-go copied to clipboard

ably-go should not convert `[]byte` messages to strings

Open amnonbc opened this issue 2 years ago • 5 comments

The code below send a message of type []byte. But the subscriber receives the message of type string.

https://go.dev/play/p/VUqZbF7B6Wv

2022/12/22 14:03:06 sending message [1 2 3 4] of type []uint8
2022/12/22 14:03:06 Received message  of type: string

According to the Spec (RSL6a) All messages received will be decoded automatically based on the encoding field and the payloads will be converted into the format they were originally sent using i.e. binary, string, or JSON

In this case the message was sent as []byte so should have been received as as []byte.

package main

import (
	"context"
	"github.com/ably/ably-go/ably"
	"log"
	"os"
)

func sub(client *ably.Realtime, done chan struct{}) {
	channel := client.Channels.Get("quickstart")
	_, err := channel.Subscribe(context.Background(), "greeting", func(msg *ably.Message) {
		log.Printf("Received message %v of type: %T", msg.Data, msg.Data)
		close(done)
	})
	if err != nil {
		panic(err)
	}

}

func main() {

	key := os.Getenv("ABLY_KEY")
	client, err := ably.NewRealtime(ably.WithKey(key))
	if err != nil {
		panic(err)
	}
	done := make(chan struct{})
	go sub(client, done)

	channel := client.Channels.Get("quickstart")
	data := []byte{1, 2, 3, 4}
	log.Printf("sending message %v of type %T", data, data)
	err = channel.Publish(context.Background(), "greeting", data)
	if err != nil {
		panic(err)
	}
	<-done
}

┆Issue is synchronized with this Jira Task by Unito

amnonbc avatar Dec 22 '22 11:12 amnonbc

➤ Automation for Jira commented:

The link to the corresponding Jira issue is https://ably.atlassian.net/browse/SDK-3196

sync-by-unito[bot] avatar Dec 22 '22 11:12 sync-by-unito[bot]

➤ Amnon Cohen commented:

The problem is in the codec, as you can see in this failing test:

func TestSmallByteData(t *testing.T) {
	src := []byte("abc")
	encodedBytes, err := ablyutil.MarshalMsgpack(src)
	assert.NoError(t, err)

	var decoded interface{}
	err = ablyutil.UnmarshalMsgpack(encodedBytes, &decoded)
	assert.NoError(t, err)

	assert.IsType(t, src, decoded)
}

sync-by-unito[bot] avatar Jan 04 '23 10:01 sync-by-unito[bot]

func TestUnmarshallByte(t *testing.T) {
	buf := []byte{
		0xc4,     // bin8
		2,        // len
		'a', 'a', // bytes
	}
	var target interface{}

	err := UnmarshalMsgpack(buf, &target)
	require.NoError(t, err)
	assert.IsType(t, []byte{}, target,
		"bin8 should be decoded as []byte, but instead we got %T", target)
}

In github.com/ugorji/go/[email protected]/msgpack.go:494

		case bd == mpBin8, bd == mpBin16, bd == mpBin32:
			fauxUnionReadRawBytes(d, &d.d, n, d.h.RawToString)

which calls

func fauxUnionReadRawBytes(dr decDriver, d *Decoder, n *fauxUnion, rawToString bool) {
	if rawToString {
		n.v = valueTypeString
		n.s = string(dr.DecodeBytes(d.b[:], true))
	} else {
		n.v = valueTypeBytes
		n.l = dr.DecodeBytes(nil, false)
	}
}

amnonbc avatar Jan 06 '23 14:01 amnonbc

I added a bug report to https://github.com/ugorji/go/issues/387

amnonbc avatar Jan 11 '23 10:01 amnonbc

See https://github.com/ably/ably-go/pull/581 as a sample fix.

amnonbc avatar Mar 07 '23 11:03 amnonbc