145 lines
3.6 KiB
Go
145 lines
3.6 KiB
Go
// SPDX-FileCopyrightText: 2021 The NGI Pointer Secure-Scuttlebutt Team of 2020/2021
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package roomstate
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"sync"
|
|
|
|
"github.com/ssbc/go-muxrpc/v2"
|
|
kitlog "go.mindeco.de/log"
|
|
|
|
refs "github.com/ssbc/go-ssb-refs"
|
|
"github.com/ssbc/go-ssb-room/v2/internal/broadcasts"
|
|
)
|
|
|
|
type Manager struct {
|
|
logger kitlog.Logger
|
|
|
|
endpointsUpdater broadcasts.EndpointsEmitter
|
|
endpointsbroadcaster *broadcasts.EndpointsBroadcast
|
|
|
|
attendantsUpdater broadcasts.AttendantsEmitter
|
|
attendantsbroadcaster *broadcasts.AttendantsBroadcast
|
|
|
|
roomMu *sync.Mutex
|
|
room roomStateMap
|
|
}
|
|
|
|
func NewManager(log kitlog.Logger) *Manager {
|
|
var m Manager
|
|
m.logger = log
|
|
m.endpointsUpdater, m.endpointsbroadcaster = broadcasts.NewEndpointsEmitter()
|
|
m.attendantsUpdater, m.attendantsbroadcaster = broadcasts.NewAttendantsEmitter()
|
|
m.roomMu = new(sync.Mutex)
|
|
m.room = make(roomStateMap)
|
|
|
|
return &m
|
|
}
|
|
|
|
// roomStateMap is a single room
|
|
type roomStateMap map[string]muxrpc.Endpoint
|
|
|
|
// copy map entries to list for broadcast update
|
|
func (rsm roomStateMap) AsList() []string {
|
|
memberList := make([]string, 0, len(rsm))
|
|
for m := range rsm {
|
|
memberList = append(memberList, m)
|
|
}
|
|
sort.Strings(memberList)
|
|
return memberList
|
|
}
|
|
|
|
func (m *Manager) RegisterLegacyEndpoints(sink broadcasts.EndpointsEmitter) {
|
|
m.endpointsbroadcaster.Register(sink)
|
|
}
|
|
|
|
func (m *Manager) RegisterAttendantsUpdates(sink broadcasts.AttendantsEmitter) {
|
|
m.attendantsbroadcaster.Register(sink)
|
|
}
|
|
|
|
// List just returns a list of feed references as strings
|
|
func (m *Manager) List() []string {
|
|
m.roomMu.Lock()
|
|
defer m.roomMu.Unlock()
|
|
return m.room.AsList()
|
|
}
|
|
|
|
func (m *Manager) ListAsRefs() []refs.FeedRef {
|
|
m.roomMu.Lock()
|
|
lst := m.room.AsList()
|
|
m.roomMu.Unlock()
|
|
|
|
rlst := make([]refs.FeedRef, len(lst))
|
|
for i, s := range lst {
|
|
fr, err := refs.ParseFeedRef(s)
|
|
if err != nil {
|
|
panic(fmt.Errorf("invalid feed ref in room state: %d: %s", i, err))
|
|
}
|
|
rlst[i] = fr
|
|
}
|
|
return rlst
|
|
}
|
|
|
|
// AddEndpoint adds the endpoint to the room
|
|
func (m *Manager) AddEndpoint(who refs.FeedRef, edp muxrpc.Endpoint) {
|
|
m.roomMu.Lock()
|
|
// add ref to to the room map
|
|
m.room[who.String()] = edp
|
|
currentMembers := m.room.AsList()
|
|
m.roomMu.Unlock()
|
|
// update all the connected tunnel.endpoints calls
|
|
m.endpointsUpdater.Update(currentMembers)
|
|
// update all the connected room.attendants calls
|
|
m.attendantsUpdater.Joined(who)
|
|
}
|
|
|
|
// Remove removes the peer from the room
|
|
func (m *Manager) Remove(who refs.FeedRef) {
|
|
m.roomMu.Lock()
|
|
// remove ref from lobby
|
|
delete(m.room, who.String())
|
|
currentMembers := m.room.AsList()
|
|
m.roomMu.Unlock()
|
|
// update all the connected tunnel.endpoints calls
|
|
m.endpointsUpdater.Update(currentMembers)
|
|
// update all the connected room.attendants calls
|
|
m.attendantsUpdater.Left(who)
|
|
}
|
|
|
|
// AlreadyAdded returns true if the peer was already added to the room.
|
|
// if it isn't it will be added.
|
|
func (m *Manager) AlreadyAdded(who refs.FeedRef, edp muxrpc.Endpoint) bool {
|
|
m.roomMu.Lock()
|
|
|
|
var currentMembers []string
|
|
// if the peer didn't call tunnel.announce()
|
|
_, has := m.room[who.String()]
|
|
if !has {
|
|
// register them as if they didnt
|
|
m.room[who.String()] = edp
|
|
currentMembers = m.room.AsList()
|
|
}
|
|
m.roomMu.Unlock()
|
|
|
|
if !has {
|
|
// update everyone
|
|
m.endpointsUpdater.Update(currentMembers)
|
|
m.attendantsUpdater.Joined(who)
|
|
}
|
|
|
|
return has
|
|
}
|
|
|
|
// Has returns true and the endpoint if the peer is in the room
|
|
func (m *Manager) Has(who refs.FeedRef) (muxrpc.Endpoint, bool) {
|
|
m.roomMu.Lock()
|
|
// add ref to to the room map
|
|
edp, has := m.room[who.String()]
|
|
m.roomMu.Unlock()
|
|
return edp, has
|
|
}
|