<commit_before>package lobby

import (
	"errors"
	"log"
	"net/http"
	"sync"

	"github.com/cenk/rpc2"
	"github.com/cenk/rpc2/jsonrpc"
	"github.com/kellydunn/golang-geo"
	"golang.org/x/net/websocket"
)

var (
	ErrAlreadyExists = errors.New("a lobby with that ID has already been created by someone else")
	ErrNotFound      = errors.New("can't find the requested lobby")
	ErrNotAuthorized = errors.New("invalid credentials")
)

const lobbiesKey = "lobbies"

type Location struct {
	Latitude, Longitude float64
}

// Point returns the geo.Point that represents the location.
func (l Location) Point() *geo.Point {
	return geo.NewPoint(l.Latitude, l.Longitude)
}

type Lobby struct {
	ID, Name, Creator, Service string
	Hidden, RequiresPassword   bool
	Location                   *Location
	Distance                   float64
	People, Capacity           int

	client *rpc2.Client
}

type Server struct {
	rpc         *rpc2.Server
	lobbies     map[string]*Lobby
	lobbiesLock sync.RWMutex
	mux         *http.ServeMux
}

// NewServer creates a Server.
func NewServer() *Server {
	s := &Server{
		rpc:     rpc2.NewServer(),
		lobbies: make(map[string]*Lobby),
		mux:     http.NewServeMux(),
	}

	s.mux.Handle("/ws", websocket.Handler(s.Serve))

	s.rpc.Handle("lobby.new", s.newLobby)
	s.rpc.Handle("lobby.connect", s.connectLobby)
	s.rpc.Handle("lobby.list", s.listLobby)
	s.rpc.OnDisconnect(s.disconnect)

	return s
}

type NewLobbyResponse struct{}

func (s *Server) newLobby(client *rpc2.Client, req *Lobby, resp *NewLobbyResponse) error {
	log.Printf("lobby.new: %+v", req)
	s.lobbiesLock.Lock()
	defer s.lobbiesLock.Unlock()
	if lobby, ok := s.lobbies[req.ID]; ok && lobby.client != client {
		return ErrAlreadyExists
	}
	req.client = client
	s.lobbies[req.ID] = req
	var lobbies []*Lobby
	if lobbiesInterface, ok := client.State.Get(lobbiesKey); ok {
		lobbies = lobbiesInterface.([]*Lobby)
	}
	lobbies = append(lobbies, req)
	client.State.Set(lobbiesKey, lobbies)
	return nil
}
<commit_msg>Added a health endpoint to for monitoring purposes.<commit_after>package lobby

import (
	"errors"
	"log"
	"net/http"
	"sync"

	"github.com/cenk/rpc2"
	"github.com/cenk/rpc2/jsonrpc"
	geo "github.com/kellydunn/golang-geo"
	"golang.org/x/net/websocket"
)

var (
	ErrAlreadyExists = errors.New("a lobby with that ID has already been created by someone else")
	ErrNotFound      = errors.New("can't find the requested lobby")
	ErrNotAuthorized = errors.New("invalid credentials")
)

const lobbiesKey = "lobbies"

type Location struct {
	Latitude, Longitude float64
}

// Point returns the geo.Point that represents the location.
func (l Location) Point() *geo.Point {
	return geo.NewPoint(l.Latitude, l.Longitude)
}

type Lobby struct {
	ID, Name, Creator, Service string
	Hidden, RequiresPassword   bool
	Location                   *Location
	Distance                   float64
	People, Capacity           int

	client *rpc2.Client
}

type Server struct {
	rpc         *rpc2.Server
	lobbies     map[string]*Lobby
	lobbiesLock sync.RWMutex
	mux         *http.ServeMux
}

// NewServer creates a Server.
func NewServer() *Server {
	s := &Server{
		rpc:     rpc2.NewServer(),
		lobbies: make(map[string]*Lobby),
		mux:     http.NewServeMux(),
	}

	s.mux.Handle("/ws", websocket.Handler(s.Serve))

	s.rpc.Handle("lobby.new", s.newLobby)
	s.rpc.Handle("lobby.connect", s.connectLobby)
	s.rpc.Handle("lobby.list", s.listLobby)
	s.rpc.OnDisconnect(s.disconnect)

	s.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("ok"))
	})

	return s
}

type NewLobbyResponse struct{}

func (s *Server) newLobby(client *rpc2.Client, req *Lobby, resp *NewLobbyResponse) error {
	log.Printf("lobby.new: %+v", req)
	s.lobbiesLock.Lock()
	defer s.lobbiesLock.Unlock()
	if lobby, ok := s.lobbies[req.ID]; ok && lobby.client != client {
		return ErrAlreadyExists
	}
	req.client = client
	s.lobbies[req.ID] = req
	var lobbies []*Lobby
	if lobbiesInterface, ok := client.State.Get(lobbiesKey); ok {
		lobbies = lobbiesInterface.([]*Lobby)
	}
	lobbies = append(lobbies, req)
	client.State.Set(lobbiesKey, lobbies)
	return nil
}

{'fraction_non_alphanumeric': 0.13262084041777994, 'fraction_numerical': 0.004857906242409522, 'mean_word_length': 3.6848691695108076, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1402909', 'n_tokens_mistral': 1563, 'n_tokens_neox': 1504, 'n_words': 344}