func (rtm *RTM) handleEvents(keepRunning chan bool, interval time.Duration) {
	ticker := time.NewTicker(interval)
	defer ticker.Stop()
	for {
		select {
		case intentional := <-rtm.killChannel:
			_ = rtm.killConnection(keepRunning, intentional)
			return
		case <-ticker.C:
			err := rtm.ping()
			if err != nil {
				_ = rtm.killConnection(keepRunning, false)
				return
			}
		case <-rtm.forcePing:
			err := rtm.ping()
			if err != nil {
				_ = rtm.killConnection(keepRunning, false)
				return
			}
		case msg := <-rtm.outgoingMessages:
			rtm.sendOutgoingMessage(msg)
		case rawEvent := <-rtm.rawEvents:
			rtm.handleRawEvent(rawEvent)
		}
	}
}
handleEvents is a blocking function that handles all events. This sends
pings when asked to (on rtm.forcePing) and upon every given elapsed
interval. This also sends outgoing messages that are received from the RTM's
outgoingMessages channel. This also handles incoming raw events from the RTM
rawEvents channel.
package slack
import (
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"time"
	"golang.org/x/net/websocket"
)
func (rtm *RTM) ManageConnection() {
	var connectionCount int
	for {
		connectionCount++
		info, conn, err := rtm.connect(connectionCount)
		if err != nil {
			return
		}
		rtm.info = info
		rtm.IncomingEvents <- RTMEvent{"connected", &ConnectedEvent{
			ConnectionCount: connectionCount,
			Info:            info,
		}}
		rtm.conn = conn
		rtm.isConnected = true
		keepRunning := make(chan bool)
		go rtm.handleIncomingEvents(keepRunning)
		rtm.handleEvents(keepRunning, 30*time.Second)
		if rtm.wasIntentional {
			return
		}
	}
}
func (rtm *RTM) connect(connectionCount int) (*Info, *websocket.Conn, error) {
	boff := &backoff{
		Min:    100 * time.Millisecond,
		Max:    5 * time.Minute,
		Factor: 2,
		Jitter: true,
	}
	for {
		rtm.IncomingEvents <- RTMEvent{"connecting", &ConnectingEvent{
			Attempt:         boff.attempts + 1,
			ConnectionCount: connectionCount,
		}}
		info, conn, err := rtm.startRTMAndDial()
		if err == nil {
			return info, conn, nil
		}
		if sErr, ok := err.(*WebError); ok && (sErr.Error() == "invalid_auth" || sErr.Error() == "account_inactive") {
			rtm.IncomingEvents <- RTMEvent{"invalid_auth", &InvalidAuthEvent{}}
			return nil, nil, sErr
		}
		rtm.IncomingEvents <- RTMEvent{"connection_error", &ConnectionErrorEvent{
			Attempt:  boff.attempts,
			ErrorObj: err,
		}}
		dur := boff.Duration()
		rtm.Debugf("reconnection %d failed: %s", boff.attempts+1, err)
		rtm.Debugln(" -> reconnecting in", dur)
		time.Sleep(dur)
	}
}
func (rtm *RTM) startRTMAndDial() (*Info, *websocket.Conn, error) {
	info, url, err := rtm.StartRTM()
	if err != nil {
		return nil, nil, err
	}
	conn, err := websocketProxyDial(url, "http://api.slack.com")
	if err != nil {
		return nil, nil, err
	}
	return info, conn, err
}
func (rtm *RTM) killConnection(keepRunning chan bool, intentional bool) error {
	rtm.Debugln("killing connection")
	if rtm.isConnected {
		close(keepRunning)
	}
	rtm.isConnected = false
	rtm.wasIntentional = intentional
	err := rtm.conn.Close()
	rtm.IncomingEvents <- RTMEvent{"disconnected", &DisconnectedEvent{intentional}}
	return err
}