func (rtm *RTM) sendOutgoingMessage(msg OutgoingMessage) {
	rtm.Debugln("Sending message:", msg)
	if len(msg.Text) > MaxMessageTextLength {
		rtm.IncomingEvents <- RTMEvent{"outgoing_error", &MessageTooLongEvent{
			Message:   msg,
			MaxLength: MaxMessageTextLength,
		}}
		return
	}
	fmt.Println("outgoing msg", msg)
	err := websocket.JSON.Send(rtm.conn, msg)
	if err != nil {
		rtm.IncomingEvents <- RTMEvent{"outgoing_error", &OutgoingErrorEvent{
			Message:  msg,
			ErrorObj: err,
		}}
		fmt.Println("error here", err)
	}
}
sendOutgoingMessage sends the given OutgoingMessage to the slack websocket.

It does not currently detect if a outgoing message fails due to a disconnect
and instead lets a future failed 'PING' detect the failed connection.
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
}
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)
		}
	}
}
func (rtm *RTM) handleIncomingEvents(keepRunning <-chan bool) {
	for {
		select {
		case <-keepRunning:
			return
		default:
			rtm.receiveIncomingEvent()
		}
	}
}