~samwhited/xmpp

0a0100885fc174ff8e259764f77f167f9286f732 — Sam Whited 5 years ago b364d21
Add an experimental stanza error interface
8 files changed, 170 insertions(+), 38 deletions(-)

A clienttest.go
M errors.go
M errors_test.go
A errortype_string.go
D example_test.go
A servertest.go
M stanza.go
A websocket.go
A clienttest.go => clienttest.go +27 -0
@@ 0,0 1,27 @@
// Copyright 2016 Sam Whited.
// Use of this source code is governed by the BSD 2-clause license that can be
// found in the LICENSE file.

// +build ignore

package main

import (
	"log"
	"os"

	"bitbucket.org/mellium/xmpp/client"
	"bitbucket.org/mellium/xmpp/jid"
)

func main() {
	j, err := jid.ParseString("sam@samwhited.com")
	if err != nil {
		log.Fatal(err)
	}

	c := client.New(j,
		client.Logger(log.New(os.Stderr, "", log.LstdFlags)))
	c.Connect("test")
	// c.Process()
}

M errors.go => errors.go +39 -14
@@ 6,25 6,50 @@ package xmpp

import (
	"encoding/xml"

	"bitbucket.org/mellium/xmpp/jid"
)

// New returns an error that formats as the given text and marshals with the
// given XML name and with the text as chardata.
// func Error(name xml.Name, text string) error {
// 	return &ErrorXML{
// 		XMLName:  name,
// 		CharData: text,
// 	}
// }
//go:generate stringer -type=errorType

type errorType int

const (
	// An error with type Auth indicates that an operation should be retried after
	// providing credentials.
	Auth errorType = iota

	// An error with type Cancel indicates that the error cannot be remedied and
	// the operation should not be retried.
	Cancel

	// An error with type Continue indicates that the operation can proceed (the
	// condition was only a warning).
	Continue

	// An error with type Modify indicates that the operation can be retried after
	// changing the data sent.
	Modify

	// An error with type Wait is temporary and may be retried after waiting.
	Wait
)

// Error is a trivial implementation of error intended to be marshalable and
// StanzaError is an implementation of error intended to be marshalable and
// unmarshalable as XML.
type Error struct {
	XMLName  xml.Name
type StanzaError struct {
	XMLName   xml.Name
	By        jid.JID `xml:"by,attr,omitempty"`
	Type      string  `xml:"type,attr"`
	Condition string  `xml:"-"`
	Text      struct {
		Lang     string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
		CharData string `xml:",chardata"`
	} `xml:"text urn:ietf:params:xml:ns:xmpp-stanzas"`
	InnerXML string `xml:",innerxml"`
}

// Satisfies the error interface and returns the error string.
func (e Error) Error() string {
	return e.InnerXML
// Error satisfies the error interface and returns the condition.
func (e StanzaError) Error() string {
	return e.Condition
}

M errors_test.go => errors_test.go +2 -2
@@ 4,5 4,5 @@

package xmpp

var _ error = (*Error)(nil)
var _ error = Error{}
var _ error = (*StanzaError)(nil)
var _ error = StanzaError{}

A errortype_string.go => errortype_string.go +16 -0
@@ 0,0 1,16 @@
// Code generated by "stringer -type=errorType"; DO NOT EDIT

package xmpp

import "fmt"

const _errorType_name = "AuthCancelContinueModifyWait"

var _errorType_index = [...]uint8{0, 4, 10, 18, 24, 28}

func (i errorType) String() string {
	if i < 0 || i >= errorType(len(_errorType_index)-1) {
		return fmt.Sprintf("errorType(%d)", i)
	}
	return _errorType_name[_errorType_index[i]:_errorType_index[i+1]]
}

D example_test.go => example_test.go +0 -21
@@ 1,21 0,0 @@
// Copyright 2016 Sam Whited.
// Use of this source code is governed by the BSD 2-clause license that can be
// found in the LICENSE file.

package xmpp

import (
	"encoding/xml"
	"fmt"
)

func ExampleError() {
	e := Error{
		xml.Name{"http://example.net", "comedy"},
		"There was a comedy of errors.",
	}
	b, _ := xml.Marshal(e)
	fmt.Println(string(b))
	// Output:
	// <comedy xmlns="http://example.net">There was a comedy of errors.</comedy>
}

A servertest.go => servertest.go +24 -0
@@ 0,0 1,24 @@
// Copyright 2015 Sam Whited.
// Use of this source code is governed by the BSD 2-clause license that can be
// found in the LICENSE file.

// +build ignore

package main

import (
	"fmt"
	"os"

	"bitbucket.org/mellium/xmpp"
	"bitbucket.org/mellium/xmpp/server"
)

func main() {
	st := xmpp.Stanza{ID: "Test"}
	m := xmpp.Message{xmpp.Stanza{ID: "TestM"}}
	fmt.Printf("%+v, %+v\n", m, st)
	os.Exit(0)
	s := server.New()
	s.ListenAndServe()
}

M stanza.go => stanza.go +4 -1
@@ 17,7 17,7 @@ type stanza struct {
	Inner string  `xml:",innerxml"`
	To    jid.JID `xml:"to,attr"`
	From  jid.JID `xml:"from,attr"`
	Lang  string  `xml:"xml:lang,attr"`
	Lang  string  `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
}

// Message is an XMPP stanza that contains a payload for direct one-to-one


@@ 26,6 26,7 @@ type stanza struct {
// alerts that don't require a response.
type Message struct {
	stanza

	XMLName xml.Name `xml:"message"`
}



@@ 35,6 36,7 @@ type Message struct {
// (one-to-one), or as a broadcast mechanism (one-to-many).
type Presence struct {
	stanza

	XMLName xml.Name `xml:"presence"`
}



@@ 43,5 45,6 @@ type Presence struct {
// response in the form of a result or an error.
type IQ struct {
	stanza

	XMLName xml.Name `xml:"iq"`
}

A websocket.go => websocket.go +58 -0
@@ 0,0 1,58 @@
// Copyright 2016 Sam Whited.
// Use of this source code is governed by the BSD 2-clause license that can be
// found in the LICENSE file.

package xmpp

import (
	"encoding/xml"

	"bitbucket.org/mellium/xmpp/jid"
	"golang.org/x/net/websocket"
	"golang.org/x/text/language"
)

// Open is a struct that can be marshaled and unmarshaled into a valid
// <open/> element to start a websockets session.
type Open struct {
	XMLName xml.Name     `xml:"urn:ietf:params:xml:ns:xmpp-framing open"`
	To      jid.JID      `xml:"to,attr"`
	From    jid.JID      `xml:"from,attr,omitempty"`
	Version string       `xml:"version,attr,omitempty"`
	Lang    language.Tag `xml:"http://www.w3.org/XML/1998/namespace lang,attr"`
	Id      string       `xml:"id,attr,omitempty"`
}

func (o *Open) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	return nil
}

func (o *Open) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	return e.Encode(struct {
		Open

		Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr"`
	}{
		Open: *o,
		Lang: o.Lang.String(),
	})
}

// Close is a struct that can be marshaled and unmarshaled into a valid
// <close/> element to end a websockets session.
type Close struct {
	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-framing close"`
}

// Codec returns a websocket codec for framing an XMPP session that is RFC 7395
// compliant.
func Codec() websocket.Codec {
	return websocket.Codec{
		Marshal: func(v interface{}) (data []byte, payloadType byte, err error) {
			return []byte{}, 0, nil
		},
		Unmarshal: func(data []byte, payloadType byte, v interface{}) (err error) {
			return nil
		},
	}
}