Added a goroutine to read data from the remote and parse it into
authorChris Jones <chris@cjones.org>
Sat, 24 Dec 2011 13:11:36 -0700
changeset 5 faef59c8db05
parent 4 a8fbec71a194
child 6 8e425e340ca1
Added a goroutine to read data from the remote and parse it into appropriate structures.
structs.go
xmpp.go
--- a/structs.go	Sat Dec 24 11:18:52 2011 -0700
+++ b/structs.go	Sat Dec 24 13:11:36 2011 -0700
@@ -13,6 +13,7 @@
 	"io"
 	"os"
 	"regexp"
+	"strings"
 	"xml"
 )
 
@@ -62,6 +63,10 @@
 }
 var _ xml.Marshaler = &errText{}
 
+type Unrecognized struct {
+	XMLName xml.Name
+}
+
 func (jid *JID) String() string {
 	result := jid.Domain
 	if jid.Node != nil {
@@ -106,6 +111,26 @@
 	return buf.Bytes(), nil
 }
 
+func parseStream(se xml.StartElement) (*Stream, os.Error) {
+	s := &Stream{}
+	se = se.Copy()
+	for _, attr := range se.Attr {
+		switch strings.ToLower(attr.Name.Local) {
+		case "to":
+			s.to = attr.Value
+		case "from":
+			s.from = attr.Value
+		case "id":
+			s.id = attr.Value
+		case "lang":
+			s.lang = attr.Value
+		case "version":
+			s.version = attr.Value
+		}
+	}
+	return s, nil
+}
+
 func (s *StreamError) MarshalXML() ([]byte, os.Error) {
 	buf := bytes.NewBuffer(nil)
 	buf.WriteString("<stream:error>")
--- a/xmpp.go	Sat Dec 24 11:18:52 2011 -0700
+++ b/xmpp.go	Sat Dec 24 13:11:36 2011 -0700
@@ -9,8 +9,10 @@
 import (
 	"fmt"
 	"io"
+	"log"
 	"net"
 	"os"
+	"xml"
 )
 
 const (
@@ -20,8 +22,10 @@
 
 // The client in a client-server XMPP connection.
 type Client struct {
-	//In <-chan *Stanza
-	//Out chan<- *Stanza
+	In <-chan interface{}
+	in chan interface{}
+	Out chan<- interface{}
+	out chan interface{}
 	tcp *net.TCPConn
 }
 var _ io.Closer = &Client{}
@@ -58,9 +62,63 @@
 
 	cl := Client{}
 	cl.tcp = c
+	cl.in = make(chan interface{})
+	cl.In = cl.in
+	// TODO Send readXml a reader that we can close when we
+	// negotiate TLS.
+	go readXml(cl.tcp, cl.in)
+	// TODO go writeXml(&cl)
+
 	return &cl, nil
 }
 
 func (c *Client) Close() os.Error {
 	return c.tcp.Close()
 }
+
+func readXml(r io.Reader, ch chan<- interface{}) {
+	p := xml.NewParser(r)
+	for {
+		// Sniff the next token on the stream.
+		t, err := p.Token()
+		if t == nil {
+			if err != os.EOF {
+				log.Printf("read: %v", err)
+			}
+			break
+		}
+		var se xml.StartElement
+		var ok bool
+		if se, ok = t.(xml.StartElement) ; !ok {
+			continue
+		}
+
+		// Allocate the appropriate structure for this token.
+		var obj interface{}
+		switch se.Name.Space + se.Name.Local {
+		case "stream stream":
+			st, err := parseStream(se)
+			if err != nil {
+				log.Printf("unmarshal stream: %v",
+					err)
+				break
+			}
+			ch <- st
+			continue
+		case nsStreams + " stream:error":
+			obj = &StreamError{}
+		default:
+			obj = &Unrecognized{}
+		}
+
+		// Read the complete XML stanza.
+		err = p.Unmarshal(obj, &se)
+		if err != nil {
+			log.Printf("unmarshal: %v", err)
+			break
+		}
+
+		// Put it on the channel.
+		ch <- obj
+	}
+}