~samwhited/xmpp

c703d76a24fab9aebf8a7ea4584d53721597eb82 — Sam Whited 2 years ago e0ec5e3
xmpp: add example echobot
1 files changed, 91 insertions(+), 0 deletions(-)

A echobot_example_test.go
A echobot_example_test.go => echobot_example_test.go +91 -0
@@ 0,0 1,91 @@
package xmpp_test

import (
	"context"
	"crypto/tls"
	"encoding/xml"
	"io"
	"log"

	"mellium.im/sasl"
	"mellium.im/xmlstream"
	"mellium.im/xmpp"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/stanza"
)

const (
	login = "echo@example.net"
	pass  = "just an example don't hardcode passwords"
)

func Example_echobot() {
	j := jid.MustParse(login)
	s, err := xmpp.DialClientSession(
		context.TODO(), j, "en",
		xmpp.BindResource(),
		xmpp.StartTLS(true, &tls.Config{
			ServerName: j.Domain().String(),
		}),
		xmpp.SASL("", pass, sasl.ScramSha1Plus, sasl.ScramSha1, sasl.Plain),
	)
	if err != nil {
		log.Printf("Error establishing a session: %q", err)
		return
	}
	defer func() {
		log.Println("Closing session…")
		if err := s.Close(); err != nil {
			log.Printf("Error closing session: %q", err)
		}
		log.Println("Closing conn…")
		if err := s.Conn().Close(); err != nil {
			log.Printf("Error closing connection: %q", err)
		}
	}()

	// Send initial presence to let the server know we want to receive messages.
	_, err = xmlstream.Copy(s, stanza.WrapPresence(nil, stanza.AvailablePresence, nil))
	if err != nil {
		log.Printf("Error sending initial presence: %q", err)
		return
	}

	s.Serve(xmpp.HandlerFunc(func(t xmlstream.TokenReadWriter, start *xml.StartElement) error {
		d := xml.NewTokenDecoder(t)

		// Ignore anything that's not a message. In a real system we'd want to at
		// least respond to IQs.
		if start.Name.Local != "message" {
			return nil
		}

		msg := struct {
			stanza.Message
			Body string `xml:"body"`
		}{}
		err = d.DecodeElement(&msg, start)
		if err != nil && err != io.EOF {
			log.Printf("Error decoding message: %q", err)
			return nil
		}

		// Don't reflect messages unless they are chat messages and actually have a
		// body.
		if msg.Body == "" || msg.Type != stanza.ChatMessage {
			return nil
		}

		reply := stanza.WrapMessage(
			msg.From.Bare(), stanza.ChatMessage,
			xmlstream.Wrap(xmlstream.ReaderFunc(func() (xml.Token, error) {
				return xml.CharData(msg.Body), io.EOF
			}), xml.StartElement{Name: xml.Name{Local: "body"}}),
		)
		_, err = xmlstream.Copy(s, reply)
		if err != nil {
			log.Printf("Error responding to mid-%s: %q", msg.ID, err)
		}
		return nil
	}))
}