135 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
 | |
| // See License.txt for license information.
 | |
| 
 | |
| package model
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"github.com/gorilla/websocket"
 | |
| )
 | |
| 
 | |
| type WebSocketClient struct {
 | |
| 	Url             string          // The location of the server like "ws://localhost:8065"
 | |
| 	ApiUrl          string          // The api location of the server like "ws://localhost:8065/api/v3"
 | |
| 	Conn            *websocket.Conn // The WebSocket connection
 | |
| 	AuthToken       string          // The token used to open the WebSocket
 | |
| 	Sequence        int64           // The ever-incrementing sequence attached to each WebSocket action
 | |
| 	EventChannel    chan *WebSocketEvent
 | |
| 	ResponseChannel chan *WebSocketResponse
 | |
| 	ListenError     *AppError
 | |
| }
 | |
| 
 | |
| // NewWebSocketClient constructs a new WebSocket client with convienence
 | |
| // methods for talking to the server.
 | |
| func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
 | |
| 	conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX+"/users/websocket", nil)
 | |
| 	if err != nil {
 | |
| 		return nil, NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
 | |
| 	}
 | |
| 
 | |
| 	client := &WebSocketClient{
 | |
| 		url,
 | |
| 		url + API_URL_SUFFIX,
 | |
| 		conn,
 | |
| 		authToken,
 | |
| 		1,
 | |
| 		make(chan *WebSocketEvent, 100),
 | |
| 		make(chan *WebSocketResponse, 100),
 | |
| 		nil,
 | |
| 	}
 | |
| 
 | |
| 	client.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": authToken})
 | |
| 
 | |
| 	return client, nil
 | |
| }
 | |
| 
 | |
| func (wsc *WebSocketClient) Connect() *AppError {
 | |
| 	var err error
 | |
| 	wsc.Conn, _, err = websocket.DefaultDialer.Dial(wsc.ApiUrl+"/users/websocket", nil)
 | |
| 	if err != nil {
 | |
| 		return NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
 | |
| 	}
 | |
| 
 | |
| 	wsc.EventChannel = make(chan *WebSocketEvent, 100)
 | |
| 	wsc.ResponseChannel = make(chan *WebSocketResponse, 100)
 | |
| 
 | |
| 	wsc.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": wsc.AuthToken})
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (wsc *WebSocketClient) Close() {
 | |
| 	wsc.Conn.Close()
 | |
| }
 | |
| 
 | |
| func (wsc *WebSocketClient) Listen() {
 | |
| 	go func() {
 | |
| 		defer func() {
 | |
| 			wsc.Conn.Close()
 | |
| 			close(wsc.EventChannel)
 | |
| 			close(wsc.ResponseChannel)
 | |
| 		}()
 | |
| 
 | |
| 		for {
 | |
| 			var rawMsg json.RawMessage
 | |
| 			var err error
 | |
| 			if _, rawMsg, err = wsc.Conn.ReadMessage(); err != nil {
 | |
| 				if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
 | |
| 					wsc.ListenError = NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
 | |
| 				}
 | |
| 
 | |
| 				return
 | |
| 			}
 | |
| 
 | |
| 			var event WebSocketEvent
 | |
| 			if err := json.Unmarshal(rawMsg, &event); err == nil && event.IsValid() {
 | |
| 				wsc.EventChannel <- &event
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 			var response WebSocketResponse
 | |
| 			if err := json.Unmarshal(rawMsg, &response); err == nil && response.IsValid() {
 | |
| 				wsc.ResponseChannel <- &response
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 	}()
 | |
| }
 | |
| 
 | |
| func (wsc *WebSocketClient) SendMessage(action string, data map[string]interface{}) {
 | |
| 	req := &WebSocketRequest{}
 | |
| 	req.Seq = wsc.Sequence
 | |
| 	req.Action = action
 | |
| 	req.Data = data
 | |
| 
 | |
| 	wsc.Sequence++
 | |
| 
 | |
| 	wsc.Conn.WriteJSON(req)
 | |
| }
 | |
| 
 | |
| // UserTyping will push a user_typing event out to all connected users
 | |
| // who are in the specified channel
 | |
| func (wsc *WebSocketClient) UserTyping(channelId, parentId string) {
 | |
| 	data := map[string]interface{}{
 | |
| 		"channel_id": channelId,
 | |
| 		"parent_id":  parentId,
 | |
| 	}
 | |
| 
 | |
| 	wsc.SendMessage("user_typing", data)
 | |
| }
 | |
| 
 | |
| // GetStatuses will return a map of string statuses using user id as the key
 | |
| func (wsc *WebSocketClient) GetStatuses() {
 | |
| 	wsc.SendMessage("get_statuses", nil)
 | |
| }
 | |
| 
 | |
| // GetStatusesByIds will fetch certain user statuses based on ids and return
 | |
| // a map of string statuses using user id as the key
 | |
| func (wsc *WebSocketClient) GetStatusesByIds(userIds []string) {
 | |
| 	data := map[string]interface{}{
 | |
| 		"user_ids": userIds,
 | |
| 	}
 | |
| 	wsc.SendMessage("get_statuses_by_ids", data)
 | |
| }
 | 
