"context"
)
-func (ms *MonopolyServer) addSubscriber(s *subscriber, userUUID string) {
+func (ms *MServer) addSubscriber(s *MSub, userUUID string) {
ms.subscribersMu.Lock()
- ms.subscribers[s] = userUUID
+ ms.Subscribers[s] = userUUID
+ ms.Users[userUUID].Subscription = s
ms.subscribersMu.Unlock()
}
-func (ms *MonopolyServer) deleteSubscriber(s *subscriber) {
+func (ms *MServer) deleteSubscriber(s *MSub) {
ms.subscribersMu.Lock()
- delete(ms.subscribers, s)
+ delete(ms.Users, ms.Subscribers[s])
+ delete(ms.Subscribers, s)
ms.subscribersMu.Unlock()
}
-func (ms *MonopolyServer) start() {
+func (ms *MServer) start() {
ms.subscribersMu.Lock()
defer ms.subscribersMu.Unlock()
ms.publishLimiter.Wait(context.Background())
var players []Player
- for _, userUUID := range ms.subscribers {
+ for _, userUUID := range ms.Subscribers {
players = append(players, InitPlayer(userUUID))
}
ms.gameCtxMu.Unlock()
msg := []byte{MSG_START}
- for s := range ms.subscribers {
+ for s := range ms.Subscribers {
select {
- case s.msgs <- msg:
+ case s.Msgs <- msg:
default:
- go s.closeSlow()
+ go s.CloseSlow()
}
}
}
-func (ms *MonopolyServer) roll() {
+func (ms *MServer) roll() {
ms.gameCtx.RollDice()
ms.gameCtx.ProcessMovement()
ms.gameCtx.logGameCtx()
}
-func (ms *MonopolyServer) buy() {
+func (ms *MServer) buy() {
ms.gameCtx.Buy()
ms.gameCtx.logGameCtx()
import (
"context"
"errors"
- "github.com/coder/websocket"
- "github.com/google/uuid"
"io"
"net"
"net/http"
"sync"
"time"
+
+ "github.com/coder/websocket"
+ "github.com/google/uuid"
)
-func (ms *MonopolyServer) subscribeHandler(w http.ResponseWriter, r *http.Request) {
+func (ms *MServer) subscribeHandler(w http.ResponseWriter, r *http.Request) {
err := ms.subscribe(w, r)
if errors.Is(err, context.Canceled) {
return
}
}
-func (ms *MonopolyServer) loggedInHandler(w http.ResponseWriter, r *http.Request) {
+func (ms *MServer) loggedInHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
userUUID := cookie.Value
- _, ok := ms.users[userUUID]
+ _, ok := ms.Users[userUUID]
if !ok {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
w.WriteHeader(http.StatusOK)
}
-func (ms *MonopolyServer) loginHandler(w http.ResponseWriter, r *http.Request) {
+func (ms *MServer) loginHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
http.Error(w, http.StatusText(http.StatusRequestEntityTooLarge), http.StatusRequestEntityTooLarge)
return
}
+
+ cookie, err := r.Cookie("user")
+ if err != http.ErrNoCookie {
+ cookieUserUUID := cookie.Value
+ _, ok := ms.Users[cookieUserUUID]
+ if !ok { // user has cookie, player does not exist
+ // http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
+ // return
+ } else { // user has cookie, player exists
+ ms.Users[cookieUserUUID].Username = string(username)
+ w.WriteHeader(http.StatusOK)
+ return
+ }
+ }
+
+ if ms.gameCtx != nil {
+ http.Error(w, http.StatusText(http.StatusConflict), http.StatusConflict)
+ return
+ }
+
userUUID := uuid.NewString()
- ms.users[userUUID] = string(username)
+ ms.Users[userUUID] = &MUser{
+ Username: string(username),
+ Subscription: nil,
+ }
http.SetCookie(w, &http.Cookie{
Name: "user",
w.WriteHeader(http.StatusOK)
}
-func (ms *MonopolyServer) startHandler(w http.ResponseWriter, r *http.Request) {
+func (ms *MServer) subscribe(w http.ResponseWriter, r *http.Request) error {
+ cookie, err := r.Cookie("user")
+ if err != nil {
+ if errors.Is(err, http.ErrNoCookie) {
+ http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
+ return err
+ }
+
+ http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
+ return err
+ }
+
+ userUUID := cookie.Value
+
+ if mUser, exists := ms.Users[userUUID]; exists {
+ if mUser.Subscription != nil {
+ http.Error(w, "Can only have one websocket connection at a time", http.StatusConflict)
+ return errors.New("Can only have one websocket connection at a time")
+ }
+ } else {
+ http.Error(w, "User does not exist", http.StatusNotFound)
+ return errors.New("User not found")
+ }
+
+ var mu sync.Mutex
+ var c *websocket.Conn
+ var closed bool
+
+ s := &MSub{
+ Msgs: make(chan []byte, ms.subscriberMessageBuffer),
+ CloseSlow: func() {
+ mu.Lock()
+ defer mu.Unlock()
+ closed = true
+ if c != nil {
+ c.Close(websocket.StatusPolicyViolation, "connection too slow to keep up with messages")
+ }
+ },
+ }
+ ms.addSubscriber(s, userUUID)
+
+ defer ms.deleteSubscriber(s)
+
+ c2, err := websocket.Accept(w, r, nil)
+ if err != nil {
+ return err
+ }
+
+ mu.Lock()
+ if closed {
+ mu.Unlock()
+ return net.ErrClosed
+ }
+
+ c = c2
+ mu.Unlock()
+ defer c.CloseNow()
+
+ ctx := c.CloseRead(context.Background())
+ for {
+ select {
+ case msg := <-s.Msgs:
+ err := writeTimeout(ctx, time.Second*5, c, msg)
+ if err != nil {
+ return err
+ }
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+ }
+}
+
+// func (ms *MonopolyServer) publish(msg []byte) {
+// ms.subscribersMu.Lock()
+// defer ms.subscribersMu.Unlock()
+//
+// ms.publishLimiter.Wait(context.Background())
+//
+// for s := range ms.subscribers {
+// select {
+// case s.msgs <- msg:
+// default:
+// go s.closeSlow()
+// }
+// }
+//
+// }
+
+func (ms *MServer) startHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
userUUID := cookie.Value
- _, ok := ms.users[userUUID]
+ _, ok := ms.Users[userUUID]
if !ok {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
w.WriteHeader(http.StatusAccepted)
}
-func (ms *MonopolyServer) buyHandler(w http.ResponseWriter, r *http.Request) {
+func (ms *MServer) buyHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
userUUID := cookie.Value
- _, ok := ms.users[userUUID]
+ _, ok := ms.Users[userUUID]
if !ok {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
w.WriteHeader(http.StatusOK)
}
-func (ms *MonopolyServer) rollHandler(w http.ResponseWriter, r *http.Request) {
+func (ms *MServer) rollHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
userUUID := cookie.Value
- _, ok := ms.users[userUUID]
+ _, ok := ms.Users[userUUID]
if !ok {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
ms.roll()
w.WriteHeader(http.StatusOK)
}
-
-func (ms *MonopolyServer) subscribe(w http.ResponseWriter, r *http.Request) error {
- cookie, err := r.Cookie("user")
- if err != nil {
- if err == http.ErrNoCookie {
- http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
- return err
- }
-
- http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
- return err
- }
-
- userUUID := cookie.Value
-
- var mu sync.Mutex
- var c *websocket.Conn
- var closed bool
-
- s := &subscriber{
- msgs: make(chan []byte, ms.subscriberMessageBuffer),
- closeSlow: func() {
- mu.Lock()
- defer mu.Unlock()
- closed = true
- if c != nil {
- c.Close(websocket.StatusPolicyViolation, "connection too slow to keep up with messages")
- }
- },
- }
- ms.addSubscriber(s, userUUID)
- defer ms.deleteSubscriber(s)
-
- c2, err := websocket.Accept(w, r, nil)
- if err != nil {
- return err
- }
-
- mu.Lock()
- if closed {
- mu.Unlock()
- return net.ErrClosed
- }
-
- c = c2
- mu.Unlock()
- defer c.CloseNow()
-
- ctx := c.CloseRead(context.Background())
- for {
- select {
- case msg := <-s.msgs:
- err := writeTimeout(ctx, time.Second*5, c, msg)
- if err != nil {
- return err
- }
- case <-ctx.Done():
- return ctx.Err()
- }
- }
-}
-
-// func (ms *MonopolyServer) publish(msg []byte) {
-// ms.subscribersMu.Lock()
-// defer ms.subscribersMu.Unlock()
-//
-// ms.publishLimiter.Wait(context.Background())
-//
-// for s := range ms.subscribers {
-// select {
-// case s.msgs <- msg:
-// default:
-// go s.closeSlow()
-// }
-// }
-//
-// }