matterbridge/vendor/github.com/mattermost/platform/model/websocket_client.go

168 lines
4.9 KiB
Go
Raw Normal View History

2017-08-16 21:37:37 +00:00
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
2016-08-15 16:47:31 +00:00
// See License.txt for license information.
package model
import (
"encoding/json"
2018-02-08 23:11:04 +00:00
"net/http"
2016-08-15 16:47:31 +00:00
"github.com/gorilla/websocket"
)
2017-03-25 20:04:10 +00:00
const (
SOCKET_MAX_MESSAGE_SIZE_KB = 8 * 1024 // 8KB
)
2016-08-15 16:47:31 +00:00
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"
2017-08-16 21:37:37 +00:00
ConnectUrl string // The websocket URL to connect to like "ws://localhost:8065/api/v3/path/to/websocket"
2016-08-15 16:47:31 +00:00
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
2016-11-12 21:00:53 +00:00
ListenError *AppError
2016-08-15 16:47:31 +00:00
}
// NewWebSocketClient constructs a new WebSocket client with convienence
// methods for talking to the server.
func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
2017-03-25 20:04:10 +00:00
conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX_V3+"/users/websocket", nil)
2016-08-15 16:47:31 +00:00
if err != nil {
2018-02-08 23:11:04 +00:00
return nil, NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
2016-08-15 16:47:31 +00:00
}
2016-11-12 21:00:53 +00:00
client := &WebSocketClient{
2016-08-15 16:47:31 +00:00
url,
2017-03-25 20:04:10 +00:00
url + API_URL_SUFFIX_V3,
2017-08-16 21:37:37 +00:00
url + API_URL_SUFFIX_V3 + "/users/websocket",
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
}
// NewWebSocketClient4 constructs a new WebSocket client with convienence
// methods for talking to the server. Uses the v4 endpoint.
func NewWebSocketClient4(url, authToken string) (*WebSocketClient, *AppError) {
conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX+"/websocket", nil)
if err != nil {
2018-02-08 23:11:04 +00:00
return nil, NewAppError("NewWebSocketClient4", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
2017-08-16 21:37:37 +00:00
}
client := &WebSocketClient{
url,
url + API_URL_SUFFIX,
url + API_URL_SUFFIX + "/websocket",
2016-08-15 16:47:31 +00:00
conn,
authToken,
1,
make(chan *WebSocketEvent, 100),
make(chan *WebSocketResponse, 100),
2016-11-12 21:00:53 +00:00
nil,
}
client.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": authToken})
return client, nil
2016-08-15 16:47:31 +00:00
}
func (wsc *WebSocketClient) Connect() *AppError {
var err error
2017-08-16 21:37:37 +00:00
wsc.Conn, _, err = websocket.DefaultDialer.Dial(wsc.ConnectUrl, nil)
2016-08-15 16:47:31 +00:00
if err != nil {
2018-02-08 23:11:04 +00:00
return NewAppError("Connect", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
2016-08-15 16:47:31 +00:00
}
2016-11-12 21:00:53 +00:00
wsc.EventChannel = make(chan *WebSocketEvent, 100)
wsc.ResponseChannel = make(chan *WebSocketResponse, 100)
wsc.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": wsc.AuthToken})
2016-08-15 16:47:31 +00:00
return nil
}
func (wsc *WebSocketClient) Close() {
wsc.Conn.Close()
}
func (wsc *WebSocketClient) Listen() {
go func() {
2016-11-12 21:00:53 +00:00
defer func() {
wsc.Conn.Close()
close(wsc.EventChannel)
close(wsc.ResponseChannel)
}()
2016-08-15 16:47:31 +00:00
for {
var rawMsg json.RawMessage
var err error
if _, rawMsg, err = wsc.Conn.ReadMessage(); err != nil {
2016-11-12 21:00:53 +00:00
if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
2018-02-08 23:11:04 +00:00
wsc.ListenError = NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
2016-11-12 21:00:53 +00:00
}
2016-08-15 16:47:31 +00:00
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
}
2016-11-12 21:00:53 +00:00
2016-08-15 16:47:31 +00:00
}
}()
}
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)
}
2016-11-12 21:00:53 +00:00
// 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)
}