mirror of https://bitbucket.org/ausocean/av.git
Export Property members so getters are no longer required and made amf.GetProp a method on Object.
This commit is contained in:
parent
396c809424
commit
2105339657
|
@ -70,16 +70,16 @@ const (
|
|||
|
||||
// AMF represents an AMF message (object), which is simply a collection of properties.
|
||||
type Object struct {
|
||||
Props []Property // ToDo: consider not exporting this
|
||||
Props []Property
|
||||
}
|
||||
|
||||
// Property represents an AMF property.
|
||||
type Property struct {
|
||||
name string
|
||||
dtype uint8
|
||||
number float64
|
||||
str string
|
||||
obj Object
|
||||
Name string
|
||||
Type uint8
|
||||
Number float64
|
||||
String string
|
||||
Object Object
|
||||
}
|
||||
|
||||
// AMF errors.
|
||||
|
@ -91,6 +91,7 @@ var (
|
|||
ErrDecodingName = errors.New("amf: name decoding error")
|
||||
ErrDecodingString = errors.New("amf: string decoding error")
|
||||
ErrUnexpectedEnd = errors.New("amf: unexpected end")
|
||||
ErrPropertyNotFound = errors.New("amf: property not found")
|
||||
)
|
||||
|
||||
// DecodeInt16 decodes a 16-bit integer.
|
||||
|
@ -259,56 +260,31 @@ func EncodeNamedBoolean(buf []byte, key string, val bool) ([]byte, error) {
|
|||
return EncodeBoolean(buf[len(key):], val)
|
||||
}
|
||||
|
||||
// Property functions.
|
||||
|
||||
func PropSetName(prop *Property, name string) {
|
||||
prop.name = name
|
||||
}
|
||||
|
||||
func PropGetNumber(prop *Property) float64 {
|
||||
return prop.number
|
||||
}
|
||||
|
||||
func PropGetString(prop *Property) string {
|
||||
if prop.dtype == typeString {
|
||||
return prop.str
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func PropGetObject(prop *Property, obj *Object) {
|
||||
if prop.dtype == TypeObject {
|
||||
*obj = prop.obj
|
||||
} else {
|
||||
*obj = Object{}
|
||||
}
|
||||
}
|
||||
|
||||
// PropEncode encodes a property.
|
||||
func PropEncode(p *Property, buf []byte) ([]byte, error) {
|
||||
if p.dtype == typeInvalid {
|
||||
if p.Type == typeInvalid {
|
||||
return nil, ErrShortBuffer
|
||||
}
|
||||
|
||||
if p.dtype != TypeNull && len(p.name)+2+1 >= len(buf) {
|
||||
if p.Type != TypeNull && len(p.Name)+2+1 >= len(buf) {
|
||||
return nil, ErrShortBuffer
|
||||
}
|
||||
|
||||
if p.dtype != TypeNull && len(p.name) != 0 {
|
||||
binary.BigEndian.PutUint16(buf[:2], uint16(len(p.name)))
|
||||
if p.Type != TypeNull && len(p.Name) != 0 {
|
||||
binary.BigEndian.PutUint16(buf[:2], uint16(len(p.Name)))
|
||||
buf = buf[2:]
|
||||
copy(buf, p.name)
|
||||
buf = buf[len(p.name):]
|
||||
copy(buf, p.Name)
|
||||
buf = buf[len(p.Name):]
|
||||
}
|
||||
|
||||
var err error
|
||||
switch p.dtype {
|
||||
switch p.Type {
|
||||
case typeNumber:
|
||||
buf, err = EncodeNumber(buf, p.number)
|
||||
buf, err = EncodeNumber(buf, p.Number)
|
||||
case typeBoolean:
|
||||
buf, err = EncodeBoolean(buf, p.number != 0)
|
||||
buf, err = EncodeBoolean(buf, p.Number != 0)
|
||||
case typeString:
|
||||
buf, err = EncodeString(buf, p.str)
|
||||
buf, err = EncodeString(buf, p.String)
|
||||
case TypeNull:
|
||||
if len(buf) < 2 {
|
||||
return nil, ErrShortBuffer
|
||||
|
@ -316,11 +292,11 @@ func PropEncode(p *Property, buf []byte) ([]byte, error) {
|
|||
buf[0] = TypeNull
|
||||
buf = buf[1:]
|
||||
case TypeObject:
|
||||
buf, err = Encode(&p.obj, buf)
|
||||
buf, err = Encode(&p.Object, buf)
|
||||
case typeEcmaArray:
|
||||
buf, err = EncodeEcmaArray(&p.obj, buf)
|
||||
buf, err = EncodeEcmaArray(&p.Object, buf)
|
||||
case typeStrictArray:
|
||||
buf, err = EncodeArray(&p.obj, buf)
|
||||
buf, err = EncodeArray(&p.Object, buf)
|
||||
default:
|
||||
buf, err = nil, ErrInvalidType
|
||||
}
|
||||
|
@ -329,8 +305,6 @@ func PropEncode(p *Property, buf []byte) ([]byte, error) {
|
|||
|
||||
// PropDecode decodes a property, returning the number of bytes consumed from the supplied buffer.
|
||||
func PropDecode(prop *Property, buf []byte, decodeName bool) (int, error) {
|
||||
prop.name = ""
|
||||
|
||||
sz := len(buf)
|
||||
if len(buf) == 0 {
|
||||
return 0, ErrEndOfBuffer
|
||||
|
@ -345,23 +319,25 @@ func PropDecode(prop *Property, buf []byte, decodeName bool) (int, error) {
|
|||
return 0, ErrDecodingName
|
||||
}
|
||||
|
||||
prop.name = DecodeString(buf)
|
||||
prop.Name = DecodeString(buf)
|
||||
buf = buf[2+n:]
|
||||
} else {
|
||||
prop.Name = ""
|
||||
}
|
||||
|
||||
if len(buf) == 0 {
|
||||
return 0, ErrEndOfBuffer
|
||||
}
|
||||
|
||||
prop.dtype = uint8(buf[0])
|
||||
prop.Type = uint8(buf[0])
|
||||
buf = buf[1:]
|
||||
|
||||
switch prop.dtype {
|
||||
switch prop.Type {
|
||||
case typeNumber:
|
||||
if len(buf) < 8 {
|
||||
return 0, ErrShortBuffer
|
||||
}
|
||||
prop.number = DecodeNumber(buf[:8])
|
||||
prop.Number = DecodeNumber(buf[:8])
|
||||
buf = buf[8:]
|
||||
|
||||
case typeBoolean:
|
||||
|
@ -372,23 +348,22 @@ func PropDecode(prop *Property, buf []byte, decodeName bool) (int, error) {
|
|||
if len(buf) < int(n+2) {
|
||||
return 0, ErrShortBuffer
|
||||
}
|
||||
prop.str = DecodeString(buf)
|
||||
prop.String = DecodeString(buf)
|
||||
buf = buf[2+n:]
|
||||
|
||||
case TypeObject:
|
||||
n, err := Decode(&prop.obj, buf, true)
|
||||
n, err := Decode(&prop.Object, buf, true)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
buf = buf[n:]
|
||||
|
||||
|
||||
case TypeNull, typeUndefined, typeUnsupported:
|
||||
prop.dtype = TypeNull
|
||||
prop.Type = TypeNull
|
||||
|
||||
case typeEcmaArray:
|
||||
buf = buf[4:]
|
||||
n, err := Decode(&prop.obj, buf, true)
|
||||
n, err := Decode(&prop.Object, buf, true)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -497,19 +472,19 @@ func Decode(obj *Object, buf []byte, decodeName bool) (int, error) {
|
|||
return sz - len(buf), nil
|
||||
}
|
||||
|
||||
// GetProp returns an object's property, either by its index when idx is non-negative, or by its name when name otherwise.
|
||||
// If the matching property is not found nil is returned.
|
||||
func GetProp(obj *Object, name string, idx int) *Property {
|
||||
// GetProp returns an object's property, either by its index when idx is non-negative, or by its name otherwise.
|
||||
// If the requested property is not found an ErrPropertyNotFound error is returned.
|
||||
func (obj *Object)GetProp(name string, idx int) (*Property, error) {
|
||||
if idx >= 0 {
|
||||
if idx < len(obj.Props) {
|
||||
return &obj.Props[idx]
|
||||
return &obj.Props[idx], nil
|
||||
}
|
||||
} else {
|
||||
for i, p := range obj.Props {
|
||||
if p.name == name {
|
||||
return &obj.Props[i]
|
||||
if p.Name == name {
|
||||
return &obj.Props[i], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return nil, ErrPropertyNotFound
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ func TestNumbers(t *testing.T) {
|
|||
}
|
||||
dn := int32(DecodeInt24(buf))
|
||||
if n != dn {
|
||||
t.Errorf("DecodeInt24 did not produce original number, got %v", dn)
|
||||
t.Errorf("DecodeInt24 did not produce original Number, got %v", dn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,13 +97,13 @@ func TestNumbers(t *testing.T) {
|
|||
func TestProperties(t *testing.T) {
|
||||
var buf [1024]byte
|
||||
|
||||
// Encode/decode number properties.
|
||||
// Encode/decode Number properties.
|
||||
enc := buf[:]
|
||||
var err error
|
||||
for i, _ := range testNumbers {
|
||||
enc, err = PropEncode(&Property{dtype: typeNumber, number: float64(testNumbers[i])}, enc)
|
||||
enc, err = PropEncode(&Property{Type: typeNumber, Number: float64(testNumbers[i])}, enc)
|
||||
if err != nil {
|
||||
t.Errorf("PropEncode of number failed")
|
||||
t.Errorf("PropEncode of Number failed")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -113,10 +113,10 @@ func TestProperties(t *testing.T) {
|
|||
for i, _ := range testNumbers {
|
||||
n, err := PropDecode(&prop, dec, false)
|
||||
if err != nil {
|
||||
t.Errorf("PropDecode of number failed")
|
||||
t.Errorf("PropDecode of Number failed")
|
||||
}
|
||||
if int32(prop.number) != testNumbers[i] {
|
||||
t.Errorf("PropEncode/PropDecode returned wrong number; got %v, expected %v", int32(prop.number), testNumbers[i])
|
||||
if int32(prop.Number) != testNumbers[i] {
|
||||
t.Errorf("PropEncode/PropDecode returned wrong Number; got %v, expected %v", int32(prop.Number), testNumbers[i])
|
||||
}
|
||||
dec = dec[n:]
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ func TestProperties(t *testing.T) {
|
|||
// Encode/decode string properties.
|
||||
enc = buf[:]
|
||||
for i, _ := range testStrings {
|
||||
enc, err = PropEncode(&Property{dtype: typeString, str: testStrings[i]}, enc)
|
||||
enc, err = PropEncode(&Property{Type: typeString, String: testStrings[i]}, enc)
|
||||
if err != nil {
|
||||
t.Errorf("PropEncode of string failed")
|
||||
}
|
||||
|
@ -137,8 +137,8 @@ func TestProperties(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("PropDecode of string failed")
|
||||
}
|
||||
if prop.str != testStrings[i] {
|
||||
t.Errorf("PropEncode/PropDecode returned wrong string; got %s, expected %s", prop.str, testStrings[i])
|
||||
if prop.String != testStrings[i] {
|
||||
t.Errorf("PropEncode/PropDecode returned wrong string; got %s, expected %s", prop.String, testStrings[i])
|
||||
}
|
||||
dec = dec[n:]
|
||||
}
|
||||
|
@ -149,8 +149,8 @@ func TestProperties(t *testing.T) {
|
|||
func TestObject(t *testing.T) {
|
||||
var buf [1024]byte
|
||||
|
||||
// Construct a simple object that has one property, the number 42.
|
||||
prop1 := Property{dtype: typeNumber, number: 42}
|
||||
// Construct a simple object that has one property, the Number 42.
|
||||
prop1 := Property{Type: typeNumber, Number: 42}
|
||||
obj1 := Object{}
|
||||
obj1.Props = append(obj1.Props, prop1)
|
||||
|
||||
|
@ -171,7 +171,7 @@ func TestObject(t *testing.T) {
|
|||
}
|
||||
num := DecodeNumber(buf[2:10])
|
||||
if num != 42 {
|
||||
t.Errorf("Encoded wrong number")
|
||||
t.Errorf("Encoded wrong Number")
|
||||
}
|
||||
end := int32(DecodeInt24(buf[10:13]))
|
||||
if end != TypeObjectEnd {
|
||||
|
@ -189,8 +189,8 @@ func TestObject(t *testing.T) {
|
|||
// Construct a more complicated object.
|
||||
var obj2 Object
|
||||
for i, _ := range testStrings {
|
||||
obj2.Props = append(obj2.Props, Property{dtype: typeString, str: testStrings[i]})
|
||||
obj2.Props = append(obj2.Props, Property{dtype: typeNumber, number: float64(testNumbers[i])})
|
||||
obj2.Props = append(obj2.Props, Property{Type: typeString, String: testStrings[i]})
|
||||
obj2.Props = append(obj2.Props, Property{Type: typeNumber, Number: float64(testNumbers[i])})
|
||||
}
|
||||
|
||||
// Encode it.
|
||||
|
@ -207,4 +207,26 @@ func TestObject(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("Decode of object failed")
|
||||
}
|
||||
|
||||
// Find some properties that exist.
|
||||
prop, err := obj2.GetProp("", 2)
|
||||
if err != nil {
|
||||
t.Errorf("GetProp(2) failed")
|
||||
}
|
||||
if prop.String != "foo" {
|
||||
t.Errorf("GetProp(2) returned wrong Property")
|
||||
}
|
||||
prop, err = obj2.GetProp("", 3)
|
||||
if err != nil {
|
||||
t.Errorf("GetProp(1) failed")
|
||||
}
|
||||
if prop.Number != 1 {
|
||||
t.Errorf("GetProp(1) returned wrong Property")
|
||||
}
|
||||
|
||||
// Try to find one that doesn't exist.
|
||||
prop, err = obj2.GetProp("", 10)
|
||||
if err != ErrPropertyNotFound {
|
||||
t.Errorf("GetProp(10) failed")
|
||||
}
|
||||
}
|
||||
|
|
39
rtmp/rtmp.go
39
rtmp/rtmp.go
|
@ -686,10 +686,18 @@ func handleInvoke(s *Session, body []byte) error {
|
|||
return err
|
||||
}
|
||||
|
||||
meth := amf.PropGetString(amf.GetProp(&obj, "", 0))
|
||||
s.log(DebugLevel, pkg+"invoking method "+meth)
|
||||
txn := amf.PropGetNumber(amf.GetProp(&obj, "", 1))
|
||||
prop, err := obj.GetProp("", 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
meth := prop.String
|
||||
prop, err = obj.GetProp("", 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
txn := prop.Number
|
||||
|
||||
s.log(DebugLevel, pkg+"invoking method "+meth)
|
||||
switch meth {
|
||||
case av_result:
|
||||
var methodInvoked string
|
||||
|
@ -728,7 +736,11 @@ func handleInvoke(s *Session, body []byte) error {
|
|||
}
|
||||
|
||||
case avCreatestream:
|
||||
s.streamID = int32(amf.PropGetNumber(amf.GetProp(&obj, "", 3)))
|
||||
prop, err = obj.GetProp("", 3)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.streamID = int32(prop.Number)
|
||||
if s.link.protocol&featureWrite == 0 {
|
||||
return errNotWritable
|
||||
}
|
||||
|
@ -765,10 +777,21 @@ func handleInvoke(s *Session, body []byte) error {
|
|||
s.log(FatalLevel, pkg+"unsupported method avClose")
|
||||
|
||||
case avOnStatus:
|
||||
var obj2 amf.Object
|
||||
amf.PropGetObject(amf.GetProp(&obj, "", 3), &obj2)
|
||||
code := amf.PropGetString(amf.GetProp(&obj2, avCode, -1))
|
||||
level := amf.PropGetString(amf.GetProp(&obj2, avLevel, -1))
|
||||
prop, err = obj.GetProp("", 3)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj2 := prop.Object
|
||||
prop, err = obj2.GetProp(avCode, -1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
code := prop.String
|
||||
prop, err = obj2.GetProp(avLevel, -1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
level := prop.String
|
||||
s.log(DebugLevel, pkg+"onStatus", "code", code, "level", level)
|
||||
|
||||
switch code {
|
||||
|
|
Loading…
Reference in New Issue