Refactor / extract the registry
Work in progress
This commit is contained in:
parent
b05efea81d
commit
836e723273
16
iq.go
16
iq.go
|
@ -210,7 +210,7 @@ func (iq *IQ) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||||
if level <= 1 {
|
if level <= 1 {
|
||||||
var elt interface{}
|
var elt interface{}
|
||||||
payloadType := tt.Name.Space + " " + tt.Name.Local
|
payloadType := tt.Name.Space + " " + tt.Name.Local
|
||||||
if payloadType := typeRegistry[payloadType]; payloadType != nil {
|
if payloadType := iqTypeRegistry[payloadType]; payloadType != nil {
|
||||||
val := reflect.New(payloadType)
|
val := reflect.New(payloadType)
|
||||||
elt = val.Interface()
|
elt = val.Interface()
|
||||||
} else {
|
} else {
|
||||||
|
@ -332,15 +332,9 @@ type DiscoItem struct {
|
||||||
Node string `xml:"node,attr,omitempty"`
|
Node string `xml:"node,attr,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// TODO: Make it configurable at to be able to easily add new XMPP extensions
|
|
||||||
// in separate modules
|
|
||||||
|
|
||||||
var typeRegistry = make(map[string]reflect.Type)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
typeRegistry["http://jabber.org/protocol/disco#info query"] = reflect.TypeOf(DiscoInfo{})
|
iqTypeRegistry["http://jabber.org/protocol/disco#info query"] = reflect.TypeOf(DiscoInfo{})
|
||||||
typeRegistry["http://jabber.org/protocol/disco#items query"] = reflect.TypeOf(DiscoItems{})
|
iqTypeRegistry["http://jabber.org/protocol/disco#items query"] = reflect.TypeOf(DiscoItems{})
|
||||||
typeRegistry["urn:ietf:params:xml:ns:xmpp-bind bind"] = reflect.TypeOf(BindBind{})
|
iqTypeRegistry["urn:ietf:params:xml:ns:xmpp-bind bind"] = reflect.TypeOf(BindBind{})
|
||||||
typeRegistry["urn:xmpp:iot:control set"] = reflect.TypeOf(iot.ControlSet{})
|
iqTypeRegistry["urn:xmpp:iot:control set"] = reflect.TypeOf(iot.ControlSet{})
|
||||||
}
|
}
|
||||||
|
|
47
message.go
47
message.go
|
@ -3,7 +3,6 @@ package xmpp // import "gosrc.io/xmpp"
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
@ -87,21 +86,16 @@ func (msg *Message) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||||
switch tt := t.(type) {
|
switch tt := t.(type) {
|
||||||
|
|
||||||
case xml.StartElement:
|
case xml.StartElement:
|
||||||
var elt interface{}
|
|
||||||
elementType := tt.Name.Space
|
elementType := tt.Name.Space
|
||||||
|
if msgExt := typeRegistry.getmsgType(elementType); msgExt != nil {
|
||||||
if extensionType := msgTypeRegistry[elementType]; extensionType != nil {
|
// Decode message extension
|
||||||
val := reflect.New(extensionType)
|
err = d.DecodeElement(msgExt, &tt)
|
||||||
elt = val.Interface()
|
if err != nil {
|
||||||
if msgExt, ok := elt.(MsgExtension); ok {
|
return err
|
||||||
err = d.DecodeElement(elt, &tt)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
msg.Extensions = append(msg.Extensions, msgExt)
|
|
||||||
}
|
}
|
||||||
|
msg.Extensions = append(msg.Extensions, msgExt)
|
||||||
} else {
|
} else {
|
||||||
// Decode default message elements
|
// Decode standard message sub-elements
|
||||||
var err error
|
var err error
|
||||||
switch tt.Name.Local {
|
switch tt.Name.Local {
|
||||||
case "body":
|
case "body":
|
||||||
|
@ -125,30 +119,3 @@ func (msg *Message) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Message extensions
|
|
||||||
// Provide ability to add support to XMPP extension tags on messages
|
|
||||||
|
|
||||||
type MsgExtension interface {
|
|
||||||
IsMsgExtension()
|
|
||||||
}
|
|
||||||
|
|
||||||
// XEP-0184
|
|
||||||
type Receipt struct {
|
|
||||||
// xmlns: urn:xmpp:receipts
|
|
||||||
XMLName xml.Name
|
|
||||||
Id string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Receipt) IsMsgExtension() {}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// TODO: Make it configurable at to be able to easily add new XMPP extensions
|
|
||||||
// in separate modules
|
|
||||||
|
|
||||||
var msgTypeRegistry = make(map[string]reflect.Type)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
msgTypeRegistry["urn:xmpp:receipts"] = reflect.TypeOf(Receipt{})
|
|
||||||
}
|
|
||||||
|
|
23
msg_receipts.go
Normal file
23
msg_receipts.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package xmpp
|
||||||
|
|
||||||
|
import "encoding/xml"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Support for:
|
||||||
|
- XEP-0184 - Message Delivery Receipts: https://xmpp.org/extensions/xep-0184.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
const (
|
||||||
|
NSReceipts = "urn:xmpp:receipts"
|
||||||
|
)
|
||||||
|
|
||||||
|
// XEP-0184 message receipt markers
|
||||||
|
type Receipt struct {
|
||||||
|
MsgExtension
|
||||||
|
XMLName xml.Name
|
||||||
|
Id string
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
typeRegistry.RegisterMsgExt(NSReceipts, Receipt{})
|
||||||
|
}
|
65
registry.go
Normal file
65
registry.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package xmpp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MsgExtension interface{}
|
||||||
|
|
||||||
|
// The Registry for msg and IQ types is a global variable.
|
||||||
|
// TODO: Move to the client init process to remove the dependency on a global variable.
|
||||||
|
// That should make it possible to be able to share the decoder.
|
||||||
|
// TODO: Ensure that a client can add its own custom namespace to the registry (or overload existing ones).
|
||||||
|
var typeRegistry = newRegistry()
|
||||||
|
|
||||||
|
type namespace = string
|
||||||
|
|
||||||
|
type registry struct {
|
||||||
|
// Key is namespace of message extension
|
||||||
|
msgTypes map[namespace]reflect.Type
|
||||||
|
msgTypesLock *sync.RWMutex
|
||||||
|
|
||||||
|
iqTypes map[namespace]reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRegistry() registry {
|
||||||
|
return registry{
|
||||||
|
msgTypes: make(map[namespace]reflect.Type),
|
||||||
|
msgTypesLock: &sync.RWMutex{},
|
||||||
|
iqTypes: make(map[namespace]reflect.Type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mutexes are not needed when adding a Message or IQ extension in init function.
|
||||||
|
// However, forcing the use of the mutex protect the data structure against unexpected use
|
||||||
|
// of the registry by developers using the library.
|
||||||
|
func (r registry) RegisterMsgExt(namespace string, extension MsgExtension) {
|
||||||
|
r.msgTypesLock.Lock()
|
||||||
|
defer r.msgTypesLock.Unlock()
|
||||||
|
r.msgTypes[namespace] = reflect.TypeOf(extension)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r registry) getMsgExtType(namespace string) reflect.Type {
|
||||||
|
r.msgTypesLock.RLock()
|
||||||
|
defer r.msgTypesLock.RUnlock()
|
||||||
|
return r.msgTypes[namespace]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r registry) getmsgType(namespace string) MsgExtension {
|
||||||
|
if extensionType := r.getMsgExtType(namespace); extensionType != nil {
|
||||||
|
val := reflect.New(extensionType)
|
||||||
|
elt := val.Interface()
|
||||||
|
if msgExt, ok := elt.(MsgExtension); ok {
|
||||||
|
return msgExt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registry to support message extensions
|
||||||
|
//var msgTypeRegistry = make(map[string]reflect.Type)
|
||||||
|
|
||||||
|
// Registry to instantiate the right IQ payload element
|
||||||
|
// Key is namespace and key of the payload
|
||||||
|
var iqTypeRegistry = make(map[string]reflect.Type)
|
Loading…
Reference in a new issue