func initMetrics() *Metrics {
	return &Metrics{
		startTime: time.Now(),
	}
}
initMetrics set metrics with default value and define the starting point
for duration calculation (connect time, login time, etc).
package xmpp
import (
	"context"
	"errors"
	"sync"
	"time"
	"golang.org/x/xerrors"
	"gosrc.io/xmpp/stanza"
)
type StreamClient interface {
	Connect() error
	Resume() error
	Send(packet stanza.Packet) error
	SendIQ(ctx context.Context, iq *stanza.IQ) (chan stanza.IQ, error)
	SendRaw(packet string) error
	Disconnect() error
	SetHandler(handler EventHandler)
}
type Sender interface {
	Send(packet stanza.Packet) error
	SendIQ(ctx context.Context, iq *stanza.IQ) (chan stanza.IQ, error)
	SendRaw(packet string) error
}
type StreamManager struct {
	client      StreamClient
	PostConnect PostConnect
	Metrics *Metrics
	wg sync.WaitGroup
}
type PostConnect func(c Sender)
func NewStreamManager(client StreamClient, pc PostConnect) *StreamManager {
	return &StreamManager{
		client:      client,
		PostConnect: pc,
	}
}
func (sm *StreamManager) Run() error {
	if sm.client == nil {
		return errors.New("missing stream client")
	}
	handler := func(e Event) error {
		switch e.State.state {
		case StateSessionEstablished:
			sm.Metrics.setLoginTime()
		case StateDisconnected:
			return sm.resume()
		case StateStreamError:
			sm.client.Disconnect()
			if e.StreamError != "conflict" {
				return sm.resume()
			}
		case StatePermanentError:
		}
		return nil
	}
	sm.client.SetHandler(handler)
	sm.wg.Add(1)
	if err := sm.connect(); err != nil {
		sm.wg.Done()
		return err
	}
	sm.wg.Wait()
	return nil
}
func (sm *StreamManager) Stop() {
	sm.client.SetHandler(nil)
	sm.client.Disconnect()
	sm.wg.Done()
}
func (sm *StreamManager) connect() error {
	if sm.client != nil {
		if c, ok := sm.client.(*Client); ok {
			if c.CurrentState.getState() == StateDisconnected {
				sm.Metrics = initMetrics()
				err := c.Connect()
				if err != nil {
					return err
				}
				if sm.PostConnect != nil {
					sm.PostConnect(sm.client)
				}
				return nil
			}
		}
	}
	return errors.New("client is not disconnected")
}
func (sm *StreamManager) resume() error {
	var backoff backoff  
	for {
		var err error
		sm.Metrics = initMetrics()
		if err = sm.client.Resume(); err != nil {
			var actualErr ConnError
			if xerrors.As(err, &actualErr) {
				if actualErr.Permanent {
					return xerrors.Errorf("unrecoverable connect error %#v", actualErr)
				}
			}
			backoff.wait()
		} else {  
			break
		}
	}
	if sm.PostConnect != nil {
		sm.PostConnect(sm.client)
	}
	return nil
}
type Metrics struct {
	startTime time.Time
	LoginTime time.Duration
}