mirror of
https://github.com/livekit/livekit.git
synced 2026-07-28 09:59:26 +00:00
Small refactor (#148)
* small refactor * extra line * fix room allocator test * selector fakes not used * keep decisions out of router * put nodeId logic back * fix room allocator test
This commit is contained in:
+11
-9
@@ -10,8 +10,6 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/routing/selector"
|
||||
)
|
||||
|
||||
var DefaultStunServers = []string{
|
||||
@@ -112,9 +110,17 @@ type WebHookConfig struct {
|
||||
}
|
||||
|
||||
type NodeSelectorConfig struct {
|
||||
Kind string `yaml:"kind"`
|
||||
SysloadLimit float32 `yaml:"sysload_limit"`
|
||||
Regions []selector.RegionConfig `yaml:"regions"`
|
||||
Kind string `yaml:"kind"`
|
||||
SysloadLimit float32 `yaml:"sysload_limit"`
|
||||
Regions []RegionConfig `yaml:"regions"`
|
||||
}
|
||||
|
||||
// RegionConfig lists available regions and their latitude/longitude, so the selector would prefer
|
||||
// regions that are closer
|
||||
type RegionConfig struct {
|
||||
Name string `yaml:"name"`
|
||||
Lat float64 `yaml:"lat"`
|
||||
Lon float64 `yaml:"lon"`
|
||||
}
|
||||
|
||||
func NewConfig(confString string, c *cli.Context) (*Config, error) {
|
||||
@@ -255,7 +261,3 @@ func (conf *Config) unmarshalKeys(keys string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAudioConfig(conf *Config) AudioConfig {
|
||||
return conf.Audio
|
||||
}
|
||||
|
||||
@@ -3,8 +3,12 @@ package routing
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/livekit/protocol/logger"
|
||||
livekit "github.com/livekit/protocol/proto"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/config"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate
|
||||
@@ -40,15 +44,17 @@ type RTCMessageCallback func(ctx context.Context, roomName, identity string, msg
|
||||
// Router allows multiple nodes to coordinate the participant session
|
||||
//counterfeiter:generate . Router
|
||||
type Router interface {
|
||||
GetNodeForRoom(ctx context.Context, roomName string) (*livekit.Node, error)
|
||||
SetNodeForRoom(ctx context.Context, roomName string, nodeId string) error
|
||||
ClearRoomState(ctx context.Context, roomName string) error
|
||||
RegisterNode() error
|
||||
UnregisterNode() error
|
||||
RemoveDeadNodes() error
|
||||
|
||||
GetNode(nodeId string) (*livekit.Node, error)
|
||||
ListNodes() ([]*livekit.Node, error)
|
||||
|
||||
GetNodeForRoom(ctx context.Context, roomName string) (*livekit.Node, error)
|
||||
SetNodeForRoom(ctx context.Context, roomName, nodeId string) error
|
||||
ClearRoomState(ctx context.Context, roomName string) error
|
||||
|
||||
// StartParticipantSignal participant signal connection is ready to start
|
||||
StartParticipantSignal(ctx context.Context, roomName string, pi ParticipantInit) (connectionId string, reqSink MessageSink, resSource MessageSource, err error)
|
||||
|
||||
@@ -62,12 +68,16 @@ type Router interface {
|
||||
OnRTCMessage(callback RTCMessageCallback)
|
||||
|
||||
Start() error
|
||||
PreStop()
|
||||
Drain()
|
||||
Stop()
|
||||
}
|
||||
|
||||
// NodeSelector selects an appropriate node to run the current session
|
||||
//counterfeiter:generate . NodeSelector
|
||||
type NodeSelector interface {
|
||||
SelectNode(nodes []*livekit.Node, room *livekit.Room) (*livekit.Node, error)
|
||||
func CreateRouter(conf *config.Config, rc *redis.Client, node LocalNode) Router {
|
||||
if rc != nil {
|
||||
return NewRedisRouter(node, rc)
|
||||
}
|
||||
|
||||
// local routing and store
|
||||
logger.Infow("using single-node routing")
|
||||
return NewLocalRouter(node)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func (r *LocalRouter) GetNodeForRoom(ctx context.Context, roomName string) (*liv
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (r *LocalRouter) SetNodeForRoom(ctx context.Context, roomName string, nodeId string) error {
|
||||
func (r *LocalRouter) SetNodeForRoom(ctx context.Context, roomName, nodeId string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ func (r *LocalRouter) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *LocalRouter) PreStop() {
|
||||
func (r *LocalRouter) Drain() {
|
||||
r.currentNode.State = livekit.NodeState_SHUTTING_DOWN
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/livekit/livekit-server/pkg/routing/selector"
|
||||
"github.com/livekit/protocol/logger"
|
||||
livekit "github.com/livekit/protocol/proto"
|
||||
"github.com/livekit/protocol/utils"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/routing/selector"
|
||||
"github.com/livekit/livekit-server/pkg/utils/stats"
|
||||
)
|
||||
|
||||
@@ -26,6 +26,7 @@ const (
|
||||
// Because
|
||||
type RedisRouter struct {
|
||||
LocalRouter
|
||||
|
||||
rc *redis.Client
|
||||
ctx context.Context
|
||||
isStarted utils.AtomicFlag
|
||||
@@ -85,7 +86,7 @@ func (r *RedisRouter) GetNodeForRoom(ctx context.Context, roomName string) (*liv
|
||||
return r.GetNode(nodeId)
|
||||
}
|
||||
|
||||
func (r *RedisRouter) SetNodeForRoom(ctx context.Context, roomName string, nodeId string) error {
|
||||
func (r *RedisRouter) SetNodeForRoom(ctx context.Context, roomName, nodeId string) error {
|
||||
return r.rc.HSet(r.ctx, NodeRoomKey, roomName, nodeId).Err()
|
||||
}
|
||||
|
||||
@@ -259,7 +260,7 @@ func (r *RedisRouter) Start() error {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RedisRouter) PreStop() {
|
||||
func (r *RedisRouter) Drain() {
|
||||
r.currentNode.State = livekit.NodeState_SHUTTING_DOWN
|
||||
r.RegisterNode()
|
||||
}
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
// Code generated by counterfeiter. DO NOT EDIT.
|
||||
package routingfakes
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/routing"
|
||||
livekit "github.com/livekit/protocol/proto"
|
||||
)
|
||||
|
||||
type FakeNodeSelector struct {
|
||||
SelectNodeStub func([]*livekit.Node, *livekit.Room) (*livekit.Node, error)
|
||||
selectNodeMutex sync.RWMutex
|
||||
selectNodeArgsForCall []struct {
|
||||
arg1 []*livekit.Node
|
||||
arg2 *livekit.Room
|
||||
}
|
||||
selectNodeReturns struct {
|
||||
result1 *livekit.Node
|
||||
result2 error
|
||||
}
|
||||
selectNodeReturnsOnCall map[int]struct {
|
||||
result1 *livekit.Node
|
||||
result2 error
|
||||
}
|
||||
invocations map[string][][]interface{}
|
||||
invocationsMutex sync.RWMutex
|
||||
}
|
||||
|
||||
func (fake *FakeNodeSelector) SelectNode(arg1 []*livekit.Node, arg2 *livekit.Room) (*livekit.Node, error) {
|
||||
var arg1Copy []*livekit.Node
|
||||
if arg1 != nil {
|
||||
arg1Copy = make([]*livekit.Node, len(arg1))
|
||||
copy(arg1Copy, arg1)
|
||||
}
|
||||
fake.selectNodeMutex.Lock()
|
||||
ret, specificReturn := fake.selectNodeReturnsOnCall[len(fake.selectNodeArgsForCall)]
|
||||
fake.selectNodeArgsForCall = append(fake.selectNodeArgsForCall, struct {
|
||||
arg1 []*livekit.Node
|
||||
arg2 *livekit.Room
|
||||
}{arg1Copy, arg2})
|
||||
stub := fake.SelectNodeStub
|
||||
fakeReturns := fake.selectNodeReturns
|
||||
fake.recordInvocation("SelectNode", []interface{}{arg1Copy, arg2})
|
||||
fake.selectNodeMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1, arg2)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
func (fake *FakeNodeSelector) SelectNodeCallCount() int {
|
||||
fake.selectNodeMutex.RLock()
|
||||
defer fake.selectNodeMutex.RUnlock()
|
||||
return len(fake.selectNodeArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeNodeSelector) SelectNodeCalls(stub func([]*livekit.Node, *livekit.Room) (*livekit.Node, error)) {
|
||||
fake.selectNodeMutex.Lock()
|
||||
defer fake.selectNodeMutex.Unlock()
|
||||
fake.SelectNodeStub = stub
|
||||
}
|
||||
|
||||
func (fake *FakeNodeSelector) SelectNodeArgsForCall(i int) ([]*livekit.Node, *livekit.Room) {
|
||||
fake.selectNodeMutex.RLock()
|
||||
defer fake.selectNodeMutex.RUnlock()
|
||||
argsForCall := fake.selectNodeArgsForCall[i]
|
||||
return argsForCall.arg1, argsForCall.arg2
|
||||
}
|
||||
|
||||
func (fake *FakeNodeSelector) SelectNodeReturns(result1 *livekit.Node, result2 error) {
|
||||
fake.selectNodeMutex.Lock()
|
||||
defer fake.selectNodeMutex.Unlock()
|
||||
fake.SelectNodeStub = nil
|
||||
fake.selectNodeReturns = struct {
|
||||
result1 *livekit.Node
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeNodeSelector) SelectNodeReturnsOnCall(i int, result1 *livekit.Node, result2 error) {
|
||||
fake.selectNodeMutex.Lock()
|
||||
defer fake.selectNodeMutex.Unlock()
|
||||
fake.SelectNodeStub = nil
|
||||
if fake.selectNodeReturnsOnCall == nil {
|
||||
fake.selectNodeReturnsOnCall = make(map[int]struct {
|
||||
result1 *livekit.Node
|
||||
result2 error
|
||||
})
|
||||
}
|
||||
fake.selectNodeReturnsOnCall[i] = struct {
|
||||
result1 *livekit.Node
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeNodeSelector) Invocations() map[string][][]interface{} {
|
||||
fake.invocationsMutex.RLock()
|
||||
defer fake.invocationsMutex.RUnlock()
|
||||
fake.selectNodeMutex.RLock()
|
||||
defer fake.selectNodeMutex.RUnlock()
|
||||
copiedInvocations := map[string][][]interface{}{}
|
||||
for key, value := range fake.invocations {
|
||||
copiedInvocations[key] = value
|
||||
}
|
||||
return copiedInvocations
|
||||
}
|
||||
|
||||
func (fake *FakeNodeSelector) recordInvocation(key string, args []interface{}) {
|
||||
fake.invocationsMutex.Lock()
|
||||
defer fake.invocationsMutex.Unlock()
|
||||
if fake.invocations == nil {
|
||||
fake.invocations = map[string][][]interface{}{}
|
||||
}
|
||||
if fake.invocations[key] == nil {
|
||||
fake.invocations[key] = [][]interface{}{}
|
||||
}
|
||||
fake.invocations[key] = append(fake.invocations[key], args)
|
||||
}
|
||||
|
||||
var _ routing.NodeSelector = new(FakeNodeSelector)
|
||||
@@ -22,6 +22,10 @@ type FakeRouter struct {
|
||||
clearRoomStateReturnsOnCall map[int]struct {
|
||||
result1 error
|
||||
}
|
||||
DrainStub func()
|
||||
drainMutex sync.RWMutex
|
||||
drainArgsForCall []struct {
|
||||
}
|
||||
GetNodeStub func(string) (*livekit.Node, error)
|
||||
getNodeMutex sync.RWMutex
|
||||
getNodeArgsForCall []struct {
|
||||
@@ -71,10 +75,6 @@ type FakeRouter struct {
|
||||
onRTCMessageArgsForCall []struct {
|
||||
arg1 routing.RTCMessageCallback
|
||||
}
|
||||
PreStopStub func()
|
||||
preStopMutex sync.RWMutex
|
||||
preStopArgsForCall []struct {
|
||||
}
|
||||
RegisterNodeStub func() error
|
||||
registerNodeMutex sync.RWMutex
|
||||
registerNodeArgsForCall []struct {
|
||||
@@ -231,6 +231,30 @@ func (fake *FakeRouter) ClearRoomStateReturnsOnCall(i int, result1 error) {
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *FakeRouter) Drain() {
|
||||
fake.drainMutex.Lock()
|
||||
fake.drainArgsForCall = append(fake.drainArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.DrainStub
|
||||
fake.recordInvocation("Drain", []interface{}{})
|
||||
fake.drainMutex.Unlock()
|
||||
if stub != nil {
|
||||
fake.DrainStub()
|
||||
}
|
||||
}
|
||||
|
||||
func (fake *FakeRouter) DrainCallCount() int {
|
||||
fake.drainMutex.RLock()
|
||||
defer fake.drainMutex.RUnlock()
|
||||
return len(fake.drainArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeRouter) DrainCalls(stub func()) {
|
||||
fake.drainMutex.Lock()
|
||||
defer fake.drainMutex.Unlock()
|
||||
fake.DrainStub = stub
|
||||
}
|
||||
|
||||
func (fake *FakeRouter) GetNode(arg1 string) (*livekit.Node, error) {
|
||||
fake.getNodeMutex.Lock()
|
||||
ret, specificReturn := fake.getNodeReturnsOnCall[len(fake.getNodeArgsForCall)]
|
||||
@@ -480,30 +504,6 @@ func (fake *FakeRouter) OnRTCMessageArgsForCall(i int) routing.RTCMessageCallbac
|
||||
return argsForCall.arg1
|
||||
}
|
||||
|
||||
func (fake *FakeRouter) PreStop() {
|
||||
fake.preStopMutex.Lock()
|
||||
fake.preStopArgsForCall = append(fake.preStopArgsForCall, struct {
|
||||
}{})
|
||||
stub := fake.PreStopStub
|
||||
fake.recordInvocation("PreStop", []interface{}{})
|
||||
fake.preStopMutex.Unlock()
|
||||
if stub != nil {
|
||||
fake.PreStopStub()
|
||||
}
|
||||
}
|
||||
|
||||
func (fake *FakeRouter) PreStopCallCount() int {
|
||||
fake.preStopMutex.RLock()
|
||||
defer fake.preStopMutex.RUnlock()
|
||||
return len(fake.preStopArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeRouter) PreStopCalls(stub func()) {
|
||||
fake.preStopMutex.Lock()
|
||||
defer fake.preStopMutex.Unlock()
|
||||
fake.PreStopStub = stub
|
||||
}
|
||||
|
||||
func (fake *FakeRouter) RegisterNode() error {
|
||||
fake.registerNodeMutex.Lock()
|
||||
ret, specificReturn := fake.registerNodeReturnsOnCall[len(fake.registerNodeArgsForCall)]
|
||||
@@ -944,6 +944,8 @@ func (fake *FakeRouter) Invocations() map[string][][]interface{} {
|
||||
defer fake.invocationsMutex.RUnlock()
|
||||
fake.clearRoomStateMutex.RLock()
|
||||
defer fake.clearRoomStateMutex.RUnlock()
|
||||
fake.drainMutex.RLock()
|
||||
defer fake.drainMutex.RUnlock()
|
||||
fake.getNodeMutex.RLock()
|
||||
defer fake.getNodeMutex.RUnlock()
|
||||
fake.getNodeForRoomMutex.RLock()
|
||||
@@ -954,8 +956,6 @@ func (fake *FakeRouter) Invocations() map[string][][]interface{} {
|
||||
defer fake.onNewParticipantRTCMutex.RUnlock()
|
||||
fake.onRTCMessageMutex.RLock()
|
||||
defer fake.onRTCMessageMutex.RUnlock()
|
||||
fake.preStopMutex.RLock()
|
||||
defer fake.preStopMutex.RUnlock()
|
||||
fake.registerNodeMutex.RLock()
|
||||
defer fake.registerNodeMutex.RUnlock()
|
||||
fake.removeDeadNodesMutex.RLock()
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package selector
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
livekit "github.com/livekit/protocol/proto"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/config"
|
||||
)
|
||||
|
||||
var ErrUnsupportedSelector = errors.New("unsupported node selector")
|
||||
|
||||
// NodeSelector selects an appropriate node to run the current session
|
||||
type NodeSelector interface {
|
||||
SelectNode(nodes []*livekit.Node) (*livekit.Node, error)
|
||||
}
|
||||
|
||||
func CreateNodeSelector(conf *config.Config) (NodeSelector, error) {
|
||||
kind := conf.NodeSelector.Kind
|
||||
if kind == "" {
|
||||
kind = "random"
|
||||
}
|
||||
switch kind {
|
||||
case "sysload":
|
||||
return &SystemLoadSelector{
|
||||
SysloadLimit: conf.NodeSelector.SysloadLimit,
|
||||
}, nil
|
||||
case "regionaware":
|
||||
s, err := NewRegionAwareSelector(conf.Region, conf.NodeSelector.Regions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.SysloadLimit = conf.NodeSelector.SysloadLimit
|
||||
return s, nil
|
||||
case "random":
|
||||
return &RandomSelector{}, nil
|
||||
default:
|
||||
return nil, ErrUnsupportedSelector
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
type RandomSelector struct {
|
||||
}
|
||||
|
||||
func (s *RandomSelector) SelectNode(nodes []*livekit.Node, room *livekit.Room) (*livekit.Node, error) {
|
||||
func (s *RandomSelector) SelectNode(nodes []*livekit.Node) (*livekit.Node, error) {
|
||||
nodes = GetAvailableNodes(nodes)
|
||||
if len(nodes) == 0 {
|
||||
return nil, ErrNoAvailableNodes
|
||||
|
||||
@@ -5,25 +5,19 @@ import (
|
||||
|
||||
livekit "github.com/livekit/protocol/proto"
|
||||
"github.com/thoas/go-funk"
|
||||
)
|
||||
|
||||
// RegionConfig lists available regions and their latitude/longitude, so the selector would prefer
|
||||
// regions that are closer
|
||||
type RegionConfig struct {
|
||||
Name string `yaml:"name"`
|
||||
Lat float64 `yaml:"lat"`
|
||||
Lon float64 `yaml:"lon"`
|
||||
}
|
||||
"github.com/livekit/livekit-server/pkg/config"
|
||||
)
|
||||
|
||||
// RegionAwareSelector prefers available nodes that are closest to the region of the current instance
|
||||
type RegionAwareSelector struct {
|
||||
SystemLoadSelector
|
||||
CurrentRegion string
|
||||
regionDistances map[string]float64
|
||||
regions []RegionConfig
|
||||
regions []config.RegionConfig
|
||||
}
|
||||
|
||||
func NewRegionAwareSelector(currentRegion string, regions []RegionConfig) (*RegionAwareSelector, error) {
|
||||
func NewRegionAwareSelector(currentRegion string, regions []config.RegionConfig) (*RegionAwareSelector, error) {
|
||||
if currentRegion == "" {
|
||||
return nil, ErrCurrentRegionNotSet
|
||||
}
|
||||
@@ -34,7 +28,7 @@ func NewRegionAwareSelector(currentRegion string, regions []RegionConfig) (*Regi
|
||||
regions: regions,
|
||||
}
|
||||
|
||||
var currentRC *RegionConfig
|
||||
var currentRC *config.RegionConfig
|
||||
|
||||
for _, region := range regions {
|
||||
if region.Name == currentRegion {
|
||||
@@ -56,7 +50,7 @@ func NewRegionAwareSelector(currentRegion string, regions []RegionConfig) (*Regi
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *RegionAwareSelector) SelectNode(nodes []*livekit.Node, room *livekit.Room) (*livekit.Node, error) {
|
||||
func (s *RegionAwareSelector) SelectNode(nodes []*livekit.Node) (*livekit.Node, error) {
|
||||
nodes, err := s.SystemLoadSelector.filterNodes(nodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/routing/selector"
|
||||
livekit "github.com/livekit/protocol/proto"
|
||||
"github.com/livekit/protocol/utils"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/config"
|
||||
"github.com/livekit/livekit-server/pkg/routing/selector"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -18,7 +20,7 @@ const (
|
||||
)
|
||||
|
||||
func TestRegionAwareRouting(t *testing.T) {
|
||||
rc := []selector.RegionConfig{
|
||||
rc := []config.RegionConfig{
|
||||
{
|
||||
Name: regionWest,
|
||||
Lat: 37.64046607830567,
|
||||
@@ -42,7 +44,7 @@ func TestRegionAwareRouting(t *testing.T) {
|
||||
s, err := selector.NewRegionAwareSelector(regionEast, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
node, err := s.SelectNode(nodes, nil)
|
||||
node, err := s.SelectNode(nodes)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, node)
|
||||
})
|
||||
@@ -59,7 +61,7 @@ func TestRegionAwareRouting(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
s.SysloadLimit = loadLimit
|
||||
|
||||
node, err := s.SelectNode(nodes, nil)
|
||||
node, err := s.SelectNode(nodes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedNode, node)
|
||||
})
|
||||
@@ -76,7 +78,7 @@ func TestRegionAwareRouting(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
s.SysloadLimit = loadLimit
|
||||
|
||||
node, err := s.SelectNode(nodes, nil)
|
||||
node, err := s.SelectNode(nodes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedNode, node)
|
||||
})
|
||||
@@ -92,7 +94,7 @@ func TestRegionAwareRouting(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
s.SysloadLimit = loadLimit
|
||||
|
||||
node, err := s.SelectNode(nodes, nil)
|
||||
node, err := s.SelectNode(nodes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedNode, node)
|
||||
})
|
||||
@@ -110,7 +112,7 @@ func TestRegionAwareRouting(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
s.SysloadLimit = loadLimit
|
||||
|
||||
node, err := s.SelectNode(nodes, nil)
|
||||
node, err := s.SelectNode(nodes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedNode, node)
|
||||
})
|
||||
@@ -122,7 +124,7 @@ func TestRegionAwareRouting(t *testing.T) {
|
||||
s, err := selector.NewRegionAwareSelector(regionEast, rc)
|
||||
require.NoError(t, err)
|
||||
|
||||
node, err := s.SelectNode(nodes, nil)
|
||||
node, err := s.SelectNode(nodes)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, node)
|
||||
})
|
||||
|
||||
@@ -33,7 +33,7 @@ func (s *SystemLoadSelector) filterNodes(nodes []*livekit.Node) ([]*livekit.Node
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func (s *SystemLoadSelector) SelectNode(nodes []*livekit.Node, room *livekit.Room) (*livekit.Node, error) {
|
||||
func (s *SystemLoadSelector) SelectNode(nodes []*livekit.Node) (*livekit.Node, error) {
|
||||
nodes, err := s.filterNodes(nodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/routing/selector"
|
||||
livekit "github.com/livekit/protocol/proto"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/routing/selector"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -33,19 +34,19 @@ func TestSystemLoadSelector_SelectNode(t *testing.T) {
|
||||
selector := selector.SystemLoadSelector{SysloadLimit: 1.0}
|
||||
|
||||
nodes := []*livekit.Node{}
|
||||
_, err := selector.SelectNode(nodes, nil)
|
||||
_, err := selector.SelectNode(nodes)
|
||||
require.Error(t, err, "should error no available nodes")
|
||||
|
||||
// Select a node with high load when no nodes with low load are available
|
||||
nodes = []*livekit.Node{nodeLoadHigh}
|
||||
if _, err := selector.SelectNode(nodes, nil); err != nil {
|
||||
if _, err := selector.SelectNode(nodes); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Select a node with low load when available
|
||||
nodes = []*livekit.Node{nodeLoadLow, nodeLoadHigh}
|
||||
for i := 0; i < 5; i++ {
|
||||
node, err := selector.SelectNode(nodes, nil)
|
||||
node, err := selector.SelectNode(nodes)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@ import (
|
||||
"github.com/thoas/go-funk"
|
||||
)
|
||||
|
||||
const (
|
||||
AvailableSeconds = 5
|
||||
)
|
||||
const AvailableSeconds = 5
|
||||
|
||||
// checks if a node has been updated recently to be considered for selection
|
||||
func IsAvailable(node *livekit.Node) bool {
|
||||
|
||||
@@ -9,5 +9,4 @@ var (
|
||||
ErrParticipantNotFound = errors.New("participant does not exist")
|
||||
ErrTrackNotFound = errors.New("track is not found")
|
||||
ErrWebHookMissingAPIKey = errors.New("api_key is required to use webhooks")
|
||||
ErrUnsupportedSelector = errors.New("unsupported node selector")
|
||||
)
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate
|
||||
|
||||
// encapsulates CRUD operations for room settings
|
||||
// look up participant
|
||||
//counterfeiter:generate . RoomStore
|
||||
type RoomStore interface {
|
||||
StoreRoom(ctx context.Context, room *livekit.Room) error
|
||||
|
||||
@@ -4,29 +4,34 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/routing/selector"
|
||||
"github.com/livekit/protocol/logger"
|
||||
livekit "github.com/livekit/protocol/proto"
|
||||
"github.com/livekit/protocol/utils"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/config"
|
||||
"github.com/livekit/livekit-server/pkg/routing"
|
||||
"github.com/livekit/livekit-server/pkg/routing/selector"
|
||||
)
|
||||
|
||||
type RoomAllocator struct {
|
||||
config *config.Config
|
||||
router routing.Router
|
||||
selector routing.NodeSelector
|
||||
selector selector.NodeSelector
|
||||
roomStore RoomStore
|
||||
}
|
||||
|
||||
func NewRoomAllocator(conf *config.Config, router routing.Router, selector routing.NodeSelector, rs RoomStore) *RoomAllocator {
|
||||
func NewRoomAllocator(conf *config.Config, router routing.Router, rs RoomStore) (*RoomAllocator, error) {
|
||||
ns, err := selector.CreateNodeSelector(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &RoomAllocator{
|
||||
config: conf,
|
||||
router: router,
|
||||
selector: selector,
|
||||
selector: ns,
|
||||
roomStore: rs,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateRoom creates a new room from a request and allocates it to a node to handle
|
||||
@@ -64,35 +69,36 @@ func (r *RoomAllocator) CreateRoom(ctx context.Context, req *livekit.CreateRoomR
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Is that node still available?
|
||||
node, err := r.router.GetNodeForRoom(ctx, rm.Name)
|
||||
// check if room already assigned
|
||||
existing, err := r.router.GetNodeForRoom(ctx, rm.Name)
|
||||
if err != routing.ErrNotFound && err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// keep it on that node
|
||||
if err == nil && selector.IsAvailable(node) {
|
||||
// if already assigned and still available, keep it on that node
|
||||
if err == nil && selector.IsAvailable(existing) {
|
||||
return rm, nil
|
||||
}
|
||||
|
||||
// select a new node
|
||||
nodeId := req.NodeId
|
||||
if nodeId == "" {
|
||||
// select a node for room
|
||||
nodes, err := r.router.ListNodes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
node, err := r.selector.SelectNode(nodes, rm)
|
||||
node, err := r.selector.SelectNode(nodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nodeId = node.Id
|
||||
}
|
||||
|
||||
logger.Debugw("selected node for room", "room", rm.Name, "roomID", rm.Sid, "nodeID", nodeId)
|
||||
if err := r.router.SetNodeForRoom(ctx, req.Name, nodeId); err != nil {
|
||||
err = r.router.SetNodeForRoom(ctx, rm.Name, nodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/routing/selector"
|
||||
livekit "github.com/livekit/protocol/proto"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -32,12 +31,12 @@ func newTestRoomAllocator(t *testing.T) (*service.RoomAllocator, *config.Config)
|
||||
router := &routingfakes.FakeRouter{}
|
||||
conf, err := config.NewConfig("", nil)
|
||||
require.NoError(t, err)
|
||||
selector := &selector.RandomSelector{}
|
||||
node, err := routing.NewLocalNode(conf)
|
||||
require.NoError(t, err)
|
||||
|
||||
router.GetNodeForRoomReturns(node, nil)
|
||||
|
||||
ra := service.NewRoomAllocator(conf, router, selector, store)
|
||||
ra, err := service.NewRoomAllocator(conf, router, store)
|
||||
require.NoError(t, err)
|
||||
return ra, conf
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ type LocalRoomManager struct {
|
||||
RoomStore
|
||||
|
||||
lock sync.RWMutex
|
||||
selector routing.NodeSelector
|
||||
router routing.Router
|
||||
currentNode routing.LocalNode
|
||||
notifier webhook.Notifier
|
||||
@@ -37,20 +36,20 @@ type LocalRoomManager struct {
|
||||
rooms map[string]*rtc.Room
|
||||
}
|
||||
|
||||
func NewLocalRoomManager(rp RoomStore, router routing.Router, currentNode routing.LocalNode, selector routing.NodeSelector,
|
||||
notifier webhook.Notifier, conf *config.Config) (*LocalRoomManager, error) {
|
||||
func NewLocalRoomManager(conf *config.Config, rs RoomStore, router routing.Router, currentNode routing.LocalNode,
|
||||
notifier webhook.Notifier) (*LocalRoomManager, error) {
|
||||
|
||||
rtcConf, err := rtc.NewWebRTCConfig(conf, currentNode.Ip)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := &LocalRoomManager{
|
||||
RoomStore: rp,
|
||||
RoomStore: rs,
|
||||
lock: sync.RWMutex{},
|
||||
rtcConfig: rtcConf,
|
||||
config: conf,
|
||||
router: router,
|
||||
selector: selector,
|
||||
notifier: notifier,
|
||||
currentNode: currentNode,
|
||||
webhookPool: workerpool.New(1),
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
// A rooms service that supports a single node
|
||||
type RoomService struct {
|
||||
router routing.Router
|
||||
selector routing.NodeSelector
|
||||
roomAllocator *RoomAllocator
|
||||
roomStore RoomStore
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ func (s *LivekitServer) Start() error {
|
||||
|
||||
func (s *LivekitServer) Stop(force bool) {
|
||||
// wait for all participants to exit
|
||||
s.router.PreStop()
|
||||
s.router.Drain()
|
||||
partTicker := time.NewTicker(5 * time.Second)
|
||||
waitingForParticipants := !force && s.roomManager.HasParticipants()
|
||||
for waitingForParticipants {
|
||||
|
||||
@@ -1,153 +1,14 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/google/wire"
|
||||
"github.com/livekit/protocol/auth"
|
||||
"github.com/livekit/protocol/logger"
|
||||
livekit "github.com/livekit/protocol/proto"
|
||||
"github.com/livekit/protocol/utils"
|
||||
"github.com/livekit/protocol/webhook"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/config"
|
||||
"github.com/livekit/livekit-server/pkg/routing"
|
||||
"github.com/livekit/livekit-server/pkg/routing/selector"
|
||||
)
|
||||
|
||||
var ServiceSet = wire.NewSet(
|
||||
createRedisClient,
|
||||
createMessageBus,
|
||||
createRouter,
|
||||
createStore,
|
||||
CreateKeyProvider,
|
||||
CreateWebhookNotifier,
|
||||
CreateNodeSelector,
|
||||
NewRecordingService,
|
||||
NewRoomAllocator,
|
||||
NewRoomService,
|
||||
NewRTCService,
|
||||
NewLivekitServer,
|
||||
NewLocalRoomManager,
|
||||
newTurnAuthHandler,
|
||||
NewTurnServer,
|
||||
config.GetAudioConfig,
|
||||
wire.Bind(new(RoomManager), new(*LocalRoomManager)),
|
||||
wire.Bind(new(livekit.RoomService), new(*RoomService)),
|
||||
)
|
||||
|
||||
func CreateKeyProvider(conf *config.Config) (auth.KeyProvider, error) {
|
||||
// prefer keyfile if set
|
||||
if conf.KeyFile != "" {
|
||||
if st, err := os.Stat(conf.KeyFile); err != nil {
|
||||
return nil, err
|
||||
} else if st.Mode().Perm() != 0600 {
|
||||
return nil, fmt.Errorf("key file must have permission set to 600")
|
||||
}
|
||||
f, err := os.Open(conf.KeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
_ = f.Close()
|
||||
}()
|
||||
return auth.NewFileBasedKeyProviderFromReader(f)
|
||||
}
|
||||
|
||||
if len(conf.Keys) == 0 {
|
||||
return nil, errors.New("one of key-file or keys must be provided in order to support a secure installation")
|
||||
}
|
||||
|
||||
return auth.NewFileBasedKeyProviderFromMap(conf.Keys), nil
|
||||
}
|
||||
|
||||
func CreateWebhookNotifier(conf *config.Config, provider auth.KeyProvider) (webhook.Notifier, error) {
|
||||
wc := conf.WebHook
|
||||
if len(wc.URLs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
secret := provider.GetSecret(wc.APIKey)
|
||||
if secret == "" {
|
||||
return nil, ErrWebHookMissingAPIKey
|
||||
}
|
||||
|
||||
return webhook.NewNotifier(wc.APIKey, secret, wc.URLs), nil
|
||||
}
|
||||
|
||||
func CreateNodeSelector(conf *config.Config) (routing.NodeSelector, error) {
|
||||
kind := conf.NodeSelector.Kind
|
||||
if kind == "" {
|
||||
kind = "random"
|
||||
}
|
||||
switch kind {
|
||||
case "sysload":
|
||||
return &selector.SystemLoadSelector{
|
||||
SysloadLimit: conf.NodeSelector.SysloadLimit,
|
||||
}, nil
|
||||
case "regionaware":
|
||||
s, err := selector.NewRegionAwareSelector(conf.Region, conf.NodeSelector.Regions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.SysloadLimit = conf.NodeSelector.SysloadLimit
|
||||
return s, nil
|
||||
case "random":
|
||||
return &selector.RandomSelector{}, nil
|
||||
default:
|
||||
return nil, ErrUnsupportedSelector
|
||||
}
|
||||
}
|
||||
|
||||
func createRedisClient(conf *config.Config) (*redis.Client, error) {
|
||||
if !conf.HasRedis() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
logger.Infow("using multi-node routing via redis", "addr", conf.Redis.Address)
|
||||
rc := redis.NewClient(&redis.Options{
|
||||
Addr: conf.Redis.Address,
|
||||
Username: conf.Redis.Username,
|
||||
Password: conf.Redis.Password,
|
||||
DB: conf.Redis.DB,
|
||||
})
|
||||
if err := rc.Ping(context.Background()).Err(); err != nil {
|
||||
err = errors.Wrap(err, "unable to connect to redis")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
func createMessageBus(rc *redis.Client) utils.MessageBus {
|
||||
if rc == nil {
|
||||
return nil
|
||||
}
|
||||
return utils.NewRedisMessageBus(rc)
|
||||
}
|
||||
|
||||
func createRouter(rc *redis.Client, node routing.LocalNode) routing.Router {
|
||||
if rc != nil {
|
||||
return routing.NewRedisRouter(node, rc)
|
||||
}
|
||||
|
||||
// local routing and store
|
||||
logger.Infow("using single-node routing")
|
||||
return routing.NewLocalRouter(node)
|
||||
}
|
||||
|
||||
func createStore(rc *redis.Client) RoomStore {
|
||||
if rc != nil {
|
||||
return NewRedisRoomStore(rc)
|
||||
}
|
||||
return NewLocalRoomStore()
|
||||
}
|
||||
|
||||
func handleError(w http.ResponseWriter, status int, msg string) {
|
||||
// GetLogger already with extra depth 1
|
||||
logger.GetLogger().V(1).Info("error handling request", "error", msg, "status", status)
|
||||
|
||||
+101
-5
@@ -3,7 +3,19 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/google/wire"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/livekit/protocol/auth"
|
||||
"github.com/livekit/protocol/logger"
|
||||
livekit "github.com/livekit/protocol/proto"
|
||||
"github.com/livekit/protocol/utils"
|
||||
"github.com/livekit/protocol/webhook"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/config"
|
||||
"github.com/livekit/livekit-server/pkg/routing"
|
||||
@@ -11,18 +23,102 @@ import (
|
||||
|
||||
func InitializeServer(conf *config.Config, currentNode routing.LocalNode) (*LivekitServer, error) {
|
||||
wire.Build(
|
||||
ServiceSet,
|
||||
createRedisClient,
|
||||
createMessageBus,
|
||||
createStore,
|
||||
createKeyProvider,
|
||||
createWebhookNotifier,
|
||||
routing.CreateRouter,
|
||||
NewRecordingService,
|
||||
NewRoomAllocator,
|
||||
NewRoomService,
|
||||
NewRTCService,
|
||||
NewLocalRoomManager,
|
||||
newTurnAuthHandler,
|
||||
NewTurnServer,
|
||||
wire.Bind(new(livekit.RoomService), new(*RoomService)),
|
||||
NewLivekitServer,
|
||||
)
|
||||
return &LivekitServer{}, nil
|
||||
}
|
||||
|
||||
func InitializeRouter(conf *config.Config, currentNode routing.LocalNode) (routing.Router, error) {
|
||||
wire.Build(
|
||||
wire.NewSet(
|
||||
createRedisClient,
|
||||
createRouter,
|
||||
),
|
||||
createRedisClient,
|
||||
routing.CreateRouter,
|
||||
)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func createKeyProvider(conf *config.Config) (auth.KeyProvider, error) {
|
||||
// prefer keyfile if set
|
||||
if conf.KeyFile != "" {
|
||||
if st, err := os.Stat(conf.KeyFile); err != nil {
|
||||
return nil, err
|
||||
} else if st.Mode().Perm() != 0600 {
|
||||
return nil, fmt.Errorf("key file must have permission set to 600")
|
||||
}
|
||||
f, err := os.Open(conf.KeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
_ = f.Close()
|
||||
}()
|
||||
return auth.NewFileBasedKeyProviderFromReader(f)
|
||||
}
|
||||
|
||||
if len(conf.Keys) == 0 {
|
||||
return nil, errors.New("one of key-file or keys must be provided in order to support a secure installation")
|
||||
}
|
||||
|
||||
return auth.NewFileBasedKeyProviderFromMap(conf.Keys), nil
|
||||
}
|
||||
|
||||
func createWebhookNotifier(conf *config.Config, provider auth.KeyProvider) (webhook.Notifier, error) {
|
||||
wc := conf.WebHook
|
||||
if len(wc.URLs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
secret := provider.GetSecret(wc.APIKey)
|
||||
if secret == "" {
|
||||
return nil, ErrWebHookMissingAPIKey
|
||||
}
|
||||
|
||||
return webhook.NewNotifier(wc.APIKey, secret, wc.URLs), nil
|
||||
}
|
||||
|
||||
func createRedisClient(conf *config.Config) (*redis.Client, error) {
|
||||
if !conf.HasRedis() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
logger.Infow("using multi-node routing via redis", "addr", conf.Redis.Address)
|
||||
rc := redis.NewClient(&redis.Options{
|
||||
Addr: conf.Redis.Address,
|
||||
Username: conf.Redis.Username,
|
||||
Password: conf.Redis.Password,
|
||||
DB: conf.Redis.DB,
|
||||
})
|
||||
if err := rc.Ping(context.Background()).Err(); err != nil {
|
||||
err = errors.Wrap(err, "unable to connect to redis")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
func createMessageBus(rc *redis.Client) utils.MessageBus {
|
||||
if rc == nil {
|
||||
return nil
|
||||
}
|
||||
return utils.NewRedisMessageBus(rc)
|
||||
}
|
||||
|
||||
func createStore(rc *redis.Client) RoomStore {
|
||||
if rc != nil {
|
||||
return NewRedisRoomStore(rc)
|
||||
}
|
||||
return NewLocalRoomStore()
|
||||
}
|
||||
|
||||
+89
-8
@@ -6,8 +6,17 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/livekit/livekit-server/pkg/config"
|
||||
"github.com/livekit/livekit-server/pkg/routing"
|
||||
"github.com/livekit/protocol/auth"
|
||||
"github.com/livekit/protocol/logger"
|
||||
"github.com/livekit/protocol/utils"
|
||||
"github.com/livekit/protocol/webhook"
|
||||
"github.com/pkg/errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Injectors from wire.go:
|
||||
@@ -17,29 +26,28 @@ func InitializeServer(conf *config.Config, currentNode routing.LocalNode) (*Live
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
router := createRouter(client, currentNode)
|
||||
nodeSelector, err := CreateNodeSelector(conf)
|
||||
router := routing.CreateRouter(conf, client, currentNode)
|
||||
roomStore := createStore(client)
|
||||
roomAllocator, err := NewRoomAllocator(conf, router, roomStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roomStore := createStore(client)
|
||||
roomAllocator := NewRoomAllocator(conf, router, nodeSelector, roomStore)
|
||||
roomService, err := NewRoomService(roomAllocator, roomStore, router)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
messageBus := createMessageBus(client)
|
||||
keyProvider, err := CreateKeyProvider(conf)
|
||||
keyProvider, err := createKeyProvider(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
notifier, err := CreateWebhookNotifier(conf, keyProvider)
|
||||
notifier, err := createWebhookNotifier(conf, keyProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
recordingService := NewRecordingService(messageBus, notifier)
|
||||
rtcService := NewRTCService(conf, roomAllocator, router, currentNode)
|
||||
localRoomManager, err := NewLocalRoomManager(roomStore, router, currentNode, nodeSelector, notifier, conf)
|
||||
localRoomManager, err := NewLocalRoomManager(conf, roomStore, router, currentNode, notifier)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -60,6 +68,79 @@ func InitializeRouter(conf *config.Config, currentNode routing.LocalNode) (routi
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
router := createRouter(client, currentNode)
|
||||
router := routing.CreateRouter(conf, client, currentNode)
|
||||
return router, nil
|
||||
}
|
||||
|
||||
// wire.go:
|
||||
|
||||
func createKeyProvider(conf *config.Config) (auth.KeyProvider, error) {
|
||||
|
||||
if conf.KeyFile != "" {
|
||||
if st, err := os.Stat(conf.KeyFile); err != nil {
|
||||
return nil, err
|
||||
} else if st.Mode().Perm() != 0600 {
|
||||
return nil, fmt.Errorf("key file must have permission set to 600")
|
||||
}
|
||||
f, err := os.Open(conf.KeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
_ = f.Close()
|
||||
}()
|
||||
return auth.NewFileBasedKeyProviderFromReader(f)
|
||||
}
|
||||
|
||||
if len(conf.Keys) == 0 {
|
||||
return nil, errors.New("one of key-file or keys must be provided in order to support a secure installation")
|
||||
}
|
||||
|
||||
return auth.NewFileBasedKeyProviderFromMap(conf.Keys), nil
|
||||
}
|
||||
|
||||
func createWebhookNotifier(conf *config.Config, provider auth.KeyProvider) (webhook.Notifier, error) {
|
||||
wc := conf.WebHook
|
||||
if len(wc.URLs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
secret := provider.GetSecret(wc.APIKey)
|
||||
if secret == "" {
|
||||
return nil, ErrWebHookMissingAPIKey
|
||||
}
|
||||
|
||||
return webhook.NewNotifier(wc.APIKey, secret, wc.URLs), nil
|
||||
}
|
||||
|
||||
func createRedisClient(conf *config.Config) (*redis.Client, error) {
|
||||
if !conf.HasRedis() {
|
||||
return nil, nil
|
||||
}
|
||||
logger.Infow("using multi-node routing via redis", "addr", conf.Redis.Address)
|
||||
rc := redis.NewClient(&redis.Options{
|
||||
Addr: conf.Redis.Address,
|
||||
Username: conf.Redis.Username,
|
||||
Password: conf.Redis.Password,
|
||||
DB: conf.Redis.DB,
|
||||
})
|
||||
if err := rc.Ping(context.Background()).Err(); err != nil {
|
||||
err = errors.Wrap(err, "unable to connect to redis")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
func createMessageBus(rc *redis.Client) utils.MessageBus {
|
||||
if rc == nil {
|
||||
return nil
|
||||
}
|
||||
return utils.NewRedisMessageBus(rc)
|
||||
}
|
||||
|
||||
func createStore(rc *redis.Client) RoomStore {
|
||||
if rc != nil {
|
||||
return NewRedisRoomStore(rc)
|
||||
}
|
||||
return NewLocalRoomStore()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user