mirror of
https://github.com/harshabose/socket-comm.git
synced 2025-10-16 12:40:43 +08:00
188 lines
4.4 KiB
Go
188 lines
4.4 KiB
Go
package room
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/harshabose/socket-comm/pkg/message"
|
|
"github.com/harshabose/socket-comm/pkg/middleware/chat/errors"
|
|
"github.com/harshabose/socket-comm/pkg/middleware/chat/interfaces"
|
|
"github.com/harshabose/socket-comm/pkg/middleware/chat/types"
|
|
)
|
|
|
|
type Room struct {
|
|
// NOTE: MAYBE A CONFIG FOR ROOM?
|
|
roomid types.RoomID
|
|
allowed []types.ClientID
|
|
participants map[types.ClientID]interfaces.State
|
|
cancel context.CancelFunc
|
|
ctx context.Context
|
|
}
|
|
|
|
func NewRoom(ctx context.Context, cancel context.CancelFunc, id types.RoomID, allowed []types.ClientID) *Room {
|
|
return &Room{
|
|
ctx: ctx,
|
|
cancel: cancel,
|
|
roomid: id,
|
|
allowed: allowed,
|
|
participants: make(map[types.ClientID]interfaces.State),
|
|
}
|
|
}
|
|
|
|
func (r *Room) ID() types.RoomID {
|
|
return r.roomid
|
|
}
|
|
|
|
func (r *Room) Add(roomid types.RoomID, s interfaces.State) error {
|
|
if roomid != r.roomid {
|
|
return errors.ErrWrongRoom
|
|
}
|
|
|
|
id, err := s.GetClientID()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
select {
|
|
case <-r.ctx.Done():
|
|
return fmt.Errorf("error while adding client to room. client ID: %s; room ID: %s; err: %s", id, r.roomid, errors.ErrContextCancelled.Error())
|
|
default:
|
|
if !r.isAllowed(id) {
|
|
return fmt.Errorf("error while adding client to room. client ID: %s; room ID: %s; err: %s", id, r.roomid, errors.ErrClientNotAllowedInRoom.Error())
|
|
}
|
|
|
|
if r.isParticipant(id) {
|
|
return fmt.Errorf("client with id '%s' already existing in the room with id %s; err: %s", id, r.roomid, errors.ErrClientIsAlreadyParticipant)
|
|
}
|
|
|
|
r.participants[id] = s
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (r *Room) isAllowed(id types.ClientID) bool {
|
|
select {
|
|
case <-r.ctx.Done():
|
|
return false
|
|
default:
|
|
if len(r.allowed) == 0 {
|
|
return true
|
|
}
|
|
|
|
for _, allowedID := range r.allowed {
|
|
if allowedID == id {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (r *Room) forEachBoolean(f func(id types.ClientID) bool, ids ...types.ClientID) bool {
|
|
if len(ids) == 0 {
|
|
return false
|
|
}
|
|
|
|
for _, id := range ids {
|
|
if !f(id) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (r *Room) Remove(roomid types.RoomID, s interfaces.State) error {
|
|
if roomid != r.roomid {
|
|
return errors.ErrWrongRoom
|
|
}
|
|
|
|
id, err := s.GetClientID()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
select {
|
|
case <-r.ctx.Done():
|
|
return fmt.Errorf("error while removing client to room. client ID: %s; room ID: %s; err: %s", id, r.roomid, errors.ErrContextCancelled.Error())
|
|
default:
|
|
if !r.isAllowed(id) {
|
|
return fmt.Errorf("error while removing client to room. client ID: %s; room ID: %s; err: %s", id, r.roomid, errors.ErrClientNotAllowedInRoom.Error())
|
|
}
|
|
|
|
if !r.isParticipant(id) {
|
|
return fmt.Errorf("client with id '%s' does not exist in the room with id %s; err: %s", id, r.roomid, errors.ErrClientNotAParticipant.Error())
|
|
}
|
|
|
|
delete(r.participants, id)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (r *Room) isParticipant(id types.ClientID) bool {
|
|
select {
|
|
case <-r.ctx.Done():
|
|
return false
|
|
default:
|
|
_, exists := r.participants[id]
|
|
return exists
|
|
}
|
|
}
|
|
|
|
func (r *Room) WriteRoomMessage(roomid types.RoomID, msg message.Message, from types.ClientID, tos ...types.ClientID) error {
|
|
select {
|
|
case <-r.ctx.Done():
|
|
return fmt.Errorf("error while sending message to peer in room; err: %s", errors.ErrContextCancelled.Error())
|
|
default:
|
|
if roomid != r.roomid {
|
|
return errors.ErrWrongRoom
|
|
}
|
|
|
|
if len(tos) == 0 {
|
|
return fmt.Errorf("atleast one receiver is need to use 'WriteRoomMessage' message")
|
|
}
|
|
|
|
if !r.forEachBoolean(r.isAllowed, append(tos, from)...) {
|
|
return errors.ErrClientNotAllowedInRoom
|
|
}
|
|
|
|
if !r.forEachBoolean(r.isParticipant, append(tos, from)...) {
|
|
return errors.ErrClientNotAParticipant
|
|
}
|
|
|
|
for _, to := range tos {
|
|
s, ok := (r.participants[to]).(interfaces.CanWriteMessage)
|
|
if !ok {
|
|
return errors.ErrInterfaceMisMatch
|
|
}
|
|
|
|
if err := s.Write(msg); err != nil {
|
|
return fmt.Errorf("error while sending message to peer in room; err: %s", err.Error())
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (r *Room) GetParticipants() []types.ClientID {
|
|
select {
|
|
case <-r.ctx.Done():
|
|
return make([]types.ClientID, 0) // EMPTY LIST
|
|
default:
|
|
clients := make([]types.ClientID, 0)
|
|
for id, _ := range r.participants {
|
|
clients = append(clients, id)
|
|
}
|
|
return clients
|
|
}
|
|
}
|
|
|
|
func (r *Room) Close() error {
|
|
r.cancel()
|
|
r.participants = make(map[types.ClientID]interfaces.State)
|
|
r.allowed = make([]types.ClientID, 0)
|
|
return nil
|
|
}
|