Refactor
This commit is contained in:
+96
-35
@@ -1,8 +1,9 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"sprintpadawan/lib"
|
||||
@@ -35,7 +36,7 @@ type RoomData struct {
|
||||
|
||||
var (
|
||||
roomClients = make(map[int][]*sseClient)
|
||||
clientsMu sync.Mutex
|
||||
clientsMu sync.RWMutex
|
||||
)
|
||||
|
||||
func addSSEClient(roomID, userID int, ch chan string) {
|
||||
@@ -60,23 +61,48 @@ func removeSSEClient(roomID int, ch chan string) {
|
||||
}
|
||||
|
||||
func broadcast(roomID int, event string) {
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
alive := roomClients[roomID][:0]
|
||||
for _, c := range roomClients[roomID] {
|
||||
clientsMu.RLock()
|
||||
snapshot := append([]*sseClient(nil), roomClients[roomID]...)
|
||||
clientsMu.RUnlock()
|
||||
|
||||
if len(snapshot) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
deadSet := make(map[*sseClient]struct{})
|
||||
for _, c := range snapshot {
|
||||
select {
|
||||
case c.ch <- event:
|
||||
alive = append(alive, c)
|
||||
default:
|
||||
// drop dead client
|
||||
deadSet[c] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
if len(deadSet) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
|
||||
current := roomClients[roomID]
|
||||
alive := current[:0]
|
||||
for _, c := range current {
|
||||
if _, dead := deadSet[c]; dead {
|
||||
continue
|
||||
}
|
||||
alive = append(alive, c)
|
||||
}
|
||||
if len(alive) == 0 {
|
||||
delete(roomClients, roomID)
|
||||
return
|
||||
}
|
||||
roomClients[roomID] = alive
|
||||
}
|
||||
|
||||
func GetConnectedUserIDs(roomID int) []int {
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
clientsMu.RLock()
|
||||
defer clientsMu.RUnlock()
|
||||
seen := make(map[int]bool)
|
||||
var ids []int
|
||||
for _, c := range roomClients[roomID] {
|
||||
@@ -101,19 +127,45 @@ func scaleToOptions(scale string) []string {
|
||||
}
|
||||
}
|
||||
|
||||
func getRoomID(r *http.Request) int {
|
||||
func getRoomID(r *http.Request) (int, error) {
|
||||
return getPathInt(r, "id")
|
||||
}
|
||||
|
||||
func getPathInt(r *http.Request, key string) int {
|
||||
var id int
|
||||
fmt.Sscanf(r.PathValue(key), "%d", &id)
|
||||
return id
|
||||
func getPathInt(r *http.Request, key string) (int, error) {
|
||||
raw := r.PathValue(key)
|
||||
if raw == "" {
|
||||
return 0, errors.New("missing path parameter")
|
||||
}
|
||||
id, err := strconv.Atoi(raw)
|
||||
if err != nil || id <= 0 {
|
||||
return 0, errors.New("invalid path parameter")
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func buildRoomData(room *lib.Room, user *lib.User) RoomData {
|
||||
members, _ := lib.GetRoomMembers(room.ID)
|
||||
stories, _ := lib.GetStoriesForRoom(room.ID)
|
||||
func getFormInt(r *http.Request, key string) (int, error) {
|
||||
raw := r.FormValue(key)
|
||||
if raw == "" {
|
||||
return 0, errors.New("missing form value")
|
||||
}
|
||||
id, err := strconv.Atoi(raw)
|
||||
if err != nil || id <= 0 {
|
||||
return 0, errors.New("invalid form value")
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func buildRoomData(room *lib.Room, user *lib.User) (RoomData, error) {
|
||||
members, err := lib.GetRoomMembers(room.ID)
|
||||
if err != nil {
|
||||
return RoomData{}, err
|
||||
}
|
||||
|
||||
stories, err := lib.GetStoriesForRoom(room.ID)
|
||||
if err != nil {
|
||||
return RoomData{}, err
|
||||
}
|
||||
|
||||
connectedIDs := GetConnectedUserIDs(room.ID)
|
||||
connectedMap := make(map[int]bool)
|
||||
for _, cid := range connectedIDs {
|
||||
@@ -121,9 +173,30 @@ func buildRoomData(room *lib.Room, user *lib.User) RoomData {
|
||||
}
|
||||
connectedMap[user.ID] = true
|
||||
|
||||
var activeVotes []lib.Vote
|
||||
storyIDs := make([]int, 0, len(stories))
|
||||
revealedStoryIDs := make([]int, 0, len(stories))
|
||||
for _, s := range stories {
|
||||
storyIDs = append(storyIDs, s.ID)
|
||||
if s.Voted {
|
||||
revealedStoryIDs = append(revealedStoryIDs, s.ID)
|
||||
}
|
||||
}
|
||||
|
||||
votesByStory, err := lib.GetVotesForStories(storyIDs)
|
||||
if err != nil {
|
||||
return RoomData{}, err
|
||||
}
|
||||
|
||||
storyVotes, err := lib.GetVoteViewsForStories(revealedStoryIDs)
|
||||
if err != nil {
|
||||
return RoomData{}, err
|
||||
}
|
||||
|
||||
activeVotesByUser := make(map[int]bool)
|
||||
if room.ActiveStoryID != nil {
|
||||
activeVotes, _ = lib.GetVotesForStory(*room.ActiveStoryID)
|
||||
for _, v := range votesByStory[*room.ActiveStoryID] {
|
||||
activeVotesByUser[v.UserID] = true
|
||||
}
|
||||
}
|
||||
|
||||
var memberViews []MemberView
|
||||
@@ -131,13 +204,7 @@ func buildRoomData(room *lib.Room, user *lib.User) RoomData {
|
||||
if !connectedMap[m.ID] {
|
||||
continue
|
||||
}
|
||||
hasVoted := false
|
||||
for _, v := range activeVotes {
|
||||
if v.UserID == m.ID {
|
||||
hasVoted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
hasVoted := activeVotesByUser[m.ID]
|
||||
memberViews = append(memberViews, MemberView{
|
||||
Username: m.Username,
|
||||
HasVoted: hasVoted,
|
||||
@@ -146,18 +213,12 @@ func buildRoomData(room *lib.Room, user *lib.User) RoomData {
|
||||
}
|
||||
|
||||
userVotes := make(map[int]string)
|
||||
storyVotes := make(map[int][]lib.VoteView)
|
||||
for _, s := range stories {
|
||||
votes, _ := lib.GetVotesForStory(s.ID)
|
||||
for _, v := range votes {
|
||||
for _, v := range votesByStory[s.ID] {
|
||||
if v.UserID == user.ID {
|
||||
userVotes[s.ID] = v.Value
|
||||
}
|
||||
}
|
||||
if s.Voted {
|
||||
vv, _ := lib.GetVotesWithUsernames(s.ID)
|
||||
storyVotes[s.ID] = vv
|
||||
}
|
||||
}
|
||||
|
||||
return RoomData{
|
||||
@@ -168,5 +229,5 @@ func buildRoomData(room *lib.Room, user *lib.User) RoomData {
|
||||
IsOwner: room.OwnerID == user.ID,
|
||||
UserVotes: userVotes,
|
||||
StoryVotes: storyVotes,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user