some-automoderation/routes/room_page.go

300 lines
8.9 KiB
Go

package routes
import (
"bytes"
"embed"
"fmt"
"html/template"
"log"
"net/http"
"strconv"
"strings"
"sunshine.industries/some-automoderation/rooms"
"sunshine.industries/some-automoderation/sessions"
)
const roomPath = "/room/"
const raiseHandPath = "/rooms/raise/"
const subscribeRoomPath = "/rooms/subscribe"
// registering all routes for page and logic of /room/:roomName
func registerPageRoutes(
templateFs *embed.FS,
sessionSM sessions.SessionManagement,
roomsM rooms.RoomManager,
) {
http.Handle(roomPath, // ending in / captures all following path sections, i.e room name
http.StripPrefix(roomPath, roomPageRoute(templateFs, roomsM, sessionSM)))
http.Handle(raiseHandPath, // ending in / captures all following path sections, i.e gesture num
authedPageMiddleware(
sessionSM,
http.StripPrefix(raiseHandPath, raiseGestureHandRoute(roomsM))))
http.Handle("/rooms/releaseHand",
authedPageMiddleware(sessionSM, releaseHandRoute(roomsM)))
http.Handle(subscribeRoomPath,
authedPageMiddleware(
sessionSM,
http.StripPrefix(subscribeRoomPath, streamingRoomStates(templateFs, roomsM))))
http.HandleFunc("/rooms/preview-templates", roomTemplatesPreview(templateFs))
http.HandleFunc("/rooms/speakerControls", speakerControlsRoute(templateFs))
}
func streamingRoomStates(
templateFs *embed.FS,
roomsM rooms.RoomManager,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
roomName := r.FormValue("roomName")
defer log.Printf("/rooms/subscribe/%s stream ended\n", roomName)
session, found := getContextSession(r.Context())
if !found {
log.Printf("/rooms/raiseGesture session not found, should be impossible")
// TODO return error i guess
return
}
if session.RoomId != roomName {
// not authorized
log.Printf("/rooms/streamingRoom got unauth with session.RoomId (%s) != roomName (%s)", session.RoomId, roomName)
w.WriteHeader(http.StatusUnauthorized)
return
}
log.Printf("Starting stream for room %s for %d\n", roomName, session.PersonId)
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
w.Header().Set("Content-Type", "text/event-stream")
templFile := "templates/room.gohtml"
tableTemplates := "templates/tableTemplates.gohtml"
tmpl := template.Must(
template.New("").ParseFS(templateFs, tableTemplates, templFile))
roomStream := roomsM.Subscribe(r.Context(), roomName)
for room := range roomStream {
// log.Printf("/rooms/streamingRoom iterating with %+v", room)
fmt.Fprint(w, "event: roomTableUpdate\ndata: ")
var buffer bytes.Buffer
roomTemplateData := roomTableData{
Room: &room,
currentPerson: session.PersonId,
}
err := tmpl.ExecuteTemplate(&buffer, "simpleRoomShow", &roomTemplateData)
if err != nil {
log.Printf("/rooms/subscribe/%s got error on template %s", roomName, err)
}
templateStr := buffer.String()
templateLine := strings.ReplaceAll(templateStr, "\n", "")
fmt.Fprint(w, templateLine)
fmt.Fprint(w, "\n\n")
w.(http.Flusher).Flush()
if session.PersonId == room.CurrentSpeaker {
log.Printf("/rooms/subscribe sending 'become-speaker' to %s", session.PersonId)
fmt.Fprint(w, "event: become-speaker\ndata:yo\n\n")
w.(http.Flusher).Flush()
}
}
}
}
// if currently speaking? i guess first lower the hand and then raise new
// TODO should return control for raised state
func raiseGestureHandRoute(
roomsM rooms.RoomManager,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
gestureInd, err := strconv.Atoi(r.URL.Path)
selectedGesture, found := rooms.GestureFromInt(gestureInd)
if err != nil || !found {
log.Printf("/rooms/raiseGesture error %s gettin hand symbol index from path %s\n", err, r.URL.Path)
return
}
log.Printf("/rooms/raiseGesture successfully got gesture %d : %s", selectedGesture, selectedGesture.String())
session, found := getContextSession(r.Context())
if !found {
log.Printf("/rooms/raiseGesture session not found, should be impossible")
// TODO return error i guess
return
}
var room rooms.Room
err = roomsM.Update(r.Context(), session.RoomId, func(fromRoom rooms.Room) (toRoom rooms.Room) {
toRoom = fromRoom.RaiseHand(session.PersonId, selectedGesture)
room = toRoom
return toRoom
})
if err != nil {
log.Printf("/rooms/raiseGesture error saving hand: %s\n", err)
return
// TODO return error i guess
}
tableTemplates := "templates/room.gohtml"
tmpl := template.Must(
template.New("").ParseFS(templateFs, tableTemplates))
if session.PersonId == room.CurrentSpeaker {
tmpl.ExecuteTemplate(w, "speakerControls", nil)
return
} else {
var gesturesData []GestureData
for _, gesture := range rooms.GesturesHighToLow {
gesturesData = append(gesturesData, GestureData{
Url: fmt.Sprintf("%s%d", raiseHandPath, gesture),
Gesture: gesture,
IsSelected: selectedGesture == gesture,
})
}
err = tmpl.ExecuteTemplate(w, "controls", &gesturesData)
if err != nil {
log.Printf("/rooms/releaseHand error saving hand: %s\n", err)
return
// TODO return error i guess
}
}
}
}
// TODO should return lowered control for passed hand gesture, i guess optional
func releaseHandRoute(
roomsM rooms.RoomManager,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
session, found := getContextSession(r.Context())
if !found {
log.Printf("/rooms/releaseHand session not found, should be impossible")
// TODO return error i guess
return
}
err := roomsM.Update(r.Context(), session.RoomId, func(fromRoom rooms.Room) (toRoom rooms.Room) {
toRoom = fromRoom
toRoom.ReleaseHand(session.PersonId)
return toRoom
})
if err != nil {
log.Printf("/rooms/releaseHand error saving hand: %s\n", err)
return
// TODO return error i guess
}
tableTemplates := "templates/room.gohtml"
tmpl := template.Must(
template.New("").ParseFS(templateFs, tableTemplates))
var gesturesData []GestureData
for _, gesture := range rooms.GesturesHighToLow {
gesturesData = append(gesturesData, GestureData{
Url: fmt.Sprintf("%s%d", raiseHandPath, gesture),
Gesture: gesture,
IsSelected: false,
})
}
err = tmpl.ExecuteTemplate(w, "controls", &gesturesData)
if err != nil {
log.Printf("/rooms/releaseHand error saving hand: %s\n", err)
return
// TODO return error i guess
}
}
}
func roomPageRoute(
templateFs *embed.FS,
roomsM rooms.RoomManager,
sessionSM sessions.SessionManagement,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
roomName := r.URL.Path
if roomName == "" {
log.Printf("access to empty room")
// TODO return error i suppose
w.Header().Add("HX-Redirect", "/")
return
}
// check session,
session, err := getRequestSession(r, sessionSM)
room, found, err := roomsM.Get(roomName)
if err != nil || session.RoomId != roomName {
log.Printf("not authed with session %+v | error %s, but for wrong room, trying to access %s", session, err, roomName)
renderLoginPage(w, roomName, found)
return
}
if err != nil || !found {
log.Printf("/room room for name %s not found or err: %s / found %t", roomName, err, found)
// TODO here should be append to error place
w.Header().Add("HX-Redirect", "/")
return
}
// now we should have a session for this specific room
fmt.Printf("all checks for room %s passed with %+v", roomName, session)
templFile := "templates/room.gohtml"
baseFile := "templates/base.gohtml"
tableTemplates := "templates/tableTemplates.gohtml"
tmpl := template.Must(
template.New("").ParseFS(templateFs, tableTemplates, templFile, baseFile))
var gesturesData []GestureData
selectedGesture, isSelected := room.ParticipantHands[session.PersonId]
for _, gesture := range rooms.GesturesHighToLow {
gesturesData = append(gesturesData, GestureData{
Url: fmt.Sprintf("%s%d", raiseHandPath, gesture),
Gesture: gesture,
IsSelected: isSelected && selectedGesture == gesture,
})
}
contentData := struct {
Room *roomTableData
Gestures []GestureData
}{
Room: &roomTableData{
Room: &room,
currentPerson: session.PersonId,
},
Gestures: gesturesData,
}
data := pageData{
Base: baseData{
Title: "room-lala-from-base",
},
Content: contentData,
Header: headerData{
Title: room.Name,
},
}
err = tmpl.ExecuteTemplate(w, "full-page", data)
if err != nil {
log.Printf("/room/%s my error in executing template, huh\n %s", roomName, err)
}
}
}
func speakerControlsRoute(
templateFs *embed.FS,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
templateFile := "templates/room.gohtml"
tmpl := template.Must(template.ParseFS(templateFs, templateFile))
tmpl.ExecuteTemplate(w, "speakerControls", nil)
}
}
type GestureData struct {
Url string
Gesture rooms.HandGesture
IsSelected bool
}