summaryrefslogtreecommitdiffstats
path: root/api/web_conn.go
diff options
context:
space:
mode:
Diffstat (limited to 'api/web_conn.go')
-rw-r--r--api/web_conn.go149
1 files changed, 94 insertions, 55 deletions
diff --git a/api/web_conn.go b/api/web_conn.go
index f4bd493bb..7f3c1f875 100644
--- a/api/web_conn.go
+++ b/api/web_conn.go
@@ -4,54 +4,52 @@
package api
import (
+ "fmt"
"time"
"github.com/mattermost/platform/model"
+ l4g "github.com/alecthomas/log4go"
"github.com/gorilla/websocket"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
const (
- WRITE_WAIT = 10 * time.Second
- PONG_WAIT = 60 * time.Second
- PING_PERIOD = (PONG_WAIT * 9) / 10
- MAX_SIZE = 512
- REDIS_WAIT = 60 * time.Second
+ WRITE_WAIT = 30 * time.Second
+ PONG_WAIT = 100 * time.Second
+ PING_PERIOD = (PONG_WAIT * 6) / 10
)
type WebConn struct {
- WebSocket *websocket.Conn
- Send chan model.WebSocketMessage
- SessionToken string
- UserId string
- T goi18n.TranslateFunc
- Locale string
- isMemberOfChannel map[string]bool
- isMemberOfTeam map[string]bool
+ WebSocket *websocket.Conn
+ Send chan model.WebSocketMessage
+ SessionToken string
+ UserId string
+ T goi18n.TranslateFunc
+ Locale string
+ AllChannelMembers map[string]string
+ LastAllChannelMembersTime int64
}
func NewWebConn(c *Context, ws *websocket.Conn) *WebConn {
go SetStatusOnline(c.Session.UserId, c.Session.Id, false)
return &WebConn{
- Send: make(chan model.WebSocketMessage, 64),
- WebSocket: ws,
- UserId: c.Session.UserId,
- SessionToken: c.Session.Token,
- T: c.T,
- Locale: c.Locale,
- isMemberOfChannel: make(map[string]bool),
- isMemberOfTeam: make(map[string]bool),
+ Send: make(chan model.WebSocketMessage, 256),
+ WebSocket: ws,
+ UserId: c.Session.UserId,
+ SessionToken: c.Session.Token,
+ T: c.T,
+ Locale: c.Locale,
}
}
func (c *WebConn) readPump() {
defer func() {
- hub.Unregister(c)
+ HubUnregister(c)
c.WebSocket.Close()
}()
- c.WebSocket.SetReadLimit(MAX_SIZE)
+ c.WebSocket.SetReadLimit(SOCKET_MAX_MESSAGE_SIZE_KB)
c.WebSocket.SetReadDeadline(time.Now().Add(PONG_WAIT))
c.WebSocket.SetPongHandler(func(string) error {
c.WebSocket.SetReadDeadline(time.Now().Add(PONG_WAIT))
@@ -62,6 +60,13 @@ func (c *WebConn) readPump() {
for {
var req model.WebSocketRequest
if err := c.WebSocket.ReadJSON(&req); err != nil {
+ // browsers will appear as CloseNoStatusReceived
+ if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
+ l4g.Debug(fmt.Sprintf("websocket.read: client side closed socket userId=%v", c.UserId))
+ } else {
+ l4g.Debug(fmt.Sprintf("websocket.read: cannot read, closing websocket for userId=%v error=%v", c.UserId, err.Error()))
+ }
+
return
} else {
BaseRoutes.WebSocket.ServeWebSocket(c, &req)
@@ -87,63 +92,97 @@ func (c *WebConn) writePump() {
}
c.WebSocket.SetWriteDeadline(time.Now().Add(WRITE_WAIT))
- if err := c.WebSocket.WriteJSON(msg); err != nil {
+ if err := c.WebSocket.WriteMessage(websocket.TextMessage, msg.GetPreComputeJson()); err != nil {
+ // browsers will appear as CloseNoStatusReceived
+ if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
+ l4g.Debug(fmt.Sprintf("websocket.send: client side closed socket userId=%v", c.UserId))
+ } else {
+ l4g.Debug(fmt.Sprintf("websocket.send: cannot send, closing websocket for userId=%v, error=%v", c.UserId, err.Error()))
+ }
+
return
}
case <-ticker.C:
c.WebSocket.SetWriteDeadline(time.Now().Add(WRITE_WAIT))
if err := c.WebSocket.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
+ // browsers will appear as CloseNoStatusReceived
+ if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
+ l4g.Debug(fmt.Sprintf("websocket.ticker: client side closed socket userId=%v", c.UserId))
+ } else {
+ l4g.Debug(fmt.Sprintf("websocket.ticker: cannot read, closing websocket for userId=%v error=%v", c.UserId, err.Error()))
+ }
+
return
}
}
}
}
-func (c *WebConn) InvalidateCache() {
- c.isMemberOfTeam = make(map[string]bool)
- c.isMemberOfChannel = make(map[string]bool)
-}
+func (webCon *WebConn) InvalidateCache() {
+ webCon.AllChannelMembers = nil
+ webCon.LastAllChannelMembersTime = 0
-func (c *WebConn) InvalidateCacheForChannel(channelId string) {
- delete(c.isMemberOfChannel, channelId)
}
-func (c *WebConn) IsMemberOfTeam(teamId string) bool {
- isMember, ok := c.isMemberOfTeam[teamId]
- if !ok {
- session := GetSession(c.SessionToken)
- if session == nil {
- isMember = false
- c.isMemberOfTeam[teamId] = isMember
- } else {
- member := session.GetTeamByTeamId(teamId)
+func (webCon *WebConn) ShouldSendEvent(msg *model.WebSocketEvent) bool {
+ // If the event is destined to a specific user
+ if len(msg.Broadcast.UserId) > 0 && webCon.UserId != msg.Broadcast.UserId {
+ return false
+ }
+
+ // if the user is omitted don't send the message
+ if len(msg.Broadcast.OmitUsers) > 0 {
+ if _, ok := msg.Broadcast.OmitUsers[webCon.UserId]; ok {
+ return false
+ }
+ }
- if member != nil {
- isMember = true
- c.isMemberOfTeam[teamId] = isMember
+ // Only report events to users who are in the channel for the event
+ if len(msg.Broadcast.ChannelId) > 0 {
+
+ if model.GetMillis()-webCon.LastAllChannelMembersTime > 1000*60*15 { // 15 minutes
+ webCon.AllChannelMembers = nil
+ webCon.LastAllChannelMembersTime = 0
+ }
+
+ if webCon.AllChannelMembers == nil {
+ if result := <-Srv.Store.Channel().GetAllChannelMembersForUser(webCon.UserId, true); result.Err != nil {
+ l4g.Error("webhub.shouldSendEvent: " + result.Err.Error())
+ return false
} else {
- isMember = true
- c.isMemberOfTeam[teamId] = isMember
+ webCon.AllChannelMembers = result.Data.(map[string]string)
+ webCon.LastAllChannelMembersTime = model.GetMillis()
}
+ }
+ if _, ok := webCon.AllChannelMembers[msg.Broadcast.ChannelId]; ok {
+ return true
+ } else {
+ return false
}
}
- return isMember
+ // Only report events to users who are in the team for the event
+ if len(msg.Broadcast.TeamId) > 0 {
+ return webCon.IsMemberOfTeam(msg.Broadcast.TeamId)
+
+ }
+
+ return true
}
-func (c *WebConn) IsMemberOfChannel(channelId string) bool {
- isMember, ok := c.isMemberOfChannel[channelId]
- if !ok {
- if cresult := <-Srv.Store.Channel().GetMember(channelId, c.UserId); cresult.Err != nil {
- isMember = false
- c.isMemberOfChannel[channelId] = isMember
+func (webCon *WebConn) IsMemberOfTeam(teamId string) bool {
+ session := GetSession(webCon.SessionToken)
+ if session == nil {
+ return false
+ } else {
+ member := session.GetTeamByTeamId(teamId)
+
+ if member != nil {
+ return true
} else {
- isMember = true
- c.isMemberOfChannel[channelId] = isMember
+ return false
}
}
-
- return isMember
}