forked from chteufleur/go-xmpp
Replace Send/Recv funcs with In/Out channels.
Basically, make the channels public and just let the client handle a
stream/net error if it's interested.
This simplifies the API a little and also allows an application to
select {} from the XMPP channel and any other channels at the same time.
This commit is contained in:
parent
e22b95e43e
commit
cc012762e9
20
client.go
20
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)
|
||||
|
||||
|
|
|
|||
10
component.go
10
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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: <error/>, <iq/>, <message/> and <presence/>
|
||||
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: <error/>, <iq/>, <message/> and
|
||||
<presence/> 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue