diff --git a/client.go b/client.go
index 752a983..301e922 100644
--- a/client.go
+++ b/client.go
@@ -19,15 +19,15 @@ func main() {
// Create stream and configure it as a client connection.
jid := must(xmpp.ParseJID(*jid)).(xmpp.JID)
stream := must(xmpp.NewStream(jid.Domain + ":5222", &xmpp.StreamConfig{LogStanzas: true})).(*xmpp.Stream)
- x := must(xmpp.NewClientXMPP(stream, jid, *password, &xmpp.ClientConfig{InsecureSkipVerify: true})).(*xmpp.XMPP)
+ client := must(xmpp.NewClientXMPP(stream, jid, *password, &xmpp.ClientConfig{InsecureSkipVerify: true})).(*xmpp.XMPP)
- log.Printf("Connection established for %s\n", x.JID)
+ log.Printf("Connection established for %s\n", client.JID)
// Announce presence.
- x.Send(xmpp.Presence{})
+ client.Out <- xmpp.Presence{}
// Filter messages into dedicated channel and start a goroutine to log them.
- _, messages := x.AddFilter(
+ _, messages := client.AddFilter(
xmpp.MatcherFunc(
func(v interface{}) bool {
_, ok := v.(*xmpp.Message)
@@ -43,20 +43,16 @@ func main() {
// Log any stanzas that are not handled elsewhere.
go func() {
- for {
- stanza, err := x.Recv()
- if err != nil {
- log.Fatal(err)
- }
- log.Printf("* recv: %v\n", stanza)
+ for x := range client.In {
+ log.Printf("* recv: %v\n", x)
}
}()
// Get disco#info for home server.
info := &DiscoInfo{}
- iq := xmpp.Iq{Id: xmpp.UUID4(), Type: "get", To: x.JID.Domain}
+ iq := xmpp.Iq{Id: xmpp.UUID4(), Type: "get", To: client.JID.Domain}
iq.PayloadEncode(info)
- reply, _ := x.SendRecv(&iq)
+ reply, _ := client.SendRecv(&iq)
reply.PayloadDecode(info)
log.Printf("* info: %v\n", info)
diff --git a/component.go b/component.go
index 449c8e4..4a2723a 100644
--- a/component.go
+++ b/component.go
@@ -19,14 +19,10 @@ func main() {
// Create stream and configure it as a component connection.
jid := must(xmpp.ParseJID(*jid)).(xmpp.JID)
stream := must(xmpp.NewStream(*addr, &xmpp.StreamConfig{LogStanzas: true})).(*xmpp.Stream)
- x := must(xmpp.NewComponentXMPP(stream, jid, *secret)).(*xmpp.XMPP)
+ comp := must(xmpp.NewComponentXMPP(stream, jid, *secret)).(*xmpp.XMPP)
- for {
- v, err := x.Recv()
- if err != nil {
- log.Fatal(err)
- }
- log.Printf("recv: %v", v)
+ for x := range comp.In {
+ log.Printf("recv: %v", x)
}
}
diff --git a/src/xmpp/doc.go b/src/xmpp/doc.go
index c131748..27d38f1 100644
--- a/src/xmpp/doc.go
+++ b/src/xmpp/doc.go
@@ -21,22 +21,30 @@
stream, err := xmpp.NewStream("localhost:5347", nil)
X, err := xmpp.NewComponentXMPP(stream, jid, "secret")
- Messages are sent using the XMPP.Send method, e.g. a client typically
- announces its presence on the XMPP network as soon as it's connected:
+ Outgoing XMPP stanzas are sent to the XMPP instance's Out channel, e.g. a
+ client typically announces its presence on the XMPP network as soon as it's
+ connected:
- X.Send(xmpp.Presence{})
+ X.Out <- xmpp.Presence{}
- Incoming messages can be received in a simple loop, ended by an os.EOF for
- clean shutdown or any other error for something unexpected. XMPP defines
- four types of stanza: , , and
- represented by Error, Iq, Message and Presence structs respectively.
+ Incoming messages are handled by consuming the XMPP instance's In channel.
+ The channel is sent all XMPP stanzas as well as terminating error (io.EOF
+ for clean shutdown or any other error for something unexpected). The
+ channel is also closed after an error.
+
+ XMPP defines four types of stanza: , , and
+ represented by Error, Iq, Message (shown below) and Presence
+ structs respectively.
- for {
- stanza, err := X.Recv()
- if err == io.EOF {
- break
+ for i := range X.In {
+ switch v := i.(type) {
+ case error:
+ log.Printf("error : %v\n", v)
+ case *xmpp.Message:
+ log.Printf("msg : %s says %s\n", v.From, v.Body)
+ default:
+ log.Printf("%T : %v\n", v, v)
}
- log.Printf("%T : %v\n", stanza, stanza)
}
Note: A "bound" JID is negotatiated during XMPP setup and may be different
diff --git a/src/xmpp/xmpp.go b/src/xmpp/xmpp.go
index 5994d41..5f79df0 100644
--- a/src/xmpp/xmpp.go
+++ b/src/xmpp/xmpp.go
@@ -9,14 +9,21 @@ import (
// Handles XMPP conversations over a Stream. Use NewClientXMPP or
// NewComponentXMPP to create and configure a XMPP instance.
type XMPP struct {
+
// JID associated with the stream. Note: this may be negotiated with the
// server during setup and so must be used for all messages.
JID JID
stream *Stream
- // Stanza channels.
- in chan interface{}
- out chan interface{}
+ // Channel of incoming messages. Values will be one of Iq, Message,
+ // Presence, Error or error. Will be closed at the end when the stream is
+ // closed or the stream's net connection dies.
+ In chan interface{}
+
+ // Channel of outgoing messages. Messages must be able to be marshaled by
+ // the standard xml package, however you should try to send one of Iq,
+ // Message or Presence.
+ Out chan interface{}
// Incoming stanza filters.
filterLock sync.Mutex
@@ -28,34 +35,20 @@ func newXMPP(jid JID, stream *Stream) *XMPP {
x := &XMPP{
JID: jid,
stream: stream,
- in: make(chan interface{}),
- out: make(chan interface{}),
+ In: make(chan interface{}),
+ Out: make(chan interface{}),
}
go x.sender()
go x.receiver()
return x
}
-// Send a stanza.
-func (x *XMPP) Send(v interface{}) {
- x.out <- v
-}
-
-// Return the next stanza.
-func (x *XMPP) Recv() (interface{}, error) {
- v := <-x.in
- if err, ok := v.(error); ok {
- return nil, err
- }
- return v, nil
-}
-
func (x *XMPP) SendRecv(iq *Iq) (*Iq, error) {
fid, ch := x.AddFilter(IqResult(iq.Id))
defer x.RemoveFilter(fid)
- x.Send(iq)
+ x.Out <- iq
stanza := <-ch
reply, ok := stanza.(*Iq)
@@ -156,19 +149,19 @@ type filter struct {
}
func (x *XMPP) sender() {
- for v := range x.out {
+ for v := range x.Out {
x.stream.Send(v)
}
}
func (x *XMPP) receiver() {
- defer close(x.in)
+ defer close(x.In)
for {
start, err := x.stream.Next()
if err != nil {
- x.in <- err
+ x.In <- err
return
}
@@ -200,7 +193,7 @@ func (x *XMPP) receiver() {
}
if !filtered {
- x.in <- v
+ x.In <- v
}
}
}
diff --git a/tail.go b/tail.go
index d283090..d77aaf7 100644
--- a/tail.go
+++ b/tail.go
@@ -51,14 +51,10 @@ func main() {
}
// Signal presence.
- x.Send(xmpp.Presence{})
+ x.Out <- xmpp.Presence{}
// Log anything that arrives.
- for {
- stanza, err := x.Recv()
- if err != nil {
- log.Fatal(err)
- }
+ for stanza := range x.In {
log.Printf("recv: %T %v", stanza, stanza)
}
}