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) } }