feat: impl release hand & next speaker selection
This commit is contained in:
parent
aa048efbd3
commit
480d007e6c
4
main.go
4
main.go
|
@ -31,10 +31,10 @@ func main() {
|
|||
|
||||
fmt.Printf("Server will start on port %d\n", port)
|
||||
|
||||
rooms := rooms.RedisRM { Rdb: rdb, }
|
||||
roomsM := rooms.RedisRM { Rdb: rdb, }
|
||||
sessions := sessions.RedisSM{ Rdb: rdb, }
|
||||
|
||||
routes.RegisterRoutes(sessions, rooms)
|
||||
routes.RegisterRoutes(sessions, roomsM)
|
||||
|
||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
package rooms
|
||||
|
||||
import (
|
||||
"log"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type Room struct {
|
||||
Name string // will be unique ID
|
||||
AdminIds []PersonId
|
||||
PasswordHash string
|
||||
CurrentSpeaker PersonId // i guess let's set to zero value when it's noone from the room
|
||||
Paricipants []Person
|
||||
// TODO hands, for each type of hand?
|
||||
// i guess participants order fixed for now?
|
||||
// and i'll still need 'current' for each hand level
|
||||
ParticipantHands map[PersonId]HandGesture
|
||||
Marks map[HandGesture]PersonId
|
||||
}
|
||||
|
||||
func (r *Room)InitMaps() {
|
||||
if r.ParticipantHands == nil {
|
||||
r.ParticipantHands = make(map[PersonId]HandGesture)
|
||||
}
|
||||
if r.Marks == nil {
|
||||
r.Marks = make(map[HandGesture]PersonId)
|
||||
}
|
||||
}
|
||||
|
||||
// and how would i organize?
|
||||
// i should have map[HandGesture]ParticipantId as mark. for 'from where to go clockwise if returning a level lover'
|
||||
// now i want methods that for some person raise some hand, so i guess it adds what? to map[ParticipantId]HandGesture
|
||||
// i suppose methods should be on a room, in a session i'd have ParticipantId to pass in, and would load room
|
||||
// and i want all parts of room in same struct, because i'd want to subscribe to changes to all of them
|
||||
|
||||
// i suppose raising a hand could be just in place adding PersonId->HandGesture,
|
||||
// but releasing hand should have additional logic
|
||||
func (r *Room) ReleaseHand(p PersonId) {
|
||||
// releasing a hand of a current speaker should result in selection of a new speaker
|
||||
log.Printf("about to release hand of %d in %s", p, r.Name)
|
||||
|
||||
// first remove hand of the requested person
|
||||
currentSpeakerGesture, currentSpeakerHandFound := r.ParticipantHands[p]
|
||||
if !currentSpeakerHandFound {
|
||||
return
|
||||
}
|
||||
|
||||
delete(r.ParticipantHands, p)
|
||||
|
||||
// if not a current speaker, no complicated logic required to release a hand
|
||||
if r.CurrentSpeaker != p {
|
||||
return
|
||||
}
|
||||
|
||||
// if a current speaker - after removing the hand, we need to find next speaker
|
||||
// from highest hand gesture to lowest, until one is found
|
||||
gestures := [...]HandGesture{Meta, ClarifyingQ, Expand, ProbingQ, ChangeTopic}
|
||||
|
||||
var nextSpeakerId PersonId
|
||||
var nextSpeakerFound bool
|
||||
|
||||
gestureIteration:
|
||||
for _, gesture := range gestures {
|
||||
log.Printf("searching for gesture %s", gesture.String())
|
||||
startIndex := r.gestureSearchStartIndex(gesture, currentSpeakerGesture)
|
||||
participantsCount := len(r.Paricipants)
|
||||
for i := 1; i < participantsCount; i++ {
|
||||
checkIndex := startIndex + i%participantsCount
|
||||
checkPerson := r.Paricipants[checkIndex]
|
||||
checkGesture, isFound := r.ParticipantHands[checkPerson.Id]
|
||||
if isFound && checkGesture == gesture {
|
||||
nextSpeakerId, nextSpeakerFound = checkPerson.Id, true
|
||||
break gestureIteration
|
||||
}
|
||||
}
|
||||
}
|
||||
if !nextSpeakerFound {
|
||||
log.Printf("there is not next speaker, that's ok")
|
||||
}
|
||||
|
||||
nextSpeakerGesture := r.ParticipantHands[nextSpeakerId]
|
||||
log.Printf("found next speaker %+v", nextSpeakerId)
|
||||
|
||||
if nextSpeakerGesture > currentSpeakerGesture {
|
||||
// raising the level of the speaker, need to save mark
|
||||
log.Printf("we do have nextSpeaker of priority %s higher than current %s", nextSpeakerGesture.String(), currentSpeakerGesture.String())
|
||||
r.Marks[currentSpeakerGesture] = p
|
||||
}
|
||||
|
||||
// also we need to remove marks from top to current speaker level
|
||||
for _, gesture := range gestures {
|
||||
if gesture < nextSpeakerGesture {
|
||||
break
|
||||
}
|
||||
delete(r.Marks, gesture)
|
||||
}
|
||||
|
||||
r.CurrentSpeaker = nextSpeakerId
|
||||
}
|
||||
|
||||
// find place to start - separate function
|
||||
// current speaker level, searched gesture level, room marks
|
||||
// if search level >= current speaker start from speaker
|
||||
// if search level < current speaekr look for mark, start from mark of that level,
|
||||
//
|
||||
// if no mark - from speaker
|
||||
func (r *Room) gestureSearchStartIndex(gesture, curSpeakerGesture HandGesture) int {
|
||||
if r.CurrentSpeaker == PersonId(0) {
|
||||
// nobody is actully a speaker
|
||||
return 0
|
||||
}
|
||||
|
||||
var personFromWhichToStartSearch PersonId
|
||||
|
||||
// if searched guesture is higher or same as current speaker, start from speaker
|
||||
if gesture >= curSpeakerGesture {
|
||||
personFromWhichToStartSearch = r.CurrentSpeaker
|
||||
}
|
||||
// if searched gesture is of lower priority from current speaker, check marks to return to, or use speaker level
|
||||
gestureMark, found := r.Marks[gesture]
|
||||
if found {
|
||||
personFromWhichToStartSearch = gestureMark
|
||||
}
|
||||
// if no mark found - count from the speaker
|
||||
personFromWhichToStartSearch = r.CurrentSpeaker
|
||||
|
||||
indexFromWhichToStart := slices.IndexFunc(r.Paricipants, func(p Person) bool {
|
||||
return p.Id == personFromWhichToStartSearch
|
||||
})
|
||||
return indexFromWhichToStart
|
||||
}
|
||||
|
||||
// sooooooo. i need hand types. are there enums in go?
|
||||
type HandGesture uint8
|
||||
|
||||
const (
|
||||
ChangeTopic HandGesture = iota
|
||||
ProbingQ
|
||||
Expand
|
||||
ClarifyingQ
|
||||
Meta
|
||||
)
|
||||
|
||||
// String() method to print the name of the days
|
||||
func (g HandGesture) String() string {
|
||||
return [...]string{"Change Topic", "Probing Quesion", "Expand", "Clarifying Quesion", "Meta"}[g]
|
||||
}
|
|
@ -5,25 +5,28 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"log"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
PersonId int
|
||||
Name string
|
||||
PasswordHash string
|
||||
type PersonId int
|
||||
|
||||
// TODO move to rooms i guess
|
||||
func RandomPersonId() PersonId {
|
||||
randInt := rand.Int()
|
||||
if randInt == 0 {
|
||||
randInt = 1
|
||||
}
|
||||
return PersonId(randInt)
|
||||
}
|
||||
|
||||
type Room struct {
|
||||
Name string // will be unique ID
|
||||
AdminIds []int
|
||||
|
||||
type Person struct {
|
||||
Id PersonId
|
||||
Name string
|
||||
PasswordHash string
|
||||
Paricipants []Person
|
||||
// TODO hands, for each type of hand?
|
||||
// i guess participants order fixed for now?
|
||||
// and i'll still need 'current' for each hand level
|
||||
}
|
||||
|
||||
// well, it seems that i'd better do marshalling into bytes then
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
|
@ -31,6 +30,7 @@ func registerLoginRoutes(
|
|||
|
||||
const authCookieName = "auth"
|
||||
const loginPath = "/login"
|
||||
|
||||
type contextKey string
|
||||
|
||||
func getContextSession(ctx context.Context) (sessions.SessionData, bool) {
|
||||
|
@ -108,14 +108,14 @@ func createRoomHandler( templateFs *embed.FS,
|
|||
return
|
||||
}
|
||||
person := rooms.Person{
|
||||
PersonId: rand.Int(),
|
||||
Id: rooms.RandomPersonId(),
|
||||
Name: r.PostFormValue("personalName"),
|
||||
PasswordHash: r.PostFormValue("personalPassword"), // TODO hash the password, not to store
|
||||
}
|
||||
newRoom := rooms.Room{
|
||||
Name: roomName,
|
||||
PasswordHash: r.PostFormValue("roomPassword"), // TODO hash the password, not to store
|
||||
AdminIds: []int{person.PersonId},
|
||||
AdminIds: []rooms.PersonId{person.Id},
|
||||
Paricipants: []rooms.Person{person},
|
||||
}
|
||||
err = roomsM.Save(newRoom)
|
||||
|
@ -123,7 +123,7 @@ func createRoomHandler( templateFs *embed.FS,
|
|||
log.Printf("what am i to do? error saving room %s", err)
|
||||
// todo return error notice somehow
|
||||
}
|
||||
newSessionId, err := sessionSM.Save(newRoom.Name, person.PersonId)
|
||||
newSessionId, err := sessionSM.Save(newRoom.Name, person.Id)
|
||||
if err != nil {
|
||||
log.Printf("what am i to do? error saving session %s", err)
|
||||
// todo return error notice somehow
|
||||
|
@ -223,7 +223,7 @@ func joinRoomHandler( templateFs *embed.FS,
|
|||
person = rooms.Person{
|
||||
Name: personName,
|
||||
PasswordHash: personPass,
|
||||
PersonId: rand.Int(),
|
||||
Id: rooms.RandomPersonId(),
|
||||
}
|
||||
err := roomsM.Update(context.TODO(), room.Name, func(fromRoom rooms.Room) (toRoom rooms.Room) {
|
||||
toRoom = fromRoom
|
||||
|
@ -242,7 +242,7 @@ func joinRoomHandler( templateFs *embed.FS,
|
|||
// now we have room and person, can create a session
|
||||
// and we've checked password
|
||||
|
||||
newSessionId, err := sessionSM.Save(room.Name, person.PersonId)
|
||||
newSessionId, err := sessionSM.Save(room.Name, person.Id)
|
||||
if err != nil {
|
||||
log.Printf("/login/submit > error saving session %s", err)
|
||||
}
|
||||
|
@ -261,4 +261,3 @@ func joinRoomHandler( templateFs *embed.FS,
|
|||
w.Header().Add("HX-Redirect", "/")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,18 +6,20 @@ import (
|
|||
"log"
|
||||
"math/rand"
|
||||
|
||||
"sunshine.industries/some-automoderation/rooms"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type SessionData struct {
|
||||
SessionId int `redis:"session_id"`
|
||||
RoomId string `redis:"room_id"`
|
||||
PersonId int `redis:"person_id"`
|
||||
PersonId rooms.PersonId `redis:"person_id"`
|
||||
}
|
||||
|
||||
type SessionManagement interface {
|
||||
Get(sessionId int) SessionData
|
||||
Save(roomName string, personId int) (int, error)
|
||||
Save(roomName string, personId rooms.PersonId) (int, error)
|
||||
}
|
||||
|
||||
var ctx = context.Background()
|
||||
|
@ -43,7 +45,7 @@ func (redisSM RedisSM) Get(sessionId int) SessionData {
|
|||
log.Printf("> successfully found %d %+v", sessionId, foundSession)
|
||||
return foundSession
|
||||
}
|
||||
func (redisSM RedisSM) Save(roomName string, personId int) (int, error) {
|
||||
func (redisSM RedisSM) Save(roomName string, personId rooms.PersonId) (int, error) {
|
||||
randId := rand.Int()
|
||||
newSession := SessionData{
|
||||
SessionId: randId,
|
||||
|
@ -64,7 +66,7 @@ func (d DummySM) Get(sessionId int) SessionData {
|
|||
log.Printf("get dummy session by %d", sessionId)
|
||||
return SessionData{}
|
||||
}
|
||||
func (d DummySM) Save(roomName string, personId int) (int, error) {
|
||||
func (d DummySM) Save(roomName string, personId rooms.PersonId) (int, error) {
|
||||
log.Printf("save dummy session with %s %d", roomName, personId)
|
||||
return 1, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue