# HG changeset patch # User Chris Jones # Date 1325112447 25200 # Node ID 4d0a369079ceee7b2bd754e30362697008c4a65e # Parent 7437d6eed2279443f274858a04be6fb5145a6fdf Removed the TextOut channel. diff -r 7437d6eed227 -r 4d0a369079ce examples/interact.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") } diff -r 7437d6eed227 -r 4d0a369079ce stream.go --- 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: diff -r 7437d6eed227 -r 4d0a369079ce structs.go --- 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 +} diff -r 7437d6eed227 -r 4d0a369079ce structs_test.go --- 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 @@ `">` assertMarshal(t, exp, iq) } + +func TestParseStanza(t *testing.T) { + str := `text` + 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 = `` + 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 = `` + st, err = ParseStanza(str) + if err != nil { + t.Fatalf("presence: %v", err) + } + assertEquals(t, "presence", st.XName()) +} diff -r 7437d6eed227 -r 4d0a369079ce xmpp.go --- 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)