Skip to content

Commit

Permalink
refactor(*) control forbidden key, etc
Browse files Browse the repository at this point in the history
- add options config item
- forbid user key
- allow signal key
- rename IsRootTag
- create observable test data
- comply with golint
  • Loading branch information
chenjunbiao committed Feb 26, 2021
1 parent e78ab17 commit bd6b1db
Show file tree
Hide file tree
Showing 15 changed files with 199 additions and 41 deletions.
30 changes: 23 additions & 7 deletions basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ type basicEncoder interface {

// basicEncoderImpl is implementation of the basicEncoder interface
type basicEncoderImpl struct {
observe byte
root byte
observe byte
root byte
forbidUserKey func(key byte) bool
allowSignalKey func(key byte) bool
}

// basicEncoderOption create basicEncoderImpl with option
Expand All @@ -30,26 +32,40 @@ func basicEncoderOptionRoot(root byte) basicEncoderOption {
}
}

// newBasicEncoder create a basicEncoder interface
func newBasicEncoder(observe byte, options ...func(*basicEncoderImpl)) basicEncoder {
if utils.ForbiddenCustomizedKey(observe) {
panic(fmt.Errorf("prohibit the use of this key: %#x", observe))
// basicEncoderOptionForbidUserKey set func to forbid some key
func basicEncoderOptionForbidUserKey(f func(key byte) bool) basicEncoderOption {
return func(b *basicEncoderImpl) {
b.forbidUserKey = f
}
}

// basicEncoderOptionAllowSignalKey set func to allow signal key
func basicEncoderOptionAllowSignalKey(f func(key byte) bool) basicEncoderOption {
return func(b *basicEncoderImpl) {
b.allowSignalKey = f
}
}

// newBasicEncoder create a basicEncoder interface
func newBasicEncoder(observe byte, options ...func(*basicEncoderImpl)) basicEncoder {
encoder := &basicEncoderImpl{observe: observe, root: utils.EmptyKey}

for _, option := range options {
option(encoder)
}

if encoder.forbidUserKey != nil && encoder.forbidUserKey(observe) {
panic(fmt.Errorf("prohibit the use of this key: %#x", observe))
}

return encoder
}

// Encode encode interface{} to bytes
func (e *basicEncoderImpl) Encode(input interface{}, signals ...*signal) (buf []byte, err error) {
encoders := make([]*PrimitivePacketEncoder, 0)
for _, signal := range signals {
encoders = append(encoders, signal.ToEncoder())
encoders = append(encoders, signal.ToEncoder(e.allowSignalKey))
}
return e.encodeBasic(input, encoders)
}
Expand Down
33 changes: 33 additions & 0 deletions basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,36 @@ func TestBasicSliceEncoderWithSignalsNoRoot(t *testing.T) {
expectedValue.Index(i).Interface(), resultValue.Index(i).Interface()))
}
}

func TestBasicForbidUserKey(t *testing.T) {
input := int32(456)

var key byte = 0x02
assert.Panics(t, func() {
newBasicEncoder(key,
basicEncoderOptionRoot(utils.RootToken),
basicEncoderOptionForbidUserKey(utils.ForbidUserKey)).
Encode(input)
}, "should forbid this Key: %#x", key)

key = 0x0f
assert.Panics(t, func() {
newBasicEncoder(key,
basicEncoderOptionRoot(utils.RootToken),
basicEncoderOptionForbidUserKey(utils.ForbidUserKey)).
Encode(input)
}, "should forbid this Key: %#x", key)
}

func TestBasicAllowSignalKey(t *testing.T) {
input := int32(456)

var signalKey byte = 0x02
assert.NotPanics(t, func() {
newBasicEncoder(0x10,
basicEncoderOptionRoot(utils.RootToken),
basicEncoderOptionAllowSignalKey(utils.AllowSignalKey)).
Encode(input, createSignal(signalKey).SetString("a"))
}, "should allow this Signal Key: %#x", signalKey)

}
12 changes: 10 additions & 2 deletions codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,17 @@ type y3Codec struct {
// Marshal encode interface to []byte
func (c y3Codec) Marshal(input interface{}) ([]byte, error) {
if c.isStruct(input) {
return newStructEncoder(c.observe, structEncoderOptionRoot(utils.RootToken)).Encode(input)
return newStructEncoder(c.observe,
structEncoderOptionRoot(utils.RootToken),
structEncoderOptionForbidUserKey(utils.ForbidUserKey),
structEncoderOptionAllowSignalKey(utils.AllowSignalKey)).
Encode(input)
}
return newBasicEncoder(c.observe, basicEncoderOptionRoot(utils.RootToken)).Encode(input)
return newBasicEncoder(c.observe,
basicEncoderOptionRoot(utils.RootToken),
basicEncoderOptionForbidUserKey(utils.ForbidUserKey),
basicEncoderOptionAllowSignalKey(utils.AllowSignalKey)).
Encode(input)
}

// isStruct determine whether an interface is a structure
Expand Down
2 changes: 2 additions & 0 deletions examples/example1/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import (
"github.com/yomorun/y3-codec-golang"
)

// SourceData define struct for this example
type SourceData struct {
Name string `y3:"0x10"`
Noise float32 `y3:"0x11"`
Therm Thermometer `y3:"0x12"`
}

// Thermometer define struct for this example
type Thermometer struct {
Temperature float32 `y3:"0x13"`
Humidity float32 `y3:"0x14"`
Expand Down
3 changes: 3 additions & 0 deletions examples/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ import (
"github.com/yomorun/y3-codec-golang"
)

// PrintNodePacket prettily print node packet
func PrintNodePacket(node *y3.NodePacket) {
PrintNodeFormat(node, " %#X=%v ", false, true)
}

// PrintArrayPacket prettily print array packet
func PrintArrayPacket(node *y3.NodePacket) {
//Parsing [0xc1, 0x06, 0x00, 0x01, 0x61, 0x00, 0x01, 0x62] EQUALS 0xc1:[0x02,0x04]")
PrintNodeFormat(node, " %#X=%v ", true, true)
}

// PrintNodeFormat prettily print array packet with format
func PrintNodeFormat(node *y3.NodePacket, format string, isArray bool, isRoot bool) {
if isRoot {
if isArray {
Expand Down
13 changes: 13 additions & 0 deletions internal/tester/data.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package tester

// BasicTestData is data of basic test
type BasicTestData struct {
Vstring string `y3:"0x10"`
Vint32 int32 `y3:"0x11"`
Expand All @@ -11,26 +12,31 @@ type BasicTestData struct {
Vbool bool `y3:"0x17"`
}

// EmbeddedTestData is data of embedded test
type EmbeddedTestData struct {
BasicTestData `y3:"0x1a"`
Vaction string `y3:"0x1b"`
}

// EmbeddedMoreTestData is data of embedded more test
type EmbeddedMoreTestData struct {
EmbeddedTestData `y3:"0x1c"`
Vanimal string `y3:"0x1d"`
}

// NamedTestData is data of named test
type NamedTestData struct {
Base BasicTestData `y3:"0x1e"`
Vaction string `y3:"0x1f"`
}

// NamedMoreTestData is data of named more test
type NamedMoreTestData struct {
MyNest NamedTestData `y3:"0x2a"`
Vanimal string `y3:"0x2b"`
}

// ArrayTestData is data of array test
type ArrayTestData struct {
Vfoo string `y3:"0x20"`
Vbar [2]string `y3:"0x21"`
Expand All @@ -42,6 +48,7 @@ type ArrayTestData struct {
Vfloat64Array [2]float64 `y3:"0x27"`
}

// SliceTestData is data of slice test
type SliceTestData struct {
Vfoo string `y3:"0x30"`
Vbar []string `y3:"0x31"`
Expand All @@ -53,32 +60,38 @@ type SliceTestData struct {
Vfloat64Slice []float64 `y3:"0x37"`
}

// SliceStructTestData is data of slice struct test
type SliceStructTestData struct {
Vstring string `y3:"0x2e"`
BaseList []BasicTestData `y3:"0x2f"`
NamedMoreList []NamedMoreTestData `y3:"0x3a"`
EmbeddedMoreList []EmbeddedMoreTestData `y3:"0x3b"`
}

// ArrayStructTestData is data of array struct test
type ArrayStructTestData struct {
Vstring string `y3:"0x2e"`
BaseList [2]BasicTestData `y3:"0x2f"`
NamedMoreList [2]NamedMoreTestData `y3:"0x3a"`
EmbeddedMoreList [2]EmbeddedMoreTestData `y3:"0x3b"`
}

// NestedTestData is data of nested test
type NestedTestData struct {
SubNested Sub1NestedTestData `y3:"0x3a"`
}

// Sub1NestedTestData is data of sub1 nested test
type Sub1NestedTestData struct {
SubNested Sub2NestedTestData `y3:"0x3b"`
}

// Sub2NestedTestData is data of sub2 nested test
type Sub2NestedTestData struct {
SubNested Sub3NestedTestData `y3:"0x3c"`
}

// Sub3NestedTestData is data of sub3 nested test
type Sub3NestedTestData struct {
BasicList []BasicTestData `y3:"0x3d"`
}
18 changes: 18 additions & 0 deletions internal/tester/data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"testing"

"github.com/yomorun/y3-codec-golang"

"github.com/stretchr/testify/assert"
)

Expand All @@ -21,3 +23,19 @@ func TestBasicTestData(t *testing.T) {
assert.NotEmpty(t, input, "Should not equal empty")
assert.Equal(t, "foo", input.Vstring, fmt.Sprintf("value does not match(%v): %v", "foo", input.Vstring))
}

func TestObservableTestData(t *testing.T) {
type ObservableTestData struct {
A float32 `y3:"0x10"`
B string `y3:"0x11"`
}

codec := y3.NewCodec(0x20)
obj := ObservableTestData{A: float32(456), B: "y3"}
buf, _ := codec.Marshal(obj)
//fmt.Printf("%#v\n", buf)
target := []byte{0x81, 0xa, 0xa0, 0x8, 0x10, 0x2, 0x43, 0xe4, 0x11, 0x2, 0x79, 0x33}
for i, v := range target {
assert.Equal(t, v, buf[i], fmt.Sprintf("should be: [%#x], but is [%#x]", v, buf[i]))
}
}
8 changes: 4 additions & 4 deletions internal/utils/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,17 @@ func KeyOf(hexStr string) byte {
return data[0]
}

// ForbiddenCustomizedKey is disabled for customized Key
func ForbiddenCustomizedKey(key byte) bool {
// ForbidUserKey forbid user set that key
func ForbidUserKey(key byte) bool {
switch key {
case 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f:
return true
}
return false
}

// AllowableSignalKey is allowed for creating Signal
func AllowableSignalKey(key byte) bool {
// AllowSignalKey allow set that signal key
func AllowSignalKey(key byte) bool {
switch key {
case 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f:
return true
Expand Down
8 changes: 4 additions & 4 deletions internal/utils/key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ func TestIsEmptyKey(t *testing.T) {
}

func TestForbiddenCustomizedKey(t *testing.T) {
assert.True(t, ForbiddenCustomizedKey(0x01), "0x01 is disabled")
assert.False(t, ForbiddenCustomizedKey(0x10), "0x10 is allowed")
assert.True(t, ForbidUserKey(0x01), "0x01 is disabled")
assert.False(t, ForbidUserKey(0x10), "0x10 is allowed")
}

func TestAllowableSignalKey(t *testing.T) {
assert.True(t, AllowableSignalKey(0x02), "0x01 is allowed")
assert.False(t, AllowableSignalKey(0x01), "0x10 is disabled")
assert.True(t, AllowSignalKey(0x02), "0x01 is allowed")
assert.False(t, AllowSignalKey(0x01), "0x10 is disabled")
}
2 changes: 1 addition & 1 deletion internal/utils/slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func ToUFloat64Slice(arg interface{}) (out []interface{}, ok bool) {
})
}

// ToUFloat64Slice converting interface to interface slice for bool
// ToBoolSlice converting interface to interface slice for bool
func ToBoolSlice(arg interface{}) (out []interface{}, ok bool) {
return ToSliceWith(arg, func(value reflect.Value) interface{} {
bl, _ := strconv.ParseBool(fmt.Sprintf("%v", value))
Expand Down
13 changes: 4 additions & 9 deletions observable.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"io"
"sync"

"github.com/yomorun/y3-codec-golang/pkg/encoding"
"github.com/yomorun/y3-codec-golang/pkg/common"
)

// Iterable iterate through and get the data of observe
Expand Down Expand Up @@ -89,6 +89,7 @@ func FromStream(reader io.Reader) Observable {
break
} else {
value := buf[:n]
//fmt.Printf("%v:\t $1 on y3 value=%#v\n", time.Now().Format("2006-01-02 15:04:05"), value)
next <- value
}
}
Expand Down Expand Up @@ -170,7 +171,7 @@ func (o *observableImpl) Subscribe(key byte) Observable {

if flow == 1 { // L
resultBuffer = append(resultBuffer, b)
l, e := decodeLength(resultBuffer[1 : length+1]) //l 是value占字节,s是l占字节
l, e := common.DecodeLength(resultBuffer[1 : length+1]) //l 是value占字节,s是l占字节

if e != nil {
length++
Expand Down Expand Up @@ -210,12 +211,6 @@ func (o *observableImpl) Subscribe(key byte) Observable {

}

func decodeLength(buf []byte) (length int32, err error) {
varCodec := encoding.VarCodec{}
err = varCodec.DecodePVarInt32(buf, &length)
return
}

func createObservable(f func(next chan interface{})) Observable {
next := make(chan interface{})
subscribers := make([]chan interface{}, 0)
Expand Down Expand Up @@ -269,7 +264,7 @@ func filterRoot(observe <-chan interface{}) <-chan interface{} {

if rootflow == 1 { // L
rootBuffer = append(rootBuffer, b)
l, e := decodeLength(rootBuffer[1 : rootlength+1])
l, e := common.DecodeLength(rootBuffer[1 : rootlength+1])

if e != nil {
rootlength++
Expand Down
4 changes: 2 additions & 2 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func DecodeLength(buf []byte) (length int32, err error) {
return
}

// RootToken judge if it is the root node
func IsRootToken(b byte) bool {
// IsRootTag judge if it is the root node
func IsRootTag(b byte) bool {
return b == (utils.MSB | utils.RootToken)
}
6 changes: 2 additions & 4 deletions signalling.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package y3

import (
"fmt"

"github.com/yomorun/y3-codec-golang/internal/utils"
)

// signal is builder for PrimitivePacketEncoder
Expand Down Expand Up @@ -35,8 +33,8 @@ func (s *signal) SetFloat64(v float64) *signal {
}

// ToEncoder return current PrimitivePacketEncoder, and checking legality
func (s *signal) ToEncoder() *PrimitivePacketEncoder {
if !utils.AllowableSignalKey(byte(s.encoder.seqID)) {
func (s *signal) ToEncoder(allow func(key byte) bool) *PrimitivePacketEncoder {
if allow != nil && !allow(byte(s.encoder.seqID)) {
panic(fmt.Errorf("it is not allowed to use this key to create a signal: %#x", byte(s.encoder.seqID)))
}

Expand Down
Loading

0 comments on commit bd6b1db

Please sign in to comment.