Added a goroutine to read data from the remote and parse it into
appropriate structures.
--- 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
+ }
+}