checkpoint messages, half-complete RPC
This commit is contained in:
parent
09d1660ce0
commit
6fea9b5124
|
@ -1,12 +1,14 @@
|
|||
package gotelem
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/tinylib/msgp/msgp"
|
||||
)
|
||||
|
||||
|
||||
// the target architecture is a subscribe function that
|
||||
// takes a can FILTER. Then the server will emit notifications.
|
||||
// that contain new can packets as they come in.
|
||||
|
@ -19,8 +21,7 @@ import (
|
|||
// since reflected code can be more complex under the hood.
|
||||
|
||||
// ServiceFunc is a RPC service handler.
|
||||
type ServiceFunc func(params msgp.Raw) (res msgp.MarshalSizer, err error)
|
||||
|
||||
type ServiceFunc func(params msgp.Raw) (res msgp.Raw, err error)
|
||||
|
||||
// RPCConn is a single RPC communication pair.
|
||||
type RPCConn struct {
|
||||
|
@ -31,15 +32,29 @@ type RPCConn struct {
|
|||
// indicates what messages we've used.
|
||||
// TODO: use a channel to return a response?
|
||||
// TODO: lock with mutex
|
||||
ct map[uint32]struct{}
|
||||
ct rpcConnTrack
|
||||
}
|
||||
|
||||
// Call intiates an RPC call to a remote method and returns the
|
||||
// response, or the error, if any.
|
||||
// TODO: determine signature
|
||||
// TODO: this should block?
|
||||
func (rpc *RPCConn) Call(method string, params msgp.Marshaler) {
|
||||
func (rpc *RPCConn) Call(method string, params msgp.Marshaler) (msgp.Raw, error) {
|
||||
|
||||
// TODO: error handling.
|
||||
rawParam, _ := params.MarshalMsg([]byte{})
|
||||
|
||||
id, cb := rpc.ct.Claim()
|
||||
|
||||
req := NewRequest(id, method, rawParam)
|
||||
|
||||
w := msgp.NewWriter(rpc.conn)
|
||||
req.EncodeMsg(w)
|
||||
|
||||
// block and wait for response.
|
||||
resp := <-cb
|
||||
|
||||
return resp.Result, &resp.Error
|
||||
}
|
||||
|
||||
// Notify initiates a notification to a remote method. It does not
|
||||
|
@ -48,6 +63,12 @@ func (rpc *RPCConn) Call(method string, params msgp.Marshaler) {
|
|||
// problem.
|
||||
func (rpc *RPCConn) Notify(method string, params msgp.Marshaler) {
|
||||
// TODO: return an error if there's a local problem?
|
||||
rawParam, _ := params.MarshalMsg([]byte{})
|
||||
|
||||
req := NewNotification(method, rawParam)
|
||||
|
||||
w := msgp.NewWriter(rpc.conn)
|
||||
req.EncodeMsg(w)
|
||||
|
||||
}
|
||||
|
||||
|
@ -73,9 +94,10 @@ func (rpc *RPCConn) Serve() {
|
|||
|
||||
var rawmsg msgp.Raw = make(msgp.Raw, 0, 4)
|
||||
|
||||
for {
|
||||
rawmsg.DecodeMsg(msgReader)
|
||||
|
||||
rpcIntf, err := parseRPC(rawmsg)
|
||||
rpcIntf, _ := parseRPC(rawmsg)
|
||||
|
||||
switch rpcObject := rpcIntf.(type) {
|
||||
case Request:
|
||||
|
@ -85,7 +107,12 @@ func (rpc *RPCConn) Serve() {
|
|||
case Notification:
|
||||
go rpc.dispatchNotif(rpcObject)
|
||||
case Response:
|
||||
// TODO: return response to caller.
|
||||
cbCh, err := rpc.ct.Clear(rpcObject.MsgId)
|
||||
if err != nil {
|
||||
// TODO: scream
|
||||
}
|
||||
cbCh <- rpcObject
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,3 +145,94 @@ func (rpc *RPCConn) dispatchNotif(req Notification) {
|
|||
}
|
||||
// no need for response.
|
||||
}
|
||||
|
||||
// RPCConntrack is a request-response tracker that is used to connect
|
||||
// the response to the appropriate caller.
|
||||
type rpcConnTrack struct {
|
||||
ct map[uint32]chan Response // TODO: change the values of the map for callbacks.
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// Get attempts to get a random mark from the mutex.
|
||||
func (c *rpcConnTrack) Claim() (uint32, chan Response) {
|
||||
// TODO: make this threadsafe.
|
||||
var val uint32
|
||||
for {
|
||||
|
||||
newVal := rand.Uint32()
|
||||
// collision is *rare* - so we just try again.
|
||||
// I hope to god you don't saturate this tracker.
|
||||
c.mu.RLock()
|
||||
if _, exist := c.ct[newVal]; !exist {
|
||||
val = newVal
|
||||
c.mu.RUnlock()
|
||||
break
|
||||
}
|
||||
c.mu.RUnlock()
|
||||
}
|
||||
|
||||
// claim it
|
||||
// the channel should be buffered. We only expect one value to go through.
|
||||
// so the size is fixed.
|
||||
ch := make(chan Response, 1)
|
||||
c.mu.Lock()
|
||||
c.ct[val] = ch
|
||||
c.mu.Unlock()
|
||||
|
||||
return val, ch
|
||||
}
|
||||
|
||||
// Clear deletes the connection from the tracker and returns the channel
|
||||
// associated with it. The caller can use the channel afterwards
|
||||
// to send the response.
|
||||
func (c *rpcConnTrack) Clear(val uint32) (chan Response, error) {
|
||||
// TODO: get a lock
|
||||
c.mu.RLock()
|
||||
ch, ok := c.ct[val]
|
||||
c.mu.RUnlock()
|
||||
if !ok {
|
||||
return nil, errors.New("invalid msg id")
|
||||
}
|
||||
c.mu.Lock()
|
||||
delete(c.ct, val)
|
||||
c.mu.Unlock()
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
// Next, we define some helper generic functions that can be used to make
|
||||
// implementing a msg wrapper easier.
|
||||
|
||||
type msgpackObject interface {
|
||||
msgp.Decodable
|
||||
msgp.Encodable
|
||||
msgp.MarshalSizer
|
||||
msgp.Unmarshaler
|
||||
}
|
||||
|
||||
// MakeService is a generic wrapper function. It takes a function with the signature
|
||||
// of func(T msgpObject)(R msgpObject, error) where T and R can be *concrete* types.
|
||||
// and returns a new function that handles conversion to/from msgp.Raw.
|
||||
// the function returned can be used by the RPCConn as a handler function.
|
||||
func MakeService[T, R msgpackObject](fn func(T) (R, error)) func(msgp.Raw) (msgp.Raw, error) {
|
||||
return func(p msgp.Raw) (msgp.Raw, error) {
|
||||
// decode the raw data into a new underlying type.
|
||||
var params T
|
||||
// TODO: handler errors
|
||||
_, err := params.UnmarshalMsg(p)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// now, call the function fn with the given params, and record the value.
|
||||
|
||||
resp, err := fn(params)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp.MarshalMsg([]byte{})
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ const (
|
|||
NotificationType RPCType = 2
|
||||
)
|
||||
|
||||
|
||||
// the messagepack RPC spec requires that the RPC wire formts are ordered arrays,
|
||||
// aka tuples. we can use msgp options to make them tuple automatically,
|
||||
// based on the order they are declared. This makes the order of these
|
||||
|
@ -74,6 +73,14 @@ type Notification struct {
|
|||
Params msgp.Raw `msg:"params,allownil"`
|
||||
}
|
||||
|
||||
func NewNotification(method string, params msgp.Raw) *Notification {
|
||||
return &Notification{
|
||||
msgtype: 2,
|
||||
Method: method,
|
||||
Params: params,
|
||||
}
|
||||
}
|
||||
|
||||
// todo: should these be functions instead, since they're arrays? and we need to determine the type beforehand.
|
||||
|
||||
func getMsgType(b []byte) RPCType {
|
||||
|
@ -95,7 +102,6 @@ func getMsgType(b []byte) RPCType {
|
|||
return RPCType(vtype)
|
||||
}
|
||||
|
||||
|
||||
// parseRPC takes a raw message and decodes it based on the first value
|
||||
// of the array (the type). It returns the decoded object. Callers
|
||||
// can use a type-switch to determine the type of the data.
|
||||
|
@ -126,14 +132,12 @@ func parseRPC(raw msgp.Raw) (interface{}, error) {
|
|||
// RPCError is a common RPC error format. It is basically a clone of the
|
||||
// JSON-RPC error format. We use it so we know what to expect there.
|
||||
|
||||
|
||||
//msgp:tuple RPCError
|
||||
type RPCError struct {
|
||||
Code int
|
||||
Desc string
|
||||
}
|
||||
|
||||
|
||||
// Converts a go error into a RPC error.
|
||||
func MakeRPCError(err error) *RPCError {
|
||||
if err == nil {
|
||||
|
@ -144,3 +148,7 @@ func MakeRPCError(err error) *RPCError {
|
|||
Desc: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RPCError) Error() string {
|
||||
return r.Desc
|
||||
}
|
||||
|
|
494
internal/gotelem/rpc_msg_gen.go
Normal file
494
internal/gotelem/rpc_msg_gen.go
Normal file
|
@ -0,0 +1,494 @@
|
|||
package gotelem
|
||||
|
||||
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"github.com/tinylib/msgp/msgp"
|
||||
)
|
||||
|
||||
// DecodeMsg implements msgp.Decodable
|
||||
func (z *Notification) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
var zb0001 uint32
|
||||
zb0001, err = dc.ReadArrayHeader()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
if zb0001 != 2 {
|
||||
err = msgp.ArrayError{Wanted: 2, Got: zb0001}
|
||||
return
|
||||
}
|
||||
z.Method, err = dc.ReadString()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Method")
|
||||
return
|
||||
}
|
||||
err = z.Params.DecodeMsg(dc)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Params")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// EncodeMsg implements msgp.Encodable
|
||||
func (z *Notification) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
// array header, size 2
|
||||
err = en.Append(0x92)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = en.WriteString(z.Method)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Method")
|
||||
return
|
||||
}
|
||||
err = z.Params.EncodeMsg(en)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Params")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalMsg implements msgp.Marshaler
|
||||
func (z *Notification) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
o = msgp.Require(b, z.Msgsize())
|
||||
// array header, size 2
|
||||
o = append(o, 0x92)
|
||||
o = msgp.AppendString(o, z.Method)
|
||||
o, err = z.Params.MarshalMsg(o)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Params")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UnmarshalMsg implements msgp.Unmarshaler
|
||||
func (z *Notification) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
var zb0001 uint32
|
||||
zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
if zb0001 != 2 {
|
||||
err = msgp.ArrayError{Wanted: 2, Got: zb0001}
|
||||
return
|
||||
}
|
||||
z.Method, bts, err = msgp.ReadStringBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Method")
|
||||
return
|
||||
}
|
||||
bts, err = z.Params.UnmarshalMsg(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Params")
|
||||
return
|
||||
}
|
||||
o = bts
|
||||
return
|
||||
}
|
||||
|
||||
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||
func (z *Notification) Msgsize() (s int) {
|
||||
s = 1 + msgp.StringPrefixSize + len(z.Method) + z.Params.Msgsize()
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeMsg implements msgp.Decodable
|
||||
func (z *RPCError) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
var zb0001 uint32
|
||||
zb0001, err = dc.ReadArrayHeader()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
if zb0001 != 2 {
|
||||
err = msgp.ArrayError{Wanted: 2, Got: zb0001}
|
||||
return
|
||||
}
|
||||
z.Code, err = dc.ReadInt()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Code")
|
||||
return
|
||||
}
|
||||
z.Desc, err = dc.ReadString()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Desc")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// EncodeMsg implements msgp.Encodable
|
||||
func (z RPCError) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
// array header, size 2
|
||||
err = en.Append(0x92)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = en.WriteInt(z.Code)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Code")
|
||||
return
|
||||
}
|
||||
err = en.WriteString(z.Desc)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Desc")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalMsg implements msgp.Marshaler
|
||||
func (z RPCError) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
o = msgp.Require(b, z.Msgsize())
|
||||
// array header, size 2
|
||||
o = append(o, 0x92)
|
||||
o = msgp.AppendInt(o, z.Code)
|
||||
o = msgp.AppendString(o, z.Desc)
|
||||
return
|
||||
}
|
||||
|
||||
// UnmarshalMsg implements msgp.Unmarshaler
|
||||
func (z *RPCError) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
var zb0001 uint32
|
||||
zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
if zb0001 != 2 {
|
||||
err = msgp.ArrayError{Wanted: 2, Got: zb0001}
|
||||
return
|
||||
}
|
||||
z.Code, bts, err = msgp.ReadIntBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Code")
|
||||
return
|
||||
}
|
||||
z.Desc, bts, err = msgp.ReadStringBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Desc")
|
||||
return
|
||||
}
|
||||
o = bts
|
||||
return
|
||||
}
|
||||
|
||||
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||
func (z RPCError) Msgsize() (s int) {
|
||||
s = 1 + msgp.IntSize + msgp.StringPrefixSize + len(z.Desc)
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeMsg implements msgp.Decodable
|
||||
func (z *RPCType) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
{
|
||||
var zb0001 int
|
||||
zb0001, err = dc.ReadInt()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
(*z) = RPCType(zb0001)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// EncodeMsg implements msgp.Encodable
|
||||
func (z RPCType) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
err = en.WriteInt(int(z))
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalMsg implements msgp.Marshaler
|
||||
func (z RPCType) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
o = msgp.Require(b, z.Msgsize())
|
||||
o = msgp.AppendInt(o, int(z))
|
||||
return
|
||||
}
|
||||
|
||||
// UnmarshalMsg implements msgp.Unmarshaler
|
||||
func (z *RPCType) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
{
|
||||
var zb0001 int
|
||||
zb0001, bts, err = msgp.ReadIntBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
(*z) = RPCType(zb0001)
|
||||
}
|
||||
o = bts
|
||||
return
|
||||
}
|
||||
|
||||
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||
func (z RPCType) Msgsize() (s int) {
|
||||
s = msgp.IntSize
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeMsg implements msgp.Decodable
|
||||
func (z *Request) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
var zb0001 uint32
|
||||
zb0001, err = dc.ReadArrayHeader()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
if zb0001 != 3 {
|
||||
err = msgp.ArrayError{Wanted: 3, Got: zb0001}
|
||||
return
|
||||
}
|
||||
z.MsgId, err = dc.ReadUint32()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "MsgId")
|
||||
return
|
||||
}
|
||||
z.Method, err = dc.ReadString()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Method")
|
||||
return
|
||||
}
|
||||
err = z.Params.DecodeMsg(dc)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Params")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// EncodeMsg implements msgp.Encodable
|
||||
func (z *Request) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
// array header, size 3
|
||||
err = en.Append(0x93)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = en.WriteUint32(z.MsgId)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "MsgId")
|
||||
return
|
||||
}
|
||||
err = en.WriteString(z.Method)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Method")
|
||||
return
|
||||
}
|
||||
err = z.Params.EncodeMsg(en)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Params")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalMsg implements msgp.Marshaler
|
||||
func (z *Request) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
o = msgp.Require(b, z.Msgsize())
|
||||
// array header, size 3
|
||||
o = append(o, 0x93)
|
||||
o = msgp.AppendUint32(o, z.MsgId)
|
||||
o = msgp.AppendString(o, z.Method)
|
||||
o, err = z.Params.MarshalMsg(o)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Params")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UnmarshalMsg implements msgp.Unmarshaler
|
||||
func (z *Request) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
var zb0001 uint32
|
||||
zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
if zb0001 != 3 {
|
||||
err = msgp.ArrayError{Wanted: 3, Got: zb0001}
|
||||
return
|
||||
}
|
||||
z.MsgId, bts, err = msgp.ReadUint32Bytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "MsgId")
|
||||
return
|
||||
}
|
||||
z.Method, bts, err = msgp.ReadStringBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Method")
|
||||
return
|
||||
}
|
||||
bts, err = z.Params.UnmarshalMsg(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Params")
|
||||
return
|
||||
}
|
||||
o = bts
|
||||
return
|
||||
}
|
||||
|
||||
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||
func (z *Request) Msgsize() (s int) {
|
||||
s = 1 + msgp.Uint32Size + msgp.StringPrefixSize + len(z.Method) + z.Params.Msgsize()
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeMsg implements msgp.Decodable
|
||||
func (z *Response) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
var zb0001 uint32
|
||||
zb0001, err = dc.ReadArrayHeader()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
if zb0001 != 3 {
|
||||
err = msgp.ArrayError{Wanted: 3, Got: zb0001}
|
||||
return
|
||||
}
|
||||
z.MsgId, err = dc.ReadUint32()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "MsgId")
|
||||
return
|
||||
}
|
||||
var zb0002 uint32
|
||||
zb0002, err = dc.ReadArrayHeader()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Error")
|
||||
return
|
||||
}
|
||||
if zb0002 != 2 {
|
||||
err = msgp.ArrayError{Wanted: 2, Got: zb0002}
|
||||
return
|
||||
}
|
||||
z.Error.Code, err = dc.ReadInt()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Error", "Code")
|
||||
return
|
||||
}
|
||||
z.Error.Desc, err = dc.ReadString()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Error", "Desc")
|
||||
return
|
||||
}
|
||||
err = z.Result.DecodeMsg(dc)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Result")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// EncodeMsg implements msgp.Encodable
|
||||
func (z *Response) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
// array header, size 3
|
||||
err = en.Append(0x93)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = en.WriteUint32(z.MsgId)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "MsgId")
|
||||
return
|
||||
}
|
||||
// array header, size 2
|
||||
err = en.Append(0x92)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = en.WriteInt(z.Error.Code)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Error", "Code")
|
||||
return
|
||||
}
|
||||
err = en.WriteString(z.Error.Desc)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Error", "Desc")
|
||||
return
|
||||
}
|
||||
err = z.Result.EncodeMsg(en)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Result")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalMsg implements msgp.Marshaler
|
||||
func (z *Response) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
o = msgp.Require(b, z.Msgsize())
|
||||
// array header, size 3
|
||||
o = append(o, 0x93)
|
||||
o = msgp.AppendUint32(o, z.MsgId)
|
||||
// array header, size 2
|
||||
o = append(o, 0x92)
|
||||
o = msgp.AppendInt(o, z.Error.Code)
|
||||
o = msgp.AppendString(o, z.Error.Desc)
|
||||
o, err = z.Result.MarshalMsg(o)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Result")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UnmarshalMsg implements msgp.Unmarshaler
|
||||
func (z *Response) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
var zb0001 uint32
|
||||
zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
if zb0001 != 3 {
|
||||
err = msgp.ArrayError{Wanted: 3, Got: zb0001}
|
||||
return
|
||||
}
|
||||
z.MsgId, bts, err = msgp.ReadUint32Bytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "MsgId")
|
||||
return
|
||||
}
|
||||
var zb0002 uint32
|
||||
zb0002, bts, err = msgp.ReadArrayHeaderBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Error")
|
||||
return
|
||||
}
|
||||
if zb0002 != 2 {
|
||||
err = msgp.ArrayError{Wanted: 2, Got: zb0002}
|
||||
return
|
||||
}
|
||||
z.Error.Code, bts, err = msgp.ReadIntBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Error", "Code")
|
||||
return
|
||||
}
|
||||
z.Error.Desc, bts, err = msgp.ReadStringBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Error", "Desc")
|
||||
return
|
||||
}
|
||||
bts, err = z.Result.UnmarshalMsg(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Result")
|
||||
return
|
||||
}
|
||||
o = bts
|
||||
return
|
||||
}
|
||||
|
||||
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||
func (z *Response) Msgsize() (s int) {
|
||||
s = 1 + msgp.Uint32Size + 1 + msgp.IntSize + msgp.StringPrefixSize + len(z.Error.Desc) + z.Result.Msgsize()
|
||||
return
|
||||
}
|
462
internal/gotelem/rpc_msg_gen_test.go
Normal file
462
internal/gotelem/rpc_msg_gen_test.go
Normal file
|
@ -0,0 +1,462 @@
|
|||
package gotelem
|
||||
|
||||
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/tinylib/msgp/msgp"
|
||||
)
|
||||
|
||||
func TestMarshalUnmarshalNotification(t *testing.T) {
|
||||
v := Notification{}
|
||||
bts, err := v.MarshalMsg(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
left, err := v.UnmarshalMsg(bts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(left) > 0 {
|
||||
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
|
||||
}
|
||||
|
||||
left, err = msgp.Skip(bts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(left) > 0 {
|
||||
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMarshalMsgNotification(b *testing.B) {
|
||||
v := Notification{}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.MarshalMsg(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAppendMsgNotification(b *testing.B) {
|
||||
v := Notification{}
|
||||
bts := make([]byte, 0, v.Msgsize())
|
||||
bts, _ = v.MarshalMsg(bts[0:0])
|
||||
b.SetBytes(int64(len(bts)))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bts, _ = v.MarshalMsg(bts[0:0])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnmarshalNotification(b *testing.B) {
|
||||
v := Notification{}
|
||||
bts, _ := v.MarshalMsg(nil)
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(bts)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := v.UnmarshalMsg(bts)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeNotification(t *testing.T) {
|
||||
v := Notification{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
|
||||
m := v.Msgsize()
|
||||
if buf.Len() > m {
|
||||
t.Log("WARNING: TestEncodeDecodeNotification Msgsize() is inaccurate")
|
||||
}
|
||||
|
||||
vn := Notification{}
|
||||
err := msgp.Decode(&buf, &vn)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
msgp.Encode(&buf, &v)
|
||||
err = msgp.NewReader(&buf).Skip()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeNotification(b *testing.B) {
|
||||
v := Notification{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
||||
en := msgp.NewWriter(msgp.Nowhere)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.EncodeMsg(en)
|
||||
}
|
||||
en.Flush()
|
||||
}
|
||||
|
||||
func BenchmarkDecodeNotification(b *testing.B) {
|
||||
v := Notification{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
||||
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||
dc := msgp.NewReader(rd)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := v.DecodeMsg(dc)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalRPCError(t *testing.T) {
|
||||
v := RPCError{}
|
||||
bts, err := v.MarshalMsg(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
left, err := v.UnmarshalMsg(bts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(left) > 0 {
|
||||
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
|
||||
}
|
||||
|
||||
left, err = msgp.Skip(bts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(left) > 0 {
|
||||
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMarshalMsgRPCError(b *testing.B) {
|
||||
v := RPCError{}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.MarshalMsg(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAppendMsgRPCError(b *testing.B) {
|
||||
v := RPCError{}
|
||||
bts := make([]byte, 0, v.Msgsize())
|
||||
bts, _ = v.MarshalMsg(bts[0:0])
|
||||
b.SetBytes(int64(len(bts)))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bts, _ = v.MarshalMsg(bts[0:0])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnmarshalRPCError(b *testing.B) {
|
||||
v := RPCError{}
|
||||
bts, _ := v.MarshalMsg(nil)
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(bts)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := v.UnmarshalMsg(bts)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeRPCError(t *testing.T) {
|
||||
v := RPCError{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
|
||||
m := v.Msgsize()
|
||||
if buf.Len() > m {
|
||||
t.Log("WARNING: TestEncodeDecodeRPCError Msgsize() is inaccurate")
|
||||
}
|
||||
|
||||
vn := RPCError{}
|
||||
err := msgp.Decode(&buf, &vn)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
msgp.Encode(&buf, &v)
|
||||
err = msgp.NewReader(&buf).Skip()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeRPCError(b *testing.B) {
|
||||
v := RPCError{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
||||
en := msgp.NewWriter(msgp.Nowhere)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.EncodeMsg(en)
|
||||
}
|
||||
en.Flush()
|
||||
}
|
||||
|
||||
func BenchmarkDecodeRPCError(b *testing.B) {
|
||||
v := RPCError{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
||||
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||
dc := msgp.NewReader(rd)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := v.DecodeMsg(dc)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalRequest(t *testing.T) {
|
||||
v := Request{}
|
||||
bts, err := v.MarshalMsg(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
left, err := v.UnmarshalMsg(bts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(left) > 0 {
|
||||
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
|
||||
}
|
||||
|
||||
left, err = msgp.Skip(bts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(left) > 0 {
|
||||
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMarshalMsgRequest(b *testing.B) {
|
||||
v := Request{}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.MarshalMsg(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAppendMsgRequest(b *testing.B) {
|
||||
v := Request{}
|
||||
bts := make([]byte, 0, v.Msgsize())
|
||||
bts, _ = v.MarshalMsg(bts[0:0])
|
||||
b.SetBytes(int64(len(bts)))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bts, _ = v.MarshalMsg(bts[0:0])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnmarshalRequest(b *testing.B) {
|
||||
v := Request{}
|
||||
bts, _ := v.MarshalMsg(nil)
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(bts)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := v.UnmarshalMsg(bts)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeRequest(t *testing.T) {
|
||||
v := Request{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
|
||||
m := v.Msgsize()
|
||||
if buf.Len() > m {
|
||||
t.Log("WARNING: TestEncodeDecodeRequest Msgsize() is inaccurate")
|
||||
}
|
||||
|
||||
vn := Request{}
|
||||
err := msgp.Decode(&buf, &vn)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
msgp.Encode(&buf, &v)
|
||||
err = msgp.NewReader(&buf).Skip()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeRequest(b *testing.B) {
|
||||
v := Request{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
||||
en := msgp.NewWriter(msgp.Nowhere)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.EncodeMsg(en)
|
||||
}
|
||||
en.Flush()
|
||||
}
|
||||
|
||||
func BenchmarkDecodeRequest(b *testing.B) {
|
||||
v := Request{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
||||
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||
dc := msgp.NewReader(rd)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := v.DecodeMsg(dc)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalResponse(t *testing.T) {
|
||||
v := Response{}
|
||||
bts, err := v.MarshalMsg(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
left, err := v.UnmarshalMsg(bts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(left) > 0 {
|
||||
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
|
||||
}
|
||||
|
||||
left, err = msgp.Skip(bts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(left) > 0 {
|
||||
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMarshalMsgResponse(b *testing.B) {
|
||||
v := Response{}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.MarshalMsg(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAppendMsgResponse(b *testing.B) {
|
||||
v := Response{}
|
||||
bts := make([]byte, 0, v.Msgsize())
|
||||
bts, _ = v.MarshalMsg(bts[0:0])
|
||||
b.SetBytes(int64(len(bts)))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bts, _ = v.MarshalMsg(bts[0:0])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnmarshalResponse(b *testing.B) {
|
||||
v := Response{}
|
||||
bts, _ := v.MarshalMsg(nil)
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(bts)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := v.UnmarshalMsg(bts)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeResponse(t *testing.T) {
|
||||
v := Response{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
|
||||
m := v.Msgsize()
|
||||
if buf.Len() > m {
|
||||
t.Log("WARNING: TestEncodeDecodeResponse Msgsize() is inaccurate")
|
||||
}
|
||||
|
||||
vn := Response{}
|
||||
err := msgp.Decode(&buf, &vn)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
msgp.Encode(&buf, &v)
|
||||
err = msgp.NewReader(&buf).Skip()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeResponse(b *testing.B) {
|
||||
v := Response{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
||||
en := msgp.NewWriter(msgp.Nowhere)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.EncodeMsg(en)
|
||||
}
|
||||
en.Flush()
|
||||
}
|
||||
|
||||
func BenchmarkDecodeResponse(b *testing.B) {
|
||||
v := Response{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
||||
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||
dc := msgp.NewReader(rd)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := v.DecodeMsg(dc)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
54
internal/gotelem/rpc_msg_test.go
Normal file
54
internal/gotelem/rpc_msg_test.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package gotelem
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/tinylib/msgp/msgp"
|
||||
)
|
||||
|
||||
func Test_parseRPC(t *testing.T) {
|
||||
type args struct {
|
||||
raw msgp.Raw
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want interface{}
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseRPC(tt.args.raw)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseRPC() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("parseRPC() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getMsgType(t *testing.T) {
|
||||
type args struct {
|
||||
b []byte
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want RPCType
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := getMsgType(tt.args.b); got != tt.want {
|
||||
t.Errorf("getMsgType() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -138,6 +138,7 @@ func encodeRemoteATCommand(at ATCmd, idx uint8, queued bool, destination uint64)
|
|||
|
||||
// let's actually define some AT commands now.
|
||||
|
||||
// TODO: should we just use a function.
|
||||
// the AT command for the ID (Network ID).
|
||||
// the network identifier is used to communicate with other devices. It must match.
|
||||
type ATCmdID struct {
|
||||
|
|
Loading…
Reference in a new issue