Major refactor into the /handlers system and wrote a bit of the architecture in the README
This commit is contained in:
@@ -11,3 +11,53 @@ $ cd _frontend
|
||||
$ npm run build
|
||||
$ go build
|
||||
```
|
||||
|
||||
## Architettura
|
||||
|
||||
Moduli principali (cose che vengono eseguite e fanno cose di _business logic_)
|
||||
|
||||
- [`/main.go`](./main.go)
|
||||
|
||||
Entry point principale del server, qui vengono inizializzate concretamente tutte le dipendenze dei vari moduli (come database, router http e servizio di autenticazione).
|
||||
|
||||
Per ora usiamo un semplice database ed un semplice servizio di autenticazione per le sessioni di accesso che tengono tutto in memoria (più avanti passeremo a SQLite, tanto basterà semplicemente scrivere un'altra implementazione per `database.Database`)
|
||||
|
||||
- [`/routes`](./routes)
|
||||
|
||||
Questo modulo dipende **molto** dal router HTTP in quanto contiene tutte le route del server. Oltre questo dipende solo dal modulo `/handlers` e non sa nulla di `/database` e `/auth`.
|
||||
|
||||
- [`/handlers`](./handlers)
|
||||
|
||||
Questo modulo permette di testare tutta l'applicazione in modo isolato dal resto in quanto non sa nulla dei router HTTP e dipende solo da `/auth` e `/database` (ed anche da `/events`, `/model` e `/util` ma questi sono moduli "puri") che possono essere facilmente _mocked_.
|
||||
|
||||
Moduli secondari (o boh "terminali" nel senso che dipendono solo da cose esterne a questo progetto)
|
||||
|
||||
- [`/events`](./events)
|
||||
|
||||
Questo modulo fornisce una struttura dati di "EventBus" che permette di mandare e ricevere eventi all'interno dell'applicazione.
|
||||
|
||||
- [`/model`](./model)
|
||||
|
||||
Questo modulo contiene i modelli di tutte le strutture usate nel database ed alcuni metodi di servizio come `User.PublicUser()` che converte un `User` in `PublicUser` che rappresenta la versione "sicura" senza i campi segreti (come l'hash della password) dell'utente.
|
||||
|
||||
- [`/database`](./database)
|
||||
|
||||
L'interfaccia principale è `Database` e contiene tutte le operazioni possibili da fare sul database. Per ora c'è solo un'implementazione in memoria data da `*memDB`
|
||||
|
||||
- [`/auth`](./auth)
|
||||
|
||||
L'interfaccia principale è `AuthService` e contiene alcuni metodi per autenticare e registrare gli utenti e creare token di sessione. Per ora l'unica implementazione è `*memAuth` e dipende da un'istanza di `database.Database` e tiene i token di sessione in memoria.
|
||||
|
||||
- [`/util`](./util)
|
||||
|
||||
Questo modulo contiene alcune funzioni di utility e per ora anche varie funzioni di validazione dei form che arrivano dalla frontend, come validazione di username e password per la registrazione degli utenti.
|
||||
|
||||
Ed infine c'è il modulo che si occupa del far avanzare le partite e della risoluzione automatica.
|
||||
|
||||
- [`/lupus`](./lupus)
|
||||
|
||||
Questo modulo non dipende da nulla, l'idea è che conterrà le strutture per gestire lo stato delle partite e gli algoritmi per la risoluzione automatica di quest'ultime.
|
||||
|
||||
Al massimo potrebbe contenere alcune informazioni su come serializzare lo stato delle partite però per ora tutte le strutture qui dentro sono annotate per essere serializzate a JSON ed anche quando passeremo ad SQLite forse converrà fare sempre così.
|
||||
|
||||
TODO: Al massimo potrebbe dipendere da `/model` ma forse non serve.
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package database
|
||||
|
||||
import "fmt"
|
||||
|
||||
func OnPartitaPlayersChange(partitaUid string) string {
|
||||
return fmt.Sprintf("partita[uid=%q].players", partitaUid)
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package events
|
||||
@@ -0,0 +1,83 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/aziis98/lupus-lite/auth"
|
||||
"github.com/aziis98/lupus-lite/database"
|
||||
"github.com/aziis98/lupus-lite/events"
|
||||
"github.com/aziis98/lupus-lite/model"
|
||||
"github.com/aziis98/lupus-lite/util"
|
||||
)
|
||||
|
||||
type Handler interface {
|
||||
DebugDatabase() any
|
||||
|
||||
UserForSession(token string) (model.User, error)
|
||||
|
||||
Login(username, password string) (string, error)
|
||||
Register(username, password, password2 string) error
|
||||
|
||||
Partite() PartiteHandler
|
||||
}
|
||||
|
||||
type server struct {
|
||||
DB database.Database
|
||||
Auth auth.AuthService
|
||||
|
||||
partiteHandler *partiteHandler
|
||||
}
|
||||
|
||||
func NewServer(
|
||||
db database.Database,
|
||||
authServiceFunc func(database.Database) auth.AuthService) Handler {
|
||||
|
||||
auth := authServiceFunc(db)
|
||||
|
||||
s := &server{
|
||||
DB: db,
|
||||
Auth: auth,
|
||||
}
|
||||
|
||||
s.partiteHandler = &partiteHandler{
|
||||
server: s,
|
||||
eventBus: events.NewEventBus(),
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *server) DebugDatabase() any {
|
||||
return s.DB
|
||||
}
|
||||
|
||||
func (s *server) UserForSession(token string) (model.User, error) {
|
||||
username, err := s.Auth.UserForSession(token)
|
||||
if err != nil {
|
||||
return model.User{}, err
|
||||
}
|
||||
|
||||
user, err := s.DB.GetUser(username)
|
||||
if err != nil {
|
||||
return model.User{}, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (s *server) Login(username, password string) (string, error) {
|
||||
return s.Auth.Login(username, password)
|
||||
}
|
||||
|
||||
func (s *server) Register(username, password, password2 string) error {
|
||||
if err := util.ValidateUsername(username); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := util.ValidatePasswords(password, password2); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.Auth.Register(username, password)
|
||||
}
|
||||
|
||||
func (s *server) Partite() PartiteHandler {
|
||||
return s.partiteHandler
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aziis98/lupus-lite/events"
|
||||
"github.com/aziis98/lupus-lite/lupus"
|
||||
"github.com/aziis98/lupus-lite/model"
|
||||
)
|
||||
|
||||
func OnPlayerJoin(partitaUid string) string {
|
||||
return fmt.Sprintf("@join partita[uid=%q]", partitaUid)
|
||||
}
|
||||
|
||||
type PartitaConfig struct {
|
||||
NumGiocatori int
|
||||
NumLupi int
|
||||
NumFattucchiere int
|
||||
NumGuardie int
|
||||
NumCacciatori int
|
||||
NumMedium int
|
||||
NumVeggenti int
|
||||
}
|
||||
|
||||
type PartiteHandler interface {
|
||||
EventBus() *events.EventBus
|
||||
|
||||
Create(ownerId string, cfg PartitaConfig) (model.Partita, error)
|
||||
GetPlayers(partitaUid string) ([]string, error)
|
||||
Join(partitaUid, username string) error
|
||||
}
|
||||
|
||||
type partiteHandler struct {
|
||||
*server
|
||||
|
||||
eventBus *events.EventBus
|
||||
}
|
||||
|
||||
func (p *partiteHandler) Create(ownerId string, cfg PartitaConfig) (model.Partita, error) {
|
||||
return p.DB.CreatePartita(ownerId, model.PartitaConfig{
|
||||
NumeroGiocatori: cfg.NumGiocatori,
|
||||
NumeroPerRuolo: map[string]int{
|
||||
lupus.Lupo.Uid: cfg.NumLupi,
|
||||
lupus.Fattucchiera.Uid: cfg.NumFattucchiere,
|
||||
lupus.Guardia.Uid: cfg.NumGuardie,
|
||||
lupus.Cacciatore.Uid: cfg.NumCacciatori,
|
||||
lupus.Medium.Uid: cfg.NumMedium,
|
||||
lupus.Veggente.Uid: cfg.NumVeggenti,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (p *partiteHandler) GetPlayers(partitaUid string) ([]string, error) {
|
||||
partita, err := p.DB.GetPartita(partitaUid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return partita.Players, nil
|
||||
}
|
||||
|
||||
func (p *partiteHandler) Join(partitaUid, username string) error {
|
||||
partita, err := p.DB.GetPartita(partitaUid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
partita.Players = append(partita.Players, username)
|
||||
|
||||
if err := p.DB.UpdatePartita(partita); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.eventBus.Dispatch(OnPlayerJoin(partitaUid), partita.Players)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *partiteHandler) EventBus() *events.EventBus {
|
||||
return p.eventBus
|
||||
}
|
||||
@@ -6,10 +6,14 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/aziis98/lupus-lite/auth"
|
||||
"github.com/aziis98/lupus-lite/database"
|
||||
"github.com/aziis98/lupus-lite/handlers"
|
||||
"github.com/aziis98/lupus-lite/routes"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
"github.com/gofiber/fiber/v2/middleware/recover"
|
||||
"github.com/gofiber/websocket/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -17,7 +21,12 @@ func main() {
|
||||
|
||||
app := fiber.New()
|
||||
|
||||
server := routes.NewServer()
|
||||
db, err := database.NewInMemoryDB()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
h := handlers.NewServer(db, auth.NewInMemoryAuthService)
|
||||
|
||||
app.Use(logger.New())
|
||||
app.Use(recover.New())
|
||||
@@ -25,14 +34,36 @@ func main() {
|
||||
// Static files
|
||||
app.Static("/", "./_frontend/dist")
|
||||
|
||||
app.Route("/", server.EventRoute)
|
||||
app.Route("/", server.PageRoutes)
|
||||
app.Route("/api", server.ApiRoutes)
|
||||
// Enable WebSocket on routes ending with "/ws"
|
||||
app.Use("/*/ws", func(c *fiber.Ctx) error {
|
||||
log.Printf("Upgrading to websocket connection")
|
||||
if websocket.IsWebSocketUpgrade(c) {
|
||||
c.Locals("allowed", true)
|
||||
return c.Next()
|
||||
}
|
||||
return fiber.ErrUpgradeRequired
|
||||
})
|
||||
|
||||
//
|
||||
// Routes
|
||||
//
|
||||
|
||||
app.Route("/", func(r fiber.Router) {
|
||||
routes.PageRoutes(r, h)
|
||||
})
|
||||
|
||||
app.Route("/api", func(r fiber.Router) {
|
||||
routes.ApiRoutes(r, h)
|
||||
})
|
||||
|
||||
//
|
||||
// Starting the server
|
||||
//
|
||||
|
||||
if strings.HasPrefix(mode, "dev") {
|
||||
log.Printf(`Running dev server for frontend: "npm run dev"`)
|
||||
|
||||
err := (exec.Command("sh", "-c", "cd _frontend/ && npm run dev").Start())
|
||||
err := exec.Command("sh", "-c", "cd _frontend/ && npm run dev").Start()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
+65
-99
@@ -3,19 +3,15 @@ package routes
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aziis98/lupus-lite/database"
|
||||
"github.com/aziis98/lupus-lite/lupus"
|
||||
"github.com/aziis98/lupus-lite/model"
|
||||
"github.com/aziis98/lupus-lite/util"
|
||||
"github.com/aziis98/lupus-lite/handlers"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func (s *Server) ApiRoutes(api fiber.Router) {
|
||||
api.Get("/status", func(c *fiber.Ctx) error {
|
||||
s, err := json.MarshalIndent(s.db, "", " ")
|
||||
func ApiRoutes(r fiber.Router, h handlers.Handler) {
|
||||
r.Get("/status", func(c *fiber.Ctx) error {
|
||||
s, err := json.MarshalIndent(h.DebugDatabase(), "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -25,17 +21,17 @@ func (s *Server) ApiRoutes(api fiber.Router) {
|
||||
return c.SendString("ok")
|
||||
})
|
||||
|
||||
api.Post("/login", func(c *fiber.Ctx) error {
|
||||
var loginForm struct {
|
||||
r.Post("/login", func(c *fiber.Ctx) error {
|
||||
var form struct {
|
||||
Username string `form:"username"`
|
||||
Password string `form:"password"`
|
||||
}
|
||||
|
||||
if err := c.BodyParser(&loginForm); err != nil {
|
||||
if err := c.BodyParser(&form); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
token, err := s.auth.Login(loginForm.Username, loginForm.Password)
|
||||
token, err := h.Login(form.Username, form.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -50,88 +46,71 @@ func (s *Server) ApiRoutes(api fiber.Router) {
|
||||
return c.Redirect("/")
|
||||
})
|
||||
|
||||
api.Post("/logout", func(c *fiber.Ctx) error {
|
||||
c.Cookie(&fiber.Cookie{
|
||||
Name: "sid",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
Expires: time.Now(),
|
||||
r.Post("/logout",
|
||||
func(c *fiber.Ctx) error {
|
||||
c.Cookie(&fiber.Cookie{
|
||||
Name: "sid",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
Expires: time.Now(),
|
||||
})
|
||||
|
||||
return c.SendString("ok")
|
||||
})
|
||||
|
||||
return c.SendString("ok")
|
||||
r.Post("/register",
|
||||
func(c *fiber.Ctx) error {
|
||||
var form struct {
|
||||
Username string `form:"username"`
|
||||
Password string `form:"password"`
|
||||
Password2 string `form:"password2"`
|
||||
}
|
||||
|
||||
if err := c.BodyParser(&form); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := h.Register(form.Username, form.Password, form.Password2); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Redirect("/login")
|
||||
})
|
||||
|
||||
r.Get("/user",
|
||||
RequireLogged(h),
|
||||
func(c *fiber.Ctx) error {
|
||||
return c.JSON(requestUser(c).PublicUser())
|
||||
})
|
||||
|
||||
r.Route("/partite", func(r fiber.Router) {
|
||||
r.Use(RequireLogged(h))
|
||||
|
||||
ApiPartite(r, h.Partite())
|
||||
})
|
||||
}
|
||||
|
||||
api.Post("/register", func(c *fiber.Ctx) error {
|
||||
var loginForm struct {
|
||||
Username string `form:"username"`
|
||||
Password string `form:"password"`
|
||||
Password2 string `form:"password2"`
|
||||
}
|
||||
func ApiPartite(r fiber.Router, p handlers.PartiteHandler) {
|
||||
r.Get("/ws", BindWebsocketToEventBus(p.EventBus()))
|
||||
|
||||
if err := c.BodyParser(&loginForm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := util.ValidateUsername(loginForm.Username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := util.ValidatePasswords(loginForm.Password, loginForm.Password2); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.auth.Register(loginForm.Username, loginForm.Password); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Redirect("/login")
|
||||
})
|
||||
|
||||
api.Post("/crea-partita", s.requireLogged, func(c *fiber.Ctx) error {
|
||||
r.Post("/", func(c *fiber.Ctx) error {
|
||||
user := requestUser(c)
|
||||
|
||||
var form struct {
|
||||
NumGiocatori string `form:"numero-giocatori"`
|
||||
NumLupi string `form:"numero-lupi"`
|
||||
NumFattucchiere string `form:"numero-fattucchiere"`
|
||||
NumGuardie string `form:"numero-guardie"`
|
||||
NumCacciatori string `form:"numero-cacciatori"`
|
||||
NumMedium string `form:"numero-medium"`
|
||||
NumVeggenti string `form:"numero-veggenti"`
|
||||
NumGiocatori int `form:"numero-giocatori"`
|
||||
NumLupi int `form:"numero-lupi"`
|
||||
NumFattucchiere int `form:"numero-fattucchiere"`
|
||||
NumGuardie int `form:"numero-guardie"`
|
||||
NumCacciatori int `form:"numero-cacciatori"`
|
||||
NumMedium int `form:"numero-medium"`
|
||||
NumVeggenti int `form:"numero-veggenti"`
|
||||
}
|
||||
|
||||
if err := c.BodyParser(&form); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg := model.PartitaConfig{
|
||||
NumeroPerRuolo: map[string]int{},
|
||||
}
|
||||
|
||||
if err := util.AtoiInto(form.NumGiocatori, &cfg.NumeroGiocatori); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Questo codice magico scorre su questa "tabella" con colonne ruolo e stringa del ruolo nel form e popola la mappa NumeroPerRuolo da uid ruolo a numero per ruolo.
|
||||
for _, r := range []struct {
|
||||
ruolo lupus.Ruolo
|
||||
num string
|
||||
}{
|
||||
{lupus.Lupo, form.NumLupi},
|
||||
{lupus.Fattucchiera, form.NumFattucchiere},
|
||||
{lupus.Guardia, form.NumGuardie},
|
||||
{lupus.Cacciatore, form.NumCacciatori},
|
||||
{lupus.Medium, form.NumMedium},
|
||||
{lupus.Veggente, form.NumVeggenti},
|
||||
} {
|
||||
num, err := strconv.Atoi(r.num)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg.NumeroPerRuolo[r.ruolo.Uid] = num
|
||||
}
|
||||
|
||||
partita, err := s.db.CreatePartita(user.Username, cfg)
|
||||
partita, err := p.Create(user.Username, handlers.PartitaConfig(form))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -139,38 +118,25 @@ func (s *Server) ApiRoutes(api fiber.Router) {
|
||||
return c.JSON(partita)
|
||||
})
|
||||
|
||||
api.Get("/user", s.requireLogged, func(c *fiber.Ctx) error {
|
||||
return c.JSON(requestUser(c).PublicUser())
|
||||
})
|
||||
|
||||
api.Get("/partita/:partita/players", func(c *fiber.Ctx) error {
|
||||
r.Get("/:partita/players", func(c *fiber.Ctx) error {
|
||||
partitaUid := c.Params("partita")
|
||||
|
||||
partita, err := s.db.GetPartita(partitaUid)
|
||||
players, err := p.GetPlayers(partitaUid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(partita.Players)
|
||||
return c.JSON(players)
|
||||
})
|
||||
|
||||
api.Get("/partita/:partita/join-partita", s.requireLogged, func(c *fiber.Ctx) error {
|
||||
r.Get("/:partita/join", func(c *fiber.Ctx) error {
|
||||
user := requestUser(c)
|
||||
partitaUid := c.Params("partita")
|
||||
|
||||
partita, err := s.db.GetPartita(partitaUid)
|
||||
if err != nil {
|
||||
if err := p.Join(partitaUid, user.Username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
partita.Players = append(partita.Players, user.Username)
|
||||
|
||||
if err := s.db.UpdatePartita(partita); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.eventBus.Dispatch(database.OnPartitaPlayersChange(partitaUid), partita.Players)
|
||||
|
||||
return c.SendString("ok")
|
||||
})
|
||||
}
|
||||
|
||||
+10
-9
@@ -3,7 +3,7 @@ package routes
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aziis98/lupus-lite/auth"
|
||||
"github.com/aziis98/lupus-lite/handlers"
|
||||
"github.com/aziis98/lupus-lite/model"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
@@ -11,26 +11,27 @@ import (
|
||||
const UserKey = "github.com/aziis98/lupus-lite/user"
|
||||
|
||||
func requestUser(c *fiber.Ctx) *model.User {
|
||||
return c.Locals(UserKey).(*model.User)
|
||||
user, ok := c.Locals(UserKey).(*model.User) // TODO: Check semantics of casting "nil" to pointer to struct
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func RequireLoggedMiddleware(auth auth.AuthService) fiber.Handler {
|
||||
func RequireLogged(server handlers.Handler) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
token := c.Cookies("sid")
|
||||
if token == "" {
|
||||
return fmt.Errorf(`request has no session token`)
|
||||
}
|
||||
|
||||
username, err := auth.UserForSession(token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user, err := auth.GetUser(username)
|
||||
user, err := server.UserForSession(token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// this is wrapped in a pointer to let "nil" mean no user logged in when calling "requestUser()"
|
||||
c.Locals(UserKey, &user)
|
||||
|
||||
return c.Next()
|
||||
|
||||
+26
-17
@@ -1,25 +1,34 @@
|
||||
package routes
|
||||
|
||||
import "github.com/gofiber/fiber/v2"
|
||||
import (
|
||||
"github.com/aziis98/lupus-lite/handlers"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func (s *Server) PageRoutes(r fiber.Router) {
|
||||
r.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("_frontend/dist/index.html")
|
||||
})
|
||||
func PageRoutes(r fiber.Router, h handlers.Handler) {
|
||||
r.Get("/",
|
||||
func(c *fiber.Ctx) error {
|
||||
return c.SendFile("_frontend/dist/index.html")
|
||||
})
|
||||
|
||||
r.Get("/login", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("_frontend/dist/login.html")
|
||||
})
|
||||
r.Get("/login",
|
||||
func(c *fiber.Ctx) error {
|
||||
return c.SendFile("_frontend/dist/login.html")
|
||||
})
|
||||
|
||||
r.Get("/register", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("_frontend/dist/register.html")
|
||||
})
|
||||
r.Get("/register",
|
||||
func(c *fiber.Ctx) error {
|
||||
return c.SendFile("_frontend/dist/register.html")
|
||||
})
|
||||
|
||||
r.Get("/crea-partita", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("_frontend/dist/crea-partita.html")
|
||||
})
|
||||
r.Get("/crea-partita",
|
||||
func(c *fiber.Ctx) error {
|
||||
return c.SendFile("_frontend/dist/crea-partita.html")
|
||||
})
|
||||
|
||||
r.Get("/p/:partita", s.requireLogged, func(c *fiber.Ctx) error {
|
||||
return c.SendFile("_frontend/dist/partita.html")
|
||||
})
|
||||
r.Get("/p/:partita",
|
||||
RequireLogged(h),
|
||||
func(c *fiber.Ctx) error {
|
||||
return c.SendFile("_frontend/dist/partita.html")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/aziis98/lupus-lite/auth"
|
||||
"github.com/aziis98/lupus-lite/database"
|
||||
"github.com/aziis98/lupus-lite/events"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
db database.Database
|
||||
auth auth.AuthService
|
||||
|
||||
// Live Updates
|
||||
eventBus *events.EventBus
|
||||
|
||||
// Utilities
|
||||
requireLogged fiber.Handler
|
||||
}
|
||||
|
||||
func NewServer() *Server {
|
||||
db, err := database.NewInMemoryDB()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
auth := auth.NewInMemoryAuthService(db)
|
||||
|
||||
return &Server{
|
||||
db: db,
|
||||
auth: auth,
|
||||
eventBus: events.NewEventBus(),
|
||||
requireLogged: RequireLoggedMiddleware(auth),
|
||||
}
|
||||
}
|
||||
+2
-111
@@ -9,103 +9,6 @@ import (
|
||||
"github.com/gofiber/websocket/v2"
|
||||
)
|
||||
|
||||
// func (s *Server) websocketHandler(handler func(c *fiber.Ctx) (interface{}, error)) fiber.Handler {
|
||||
// return websocket.New(func(c *websocket.Conn) {
|
||||
// clientId := util.GenerateRandomString(10)
|
||||
|
||||
// partitaUid := c.Params("partita")
|
||||
// log.Printf("[%v] Connection started", clientId)
|
||||
|
||||
// done := make(chan error)
|
||||
// clientListener := s.eventBus.Subscribe(
|
||||
// database.OnPartitaPlayerJoin(partitaUid),
|
||||
// func(e interface{}) {
|
||||
// partita, err := s.db.GetPartita(partitaUid)
|
||||
// if err != nil {
|
||||
// done <- err
|
||||
// return
|
||||
// }
|
||||
|
||||
// log.Printf(`[%v] Sent message`, clientId)
|
||||
// if err := c.WriteJSON(partita.Players); err != nil {
|
||||
// done <- err
|
||||
// return
|
||||
// }
|
||||
// },
|
||||
// )
|
||||
// defer func() {
|
||||
// s.eventBus.Unsubscribe(clientListener)
|
||||
// log.Printf("[%v] Connection closed", clientId)
|
||||
// }()
|
||||
|
||||
// for {
|
||||
// _, _, err := c.ReadMessage()
|
||||
// if err != nil {
|
||||
// if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
|
||||
// log.Printf("[%v] Error: %v", clientId, err)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// select {
|
||||
// case err := <-done:
|
||||
// if err != nil {
|
||||
// log.Printf(`[%v] Error: %v`, clientId, err)
|
||||
// }
|
||||
// return
|
||||
// case <-time.After(1 * time.Second):
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
// func (s *Server) registerEventBinding(event string, process func(c *fiber.Ctx, e any) (any, error)) fiber.Handler {
|
||||
// return websocket.New(func(c *websocket.Conn) {
|
||||
// clientId := util.GenerateRandomString(10)
|
||||
// log.Printf("[%v] Connection started", clientId)
|
||||
// done := make(chan error)
|
||||
// clientListener := s.eventBus.Subscribe(
|
||||
// event,
|
||||
// func(e interface{}) {
|
||||
// partita, err := s.db.GetPartita(partitaUid)
|
||||
// if err != nil {
|
||||
// done <- err
|
||||
// return
|
||||
// }
|
||||
|
||||
// log.Printf(`[%v] Sent message`, clientId)
|
||||
// if err := c.WriteJSON(partita.Players); err != nil {
|
||||
// done <- err
|
||||
// return
|
||||
// }
|
||||
// },
|
||||
// )
|
||||
// defer func() {
|
||||
// s.eventBus.Unsubscribe(clientListener)
|
||||
// log.Printf("[%v] Connection closed", clientId)
|
||||
// }()
|
||||
|
||||
// for {
|
||||
// _, _, err := c.ReadMessage()
|
||||
// if err != nil {
|
||||
// if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
|
||||
// log.Printf("[%v] Error: %v", clientId, err)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// select {
|
||||
// case err := <-done:
|
||||
// if err != nil {
|
||||
// log.Printf(`[%v] Error: %v`, clientId, err)
|
||||
// }
|
||||
// return
|
||||
// case <-time.After(1 * time.Second):
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
type clientMessage struct {
|
||||
Type string `json:"type"`
|
||||
Event string `json:"event"`
|
||||
@@ -116,8 +19,8 @@ type serverMessage struct {
|
||||
Data any `json:"data"`
|
||||
}
|
||||
|
||||
// registerEventBinder creates a WebSocket handler that can subscribe the socket to some events generated on the server, for example a message from the client like { type: "subscribe", event: "foo" } binds the connection to the event "foo" and forwards events and the associated data to client as JSON.
|
||||
func registerEventBinder(eb *events.EventBus) fiber.Handler {
|
||||
// BindWebsocketToEventBus creates a WebSocket handler that can subscribe the socket to some events generated on the server, for example a message from the client like { type: "subscribe", event: "foo" } binds the connection to the event "foo" and forwards events and the associated data to client as JSON.
|
||||
func BindWebsocketToEventBus(eb *events.EventBus) fiber.Handler {
|
||||
return websocket.New(func(c *websocket.Conn) {
|
||||
clientId := util.GenerateRandomString(10)
|
||||
|
||||
@@ -172,15 +75,3 @@ func registerEventBinder(eb *events.EventBus) fiber.Handler {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) EventRoute(r fiber.Router) {
|
||||
r.Use("/ws", func(c *fiber.Ctx) error {
|
||||
if websocket.IsWebSocketUpgrade(c) {
|
||||
c.Locals("allowed", true)
|
||||
return c.Next()
|
||||
}
|
||||
return fiber.ErrUpgradeRequired
|
||||
})
|
||||
|
||||
r.Get("/ws", registerEventBinder(s.eventBus))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user