Made a generic extension interface.
authorChris Jones <chris@cjones.org>
Sat, 07 Jan 2012 21:20:23 -0700
changeset 60 6d4f43f7dc19
parent 59 be6815a9653a
child 61 16513974d273
Made a generic extension interface.
roster.go
structs.go
xmpp.go
--- a/roster.go	Sat Jan 07 20:41:16 2012 -0700
+++ b/roster.go	Sat Jan 07 21:20:23 2012 -0700
@@ -12,6 +12,10 @@
 
 // This file contains support for roster management, RFC 3921, Section 7.
 
+var rosterExt Extension = Extension{StanzaHandlers:
+	map[string] func(*xml.Name) interface{}{NsRoster:
+		newRosterQuery}, Start: startRosterFilter}
+
 // Roster query/result
 type RosterQuery struct {
 	XMLName xml.Name `xml:"jabber:iq:roster query"`
--- a/structs.go	Sat Jan 07 20:41:16 2012 -0700
+++ b/structs.go	Sat Jan 07 21:20:23 2012 -0700
@@ -530,6 +530,10 @@
 	return stan, nil
 }
 
+var bindExt Extension = Extension{StanzaHandlers:
+	map[string] func(*xml.Name) interface{}{NsBind: newBind},
+		Start: func(cl *Client) {}}
+
 func newBind(name *xml.Name) interface{} {
 	return &bindIq{}
 }
--- a/xmpp.go	Sat Jan 07 20:41:16 2012 -0700
+++ b/xmpp.go	Sat Jan 07 21:20:23 2012 -0700
@@ -62,6 +62,12 @@
 	}(idCh)
 }
 
+// Extensions can add stanza filters and/or new XML element types.
+type Extension struct {
+	StanzaHandlers map[string] func(*xml.Name) interface{}
+	Start func(*Client)
+}
+
 // The client in a client-server XMPP connection.
 type Client struct {
 	// This client's unique ID. It's unique within the context of
@@ -96,18 +102,18 @@
 }
 var _ io.Closer = &Client{}
 
-// BUG(cjyar): Replace extStanza with a generalized extension interface
-// that handles starting filters, registering extended stanzes, and
-// anything else an extension has to do.
-
 // Connect to the appropriate server and authenticate as the given JID
 // with the given password. This function will return as soon as a TCP
 // connection has been established, but before XMPP stream negotiation
 // has completed. The negotiation will occur asynchronously, and any
 // send operation to Client.Out will block until negotiation (resource
 // binding) is complete.
-func NewClient(jid *JID, password string,
-	extStanza map[string] func(*xml.Name) interface{}) (*Client, os.Error) {
+func NewClient(jid *JID, password string, exts []Extension) (*Client,
+	os.Error) {
+	// Include the mandatory extensions.
+	exts = append(exts, rosterExt)
+	exts = append(exts, bindExt)
+
 	// Resolve the domain in the JID.
 	_, srvs, err := net.LookupSRV(clientSrv, "tcp", jid.Domain)
 	if err != nil {
@@ -143,11 +149,12 @@
 	cl.handlers = make(chan *stanzaHandler, 100)
 	cl.inputControl = make(chan int)
 
-	if extStanza == nil {
-		extStanza = make(map[string] func(*xml.Name) interface{})
+	extStanza := make(map[string] func(*xml.Name) interface{})
+	for _, ext := range(exts) {
+		for k, v := range(ext.StanzaHandlers) {
+			extStanza[k] = v
+		}
 	}
-	extStanza[NsRoster] = newRosterQuery
-	extStanza[NsBind] = newBind
 
 	// Start the transport handler, initially unencrypted.
 	tlsr, tlsw := cl.startTransport()
@@ -160,19 +167,22 @@
 	// events and responds to them.
 	stIn := cl.startStreamReader(xmlIn, cl.xmlOut)
 	clOut := cl.startStreamWriter(cl.xmlOut)
+	cl.Out = clOut
 
 	// Start the manager for the filters that can modify what the
 	// app sees.
 	clIn := cl.startFilter(stIn)
-	startRosterFilter(cl)
+	cl.In = clIn
+
+	// Add filters for our extensions.
+	for _, ext := range(exts) {
+		ext.Start(cl)
+	}
 
 	// Initial handshake.
 	hsOut := &stream{To: jid.Domain, Version: Version}
 	cl.xmlOut <- hsOut
 
-	cl.In = clIn
-	cl.Out = clOut
-
 	return cl, nil
 }