|
|
@ -4,7 +4,6 @@ import (
|
|
|
|
"context"
|
|
|
|
"context"
|
|
|
|
"encoding/xml"
|
|
|
|
"encoding/xml"
|
|
|
|
"errors"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"io"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
"net"
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
@ -60,21 +59,21 @@ type EventManager struct {
|
|
|
|
Handler EventHandler
|
|
|
|
Handler EventHandler
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (em EventManager) updateState(state ConnState) {
|
|
|
|
func (em *EventManager) updateState(state ConnState) {
|
|
|
|
em.CurrentState = state
|
|
|
|
em.CurrentState = state
|
|
|
|
if em.Handler != nil {
|
|
|
|
if em.Handler != nil {
|
|
|
|
em.Handler(Event{State: em.CurrentState})
|
|
|
|
em.Handler(Event{State: em.CurrentState})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (em EventManager) disconnected(state SMState) {
|
|
|
|
func (em *EventManager) disconnected(state SMState) {
|
|
|
|
em.CurrentState = StateDisconnected
|
|
|
|
em.CurrentState = StateDisconnected
|
|
|
|
if em.Handler != nil {
|
|
|
|
if em.Handler != nil {
|
|
|
|
em.Handler(Event{State: em.CurrentState, SMState: state})
|
|
|
|
em.Handler(Event{State: em.CurrentState, SMState: state})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (em EventManager) streamError(error, desc string) {
|
|
|
|
func (em *EventManager) streamError(error, desc string) {
|
|
|
|
em.CurrentState = StateStreamError
|
|
|
|
em.CurrentState = StateStreamError
|
|
|
|
if em.Handler != nil {
|
|
|
|
if em.Handler != nil {
|
|
|
|
em.Handler(Event{State: em.CurrentState, StreamError: error, Description: desc})
|
|
|
|
em.Handler(Event{State: em.CurrentState, StreamError: error, Description: desc})
|
|
|
@ -110,6 +109,9 @@ Setting up the client / Checking the parameters
|
|
|
|
// If host is not specified, the DNS SRV should be used to find the host from the domainpart of the JID.
|
|
|
|
// If host is not specified, the DNS SRV should be used to find the host from the domainpart of the JID.
|
|
|
|
// Default the port to 5222.
|
|
|
|
// Default the port to 5222.
|
|
|
|
func NewClient(config Config, r *Router, errorHandler func(error)) (c *Client, err error) {
|
|
|
|
func NewClient(config Config, r *Router, errorHandler func(error)) (c *Client, err error) {
|
|
|
|
|
|
|
|
if config.KeepaliveInterval == 0 {
|
|
|
|
|
|
|
|
config.KeepaliveInterval = time.Second * 30
|
|
|
|
|
|
|
|
}
|
|
|
|
// Parse JID
|
|
|
|
// Parse JID
|
|
|
|
if config.parsedJid, err = NewJid(config.Jid); err != nil {
|
|
|
|
if config.parsedJid, err = NewJid(config.Jid); err != nil {
|
|
|
|
err = errors.New("missing jid")
|
|
|
|
err = errors.New("missing jid")
|
|
|
@ -188,7 +190,7 @@ func (c *Client) Resume(state SMState) error {
|
|
|
|
|
|
|
|
|
|
|
|
// Start the keepalive go routine
|
|
|
|
// Start the keepalive go routine
|
|
|
|
keepaliveQuit := make(chan struct{})
|
|
|
|
keepaliveQuit := make(chan struct{})
|
|
|
|
go keepalive(c, keepaliveQuit)
|
|
|
|
go keepalive(c.transport, c.config.KeepaliveInterval, keepaliveQuit)
|
|
|
|
// Start the receiver go routine
|
|
|
|
// Start the receiver go routine
|
|
|
|
state = c.Session.SMState
|
|
|
|
state = c.Session.SMState
|
|
|
|
go c.recv(state, keepaliveQuit)
|
|
|
|
go c.recv(state, keepaliveQuit)
|
|
|
@ -197,7 +199,7 @@ func (c *Client) Resume(state SMState) error {
|
|
|
|
//fmt.Fprintf(client.conn, "<presence xml:lang='en'><show>%s</show><status>%s</status></presence>", "chat", "Online")
|
|
|
|
//fmt.Fprintf(client.conn, "<presence xml:lang='en'><show>%s</show><status>%s</status></presence>", "chat", "Online")
|
|
|
|
// TODO: Do we always want to send initial presence automatically ?
|
|
|
|
// TODO: Do we always want to send initial presence automatically ?
|
|
|
|
// Do we need an option to avoid that or do we rely on client to send the presence itself ?
|
|
|
|
// Do we need an option to avoid that or do we rely on client to send the presence itself ?
|
|
|
|
_, err = fmt.Fprintf(c.transport, "<presence/>")
|
|
|
|
err = c.sendWithWriter(c.transport, []byte("<presence/>"))
|
|
|
|
|
|
|
|
|
|
|
|
return err
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -312,10 +314,8 @@ func (c *Client) recv(state SMState, keepaliveQuit chan<- struct{}) {
|
|
|
|
// Loop: send whitespace keepalive to server
|
|
|
|
// Loop: send whitespace keepalive to server
|
|
|
|
// This is use to keep the connection open, but also to detect connection loss
|
|
|
|
// This is use to keep the connection open, but also to detect connection loss
|
|
|
|
// and trigger proper client connection shutdown.
|
|
|
|
// and trigger proper client connection shutdown.
|
|
|
|
func keepalive(c *Client, quit <-chan struct{}) {
|
|
|
|
func keepalive(transport Transport, interval time.Duration, quit <-chan struct{}) {
|
|
|
|
// TODO: Make keepalive interval configurable
|
|
|
|
ticker := time.NewTicker(interval)
|
|
|
|
transport := c.transport
|
|
|
|
|
|
|
|
ticker := time.NewTicker(30 * time.Second)
|
|
|
|
|
|
|
|
for {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
select {
|
|
|
|
case <-ticker.C:
|
|
|
|
case <-ticker.C:
|
|
|
|