client.go
func (c *Client) handleLine(line string) error {
	go func() {
		// Send a message on the `messageReceived` channel, but do not block in case no one is receiving on the other end
		select {
		case c.messageReceived <- true:
		default:
		}
	}()

	message := ParseMessage(line)

	switch msg := message.(type) {
	case *WhisperMessage:
		if c.onWhisperMessage != nil {
			c.onWhisperMessage(*msg)
		}
		return nil

	case *PrivateMessage:
		if c.onPrivateMessage != nil {
			c.onPrivateMessage(*msg)
		}
		return nil

	case *ClearChatMessage:
		if c.onClearChatMessage != nil {
			c.onClearChatMessage(*msg)
		}
		return nil

	case *RoomStateMessage:
		if c.onRoomStateMessage != nil {
			c.onRoomStateMessage(*msg)
		}
		return nil

	case *UserNoticeMessage:
		if c.onUserNoticeMessage != nil {
			c.onUserNoticeMessage(*msg)
		}
		return nil

	case *UserStateMessage:
		if c.onUserStateMessage != nil {
			c.onUserStateMessage(*msg)
		}
		return nil

	case *NoticeMessage:
		if c.onNoticeMessage != nil {
			c.onNoticeMessage(*msg)
		}
		return c.handleNoticeMessage(*msg)

	case *UserJoinMessage:
		if c.handleUserJoinMessage(*msg) {
			if c.onUserJoinMessage != nil {
				c.onUserJoinMessage(*msg)
			}
		}
		return nil

	case *UserPartMessage:
		if c.handleUserPartMessage(*msg) {
			if c.onUserPartMessage != nil {
				c.onUserPartMessage(*msg)
			}
		}
		return nil

	case *ReconnectMessage:
		// https://dev.twitch.tv/docs/irc/commands/#reconnect-twitch-commands
		if c.onReconnectMessage != nil {
			c.onReconnectMessage(*msg)
		}
		return errReconnect

	case *NamesMessage:
		if c.onNamesMessage != nil {
			c.onNamesMessage(*msg)
		}
		c.handleNamesMessage(*msg)
		return nil

	case *PingMessage:
		if c.onPingMessage != nil {
			c.onPingMessage(*msg)
		}
		c.handlePingMessage(*msg)
		return nil

	case *PongMessage:
		if c.onPongMessage != nil {
			c.onPongMessage(*msg)
		}
		c.handlePongMessage(*msg)
		return nil

	case *RawMessage:
		if c.onUnsetMessage != nil {
			c.onUnsetMessage(*msg)
		}
	}

	return nil
}
func (c *Client) handleLine(line string) error {
	go func() {
		// Send a message on the `messageReceived` channel, but do not block in case no one is receiving on the other end
		select {
		case c.messageReceived <- true:
		default:
		}
	}()

	message := ParseMessage(line)

	switch msg := message.(type) {
	case *WhisperMessage:
		if c.onWhisperMessage != nil {
			c.onWhisperMessage(*msg)
		}
		return nil

	case *PrivateMessage:
		if c.onPrivateMessage != nil {
			c.onPrivateMessage(*msg)
		}
		return nil

	case *ClearChatMessage:
		if c.onClearChatMessage != nil {
			c.onClearChatMessage(*msg)
		}
		return nil

	case *RoomStateMessage:
		if c.onRoomStateMessage != nil {
			c.onRoomStateMessage(*msg)
		}
		return nil

	case *UserNoticeMessage:
		if c.onUserNoticeMessage != nil {
			c.onUserNoticeMessage(*msg)
		}
		return nil

	case *UserStateMessage:
		if c.onUserStateMessage != nil {
			c.onUserStateMessage(*msg)
		}
		return nil

	case *NoticeMessage:
		if c.onNoticeMessage != nil {
			c.onNoticeMessage(*msg)
		}
		return c.handleNoticeMessage(*msg)

	case *UserJoinMessage:
		if c.handleUserJoinMessage(*msg) {
			if c.onUserJoinMessage != nil {
				c.onUserJoinMessage(*msg)
			}
		}
		return nil

	case *UserPartMessage:
		if c.handleUserPartMessage(*msg) {
			if c.onUserPartMessage != nil {
				c.onUserPartMessage(*msg)
			}
		}
		return nil

	case *ReconnectMessage:
		// https://dev.twitch.tv/docs/irc/commands/#reconnect-twitch-commands
		if c.onReconnectMessage != nil {
			c.onReconnectMessage(*msg)
		}
		return errReconnect

	case *NamesMessage:
		if c.onNamesMessage != nil {
			c.onNamesMessage(*msg)
		}
		c.handleNamesMessage(*msg)
		return nil

	case *PingMessage:
		if c.onPingMessage != nil {
			c.onPingMessage(*msg)
		}
		c.handlePingMessage(*msg)
		return nil

	case *PongMessage:
		if c.onPongMessage != nil {
			c.onPongMessage(*msg)
		}
		c.handlePongMessage(*msg)
		return nil

	case *RawMessage:
		if c.onUnsetMessage != nil {
			c.onUnsetMessage(*msg)
		}
	}

	return nil
}
// Errors returned from handleLine break out of readConnections, which starts a reconnect
// This means that we should only return fatal errors as errors here