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
115
rtmp/amf/amf.go
115
rtmp/amf/amf.go
|
@ -70,27 +70,28 @@ const (
|
||||||
|
|
||||||
// AMF represents an AMF message (object), which is simply a collection of properties.
|
// AMF represents an AMF message (object), which is simply a collection of properties.
|
||||||
type Object struct {
|
type Object struct {
|
||||||
Props []Property // ToDo: consider not exporting this
|
Props []Property
|
||||||
}
|
}
|
||||||
|
|
||||||
// Property represents an AMF property.
|
// Property represents an AMF property.
|
||||||
type Property struct {
|
type Property struct {
|
||||||
name string
|
Name string
|
||||||
dtype uint8
|
Type uint8
|
||||||
number float64
|
Number float64
|
||||||
str string
|
String string
|
||||||
obj Object
|
Object Object
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMF errors.
|
// AMF errors.
|
||||||
var (
|
var (
|
||||||
ErrShortBuffer = errors.New("amf: short buffer")
|
ErrShortBuffer = errors.New("amf: short buffer")
|
||||||
ErrEndOfBuffer = errors.New("amf: end of buffer")
|
ErrEndOfBuffer = errors.New("amf: end of buffer")
|
||||||
ErrInvalidType = errors.New("amf: invalid type")
|
ErrInvalidType = errors.New("amf: invalid type")
|
||||||
ErrUnimplemented = errors.New("amf: unimplemented feature")
|
ErrUnimplemented = errors.New("amf: unimplemented feature")
|
||||||
ErrDecodingName = errors.New("amf: name decoding error")
|
ErrDecodingName = errors.New("amf: name decoding error")
|
||||||
ErrDecodingString = errors.New("amf: string decoding error")
|
ErrDecodingString = errors.New("amf: string decoding error")
|
||||||
ErrUnexpectedEnd = errors.New("amf: unexpected end")
|
ErrUnexpectedEnd = errors.New("amf: unexpected end")
|
||||||
|
ErrPropertyNotFound = errors.New("amf: property not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
// DecodeInt16 decodes a 16-bit integer.
|
// 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)
|
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.
|
// PropEncode encodes a property.
|
||||||
func PropEncode(p *Property, buf []byte) ([]byte, error) {
|
func PropEncode(p *Property, buf []byte) ([]byte, error) {
|
||||||
if p.dtype == typeInvalid {
|
if p.Type == typeInvalid {
|
||||||
return nil, ErrShortBuffer
|
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
|
return nil, ErrShortBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.dtype != TypeNull && len(p.name) != 0 {
|
if p.Type != TypeNull && len(p.Name) != 0 {
|
||||||
binary.BigEndian.PutUint16(buf[:2], uint16(len(p.name)))
|
binary.BigEndian.PutUint16(buf[:2], uint16(len(p.Name)))
|
||||||
buf = buf[2:]
|
buf = buf[2:]
|
||||||
copy(buf, p.name)
|
copy(buf, p.Name)
|
||||||
buf = buf[len(p.name):]
|
buf = buf[len(p.Name):]
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
switch p.dtype {
|
switch p.Type {
|
||||||
case typeNumber:
|
case typeNumber:
|
||||||
buf, err = EncodeNumber(buf, p.number)
|
buf, err = EncodeNumber(buf, p.Number)
|
||||||
case typeBoolean:
|
case typeBoolean:
|
||||||
buf, err = EncodeBoolean(buf, p.number != 0)
|
buf, err = EncodeBoolean(buf, p.Number != 0)
|
||||||
case typeString:
|
case typeString:
|
||||||
buf, err = EncodeString(buf, p.str)
|
buf, err = EncodeString(buf, p.String)
|
||||||
case TypeNull:
|
case TypeNull:
|
||||||
if len(buf) < 2 {
|
if len(buf) < 2 {
|
||||||
return nil, ErrShortBuffer
|
return nil, ErrShortBuffer
|
||||||
|
@ -316,11 +292,11 @@ func PropEncode(p *Property, buf []byte) ([]byte, error) {
|
||||||
buf[0] = TypeNull
|
buf[0] = TypeNull
|
||||||
buf = buf[1:]
|
buf = buf[1:]
|
||||||
case TypeObject:
|
case TypeObject:
|
||||||
buf, err = Encode(&p.obj, buf)
|
buf, err = Encode(&p.Object, buf)
|
||||||
case typeEcmaArray:
|
case typeEcmaArray:
|
||||||
buf, err = EncodeEcmaArray(&p.obj, buf)
|
buf, err = EncodeEcmaArray(&p.Object, buf)
|
||||||
case typeStrictArray:
|
case typeStrictArray:
|
||||||
buf, err = EncodeArray(&p.obj, buf)
|
buf, err = EncodeArray(&p.Object, buf)
|
||||||
default:
|
default:
|
||||||
buf, err = nil, ErrInvalidType
|
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.
|
// PropDecode decodes a property, returning the number of bytes consumed from the supplied buffer.
|
||||||
func PropDecode(prop *Property, buf []byte, decodeName bool) (int, error) {
|
func PropDecode(prop *Property, buf []byte, decodeName bool) (int, error) {
|
||||||
prop.name = ""
|
|
||||||
|
|
||||||
sz := len(buf)
|
sz := len(buf)
|
||||||
if len(buf) == 0 {
|
if len(buf) == 0 {
|
||||||
return 0, ErrEndOfBuffer
|
return 0, ErrEndOfBuffer
|
||||||
|
@ -345,23 +319,25 @@ func PropDecode(prop *Property, buf []byte, decodeName bool) (int, error) {
|
||||||
return 0, ErrDecodingName
|
return 0, ErrDecodingName
|
||||||
}
|
}
|
||||||
|
|
||||||
prop.name = DecodeString(buf)
|
prop.Name = DecodeString(buf)
|
||||||
buf = buf[2+n:]
|
buf = buf[2+n:]
|
||||||
|
} else {
|
||||||
|
prop.Name = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(buf) == 0 {
|
if len(buf) == 0 {
|
||||||
return 0, ErrEndOfBuffer
|
return 0, ErrEndOfBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
prop.dtype = uint8(buf[0])
|
prop.Type = uint8(buf[0])
|
||||||
buf = buf[1:]
|
buf = buf[1:]
|
||||||
|
|
||||||
switch prop.dtype {
|
switch prop.Type {
|
||||||
case typeNumber:
|
case typeNumber:
|
||||||
if len(buf) < 8 {
|
if len(buf) < 8 {
|
||||||
return 0, ErrShortBuffer
|
return 0, ErrShortBuffer
|
||||||
}
|
}
|
||||||
prop.number = DecodeNumber(buf[:8])
|
prop.Number = DecodeNumber(buf[:8])
|
||||||
buf = buf[8:]
|
buf = buf[8:]
|
||||||
|
|
||||||
case typeBoolean:
|
case typeBoolean:
|
||||||
|
@ -372,23 +348,22 @@ func PropDecode(prop *Property, buf []byte, decodeName bool) (int, error) {
|
||||||
if len(buf) < int(n+2) {
|
if len(buf) < int(n+2) {
|
||||||
return 0, ErrShortBuffer
|
return 0, ErrShortBuffer
|
||||||
}
|
}
|
||||||
prop.str = DecodeString(buf)
|
prop.String = DecodeString(buf)
|
||||||
buf = buf[2+n:]
|
buf = buf[2+n:]
|
||||||
|
|
||||||
case TypeObject:
|
case TypeObject:
|
||||||
n, err := Decode(&prop.obj, buf, true)
|
n, err := Decode(&prop.Object, buf, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
buf = buf[n:]
|
buf = buf[n:]
|
||||||
|
|
||||||
|
|
||||||
case TypeNull, typeUndefined, typeUnsupported:
|
case TypeNull, typeUndefined, typeUnsupported:
|
||||||
prop.dtype = TypeNull
|
prop.Type = TypeNull
|
||||||
|
|
||||||
case typeEcmaArray:
|
case typeEcmaArray:
|
||||||
buf = buf[4:]
|
buf = buf[4:]
|
||||||
n, err := Decode(&prop.obj, buf, true)
|
n, err := Decode(&prop.Object, buf, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -482,7 +457,7 @@ func Decode(obj *Object, buf []byte, decodeName bool) (int, error) {
|
||||||
for len(buf) != 0 {
|
for len(buf) != 0 {
|
||||||
if len(buf) >= 3 && DecodeInt24(buf[:3]) == TypeObjectEnd {
|
if len(buf) >= 3 && DecodeInt24(buf[:3]) == TypeObjectEnd {
|
||||||
buf = buf[3:]
|
buf = buf[3:]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
var prop Property
|
var prop Property
|
||||||
|
@ -497,19 +472,19 @@ func Decode(obj *Object, buf []byte, decodeName bool) (int, error) {
|
||||||
return sz - len(buf), nil
|
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.
|
// GetProp returns an object's property, either by its index when idx is non-negative, or by its name otherwise.
|
||||||
// If the matching property is not found nil is returned.
|
// If the requested property is not found an ErrPropertyNotFound error is returned.
|
||||||
func GetProp(obj *Object, name string, idx int) *Property {
|
func (obj *Object)GetProp(name string, idx int) (*Property, error) {
|
||||||
if idx >= 0 {
|
if idx >= 0 {
|
||||||
if idx < len(obj.Props) {
|
if idx < len(obj.Props) {
|
||||||
return &obj.Props[idx]
|
return &obj.Props[idx], nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i, p := range obj.Props {
|
for i, p := range obj.Props {
|
||||||
if p.name == name {
|
if p.Name == name {
|
||||||
return &obj.Props[i]
|
return &obj.Props[i], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil, ErrPropertyNotFound
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ func TestNumbers(t *testing.T) {
|
||||||
}
|
}
|
||||||
dn := int32(DecodeInt24(buf))
|
dn := int32(DecodeInt24(buf))
|
||||||
if n != dn {
|
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) {
|
func TestProperties(t *testing.T) {
|
||||||
var buf [1024]byte
|
var buf [1024]byte
|
||||||
|
|
||||||
// Encode/decode number properties.
|
// Encode/decode Number properties.
|
||||||
enc := buf[:]
|
enc := buf[:]
|
||||||
var err error
|
var err error
|
||||||
for i, _ := range testNumbers {
|
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 {
|
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 {
|
for i, _ := range testNumbers {
|
||||||
n, err := PropDecode(&prop, dec, false)
|
n, err := PropDecode(&prop, dec, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("PropDecode of number failed")
|
t.Errorf("PropDecode of Number failed")
|
||||||
}
|
}
|
||||||
if 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])
|
t.Errorf("PropEncode/PropDecode returned wrong Number; got %v, expected %v", int32(prop.Number), testNumbers[i])
|
||||||
}
|
}
|
||||||
dec = dec[n:]
|
dec = dec[n:]
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ func TestProperties(t *testing.T) {
|
||||||
// Encode/decode string properties.
|
// Encode/decode string properties.
|
||||||
enc = buf[:]
|
enc = buf[:]
|
||||||
for i, _ := range testStrings {
|
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 {
|
if err != nil {
|
||||||
t.Errorf("PropEncode of string failed")
|
t.Errorf("PropEncode of string failed")
|
||||||
}
|
}
|
||||||
|
@ -137,8 +137,8 @@ func TestProperties(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("PropDecode of string failed")
|
t.Errorf("PropDecode of string failed")
|
||||||
}
|
}
|
||||||
if prop.str != testStrings[i] {
|
if prop.String != testStrings[i] {
|
||||||
t.Errorf("PropEncode/PropDecode returned wrong string; got %s, expected %s", prop.str, testStrings[i])
|
t.Errorf("PropEncode/PropDecode returned wrong string; got %s, expected %s", prop.String, testStrings[i])
|
||||||
}
|
}
|
||||||
dec = dec[n:]
|
dec = dec[n:]
|
||||||
}
|
}
|
||||||
|
@ -149,8 +149,8 @@ func TestProperties(t *testing.T) {
|
||||||
func TestObject(t *testing.T) {
|
func TestObject(t *testing.T) {
|
||||||
var buf [1024]byte
|
var buf [1024]byte
|
||||||
|
|
||||||
// Construct a simple object that has one property, the number 42.
|
// Construct a simple object that has one property, the Number 42.
|
||||||
prop1 := Property{dtype: typeNumber, number: 42}
|
prop1 := Property{Type: typeNumber, Number: 42}
|
||||||
obj1 := Object{}
|
obj1 := Object{}
|
||||||
obj1.Props = append(obj1.Props, prop1)
|
obj1.Props = append(obj1.Props, prop1)
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ func TestObject(t *testing.T) {
|
||||||
}
|
}
|
||||||
num := DecodeNumber(buf[2:10])
|
num := DecodeNumber(buf[2:10])
|
||||||
if num != 42 {
|
if num != 42 {
|
||||||
t.Errorf("Encoded wrong number")
|
t.Errorf("Encoded wrong Number")
|
||||||
}
|
}
|
||||||
end := int32(DecodeInt24(buf[10:13]))
|
end := int32(DecodeInt24(buf[10:13]))
|
||||||
if end != TypeObjectEnd {
|
if end != TypeObjectEnd {
|
||||||
|
@ -189,8 +189,8 @@ func TestObject(t *testing.T) {
|
||||||
// Construct a more complicated object.
|
// Construct a more complicated object.
|
||||||
var obj2 Object
|
var obj2 Object
|
||||||
for i, _ := range testStrings {
|
for i, _ := range testStrings {
|
||||||
obj2.Props = append(obj2.Props, Property{dtype: typeString, str: testStrings[i]})
|
obj2.Props = append(obj2.Props, Property{Type: typeString, String: testStrings[i]})
|
||||||
obj2.Props = append(obj2.Props, Property{dtype: typeNumber, number: float64(testNumbers[i])})
|
obj2.Props = append(obj2.Props, Property{Type: typeNumber, Number: float64(testNumbers[i])})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode it.
|
// Encode it.
|
||||||
|
@ -207,4 +207,26 @@ func TestObject(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Decode of object failed")
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
meth := amf.PropGetString(amf.GetProp(&obj, "", 0))
|
prop, err := obj.GetProp("", 0)
|
||||||
s.log(DebugLevel, pkg+"invoking method "+meth)
|
if err != nil {
|
||||||
txn := amf.PropGetNumber(amf.GetProp(&obj, "", 1))
|
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 {
|
switch meth {
|
||||||
case av_result:
|
case av_result:
|
||||||
var methodInvoked string
|
var methodInvoked string
|
||||||
|
@ -728,7 +736,11 @@ func handleInvoke(s *Session, body []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
case avCreatestream:
|
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 {
|
if s.link.protocol&featureWrite == 0 {
|
||||||
return errNotWritable
|
return errNotWritable
|
||||||
}
|
}
|
||||||
|
@ -765,10 +777,21 @@ func handleInvoke(s *Session, body []byte) error {
|
||||||
s.log(FatalLevel, pkg+"unsupported method avClose")
|
s.log(FatalLevel, pkg+"unsupported method avClose")
|
||||||
|
|
||||||
case avOnStatus:
|
case avOnStatus:
|
||||||
var obj2 amf.Object
|
prop, err = obj.GetProp("", 3)
|
||||||
amf.PropGetObject(amf.GetProp(&obj, "", 3), &obj2)
|
if err != nil {
|
||||||
code := amf.PropGetString(amf.GetProp(&obj2, avCode, -1))
|
return err
|
||||||
level := amf.PropGetString(amf.GetProp(&obj2, avLevel, -1))
|
}
|
||||||
|
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)
|
s.log(DebugLevel, pkg+"onStatus", "code", code, "level", level)
|
||||||
|
|
||||||
switch code {
|
switch code {
|
||||||
|
|
Loading…
Reference in New Issue