Removed the TextOut channel.
authorChris Jones <chris@cjones.org>
Wed, 28 Dec 2011 15:47:27 -0700
changeset 26 4d0a369079ce
parent 25 7437d6eed227
child 27 13bcc96a5a6c
Removed the TextOut channel.
examples/interact.go
stream.go
structs.go
structs_test.go
xmpp.go
--- a/examples/interact.go	Wed Dec 28 13:32:11 2011 -0700
+++ b/examples/interact.go	Wed Dec 28 15:47:27 2011 -0700
@@ -44,7 +44,13 @@
 			break
 		}
 		s := string(p)
-		c.TextOut <- &s
+		stan, err := xmpp.ParseStanza(s)
+		if err == nil {
+			c.Out <- stan
+		} else {
+			fmt.Printf("Parse error: %v\n", err)
+			break
+		}
 	}
 	fmt.Println("done sending")
 }
--- a/stream.go	Wed Dec 28 13:32:11 2011 -0700
+++ b/stream.go	Wed Dec 28 15:47:27 2011 -0700
@@ -170,36 +170,18 @@
 	}
 }
 
-// BUG(cjyar) This should go away. We shouldn't allow writing of
-// unstructured data.
-func writeText(w io.Writer, ch <-chan *string) {
-	if debug {
-		pr, pw := io.Pipe()
-		go tee(pr, w, "C: ")
-		w = pw
-	}
-	defer tryClose(w, ch)
-
-	for str := range ch {
-		_, err := w.Write([]byte(*str))
-		if err != nil {
-			log.Printf("writeStr: %v", err)
-			break
-		}
-	}
-}
-
 func (cl *Client) readStream(srvIn <-chan interface{}, cliOut chan<- Stanza) {
 	defer tryClose(srvIn, cliOut)
 
 	handlers := make(map[string] func(Stanza) bool)
-	// BUG(cjyar) This for loop will never terminate, even when
-	// the channels are closed.
 	for {
 		select {
 		case h := <- cl.handlers:
 			handlers[h.id] = h.f
 		case x := <- srvIn:
+			if x == nil {
+				break
+			}
 			send := false
 			switch obj := x.(type) {
 			case *stream:
--- a/structs.go	Wed Dec 28 13:32:11 2011 -0700
+++ b/structs.go	Wed Dec 28 15:47:27 2011 -0700
@@ -409,3 +409,34 @@
 func (iq *Iq) MarshalXML() ([]byte, os.Error) {
 	return marshalXML(iq)
 }
+
+// Parse a string into a struct implementing Stanza -- this will be
+// either an Iq, a Message, or a Presence.
+func ParseStanza(str string) (Stanza, os.Error) {
+	r := strings.NewReader(str)
+	p := xml.NewParser(r)
+	tok, err := p.Token()
+	if err != nil {
+		return nil, err
+	}
+	se, ok := tok.(xml.StartElement)
+	if !ok {
+		return nil, os.NewError("Not a start element")
+	}
+	var stan Stanza
+	switch se.Name.Local {
+	case "iq":
+		stan = &Iq{}
+	case "message":
+		stan = &Message{}
+	case "presence":
+		stan = &Presence{}
+	default:
+		return nil, os.NewError("Not iq, message, or presence")
+	}
+	err = p.Unmarshal(stan, &se)
+	if err != nil {
+		return nil, err
+	}
+	return stan, nil
+}
--- a/structs_test.go	Wed Dec 28 13:32:11 2011 -0700
+++ b/structs_test.go	Wed Dec 28 15:47:27 2011 -0700
@@ -89,3 +89,50 @@
 		`"></bind></iq>`
 	assertMarshal(t, exp, iq)
 }
+
+func TestParseStanza(t *testing.T) {
+	str := `<iq to="alice" from="bob" id="1" type="A"` +
+		` xml:lang="en"><foo>text</foo></iq>`
+	st, err := ParseStanza(str)
+	if err != nil {
+		t.Fatalf("iq: %v", err)
+	}
+	assertEquals(t, "iq", st.XName())
+	assertEquals(t, "alice", st.XTo())
+	assertEquals(t, "bob", st.XFrom())
+	assertEquals(t, "1", st.XId())
+	assertEquals(t, "A", st.XType())
+	assertEquals(t, "en", st.XLang())
+	if st.XError() != nil {
+		t.Errorf("iq: error %v", st.XError())
+	}
+	if st.XChild() == nil {
+		t.Errorf("iq: nil child")
+	}
+	assertEquals(t, "foo", st.XChild().XMLName.Local)
+	assertEquals(t, "text", st.XChild().Chardata)
+
+	str = `<message to="alice" from="bob"/>`
+	st, err = ParseStanza(str)
+	if err != nil {
+		t.Fatalf("message: %v", err)
+	}
+	assertEquals(t, "message", st.XName())
+	assertEquals(t, "alice", st.XTo())
+	assertEquals(t, "bob", st.XFrom())
+	assertEquals(t, "", st.XId())
+	assertEquals(t, "", st.XLang())
+	if st.XError() != nil {
+		t.Errorf("message: error %v", st.XError())
+	}
+	if st.XChild() != nil {
+		t.Errorf("message: child %v", st.XChild())
+	}
+
+	str = `<presence/>`
+	st, err = ParseStanza(str)
+	if err != nil {
+		t.Fatalf("presence: %v", err)
+	}
+	assertEquals(t, "presence", st.XName())
+}
--- a/xmpp.go	Wed Dec 28 13:32:11 2011 -0700
+++ b/xmpp.go	Wed Dec 28 15:47:27 2011 -0700
@@ -63,9 +63,6 @@
 	// channel.
 	Out chan<- Stanza
 	xmlOut chan<- interface{}
-	// BUG(cjyar) Remove this. Make a Stanza parser method
-	// available for use by interact.go and similar applications.
-	TextOut chan<- *string
 }
 var _ io.Closer = &Client{}
 
@@ -114,7 +111,6 @@
 	// Start the reader and writers that convert to and from XML.
 	xmlIn := startXmlReader(tlsr)
 	cl.xmlOut = startXmlWriter(tlsw)
-	textOut := startTextWriter(tlsw)
 
 	// Start the XMPP stream handler which filters stream-level
 	// events and responds to them.
@@ -127,13 +123,12 @@
 
 	cl.In = clIn
 	cl.Out = clOut
-	cl.TextOut = textOut
 
 	return cl, nil
 }
 
 func (c *Client) Close() os.Error {
-	tryClose(c.In, c.Out, c.TextOut)
+	tryClose(c.In, c.Out)
 	return nil
 }
 
@@ -157,12 +152,6 @@
 	return ch
 }
 
-func startTextWriter(w io.Writer) chan<- *string {
-	ch := make(chan *string)
-	go writeText(w, ch)
-	return ch
-}
-
 func (cl *Client) startStreamReader(xmlIn <-chan interface{}, srvOut chan<- interface{}) <-chan Stanza {
 	ch := make(chan Stanza)
 	go cl.readStream(xmlIn, ch)