diff --git a/common/websockets.go b/common/websockets.go
index a961a647..0cc52f25 100644
--- a/common/websockets.go
+++ b/common/websockets.go
@@ -34,6 +34,7 @@ var errWsNouser = errors.New("This user isn't connected via WebSockets")
func init() {
adminStatsWatchers = make(map[*websocket.Conn]*WSUser)
topicListWatchers = make(map[*WSUser]bool)
+ topicWatchers = make(map[int]map[*WSUser]bool)
}
type WsTopicList struct {
@@ -122,6 +123,7 @@ func wsPageResponses(wsUser *WSUser, conn *websocket.Conn, page string) {
topicListMutex.Lock()
topicListWatchers[wsUser] = true
topicListMutex.Unlock()
+ // TODO: Evict from page when permissions change? Or check user perms every-time before sending data?
case strings.HasPrefix(page, "/topic/"):
//fmt.Println("entering topic prefix websockets zone")
_, tid, err := ParseSEOURL(page)
@@ -132,13 +134,12 @@ func wsPageResponses(wsUser *WSUser, conn *websocket.Conn, page string) {
if err != nil {
return
}
- var usercpy *User = BlankUser()
- *usercpy = *wsUser.User
- usercpy.Init()
-
if !Forums.Exists(topic.ParentID) {
return
}
+ var usercpy *User = BlankUser()
+ *usercpy = *wsUser.User
+ usercpy.Init()
/*skip, rerr := header.Hooks.VhookSkippable("ws_topic_check_pre_perms", w, r, usercpy, &fid, &header)
if skip || rerr != nil {
@@ -155,6 +156,14 @@ func wsPageResponses(wsUser *WSUser, conn *websocket.Conn, page string) {
if !usercpy.Perms.ViewTopic {
return
}
+
+ topicMutex.Lock()
+ _, ok := topicWatchers[topic.ID]
+ if !ok {
+ topicWatchers[topic.ID] = make(map[*WSUser]bool)
+ }
+ topicWatchers[topic.ID][wsUser] = true
+ topicMutex.Unlock()
case page == "/panel/":
if !wsUser.User.IsSuperMod {
return
@@ -180,9 +189,7 @@ func wsPageResponses(wsUser *WSUser, conn *websocket.Conn, page string) {
func wsLeavePage(wsUser *WSUser, conn *websocket.Conn, page string) {
if page == "/" {
page = Config.DefaultPath
- }
-
- if page != "" {
+ } else if page != "" {
DebugLog("Leaving page " + page)
}
switch {
@@ -194,6 +201,26 @@ func wsLeavePage(wsUser *WSUser, conn *websocket.Conn, page string) {
})
case strings.HasPrefix(page, "/topic/"):
//fmt.Println("leaving topic prefix websockets zone")
+ wsUser.FinalizePage(page, func() {
+ _, tid, err := ParseSEOURL(page)
+ if err != nil {
+ return
+ }
+ topicMutex.Lock()
+ defer topicMutex.Unlock()
+ topic, ok := topicWatchers[tid]
+ if !ok {
+ return
+ }
+ _, ok = topic[wsUser]
+ if !ok {
+ return
+ }
+ delete(topic, wsUser)
+ if len(topic) == 0 {
+ delete(topicWatchers, tid)
+ }
+ })
case page == "/panel/":
adminStatsMutex.Lock()
delete(adminStatsWatchers, conn)
@@ -209,6 +236,8 @@ func wsLeavePage(wsUser *WSUser, conn *websocket.Conn, page string) {
// TODO: Use odd-even sharding
var topicListWatchers map[*WSUser]bool
var topicListMutex sync.RWMutex
+var topicWatchers map[int]map[*WSUser]bool // map[tid]watchers
+var topicMutex sync.RWMutex
var adminStatsWatchers map[*websocket.Conn]*WSUser
var adminStatsMutex sync.RWMutex
diff --git a/common/widget_wol.go b/common/widget_wol.go
index b5a6271e..ca94e12a 100644
--- a/common/widget_wol.go
+++ b/common/widget_wol.go
@@ -25,6 +25,9 @@ func wolBuild(widget *Widget, hvars interface{}) (string, error) {
var users []*User
if ucount < 30 {
users = WsHub.AllUsers()
+ if len(users) >= 30 {
+ users = nil
+ }
}
wol := &wolUsers{hvars.(*Header), phrases.GetTmplPhrase("widget.online_name"), users, ucount}
err := wol.Header.Theme.RunTmpl("widget_online", wol, wol.Header.Writer)
diff --git a/common/widget_wol_context.go b/common/widget_wol_context.go
index 4d886da3..d86e0f31 100644
--- a/common/widget_wol_context.go
+++ b/common/widget_wol_context.go
@@ -3,13 +3,24 @@ package common
import "github.com/Azareal/Gosora/common/phrases"
func wolContextRender(widget *Widget, hvars interface{}) (string, error) {
- ucount := WsHub.UserCount()
- // We don't want a ridiculously long list, so we'll show the number if it's too high and only show staff individually
- var users []*User
- if ucount < 30 {
- users = WsHub.AllUsers()
+ header := hvars.(*Header)
+ if header.Zone != "view_topic" {
+ return "", nil
}
- wol := &wolUsers{hvars.(*Header), phrases.GetTmplPhrase("widget.online_name"), users, ucount}
- err := wol.Header.Theme.RunTmpl("widget_online", wol, wol.Header.Writer)
+ var ucount int
+ var users []*User
+ topicMutex.RLock()
+ topic, ok := topicWatchers[header.ZoneID]
+ if ok {
+ ucount = len(topic)
+ if ucount < 30 {
+ for wsUser, _ := range topic {
+ users = append(users, wsUser.User)
+ }
+ }
+ }
+ topicMutex.RUnlock()
+ wol := &wolUsers{header, phrases.GetTmplPhrase("widget.online_view_topic_name"), users, ucount}
+ err := header.Theme.RunTmpl("widget_online", wol, header.Writer)
return "", err
}
diff --git a/langs/english.json b/langs/english.json
index d52fdc54..c16b337a 100644
--- a/langs/english.json
+++ b/langs/english.json
@@ -669,6 +669,7 @@
"widget.online_name":"Online Users",
"widget.online_none_online":"No one is online.",
"widget.online_some_online":"There are %d users online.",
+ "widget.online_view_topic_name":"In Topic",
"option_yes":"Yes",
"option_no":"No",
diff --git a/routes/panel/themes.go b/routes/panel/themes.go
index b9c7fafa..efb65e81 100644
--- a/routes/panel/themes.go
+++ b/routes/panel/themes.go
@@ -4,7 +4,6 @@ import (
"database/sql"
"encoding/json"
"errors"
- "fmt"
"net/http"
"strconv"
"strings"
@@ -386,7 +385,7 @@ func widgetsParseInputs(r *http.Request, widget *common.Widget) (*common.WidgetE
return nil, errors.New("You need to fill in the body for this widget.")
}
widget.Type = wtype // ? - Are we sure we should be directly assigning user provided data even if it's validated?
- case "wol", "search_and_filter":
+ case "wol", "wol_context", "search_and_filter":
widget.Type = wtype // ? - Are we sure we should be directly assigning user provided data even if it's validated?
default:
return nil, errors.New("Unknown widget type")
@@ -397,7 +396,7 @@ func widgetsParseInputs(r *http.Request, widget *common.Widget) (*common.WidgetE
// ThemesWidgetsEditSubmit is an action which is triggered when someone sends an update request for a widget
func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, swid string) common.RouteError {
- fmt.Println("in ThemesWidgetsEditSubmit")
+ //fmt.Println("in ThemesWidgetsEditSubmit")
_, ferr := common.SimplePanelUserCheck(w, r, &user)
if ferr != nil {
return ferr
@@ -434,7 +433,7 @@ func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, user common
// ThemesWidgetsCreateSubmit is an action which is triggered when someone sends a create request for a widget
func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
- fmt.Println("in ThemesWidgetsCreateSubmit")
+ //fmt.Println("in ThemesWidgetsCreateSubmit")
isJs := (r.PostFormValue("js") == "1")
_, ferr := common.SimplePanelUserCheck(w, r, &user)
if ferr != nil {
diff --git a/templates/panel_themes_widgets_widget.html b/templates/panel_themes_widgets_widget.html
index 1419ebd0..d75bdbc1 100644
--- a/templates/panel_themes_widgets_widget.html
+++ b/templates/panel_themes_widgets_widget.html
@@ -5,7 +5,7 @@
-
+