func (c *Client) Connect() error {
	err := c.connect()
	if err != nil {
		return err
	}
	err = c.sendWithWriter(c.transport, []byte(InitialPresence))
	if c.PostConnectHook != nil {
		err = c.PostConnectHook()
		if err != nil {
			return err
		}
	}
	keepaliveQuit := make(chan struct{})
	go keepalive(c.transport, c.config.KeepaliveInterval, keepaliveQuit)
	go c.recv(keepaliveQuit)
	return err
}
Connect establishes a first time connection to a XMPP server.
It calls the PostConnectHook
package xmpp
import (
	"context"
	"encoding/xml"
	"errors"
	"io"
	"net"
	"sync"
	"time"
	"gosrc.io/xmpp/stanza"
)
type SyncConnState struct {
	sync.RWMutex
	state ConnState
}
type ConnState = uint8
func (scs *SyncConnState) getState() ConnState {
	var res ConnState
	scs.RLock()
	res = scs.state
	scs.RUnlock()
	return res
}
func (scs *SyncConnState) setState(cs ConnState) {
	scs.Lock()
	scs.state = cs
	scs.Unlock()
}
const (
	StateDisconnected ConnState = iota
	StateResuming
	StateSessionEstablished
	StateStreamError
	StatePermanentError
	InitialPresence = "<presence/>"
)
type Event struct {
	State       SyncConnState
	Description string
	StreamError string
	SMState     SMState
}
type SMState struct {
	Id string
	Inbound uint
	preferredReconAddr string
	StreamErrorGroup stanza.StanzaErrorGroup
	*stanza.UnAckQueue
}
type EventHandler func(Event) error
type EventManager struct {
	CurrentState SyncConnState
	Handler EventHandler
}
func (em *EventManager) updateState(state ConnState) {
	em.CurrentState.setState(state)
	if em.Handler != nil {
		em.Handler(Event{State: em.CurrentState})
	}
}
func (em *EventManager) disconnected(state SMState) {
	em.CurrentState.setState(StateDisconnected)
	if em.Handler != nil {
		em.Handler(Event{State: em.CurrentState, SMState: state})
	}
}
func (em *EventManager) streamError(error, desc string) {
	em.CurrentState.setState(StateStreamError)
	if em.Handler != nil {
		em.Handler(Event{State: em.CurrentState, StreamError: error, Description: desc})
	}
}
var ErrCanOnlySendGetOrSetIq = errors.New("SendIQ can only send get and set IQ stanzas")
type Client struct {
	config *Config
	Session   *Session
	transport Transport
	router *Router
	EventManager
	ErrorHandler func(error)
	PostConnectHook func() error
	PostResumeHook func() error
}
func NewClient(config *Config, r *Router, errorHandler func(error)) (c *Client, err error) {
	if config.KeepaliveInterval == 0 {
		config.KeepaliveInterval = time.Second * 30
	}
	if config.parsedJid, err = stanza.NewJid(config.Jid); err != nil {
		err = errors.New("missing jid")
		return nil, NewConnError(err, true)
	}
	if config.Credential.secret == "" {
		err = errors.New("missing credential")
		return nil, NewConnError(err, true)
	}
	if config.Address == "" {
		config.Address = config.parsedJid.Domain
		_, srvEntries, err := net.LookupSRV("xmpp-client", "tcp", config.parsedJid.Domain)
		if err == nil && len(srvEntries) > 0 {
			bestSrv := srvEntries[0]
			for _, srv := range srvEntries {
				if srv.Priority <= bestSrv.Priority && srv.Weight >= bestSrv.Weight {
					bestSrv = srv
					config.Address = ensurePort(srv.Target, int(srv.Port))
				}
			}
		}
	}
	if config.Domain == "" {
		config.Domain = config.parsedJid.Domain
	}
	c = new(Client)
	c.config = config
	c.router = r
	c.ErrorHandler = errorHandler
	if c.config.ConnectTimeout == 0 {
		c.config.ConnectTimeout = 15  
	}
	if config.TransportConfiguration.Domain == "" {
		config.TransportConfiguration.Domain = config.parsedJid.Domain
	}
	c.config.TransportConfiguration.ConnectTimeout = c.config.ConnectTimeout
	c.transport = NewClientTransport(c.config.TransportConfiguration)
	if config.StreamLogger != nil {
		c.transport.LogTraffic(config.StreamLogger)
	}
	return
}