From 89a5eafa48b177beb6f664851b41e676842eedc3 Mon Sep 17 00:00:00 2001 From: Azareal Date: Tue, 22 Jan 2019 22:06:55 +1000 Subject: [PATCH] Added the Online Users Context widget. Commented out a couple lines of debug code. Fixed a data race where the Online Users widget would sometimes show more users than it should. Added a new phrase. --- common/websockets.go | 43 ++++++++++++++++++---- common/widget_wol.go | 3 ++ common/widget_wol_context.go | 25 +++++++++---- langs/english.json | 1 + routes/panel/themes.go | 7 ++-- templates/panel_themes_widgets_widget.html | 2 +- 6 files changed, 62 insertions(+), 19 deletions(-) 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 @@ - +