--- a/xmpp.go Sat Dec 24 13:11:36 2011 -0700
+++ b/xmpp.go Sun Dec 25 18:46:13 2011 -0700
@@ -7,6 +7,7 @@
package xmpp
import (
+ "bytes"
"fmt"
"io"
"log"
@@ -18,6 +19,7 @@
const (
serverSrv = "xmpp-server"
clientSrv = "xmpp-client"
+ debug = true
)
// The client in a client-server XMPP connection.
@@ -60,23 +62,39 @@
return nil, err
}
- cl := Client{}
+ cl := new(Client)
cl.tcp = c
cl.in = make(chan interface{})
cl.In = cl.in
+ cl.out = make(chan interface{})
+ cl.Out = cl.out
// TODO Send readXml a reader that we can close when we
// negotiate TLS.
- go readXml(cl.tcp, cl.in)
- // TODO go writeXml(&cl)
+ go readXml(cl.tcp, cl.in, debug)
+ go writeXml(cl.tcp, cl.out, debug)
- return &cl, nil
+ return cl, nil
}
func (c *Client) Close() os.Error {
+ close(c.in)
+ close(c.out)
return c.tcp.Close()
}
-func readXml(r io.Reader, ch chan<- interface{}) {
+// TODO Delete; for use only by interact.go:
+func ReadXml(r io.ReadCloser, ch chan<- interface{}, dbg bool) {
+ readXml(r, ch, dbg)
+}
+
+func readXml(r io.Reader, ch chan<- interface{}, dbg bool) {
+ defer close(ch)
+ if dbg {
+ pr, pw := io.Pipe()
+ go tee(r, pw, "S: ")
+ r = pr
+ }
+
p := xml.NewParser(r)
for {
// Sniff the next token on the stream.
@@ -95,8 +113,8 @@
// Allocate the appropriate structure for this token.
var obj interface{}
- switch se.Name.Space + se.Name.Local {
- case "stream stream":
+ switch se.Name.Space + " " + se.Name.Local {
+ case nsStream + " stream":
st, err := parseStream(se)
if err != nil {
log.Printf("unmarshal stream: %v",
@@ -105,7 +123,7 @@
}
ch <- st
continue
- case nsStreams + " stream:error":
+ case "stream error":
obj = &StreamError{}
default:
obj = &Unrecognized{}
@@ -122,3 +140,51 @@
ch <- obj
}
}
+
+func writeXml(w io.Writer, ch <-chan interface{}, dbg bool) {
+ if dbg {
+ pr, pw := io.Pipe()
+ go tee(pr, w, "C: ")
+ w = pw
+ }
+
+ for obj := range ch {
+ err := xml.Marshal(w, obj)
+ if err != nil {
+ log.Printf("write: %v", err)
+ break
+ }
+ }
+}
+
+func tee(r io.Reader, w io.Writer, prefix string) {
+ defer func(xs ...interface{}) {
+ for _, x := range xs {
+ if c, ok := x.(io.Closer) ; ok {
+ c.Close()
+ }
+ }
+ }(r, w)
+
+ buf := bytes.NewBuffer(nil)
+ for {
+ var c [1]byte
+ n, _ := r.Read(c[:])
+ if n == 0 {
+ break
+ }
+ n, _ = w.Write(c[:])
+ if n == 0 {
+ break
+ }
+ buf.Write(c[:])
+ if c[0] == '\n' {
+ fmt.Printf("%s%s", prefix, buf.String())
+ buf.Reset()
+ }
+ }
+ leftover := buf.String()
+ if leftover != "" {
+ fmt.Printf("%s%s\n", prefix, leftover)
+ }
+}