Removed the TextOut channel.
--- 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)