Cleanup for Go 1. go.weekly.2012-01-15
authorChris Jones <chris@cjones.org>
Sun, 15 Apr 2012 11:20:55 -0600
branchgo.weekly.2012-01-15
changeset 93 fbd51fa6b7ea
parent 87 d19b556d4ea6
child 94 0ef947611eec
Cleanup for Go 1.
roster_test.go
stream.go
structs.go
structs_test.go
xmpp.go
--- a/roster_test.go	Mon Jan 23 21:58:53 2012 -0700
+++ b/roster_test.go	Sun Apr 15 11:20:55 2012 -0600
@@ -7,7 +7,6 @@
 import (
 	"encoding/xml"
 	"reflect"
-	"strings"
 	"testing"
 )
 
@@ -23,9 +22,8 @@
 func TestRosterIqUnmarshal(t *testing.T) {
 	str := `<iq from="from" xml:lang="en"><query xmlns="` +
 		NsRoster + `"><item jid="a@b.c"/></query></iq>`
-	r := strings.NewReader(str)
 	var st Stanza = &Iq{}
-	err := xml.Unmarshal(r, st)
+	err := xml.Unmarshal([]byte(str), st)
 	if err != nil {
 		t.Fatalf("Unmarshal: %v", err)
 	}
--- a/stream.go	Mon Jan 23 21:58:53 2012 -0700
+++ b/stream.go	Sun Apr 15 11:20:55 2012 -0600
@@ -19,7 +19,6 @@
 	"encoding/xml"
 	"fmt"
 	"io"
-	"log/syslog"
 	"math/big"
 	"net"
 	"regexp"
@@ -52,11 +51,17 @@
 
 func (cl *Client) readTransport(w io.WriteCloser) {
 	defer w.Close()
-	cl.socket.SetReadTimeout(1e8)
+	readDelay, _ := time.ParseDuration("1s")
 	p := make([]byte, 1024)
 	for {
 		if cl.socket == nil {
 			cl.waitForSocket()
+			readDelay = 0
+		}
+		if readDelay != 0 {
+			readTimeout := time.Now()
+			readTimeout.Add(readDelay)
+			cl.socket.SetReadDeadline(readTimeout)
 		}
 		nr, err := cl.socket.Read(p)
 		if nr == 0 {
@@ -103,14 +108,14 @@
 
 func readXml(r io.Reader, ch chan<- interface{},
 	extStanza map[string]func(*xml.Name) interface{}) {
-	if Loglevel >= syslog.LOG_DEBUG {
+	if Loglevel >= LOG_DEBUG {
 		pr, pw := io.Pipe()
 		go tee(r, pw, "S: ")
 		r = pr
 	}
 	defer close(ch)
 
-	p := xml.NewParser(r)
+	p := xml.NewDecoder(r)
 Loop:
 	for {
 		// Sniff the next token on the stream.
@@ -162,14 +167,14 @@
 			obj = &Presence{}
 		default:
 			obj = &Generic{}
-			if Log != nil && Loglevel >= syslog.LOG_NOTICE {
+			if Log != nil && Loglevel >= LOG_NOTICE {
 				Log.Printf("Ignoring unrecognized: %s %s",
 					se.Name.Space, se.Name.Local)
 			}
 		}
 
 		// Read the complete XML stanza.
-		err = p.Unmarshal(obj, &se)
+		err = p.DecodeElement(obj, &se)
 		if err != nil {
 			if Log != nil {
 				Log.Println("unmarshal: " + err.Error())
@@ -200,7 +205,7 @@
 	// Now parse the stanza's innerxml to find the string that we
 	// can unmarshal this nested element from.
 	reader := strings.NewReader(st.innerxml())
-	p := xml.NewParser(reader)
+	p := xml.NewDecoder(reader)
 	for {
 		t, err := p.Token()
 		if err == io.EOF {
@@ -216,7 +221,7 @@
 
 				// Unmarshal the nested element and
 				// stuff it back into the stanza.
-				err := p.Unmarshal(nested, &se)
+				err := p.DecodeElement(nested, &se)
 				if err != nil {
 					return err
 				}
@@ -229,7 +234,7 @@
 }
 
 func writeXml(w io.Writer, ch <-chan interface{}) {
-	if Loglevel >= syslog.LOG_DEBUG {
+	if Loglevel >= LOG_DEBUG {
 		pr, pw := io.Pipe()
 		go tee(pr, w, "C: ")
 		w = pw
@@ -241,7 +246,7 @@
 	}(w)
 
 	for obj := range ch {
-		err := xml.Marshal(w, obj)
+		err := xml.NewEncoder(w).Encode(obj)
 		if err != nil {
 			if Log != nil {
 				Log.Println("write: " + err.Error())
@@ -284,7 +289,7 @@
 			}
 			st, ok := x.(Stanza)
 			if !ok {
-				if Log != nil && Loglevel >= syslog.LOG_WARNING {
+				if Log != nil && Loglevel >= LOG_WARNING {
 					Log.Printf(
 						"Unhandled non-stanza: %v", x)
 				}
@@ -328,7 +333,7 @@
 				break Loop
 			}
 			if x == nil {
-				if Log != nil && Loglevel >= syslog.LOG_NOTICE {
+				if Log != nil && Loglevel >= LOG_NOTICE {
 					Log.Println("Refusing to send" +
 						" nil stanza")
 				}
@@ -349,7 +354,7 @@
 		select {
 		case newFilterOut := <-filterOut:
 			if newFilterOut == nil {
-				if Log != nil && Loglevel >= syslog.LOG_WARNING {
+				if Log != nil && Loglevel >= LOG_WARNING {
 					Log.Println("Received nil filter")
 				}
 				filterIn <- nil
@@ -378,7 +383,7 @@
 }
 
 func (cl *Client) handleStreamError(se *streamError) {
-	if Log != nil && Loglevel >= syslog.LOG_NOTICE {
+	if Log != nil && Loglevel >= LOG_NOTICE {
 		Log.Printf("Received stream error: %v", se)
 	}
 	close(cl.Out)
@@ -428,11 +433,7 @@
 	cl.socket = tls
 	cl.socketSync.Wait()
 
-	// Reset the read timeout on the (underlying) socket so the
-	// reader doesn't get woken up unnecessarily.
-	tcp.SetReadTimeout(0)
-
-	if Log != nil && Loglevel >= syslog.LOG_INFO {
+	if Log != nil && Loglevel >= LOG_INFO {
 		Log.Println("TLS negotiation succeeded.")
 	}
 	cl.Features = nil
@@ -470,8 +471,7 @@
 	}
 
 	if external {
-		auth := &auth{XMLName: xml.Name{Space: NsSASL, Local:
-				"auth"}, Mechanism: "EXTERNAL"}
+		auth := &auth{XMLName: xml.Name{Space: NsSASL, Local: "auth"}, Mechanism: "EXTERNAL"}
 		cl.xmlOut <- auth
 	} else if digestMd5 {
 		auth := &auth{XMLName: xml.Name{Space: NsSASL, Local: "auth"}, Mechanism: "DIGEST-MD5"}
@@ -479,17 +479,15 @@
 	} else {
 		if Log != nil {
 			buf := bytes.NewBuffer(nil)
-			xml.Marshal(buf, fe)
+			xml.NewEncoder(buf).Encode(fe)
 			Log.Printf("No supported mechanisms: %s",
 				buf.String())
 		}
 		abort := Generic{XMLName: xml.Name{Local: "abort",
 			Space: NsSASL}}
 		cl.xmlOut <- abort
-		se := streamError{Any: Generic{XMLName:
-				xml.Name{Local: "undefined-condition",
-				Space: NsStreams}}, Text:
-			&errText{Lang: "en", Text: "No supported mechs"}}
+		se := streamError{Any: Generic{XMLName: xml.Name{Local: "undefined-condition",
+			Space: NsStreams}}, Text: &errText{Lang: "en", Text: "No supported mechs"}}
 		cl.xmlOut <- se
 		close(cl.xmlOut)
 	}
@@ -515,11 +513,11 @@
 			cl.saslDigest2(srvMap)
 		}
 	case "failure":
-		if Log != nil && Loglevel >= syslog.LOG_NOTICE {
+		if Log != nil && Loglevel >= LOG_NOTICE {
 			Log.Println("SASL authentication failed")
 		}
 	case "success":
-		if Log != nil && Loglevel >= syslog.LOG_INFO {
+		if Log != nil && Loglevel >= LOG_INFO {
 			Log.Println("Sasl authentication succeeded")
 		}
 		cl.Features = nil
@@ -708,7 +706,7 @@
 			return false
 		}
 		cl.Jid = *jid
-		if Log != nil && Loglevel >= syslog.LOG_INFO {
+		if Log != nil && Loglevel >= LOG_INFO {
 			Log.Println("Bound resource: " + cl.Jid.String())
 		}
 		cl.bindDone()
--- a/structs.go	Mon Jan 23 21:58:53 2012 -0700
+++ b/structs.go	Sun Apr 15 11:20:55 2012 -0600
@@ -31,6 +31,7 @@
 
 // XMPP's <stream:stream> XML element
 type stream struct {
+	XMLName xml.Name `xml:"stream stream"`
 	To      string `xml:"to,attr"`
 	From    string `xml:"from,attr"`
 	Id      string `xml:"id,attr"`
@@ -38,30 +39,26 @@
 	Version string `xml:"version,attr"`
 }
 
-var _ xml.Marshaler = &stream{}
 var _ fmt.Stringer = &stream{}
 
 // <stream:error>
 type streamError struct {
-	Any  Generic `xml:",any"`
+	Any  Generic  `xml:",any"`
 	Text *errText `xml:"text"`
 }
 
-var _ xml.Marshaler = &streamError{}
-
 type errText struct {
+	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-streams text"`
 	Lang string `xml:"lang,attr"`
 	Text string `xml:",chardata"`
 }
 
-var _ xml.Marshaler = &errText{}
-
 type Features struct {
 	Starttls   *starttls `xml:"starttls"`
-	Mechanisms mechs `xml:"mechanisms"`
-	Bind       *bindIq `xml:"bind"`
-	Session    *Generic `xml:"session"`
-	Any        *Generic `xml:",any"`
+	Mechanisms mechs     `xml:"mechanisms"`
+	Bind       *bindIq   `xml:"bind"`
+	Session    *Generic  `xml:"session"`
+	Any        *Generic  `xml:",any"`
 }
 
 type starttls struct {
@@ -75,8 +72,8 @@
 
 type auth struct {
 	XMLName   xml.Name
-	Chardata  string `xml:",chardata"`
-	Mechanism string `xml:"mechanism,attr"`
+	Chardata  string   `xml:",chardata"`
+	Mechanism string   `xml:"mechanism,attr"`
 	Any       *Generic `xml:",any"`
 }
 
@@ -106,53 +103,53 @@
 
 // message stanza
 type Message struct {
-	To       string `xml:"to,attr"`
-	From     string `xml:"from,attr"`
-	Id       string `xml:"id,attr"`
-	Type     string `xml:"type,attr"`
-	Lang     string `xml:"lang,attr"`
-	Innerxml string `xml:",innerxml"`
-	Error    *Error `xml:"error"`
+	XMLName  xml.Name `xml:"message"`
+	To       string   `xml:"to,attr,omitempty"`
+	From     string   `xml:"from,attr,omitempty"`
+	Id       string   `xml:"id,attr,omitempty"`
+	Type     string   `xml:"type,attr,omitempty"`
+	Lang     string   `xml:"lang,attr,omitempty"`
+	Innerxml string   `xml:",innerxml"`
+	Error    *Error   `xml:"error"`
 	Subject  *Generic `xml:"subject"`
 	Body     *Generic `xml:"body"`
 	Thread   *Generic `xml:"thread"`
 	Nested   []interface{}
 }
 
-var _ xml.Marshaler = &Message{}
 var _ Stanza = &Message{}
 
 // presence stanza
 type Presence struct {
-	To       string `xml:"to,attr"`
-	From     string `xml:"from,attr"`
-	Id       string `xml:"id,attr"`
-	Type     string `xml:"type,attr"`
-	Lang     string `xml:"lang,attr"`
-	Innerxml string `xml:",innerxml"`
-	Error    *Error `xml:"error"`
+	XMLName  xml.Name `xml:"presence"`
+	To       string   `xml:"to,attr,omitempty"`
+	From     string   `xml:"from,attr,omitempty"`
+	Id       string   `xml:"id,attr,omitempty"`
+	Type     string   `xml:"type,attr,omitempty"`
+	Lang     string   `xml:"lang,attr,omitempty"`
+	Innerxml string   `xml:",innerxml"`
+	Error    *Error   `xml:"error"`
 	Show     *Generic `xml:"show"`
 	Status   *Generic `xml:"status"`
 	Priority *Generic `xml:"priority"`
 	Nested   []interface{}
 }
 
-var _ xml.Marshaler = &Presence{}
 var _ Stanza = &Presence{}
 
 // iq stanza
 type Iq struct {
-	To       string `xml:"to,attr"`
-	From     string `xml:"from,attr"`
-	Id       string `xml:"id,attr"`
-	Type     string `xml:"type,attr"`
-	Lang     string `xml:"lang,attr"`
+	XMLName  xml.Name `xml:"iq"`
+	To       string `xml:"to,attr,omitempty"`
+	From     string `xml:"from,attr,omitempty"`
+	Id       string `xml:"id,attr,omitempty"`
+	Type     string `xml:"type,attr,omitempty"`
+	Lang     string `xml:"xml lang,attr,omitempty"`
 	Innerxml string `xml:",innerxml"`
 	Error    *Error `xml:"error"`
 	Nested   []interface{}
 }
 
-var _ xml.Marshaler = &Iq{}
 var _ Stanza = &Iq{}
 
 // Describes an XMPP stanza error. See RFC 3920, Section 9.3.
@@ -177,7 +174,7 @@
 type Generic struct {
 	XMLName  xml.Name
 	Any      *Generic `xml:",any"`
-	Chardata string `xml:",chardata"`
+	Chardata string   `xml:",chardata"`
 }
 
 var _ fmt.Stringer = &Generic{}
@@ -207,24 +204,16 @@
 	return nil
 }
 
-func (s *stream) MarshalXML() ([]byte, error) {
+func (s *stream) String() string {
 	buf := bytes.NewBuffer(nil)
 	buf.WriteString("<stream:stream")
-	writeField(buf, "xmlns", "jabber:client")
-	writeField(buf, "xmlns:stream", NsStream)
 	writeField(buf, "to", s.To)
 	writeField(buf, "from", s.From)
 	writeField(buf, "id", s.Id)
 	writeField(buf, "xml:lang", s.Lang)
 	writeField(buf, "version", s.Version)
 	buf.WriteString(">")
-	// We never write </stream:stream>
-	return buf.Bytes(), nil
-}
-
-func (s *stream) String() string {
-	result, _ := s.MarshalXML()
-	return string(result)
+	return buf.String()
 }
 
 func parseStream(se xml.StartElement) (*stream, error) {
@@ -246,28 +235,6 @@
 	return s, nil
 }
 
-func (s *streamError) MarshalXML() ([]byte, error) {
-	buf := bytes.NewBuffer(nil)
-	buf.WriteString("<stream:error>")
-	xml.Marshal(buf, s.Any)
-	if s.Text != nil {
-		xml.Marshal(buf, s.Text)
-	}
-	buf.WriteString("</stream:error>")
-	return buf.Bytes(), nil
-}
-
-func (e *errText) MarshalXML() ([]byte, error) {
-	buf := bytes.NewBuffer(nil)
-	buf.WriteString("<text")
-	writeField(buf, "xmlns", NsStreams)
-	writeField(buf, "xml:lang", e.Lang)
-	buf.WriteString(">")
-	xml.Escape(buf, []byte(e.Text))
-	buf.WriteString("</text>")
-	return buf.Bytes(), nil
-}
-
 func writeField(w io.Writer, field, value string) {
 	if value != "" {
 		io.WriteString(w, " ")
@@ -291,72 +258,9 @@
 		u.XMLName.Local)
 }
 
-func marshalXML(st Stanza) ([]byte, error) {
-	buf := bytes.NewBuffer(nil)
-	buf.WriteString("<")
-	buf.WriteString(st.GetName())
-	if st.GetTo() != "" {
-		writeField(buf, "to", st.GetTo())
-	}
-	if st.GetFrom() != "" {
-		writeField(buf, "from", st.GetFrom())
-	}
-	if st.GetId() != "" {
-		writeField(buf, "id", st.GetId())
-	}
-	if st.GetType() != "" {
-		writeField(buf, "type", st.GetType())
-	}
-	if st.GetLang() != "" {
-		writeField(buf, "xml:lang", st.GetLang())
-	}
-	buf.WriteString(">")
-
-	if m, ok := st.(*Message); ok {
-		err := xml.Marshal(buf, m.Subject)
-		if err != nil {
-			return nil, err
-		}
-		err = xml.Marshal(buf, m.Body)
-		if err != nil {
-			return nil, err
-		}
-		err = xml.Marshal(buf, m.Thread)
-		if err != nil {
-			return nil, err
-		}
-	}
-	if p, ok := st.(*Presence); ok {
-		err := xml.Marshal(buf, p.Show)
-		if err != nil {
-			return nil, err
-		}
-		err = xml.Marshal(buf, p.Status)
-		if err != nil {
-			return nil, err
-		}
-		err = xml.Marshal(buf, p.Priority)
-		if err != nil {
-			return nil, err
-		}
-	}
-	if nested := st.GetNested(); nested != nil {
-		for _, n := range nested {
-			xml.Marshal(buf, n)
-		}
-	} else if st.innerxml() != "" {
-		buf.WriteString(st.innerxml())
-	}
-
-	buf.WriteString("</")
-	buf.WriteString(st.GetName())
-	buf.WriteString(">")
-	return buf.Bytes(), nil
-}
-
 func (er *Error) Error() string {
 	buf := bytes.NewBuffer(nil)
-	xml.Marshal(buf, er)
+	xml.NewEncoder(buf).Encode(er)
 	return buf.String()
 }
 
@@ -400,10 +304,6 @@
 	return m.Innerxml
 }
 
-func (m *Message) MarshalXML() ([]byte, error) {
-	return marshalXML(m)
-}
-
 func (p *Presence) GetName() string {
 	return "presence"
 }
@@ -444,10 +344,6 @@
 	return p.Innerxml
 }
 
-func (p *Presence) MarshalXML() ([]byte, error) {
-	return marshalXML(p)
-}
-
 func (iq *Iq) GetName() string {
 	return "iq"
 }
@@ -488,15 +384,11 @@
 	return iq.Innerxml
 }
 
-func (iq *Iq) MarshalXML() ([]byte, 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, error) {
 	r := strings.NewReader(str)
-	p := xml.NewParser(r)
+	p := xml.NewDecoder(r)
 	tok, err := p.Token()
 	if err != nil {
 		return nil, err
@@ -516,7 +408,7 @@
 	default:
 		return nil, errors.New("Not iq, message, or presence")
 	}
-	err = p.Unmarshal(stan, &se)
+	err = p.DecodeElement(stan, &se)
 	if err != nil {
 		return nil, err
 	}
--- a/structs_test.go	Mon Jan 23 21:58:53 2012 -0700
+++ b/structs_test.go	Sun Apr 15 11:20:55 2012 -0600
@@ -44,7 +44,7 @@
 
 func assertMarshal(t *testing.T, expected string, marshal interface{}) {
 	buf := bytes.NewBuffer(nil)
-	xml.Marshal(buf, marshal)
+	xml.NewEncoder(buf).Encode(marshal)
 	observed := string(buf.Bytes())
 	assertEquals(t, expected, observed)
 }
--- a/xmpp.go	Mon Jan 23 21:58:53 2012 -0700
+++ b/xmpp.go	Sun Apr 15 11:20:55 2012 -0600
@@ -14,7 +14,6 @@
 	"fmt"
 	"io"
 	"log"
-	"log/syslog"
 	"net"
 	"sync"
 )
@@ -37,12 +36,26 @@
 	clientSrv = "xmpp-client"
 )
 
+// This is copied from log/syslog, because that's not implemented on
+// Windows.
+type Priority int
+const (
+	LOG_EMERG Priority = iota
+	LOG_ALERT
+	LOG_CRIT
+	LOG_ERR
+	LOG_WARNING
+	LOG_NOTICE
+	LOG_INFO
+	LOG_DEBUG
+)
+
 var (
 	// If non-nil when NewClient() is called, log messages will be
 	// sent to this writer.
 	Log *log.Logger
 	// Threshold for which messages are logged.
-	Loglevel syslog.Priority = syslog.LOG_NOTICE
+	Loglevel Priority = LOG_NOTICE
 	// Use this Config to negotiate TLS connections.
 	TLSConfig *tls.Config = nil
 )