From 9064f6ade10b43350f6ff40fad3bca2d117ec623 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Sat, 16 Jan 2021 00:25:13 -0800 Subject: [PATCH] decouple websocket and RTC nodes, prep for distributed --- cmd/cli/client/client.go | 4 +- cmd/cli/client/trackwriter.go | 14 +- cmd/cli/commands/room.go | 25 +- cmd/cli/commands/rtc.go | 8 +- cmd/cli/commands/utils.go | 2 +- cmd/server/main.go | 18 +- go.sum | 2 + magefile.go | 32 +- pkg/auth/grants.go | 1 + pkg/config/config.go | 8 +- pkg/logger/logger.go | 33 +- pkg/routing/errors.go | 8 + pkg/routing/interfaces.go | 38 + pkg/routing/localrouter.go | 99 +++ pkg/routing/messagechannel.go | 33 + pkg/{node => routing}/node.go | 56 +- pkg/routing/routingfakes/fake_message_sink.go | 141 ++++ .../routingfakes/fake_message_source.go | 107 +++ pkg/routing/routingfakes/fake_router.go | 708 ++++++++++++++++++ pkg/rtc/config.go | 6 +- pkg/rtc/datatrack.go | 2 +- pkg/rtc/manager.go | 99 --- pkg/rtc/manager_test.go | 83 -- pkg/rtc/mediatrack.go | 18 +- pkg/rtc/participant.go | 62 +- pkg/rtc/participant_internal_test.go | 9 +- pkg/rtc/receiver.go | 2 +- pkg/rtc/room.go | 42 +- pkg/rtc/room_test.go | 31 +- pkg/rtc/types/interfaces.go | 9 +- pkg/rtc/types/typesfakes/fake_participant.go | 42 +- .../typesfakes/fake_signal_connection.go | 182 ----- pkg/rtc/utils.go | 15 +- pkg/service/auth.go | 21 +- pkg/service/errors.go | 7 + pkg/service/localroomstore.go | 74 ++ pkg/service/redisroomstore.go | 1 + pkg/service/roomservice.go | 75 ++ pkg/service/roomstore.go | 16 + pkg/service/rtc.go | 221 ------ pkg/service/rtcrunner.go | 166 ++++ pkg/service/rtcservice.go | 160 ++++ pkg/service/server.go | 117 +++ pkg/service/service.go | 147 ---- pkg/service/servicefakes/fake_room_store.go | 335 +++++++++ pkg/service/simpleroom.go | 69 -- pkg/service/utils.go | 23 + pkg/service/wire.go | 8 +- pkg/service/wire_gen.go | 20 +- pkg/{rtc => service}/wsprotocol.go | 4 +- pkg/sfu/README.md | 2 +- pkg/sfu/errors.go | 2 +- proto/livekit/model.pb.go | 139 +--- proto/livekit/room.pb.go | 181 +++-- proto/livekit/room.twirp.go | 194 ++--- proto/livekit/rtc.pb.go | 71 +- proto/model.proto | 9 +- proto/room.proto | 11 +- proto/rtc.proto | 2 +- test/integration_helpers.go | 20 +- test/integration_test.go | 10 +- 61 files changed, 2683 insertions(+), 1361 deletions(-) create mode 100644 pkg/routing/errors.go create mode 100644 pkg/routing/interfaces.go create mode 100644 pkg/routing/localrouter.go create mode 100644 pkg/routing/messagechannel.go rename pkg/{node => routing}/node.go (60%) create mode 100644 pkg/routing/routingfakes/fake_message_sink.go create mode 100644 pkg/routing/routingfakes/fake_message_source.go create mode 100644 pkg/routing/routingfakes/fake_router.go delete mode 100644 pkg/rtc/manager.go delete mode 100644 pkg/rtc/manager_test.go delete mode 100644 pkg/rtc/types/typesfakes/fake_signal_connection.go create mode 100644 pkg/service/errors.go create mode 100644 pkg/service/localroomstore.go create mode 100644 pkg/service/redisroomstore.go create mode 100644 pkg/service/roomservice.go create mode 100644 pkg/service/roomstore.go delete mode 100644 pkg/service/rtc.go create mode 100644 pkg/service/rtcrunner.go create mode 100644 pkg/service/rtcservice.go create mode 100644 pkg/service/server.go delete mode 100644 pkg/service/service.go create mode 100644 pkg/service/servicefakes/fake_room_store.go delete mode 100644 pkg/service/simpleroom.go create mode 100644 pkg/service/utils.go rename pkg/{rtc => service}/wsprotocol.go (95%) diff --git a/cmd/cli/client/client.go b/cmd/cli/client/client.go index c6635b566..ff4b8b918 100644 --- a/cmd/cli/client/client.go +++ b/cmd/cli/client/client.go @@ -168,7 +168,7 @@ func (c *RTCClient) Run() error { c.conn.SetCloseHandler(func(code int, text string) error { // when closed, stop connection - logger.GetLogger().Infow("connection closed", "code", code, "text", text) + logger.Infow("connection closed", "code", code, "text", text) c.Stop() return nil }) @@ -519,7 +519,7 @@ func (c *RTCClient) logLoop() { for !c.paused && c.reader != c.writer { val, _ := c.reader.Value.(*logEntry) if val != nil { - logger.GetLogger().Infow(val.msg, val.args...) + logger.Infow(val.msg, val.args...) } // advance reader until writer c.reader = c.reader.Next() diff --git a/cmd/cli/client/trackwriter.go b/cmd/cli/client/trackwriter.go index 27114f9bf..00e9d2ad5 100644 --- a/cmd/cli/client/trackwriter.go +++ b/cmd/cli/client/trackwriter.go @@ -54,7 +54,7 @@ func (w *TrackWriter) Start() error { return err } - logger.GetLogger().Infow("starting track writer", + logger.Infow("starting track writer", "track", w.track.ID(), "mime", w.mime) switch w.mime { @@ -106,13 +106,13 @@ func (w *TrackWriter) writeOgg() { } pageData, pageHeader, err := w.ogg.ParseNextPage() if err == io.EOF { - logger.GetLogger().Infow("all audio samples parsed and sent") + logger.Infow("all audio samples parsed and sent") w.onWriteComplete() return } if err != nil { - logger.GetLogger().Errorw("could not parse ogg page", "err", err) + logger.Errorw("could not parse ogg page", "err", err) return } @@ -122,7 +122,7 @@ func (w *TrackWriter) writeOgg() { sampleDuration := time.Duration((sampleCount/48000)*1000) * time.Millisecond if err = w.track.WriteSample(media.Sample{Data: pageData, Duration: sampleDuration}); err != nil { - logger.GetLogger().Errorw("could not write sample", "err", err) + logger.Errorw("could not write sample", "err", err) return } @@ -140,19 +140,19 @@ func (w *TrackWriter) writeVP8() { } frame, _, err := w.ivf.ParseNextFrame() if err == io.EOF { - logger.GetLogger().Infow("all video frames parsed and sent") + logger.Infow("all video frames parsed and sent") w.onWriteComplete() return } if err != nil { - logger.GetLogger().Errorw("could not parse VP8 frame", "err", err) + logger.Errorw("could not parse VP8 frame", "err", err) return } time.Sleep(sleepTime) if err = w.track.WriteSample(media.Sample{Data: frame, Duration: time.Second}); err != nil { - logger.GetLogger().Errorw("could not write sample", "err", err) + logger.Errorw("could not write sample", "err", err) return } } diff --git a/cmd/cli/commands/room.go b/cmd/cli/commands/room.go index 116b6b66d..00efac814 100644 --- a/cmd/cli/commands/room.go +++ b/cmd/cli/commands/room.go @@ -31,11 +31,10 @@ var ( }, }, { - Name: "get-room", + Name: "list-rooms", Before: createClient, - Action: getRoom, + Action: listRooms, Flags: []cli.Flag{ - roomFlag, roomHostFlag, apiKeyFlag, secretFlag, @@ -76,17 +75,15 @@ func createRoom(c *cli.Context) error { return nil } -func getRoom(c *cli.Context) error { - ctx := contextWithAccessToken(c, &auth.VideoGrant{RoomJoin: true}) - roomId := c.String("room") - room, err := roomClient.GetRoom(ctx, &livekit.GetRoomRequest{ - Room: roomId, - }) +func listRooms(c *cli.Context) error { + ctx := contextWithAccessToken(c, &auth.VideoGrant{RoomList: true}) + res, err := roomClient.ListRooms(ctx, &livekit.ListRoomsRequest{}) if err != nil { return err } - - PrintJSON(room) + for _, rm := range res.Rooms { + fmt.Printf("%s\t%s\n", rm.Sid, rm.Name) + } return nil } @@ -108,16 +105,16 @@ func contextWithAccessToken(c *cli.Context, grant *auth.VideoGrant) context.Cont ctx := context.Background() token, err := accessToken(c, grant, "") if err != nil { - logger.GetLogger().Errorw("Could not get access token", "err", err) + logger.Errorw("Could not get access token", "err", err) } if token != "" { header := make(http.Header) header.Set("Authorization", "Bearer "+token) if tctx, err := twirp.WithHTTPRequestHeaders(ctx, header); err == nil { - logger.GetLogger().Debugw("requesting with token") + logger.Debugw("requesting with token") ctx = tctx } else { - logger.GetLogger().Errorw("Error setting Twirp auth header", "err", err) + logger.Errorw("Error setting Twirp auth header", "err", err) } } return ctx diff --git a/cmd/cli/commands/rtc.go b/cmd/cli/commands/rtc.go index 61b636515..b2d907c22 100644 --- a/cmd/cli/commands/rtc.go +++ b/cmd/cli/commands/rtc.go @@ -74,10 +74,8 @@ func joinRoom(c *cli.Context) error { } } - log := logger.GetLogger() - host := c.String("host") - log.Infow("connecting to Websocket signal", "host", host) + logger.Infow("connecting to Websocket signal", "host", host) conn, err := client.NewWebSocketConn(host, token) if err != nil { return err @@ -118,7 +116,7 @@ func joinRoom(c *cli.Context) error { err = handleCommand(rc) if err != nil { - log.Errorw("could not handle command", "err", err) + logger.Errorw("could not handle command", "err", err) } rc.ResumeLogs() @@ -221,7 +219,7 @@ func handleSignals(rc *client.RTCClient) { go func() { sig := <-sigChan - logger.GetLogger().Infow("exit requested, shutting down", "signal", sig) + logger.Infow("exit requested, shutting down", "signal", sig) rc.Stop() }() } diff --git a/cmd/cli/commands/utils.go b/cmd/cli/commands/utils.go index de0e618b9..f646a8c45 100644 --- a/cmd/cli/commands/utils.go +++ b/cmd/cli/commands/utils.go @@ -24,7 +24,7 @@ var ( } rtcHostFlag = &cli.StringFlag{ Name: "host", - Value: "ws://localhost:7881", + Value: "ws://localhost:7880", } apiKeyFlag = &cli.StringFlag{ Name: "api-key", diff --git a/cmd/server/main.go b/cmd/server/main.go index 4ca01eb7a..e5f1d3e17 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -17,6 +17,7 @@ import ( "github.com/livekit/livekit-server/pkg/auth" "github.com/livekit/livekit-server/pkg/config" "github.com/livekit/livekit-server/pkg/logger" + "github.com/livekit/livekit-server/pkg/routing" "github.com/livekit/livekit-server/pkg/service" "github.com/livekit/livekit-server/pkg/utils" ) @@ -116,10 +117,19 @@ func startServer(c *cli.Context) error { if keyProvider, err = createKeyProvider(c.String("key-file"), c.String("keys")); err != nil { return err } - service.AuthRequired = true - logger.GetLogger().Infow("auth enabled", "num_keys", keyProvider.NumKeys()) + logger.Infow("auth enabled", "num_keys", keyProvider.NumKeys()) - server, err := service.InitializeServer(conf, keyProvider) + currentNode, err := routing.NewLocalNode(conf) + if err != nil { + return err + } + + // local routing and store + router := routing.NewLocalRouter(currentNode) + roomStore := service.NewLocalRoomStore() + + server, err := service.InitializeServer(conf, keyProvider, + roomStore, router, currentNode) if err != nil { return err } @@ -129,7 +139,7 @@ func startServer(c *cli.Context) error { go func() { sig := <-sigChan - logger.GetLogger().Infow("exit requested, shutting down", "signal", sig) + logger.Infow("exit requested, shutting down", "signal", sig) server.Stop() }() diff --git a/go.sum b/go.sum index 34dfc3b64..b8c51d063 100644 --- a/go.sum +++ b/go.sum @@ -211,6 +211,7 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -376,6 +377,7 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= diff --git a/magefile.go b/magefile.go index 488ad4491..cedbba578 100644 --- a/magefile.go +++ b/magefile.go @@ -14,12 +14,12 @@ import ( "strings" "github.com/magefile/mage/mg" + "github.com/magefile/mage/target" log "github.com/pion/ion-log" ) const ( - protoChecksumFile = ".checksumproto" - goChecksumFile = ".checksumgo" + goChecksumFile = ".checksumgo" ) // Default target to run when none is specified @@ -41,8 +41,15 @@ func Deps() error { // regenerate protobuf func Proto() error { - protoChecksummer := NewChecksummer("proto", protoChecksumFile, ".proto") - if !protoChecksummer.IsChanged() { + updated, err := target.Path("proto/livekit/model.pb.go", + "proto/model.proto", + "proto/room.proto", + "proto/rtc.proto", + ) + if err != nil { + return err + } + if !updated { return nil } @@ -92,13 +99,12 @@ func Proto() error { return err } - protoChecksummer.WriteChecksum() return nil } // builds LiveKit server and cli func Build() error { - mg.Deps(Proto, generateCmd) + mg.Deps(Proto, generateWire) if !checksummer.IsChanged() { fmt.Println("up to date") return nil @@ -137,7 +143,6 @@ func Test() error { func Clean() { fmt.Println("cleaning...") os.RemoveAll("bin") - os.Remove(protoChecksumFile) os.Remove(goChecksumFile) } @@ -152,14 +157,14 @@ func Generate() error { return cmd.Run() } -// code generation for cmd subfolder. It doesn't regenerate test fixtures -func generateCmd() error { +// code generation for wiring +func generateWire() error { mg.Deps(installDeps) if !checksummer.IsChanged() { return nil } - fmt.Println("generating...") + fmt.Println("wiring...") cmd := exec.Command("go", "generate", "./cmd/...") connectStd(cmd) @@ -167,7 +172,12 @@ func generateCmd() error { return err } - cmd = exec.Command("go", "generate", "./pkg/service/...") + wire, err := getToolPath("wire") + if err != nil { + return err + } + cmd = exec.Command(wire) + cmd.Dir = "pkg/service" connectStd(cmd) if err := cmd.Run(); err != nil { return err diff --git a/pkg/auth/grants.go b/pkg/auth/grants.go index c4ad5a3b2..f80a2da71 100644 --- a/pkg/auth/grants.go +++ b/pkg/auth/grants.go @@ -3,6 +3,7 @@ package auth type VideoGrant struct { RoomCreate bool `json:"room_create,omitempty"` RoomJoin bool `json:"room_join,omitempty"` + RoomList bool `json:"room_list,omitempty"` Room string `json:"room,omitempty"` } diff --git a/pkg/config/config.go b/pkg/config/config.go index 3e4c3e012..548cc64bf 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -6,9 +6,8 @@ import ( ) type Config struct { - APIPort uint32 `yaml:"api_port"` - RTCPort uint32 `yaml:"rtc_port"` - RTC RTCConfig `yaml:"rtc"` + Port uint32 `yaml:"port"` + RTC RTCConfig `yaml:"rtc"` // multi-node configuration, MultiNode bool `yaml:"multi_node"` @@ -28,8 +27,7 @@ type RTCConfig struct { func NewConfig(confString string) (*Config, error) { // start with defaults conf := &Config{ - APIPort: 7880, - RTCPort: 7881, + Port: 7880, RTC: RTCConfig{ ICEPortRangeStart: 8000, ICEPortRangeEnd: 10000, diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index b4a0d74d1..67f085a7a 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -4,9 +4,14 @@ import ( "go.uber.org/zap" ) -var logger *zap.SugaredLogger +var ( + logger *zap.SugaredLogger + zapOptions = []zap.Option{ + zap.AddCallerSkip(1), + } +) -func GetLogger() *zap.SugaredLogger { +func getLogger() *zap.SugaredLogger { if logger == nil { InitDevelopment() } @@ -14,11 +19,31 @@ func GetLogger() *zap.SugaredLogger { } func InitProduction() { - l, _ := zap.NewProduction() + l, _ := zap.NewProduction(zapOptions...) logger = l.Sugar() } func InitDevelopment() { - l, _ := zap.NewDevelopment() + l, _ := zap.NewDevelopment(zapOptions...) logger = l.Sugar() } + +func Debugw(msg string, keysAndValues ...interface{}) { + getLogger().Debugw(msg, keysAndValues...) +} + +func Infow(msg string, keysAndValues ...interface{}) { + getLogger().Infow(msg, keysAndValues...) +} + +func Warnw(msg string, keysAndValues ...interface{}) { + getLogger().Warnw(msg, keysAndValues...) +} + +func Errorw(msg string, keysAndValues ...interface{}) { + getLogger().Errorw(msg, keysAndValues...) +} + +func Desugar() *zap.Logger { + return getLogger().Desugar() +} diff --git a/pkg/routing/errors.go b/pkg/routing/errors.go new file mode 100644 index 000000000..ded1fc2a9 --- /dev/null +++ b/pkg/routing/errors.go @@ -0,0 +1,8 @@ +package routing + +import "errors" + +var ( + ErrNodeNotFound = errors.New("could not find node") + ErrHandlerNotDefined = errors.New("handler not defined") +) diff --git a/pkg/routing/interfaces.go b/pkg/routing/interfaces.go new file mode 100644 index 000000000..287abfe62 --- /dev/null +++ b/pkg/routing/interfaces.go @@ -0,0 +1,38 @@ +package routing + +import ( + "github.com/livekit/livekit-server/proto/livekit" +) + +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate + +// routes signaling message +//counterfeiter:generate . MessageSink +type MessageSink interface { + WriteMessage(msg interface{}) error + Close() +} + +//counterfeiter:generate . MessageSource +type MessageSource interface { + ReadMessage() (interface{}, error) +} + +type ParticipantCallback func(roomId, participantId, participantName string, requestSource MessageSource, responseSink MessageSink) + +//counterfeiter:generate . Router +type Router interface { + GetNodeIdForRoom(roomName string) (string, error) + RegisterNode(node *livekit.Node) error + GetNode(nodeId string) (*livekit.Node, error) + + StartParticipant(roomName, participantId, participantName, nodeId string) error + SetRTCNode(participantId, nodeId string) error + // functions for websocket handler + GetRequestSink(participantId string) MessageSink + GetResponseSource(participantId string) MessageSource + + OnNewParticipant(callback ParticipantCallback) + Start() error + Stop() +} diff --git a/pkg/routing/localrouter.go b/pkg/routing/localrouter.go new file mode 100644 index 000000000..0d6f0dc6b --- /dev/null +++ b/pkg/routing/localrouter.go @@ -0,0 +1,99 @@ +package routing + +import ( + "sync" + + "github.com/livekit/livekit-server/proto/livekit" +) + +// a router of messages +type LocalRouter struct { + currentNode LocalNode + lock sync.RWMutex + // channels for each participant + requestChannels map[string]*MessageChannel + responseChannels map[string]*MessageChannel + onNewParticipant ParticipantCallback +} + +func NewLocalRouter(currentNode LocalNode) *LocalRouter { + return &LocalRouter{ + currentNode: currentNode, + lock: sync.RWMutex{}, + requestChannels: make(map[string]*MessageChannel), + responseChannels: make(map[string]*MessageChannel), + } +} + +func (r *LocalRouter) GetNodeIdForRoom(roomName string) (string, error) { + return r.currentNode.Id, nil +} + +func (r *LocalRouter) RegisterNode(node *livekit.Node) error { + return nil +} + +func (r *LocalRouter) GetNode(nodeId string) (*livekit.Node, error) { + if nodeId == r.currentNode.Id { + return r.currentNode, nil + } + return nil, ErrNodeNotFound +} + +func (r *LocalRouter) StartParticipant(roomName, participantId, participantName, nodeId string) error { + // treat it as a new participant connecting + if r.onNewParticipant == nil { + return ErrHandlerNotDefined + } + r.onNewParticipant( + roomName, + participantId, + participantName, + r.getOrCreateMessageChannel(r.requestChannels, participantId), + r.getOrCreateMessageChannel(r.responseChannels, participantId), + ) + return nil +} + +func (r *LocalRouter) SetRTCNode(participantId, nodeId string) error { + // nothing to be done + return nil +} + +// for a local router, sink and source are pointing to the same spot +func (r *LocalRouter) GetRequestSink(participantId string) MessageSink { + return r.getOrCreateMessageChannel(r.requestChannels, participantId) +} + +func (r *LocalRouter) GetResponseSource(participantId string) MessageSource { + return r.getOrCreateMessageChannel(r.responseChannels, participantId) +} + +func (r *LocalRouter) OnNewParticipant(callback ParticipantCallback) { + r.onNewParticipant = callback +} + +func (r *LocalRouter) Start() error { + // on local routers, Start doesn't do anything, websocket connections initiate the connections + return nil +} + +func (r *LocalRouter) Stop() { +} + +func (r *LocalRouter) getOrCreateMessageChannel(target map[string]*MessageChannel, participantId string) *MessageChannel { + r.lock.RLock() + mc := target[participantId] + r.lock.RUnlock() + + if mc != nil { + return mc + } + + mc = NewMessageChannel() + r.lock.Lock() + target[participantId] = mc + r.lock.Unlock() + + return mc +} diff --git a/pkg/routing/messagechannel.go b/pkg/routing/messagechannel.go new file mode 100644 index 000000000..f0fe34f22 --- /dev/null +++ b/pkg/routing/messagechannel.go @@ -0,0 +1,33 @@ +package routing + +import ( + "io" +) + +type MessageChannel struct { + msgChan chan interface{} +} + +func NewMessageChannel() *MessageChannel { + return &MessageChannel{ + msgChan: make(chan interface{}, 1), + } +} + +func (m *MessageChannel) WriteMessage(msg interface{}) error { + m.msgChan <- msg + return nil +} + +func (m *MessageChannel) ReadMessage() (interface{}, error) { + msg := <-m.msgChan + // channel closed + if msg == nil { + return nil, io.EOF + } + return msg, nil +} + +func (m *MessageChannel) Close() { + close(m.msgChan) +} diff --git a/pkg/node/node.go b/pkg/routing/node.go similarity index 60% rename from pkg/node/node.go rename to pkg/routing/node.go index f3cc8edbc..d066ba7f5 100644 --- a/pkg/node/node.go +++ b/pkg/routing/node.go @@ -1,11 +1,11 @@ -package node +package routing import ( "context" "fmt" + "runtime" "time" - "github.com/google/wire" "github.com/pion/stun" "github.com/pkg/errors" @@ -14,13 +14,6 @@ import ( "github.com/livekit/livekit-server/proto/livekit" ) -var NodeSet = wire.NewSet(NewLocalNode) - -type Node struct { - livekit.Node - config *config.Config -} - type NodeStats struct { NumRooms int32 NumClients int32 @@ -29,36 +22,37 @@ type NodeStats struct { BytesPerMin int64 } -func NewLocalNode(conf *config.Config) (*Node, error) { - n := &Node{ - Node: livekit.Node{ - Id: utils.NewGuid(utils.NodePrefix), - RtcPort: conf.RTCPort, - }, - config: conf, - } - if err := n.DiscoverNetworkInfo(); err != nil { +type LocalNode *livekit.Node + +func NewLocalNode(conf *config.Config) (LocalNode, error) { + ip, err := GetLocalIP(conf.RTC.StunServers) + if err != nil { return nil, err } - return n, nil + return &livekit.Node{ + Id: utils.NewGuid(utils.NodePrefix), + Ip: ip, + NumCpus: uint32(runtime.NumCPU()), + }, nil } -func (n *Node) DiscoverNetworkInfo() error { - if len(n.config.RTC.StunServers) == 0 { - return errors.New("STUN servers are required but not defined") +func GetLocalIP(stunServers []string) (string, error) { + if len(stunServers) == 0 { + return "", errors.New("STUN servers are required but not defined") } - c, err := stun.Dial("udp4", n.config.RTC.StunServers[0]) + c, err := stun.Dial("udp4", stunServers[0]) if err != nil { - return err + return "", err } defer c.Close() message, err := stun.Build(stun.TransactionID, stun.BindingRequest) if err != nil { - return err + return "", err } var stunErr error + var nodeIp string err = c.Start(message, func(res stun.Event) { if res.Error != nil { stunErr = res.Error @@ -72,28 +66,28 @@ func (n *Node) DiscoverNetworkInfo() error { } ip := xorAddr.IP.To4() if ip != nil { - n.Ip = ip.String() + nodeIp = ip.String() } }) if err != nil { - return err + return "", err } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - for n.Ip == "" { + for nodeIp == "" { select { case <-ctx.Done(): msg := "could not determine public IP" if stunErr != nil { - return errors.Wrap(stunErr, msg) + return "", errors.Wrap(stunErr, msg) } else { - return fmt.Errorf(msg) + return "", fmt.Errorf(msg) } case <-time.After(100 * time.Millisecond): continue } } - return nil + return nodeIp, nil } diff --git a/pkg/routing/routingfakes/fake_message_sink.go b/pkg/routing/routingfakes/fake_message_sink.go new file mode 100644 index 000000000..f53407344 --- /dev/null +++ b/pkg/routing/routingfakes/fake_message_sink.go @@ -0,0 +1,141 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package routingfakes + +import ( + "sync" + + "github.com/livekit/livekit-server/pkg/routing" +) + +type FakeMessageSink struct { + CloseStub func() + closeMutex sync.RWMutex + closeArgsForCall []struct { + } + WriteMessageStub func(interface{}) error + writeMessageMutex sync.RWMutex + writeMessageArgsForCall []struct { + arg1 interface{} + } + writeMessageReturns struct { + result1 error + } + writeMessageReturnsOnCall map[int]struct { + result1 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeMessageSink) Close() { + fake.closeMutex.Lock() + fake.closeArgsForCall = append(fake.closeArgsForCall, struct { + }{}) + stub := fake.CloseStub + fake.recordInvocation("Close", []interface{}{}) + fake.closeMutex.Unlock() + if stub != nil { + fake.CloseStub() + } +} + +func (fake *FakeMessageSink) CloseCallCount() int { + fake.closeMutex.RLock() + defer fake.closeMutex.RUnlock() + return len(fake.closeArgsForCall) +} + +func (fake *FakeMessageSink) CloseCalls(stub func()) { + fake.closeMutex.Lock() + defer fake.closeMutex.Unlock() + fake.CloseStub = stub +} + +func (fake *FakeMessageSink) WriteMessage(arg1 interface{}) error { + fake.writeMessageMutex.Lock() + ret, specificReturn := fake.writeMessageReturnsOnCall[len(fake.writeMessageArgsForCall)] + fake.writeMessageArgsForCall = append(fake.writeMessageArgsForCall, struct { + arg1 interface{} + }{arg1}) + stub := fake.WriteMessageStub + fakeReturns := fake.writeMessageReturns + fake.recordInvocation("WriteMessage", []interface{}{arg1}) + fake.writeMessageMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeMessageSink) WriteMessageCallCount() int { + fake.writeMessageMutex.RLock() + defer fake.writeMessageMutex.RUnlock() + return len(fake.writeMessageArgsForCall) +} + +func (fake *FakeMessageSink) WriteMessageCalls(stub func(interface{}) error) { + fake.writeMessageMutex.Lock() + defer fake.writeMessageMutex.Unlock() + fake.WriteMessageStub = stub +} + +func (fake *FakeMessageSink) WriteMessageArgsForCall(i int) interface{} { + fake.writeMessageMutex.RLock() + defer fake.writeMessageMutex.RUnlock() + argsForCall := fake.writeMessageArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeMessageSink) WriteMessageReturns(result1 error) { + fake.writeMessageMutex.Lock() + defer fake.writeMessageMutex.Unlock() + fake.WriteMessageStub = nil + fake.writeMessageReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeMessageSink) WriteMessageReturnsOnCall(i int, result1 error) { + fake.writeMessageMutex.Lock() + defer fake.writeMessageMutex.Unlock() + fake.WriteMessageStub = nil + if fake.writeMessageReturnsOnCall == nil { + fake.writeMessageReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.writeMessageReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeMessageSink) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.closeMutex.RLock() + defer fake.closeMutex.RUnlock() + fake.writeMessageMutex.RLock() + defer fake.writeMessageMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeMessageSink) 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.MessageSink = new(FakeMessageSink) diff --git a/pkg/routing/routingfakes/fake_message_source.go b/pkg/routing/routingfakes/fake_message_source.go new file mode 100644 index 000000000..cce7abec9 --- /dev/null +++ b/pkg/routing/routingfakes/fake_message_source.go @@ -0,0 +1,107 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package routingfakes + +import ( + "sync" + + "github.com/livekit/livekit-server/pkg/routing" +) + +type FakeMessageSource struct { + ReadMessageStub func() (interface{}, error) + readMessageMutex sync.RWMutex + readMessageArgsForCall []struct { + } + readMessageReturns struct { + result1 interface{} + result2 error + } + readMessageReturnsOnCall map[int]struct { + result1 interface{} + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeMessageSource) ReadMessage() (interface{}, error) { + fake.readMessageMutex.Lock() + ret, specificReturn := fake.readMessageReturnsOnCall[len(fake.readMessageArgsForCall)] + fake.readMessageArgsForCall = append(fake.readMessageArgsForCall, struct { + }{}) + stub := fake.ReadMessageStub + fakeReturns := fake.readMessageReturns + fake.recordInvocation("ReadMessage", []interface{}{}) + fake.readMessageMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeMessageSource) ReadMessageCallCount() int { + fake.readMessageMutex.RLock() + defer fake.readMessageMutex.RUnlock() + return len(fake.readMessageArgsForCall) +} + +func (fake *FakeMessageSource) ReadMessageCalls(stub func() (interface{}, error)) { + fake.readMessageMutex.Lock() + defer fake.readMessageMutex.Unlock() + fake.ReadMessageStub = stub +} + +func (fake *FakeMessageSource) ReadMessageReturns(result1 interface{}, result2 error) { + fake.readMessageMutex.Lock() + defer fake.readMessageMutex.Unlock() + fake.ReadMessageStub = nil + fake.readMessageReturns = struct { + result1 interface{} + result2 error + }{result1, result2} +} + +func (fake *FakeMessageSource) ReadMessageReturnsOnCall(i int, result1 interface{}, result2 error) { + fake.readMessageMutex.Lock() + defer fake.readMessageMutex.Unlock() + fake.ReadMessageStub = nil + if fake.readMessageReturnsOnCall == nil { + fake.readMessageReturnsOnCall = make(map[int]struct { + result1 interface{} + result2 error + }) + } + fake.readMessageReturnsOnCall[i] = struct { + result1 interface{} + result2 error + }{result1, result2} +} + +func (fake *FakeMessageSource) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.readMessageMutex.RLock() + defer fake.readMessageMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeMessageSource) 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.MessageSource = new(FakeMessageSource) diff --git a/pkg/routing/routingfakes/fake_router.go b/pkg/routing/routingfakes/fake_router.go new file mode 100644 index 000000000..d5f07be3b --- /dev/null +++ b/pkg/routing/routingfakes/fake_router.go @@ -0,0 +1,708 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package routingfakes + +import ( + "sync" + + "github.com/livekit/livekit-server/pkg/routing" + "github.com/livekit/livekit-server/proto/livekit" +) + +type FakeRouter struct { + GetNodeStub func(string) (*livekit.Node, error) + getNodeMutex sync.RWMutex + getNodeArgsForCall []struct { + arg1 string + } + getNodeReturns struct { + result1 *livekit.Node + result2 error + } + getNodeReturnsOnCall map[int]struct { + result1 *livekit.Node + result2 error + } + GetNodeIdForRoomStub func(string) (string, error) + getNodeIdForRoomMutex sync.RWMutex + getNodeIdForRoomArgsForCall []struct { + arg1 string + } + getNodeIdForRoomReturns struct { + result1 string + result2 error + } + getNodeIdForRoomReturnsOnCall map[int]struct { + result1 string + result2 error + } + GetRequestSinkStub func(string) routing.MessageSink + getRequestSinkMutex sync.RWMutex + getRequestSinkArgsForCall []struct { + arg1 string + } + getRequestSinkReturns struct { + result1 routing.MessageSink + } + getRequestSinkReturnsOnCall map[int]struct { + result1 routing.MessageSink + } + GetResponseSourceStub func(string) routing.MessageSource + getResponseSourceMutex sync.RWMutex + getResponseSourceArgsForCall []struct { + arg1 string + } + getResponseSourceReturns struct { + result1 routing.MessageSource + } + getResponseSourceReturnsOnCall map[int]struct { + result1 routing.MessageSource + } + OnNewParticipantStub func(routing.ParticipantCallback) + onNewParticipantMutex sync.RWMutex + onNewParticipantArgsForCall []struct { + arg1 routing.ParticipantCallback + } + RegisterNodeStub func(*livekit.Node) error + registerNodeMutex sync.RWMutex + registerNodeArgsForCall []struct { + arg1 *livekit.Node + } + registerNodeReturns struct { + result1 error + } + registerNodeReturnsOnCall map[int]struct { + result1 error + } + SetRTCNodeStub func(string, string) error + setRTCNodeMutex sync.RWMutex + setRTCNodeArgsForCall []struct { + arg1 string + arg2 string + } + setRTCNodeReturns struct { + result1 error + } + setRTCNodeReturnsOnCall map[int]struct { + result1 error + } + StartStub func() error + startMutex sync.RWMutex + startArgsForCall []struct { + } + startReturns struct { + result1 error + } + startReturnsOnCall map[int]struct { + result1 error + } + StartParticipantStub func(string, string, string, string) error + startParticipantMutex sync.RWMutex + startParticipantArgsForCall []struct { + arg1 string + arg2 string + arg3 string + arg4 string + } + startParticipantReturns struct { + result1 error + } + startParticipantReturnsOnCall map[int]struct { + result1 error + } + StopStub func() + stopMutex sync.RWMutex + stopArgsForCall []struct { + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeRouter) GetNode(arg1 string) (*livekit.Node, error) { + fake.getNodeMutex.Lock() + ret, specificReturn := fake.getNodeReturnsOnCall[len(fake.getNodeArgsForCall)] + fake.getNodeArgsForCall = append(fake.getNodeArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.GetNodeStub + fakeReturns := fake.getNodeReturns + fake.recordInvocation("GetNode", []interface{}{arg1}) + fake.getNodeMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeRouter) GetNodeCallCount() int { + fake.getNodeMutex.RLock() + defer fake.getNodeMutex.RUnlock() + return len(fake.getNodeArgsForCall) +} + +func (fake *FakeRouter) GetNodeCalls(stub func(string) (*livekit.Node, error)) { + fake.getNodeMutex.Lock() + defer fake.getNodeMutex.Unlock() + fake.GetNodeStub = stub +} + +func (fake *FakeRouter) GetNodeArgsForCall(i int) string { + fake.getNodeMutex.RLock() + defer fake.getNodeMutex.RUnlock() + argsForCall := fake.getNodeArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeRouter) GetNodeReturns(result1 *livekit.Node, result2 error) { + fake.getNodeMutex.Lock() + defer fake.getNodeMutex.Unlock() + fake.GetNodeStub = nil + fake.getNodeReturns = struct { + result1 *livekit.Node + result2 error + }{result1, result2} +} + +func (fake *FakeRouter) GetNodeReturnsOnCall(i int, result1 *livekit.Node, result2 error) { + fake.getNodeMutex.Lock() + defer fake.getNodeMutex.Unlock() + fake.GetNodeStub = nil + if fake.getNodeReturnsOnCall == nil { + fake.getNodeReturnsOnCall = make(map[int]struct { + result1 *livekit.Node + result2 error + }) + } + fake.getNodeReturnsOnCall[i] = struct { + result1 *livekit.Node + result2 error + }{result1, result2} +} + +func (fake *FakeRouter) GetNodeIdForRoom(arg1 string) (string, error) { + fake.getNodeIdForRoomMutex.Lock() + ret, specificReturn := fake.getNodeIdForRoomReturnsOnCall[len(fake.getNodeIdForRoomArgsForCall)] + fake.getNodeIdForRoomArgsForCall = append(fake.getNodeIdForRoomArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.GetNodeIdForRoomStub + fakeReturns := fake.getNodeIdForRoomReturns + fake.recordInvocation("GetNodeIdForRoom", []interface{}{arg1}) + fake.getNodeIdForRoomMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeRouter) GetNodeIdForRoomCallCount() int { + fake.getNodeIdForRoomMutex.RLock() + defer fake.getNodeIdForRoomMutex.RUnlock() + return len(fake.getNodeIdForRoomArgsForCall) +} + +func (fake *FakeRouter) GetNodeIdForRoomCalls(stub func(string) (string, error)) { + fake.getNodeIdForRoomMutex.Lock() + defer fake.getNodeIdForRoomMutex.Unlock() + fake.GetNodeIdForRoomStub = stub +} + +func (fake *FakeRouter) GetNodeIdForRoomArgsForCall(i int) string { + fake.getNodeIdForRoomMutex.RLock() + defer fake.getNodeIdForRoomMutex.RUnlock() + argsForCall := fake.getNodeIdForRoomArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeRouter) GetNodeIdForRoomReturns(result1 string, result2 error) { + fake.getNodeIdForRoomMutex.Lock() + defer fake.getNodeIdForRoomMutex.Unlock() + fake.GetNodeIdForRoomStub = nil + fake.getNodeIdForRoomReturns = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeRouter) GetNodeIdForRoomReturnsOnCall(i int, result1 string, result2 error) { + fake.getNodeIdForRoomMutex.Lock() + defer fake.getNodeIdForRoomMutex.Unlock() + fake.GetNodeIdForRoomStub = nil + if fake.getNodeIdForRoomReturnsOnCall == nil { + fake.getNodeIdForRoomReturnsOnCall = make(map[int]struct { + result1 string + result2 error + }) + } + fake.getNodeIdForRoomReturnsOnCall[i] = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeRouter) GetRequestSink(arg1 string) routing.MessageSink { + fake.getRequestSinkMutex.Lock() + ret, specificReturn := fake.getRequestSinkReturnsOnCall[len(fake.getRequestSinkArgsForCall)] + fake.getRequestSinkArgsForCall = append(fake.getRequestSinkArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.GetRequestSinkStub + fakeReturns := fake.getRequestSinkReturns + fake.recordInvocation("GetRequestSink", []interface{}{arg1}) + fake.getRequestSinkMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeRouter) GetRequestSinkCallCount() int { + fake.getRequestSinkMutex.RLock() + defer fake.getRequestSinkMutex.RUnlock() + return len(fake.getRequestSinkArgsForCall) +} + +func (fake *FakeRouter) GetRequestSinkCalls(stub func(string) routing.MessageSink) { + fake.getRequestSinkMutex.Lock() + defer fake.getRequestSinkMutex.Unlock() + fake.GetRequestSinkStub = stub +} + +func (fake *FakeRouter) GetRequestSinkArgsForCall(i int) string { + fake.getRequestSinkMutex.RLock() + defer fake.getRequestSinkMutex.RUnlock() + argsForCall := fake.getRequestSinkArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeRouter) GetRequestSinkReturns(result1 routing.MessageSink) { + fake.getRequestSinkMutex.Lock() + defer fake.getRequestSinkMutex.Unlock() + fake.GetRequestSinkStub = nil + fake.getRequestSinkReturns = struct { + result1 routing.MessageSink + }{result1} +} + +func (fake *FakeRouter) GetRequestSinkReturnsOnCall(i int, result1 routing.MessageSink) { + fake.getRequestSinkMutex.Lock() + defer fake.getRequestSinkMutex.Unlock() + fake.GetRequestSinkStub = nil + if fake.getRequestSinkReturnsOnCall == nil { + fake.getRequestSinkReturnsOnCall = make(map[int]struct { + result1 routing.MessageSink + }) + } + fake.getRequestSinkReturnsOnCall[i] = struct { + result1 routing.MessageSink + }{result1} +} + +func (fake *FakeRouter) GetResponseSource(arg1 string) routing.MessageSource { + fake.getResponseSourceMutex.Lock() + ret, specificReturn := fake.getResponseSourceReturnsOnCall[len(fake.getResponseSourceArgsForCall)] + fake.getResponseSourceArgsForCall = append(fake.getResponseSourceArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.GetResponseSourceStub + fakeReturns := fake.getResponseSourceReturns + fake.recordInvocation("GetResponseSource", []interface{}{arg1}) + fake.getResponseSourceMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeRouter) GetResponseSourceCallCount() int { + fake.getResponseSourceMutex.RLock() + defer fake.getResponseSourceMutex.RUnlock() + return len(fake.getResponseSourceArgsForCall) +} + +func (fake *FakeRouter) GetResponseSourceCalls(stub func(string) routing.MessageSource) { + fake.getResponseSourceMutex.Lock() + defer fake.getResponseSourceMutex.Unlock() + fake.GetResponseSourceStub = stub +} + +func (fake *FakeRouter) GetResponseSourceArgsForCall(i int) string { + fake.getResponseSourceMutex.RLock() + defer fake.getResponseSourceMutex.RUnlock() + argsForCall := fake.getResponseSourceArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeRouter) GetResponseSourceReturns(result1 routing.MessageSource) { + fake.getResponseSourceMutex.Lock() + defer fake.getResponseSourceMutex.Unlock() + fake.GetResponseSourceStub = nil + fake.getResponseSourceReturns = struct { + result1 routing.MessageSource + }{result1} +} + +func (fake *FakeRouter) GetResponseSourceReturnsOnCall(i int, result1 routing.MessageSource) { + fake.getResponseSourceMutex.Lock() + defer fake.getResponseSourceMutex.Unlock() + fake.GetResponseSourceStub = nil + if fake.getResponseSourceReturnsOnCall == nil { + fake.getResponseSourceReturnsOnCall = make(map[int]struct { + result1 routing.MessageSource + }) + } + fake.getResponseSourceReturnsOnCall[i] = struct { + result1 routing.MessageSource + }{result1} +} + +func (fake *FakeRouter) OnNewParticipant(arg1 routing.ParticipantCallback) { + fake.onNewParticipantMutex.Lock() + fake.onNewParticipantArgsForCall = append(fake.onNewParticipantArgsForCall, struct { + arg1 routing.ParticipantCallback + }{arg1}) + stub := fake.OnNewParticipantStub + fake.recordInvocation("OnNewParticipant", []interface{}{arg1}) + fake.onNewParticipantMutex.Unlock() + if stub != nil { + fake.OnNewParticipantStub(arg1) + } +} + +func (fake *FakeRouter) OnNewParticipantCallCount() int { + fake.onNewParticipantMutex.RLock() + defer fake.onNewParticipantMutex.RUnlock() + return len(fake.onNewParticipantArgsForCall) +} + +func (fake *FakeRouter) OnNewParticipantCalls(stub func(routing.ParticipantCallback)) { + fake.onNewParticipantMutex.Lock() + defer fake.onNewParticipantMutex.Unlock() + fake.OnNewParticipantStub = stub +} + +func (fake *FakeRouter) OnNewParticipantArgsForCall(i int) routing.ParticipantCallback { + fake.onNewParticipantMutex.RLock() + defer fake.onNewParticipantMutex.RUnlock() + argsForCall := fake.onNewParticipantArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeRouter) RegisterNode(arg1 *livekit.Node) error { + fake.registerNodeMutex.Lock() + ret, specificReturn := fake.registerNodeReturnsOnCall[len(fake.registerNodeArgsForCall)] + fake.registerNodeArgsForCall = append(fake.registerNodeArgsForCall, struct { + arg1 *livekit.Node + }{arg1}) + stub := fake.RegisterNodeStub + fakeReturns := fake.registerNodeReturns + fake.recordInvocation("RegisterNode", []interface{}{arg1}) + fake.registerNodeMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeRouter) RegisterNodeCallCount() int { + fake.registerNodeMutex.RLock() + defer fake.registerNodeMutex.RUnlock() + return len(fake.registerNodeArgsForCall) +} + +func (fake *FakeRouter) RegisterNodeCalls(stub func(*livekit.Node) error) { + fake.registerNodeMutex.Lock() + defer fake.registerNodeMutex.Unlock() + fake.RegisterNodeStub = stub +} + +func (fake *FakeRouter) RegisterNodeArgsForCall(i int) *livekit.Node { + fake.registerNodeMutex.RLock() + defer fake.registerNodeMutex.RUnlock() + argsForCall := fake.registerNodeArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeRouter) RegisterNodeReturns(result1 error) { + fake.registerNodeMutex.Lock() + defer fake.registerNodeMutex.Unlock() + fake.RegisterNodeStub = nil + fake.registerNodeReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeRouter) RegisterNodeReturnsOnCall(i int, result1 error) { + fake.registerNodeMutex.Lock() + defer fake.registerNodeMutex.Unlock() + fake.RegisterNodeStub = nil + if fake.registerNodeReturnsOnCall == nil { + fake.registerNodeReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.registerNodeReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeRouter) SetRTCNode(arg1 string, arg2 string) error { + fake.setRTCNodeMutex.Lock() + ret, specificReturn := fake.setRTCNodeReturnsOnCall[len(fake.setRTCNodeArgsForCall)] + fake.setRTCNodeArgsForCall = append(fake.setRTCNodeArgsForCall, struct { + arg1 string + arg2 string + }{arg1, arg2}) + stub := fake.SetRTCNodeStub + fakeReturns := fake.setRTCNodeReturns + fake.recordInvocation("SetRTCNode", []interface{}{arg1, arg2}) + fake.setRTCNodeMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeRouter) SetRTCNodeCallCount() int { + fake.setRTCNodeMutex.RLock() + defer fake.setRTCNodeMutex.RUnlock() + return len(fake.setRTCNodeArgsForCall) +} + +func (fake *FakeRouter) SetRTCNodeCalls(stub func(string, string) error) { + fake.setRTCNodeMutex.Lock() + defer fake.setRTCNodeMutex.Unlock() + fake.SetRTCNodeStub = stub +} + +func (fake *FakeRouter) SetRTCNodeArgsForCall(i int) (string, string) { + fake.setRTCNodeMutex.RLock() + defer fake.setRTCNodeMutex.RUnlock() + argsForCall := fake.setRTCNodeArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeRouter) SetRTCNodeReturns(result1 error) { + fake.setRTCNodeMutex.Lock() + defer fake.setRTCNodeMutex.Unlock() + fake.SetRTCNodeStub = nil + fake.setRTCNodeReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeRouter) SetRTCNodeReturnsOnCall(i int, result1 error) { + fake.setRTCNodeMutex.Lock() + defer fake.setRTCNodeMutex.Unlock() + fake.SetRTCNodeStub = nil + if fake.setRTCNodeReturnsOnCall == nil { + fake.setRTCNodeReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.setRTCNodeReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeRouter) Start() error { + fake.startMutex.Lock() + ret, specificReturn := fake.startReturnsOnCall[len(fake.startArgsForCall)] + fake.startArgsForCall = append(fake.startArgsForCall, struct { + }{}) + stub := fake.StartStub + fakeReturns := fake.startReturns + fake.recordInvocation("Start", []interface{}{}) + fake.startMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeRouter) StartCallCount() int { + fake.startMutex.RLock() + defer fake.startMutex.RUnlock() + return len(fake.startArgsForCall) +} + +func (fake *FakeRouter) StartCalls(stub func() error) { + fake.startMutex.Lock() + defer fake.startMutex.Unlock() + fake.StartStub = stub +} + +func (fake *FakeRouter) StartReturns(result1 error) { + fake.startMutex.Lock() + defer fake.startMutex.Unlock() + fake.StartStub = nil + fake.startReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeRouter) StartReturnsOnCall(i int, result1 error) { + fake.startMutex.Lock() + defer fake.startMutex.Unlock() + fake.StartStub = nil + if fake.startReturnsOnCall == nil { + fake.startReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.startReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeRouter) StartParticipant(arg1 string, arg2 string, arg3 string, arg4 string) error { + fake.startParticipantMutex.Lock() + ret, specificReturn := fake.startParticipantReturnsOnCall[len(fake.startParticipantArgsForCall)] + fake.startParticipantArgsForCall = append(fake.startParticipantArgsForCall, struct { + arg1 string + arg2 string + arg3 string + arg4 string + }{arg1, arg2, arg3, arg4}) + stub := fake.StartParticipantStub + fakeReturns := fake.startParticipantReturns + fake.recordInvocation("StartParticipant", []interface{}{arg1, arg2, arg3, arg4}) + fake.startParticipantMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeRouter) StartParticipantCallCount() int { + fake.startParticipantMutex.RLock() + defer fake.startParticipantMutex.RUnlock() + return len(fake.startParticipantArgsForCall) +} + +func (fake *FakeRouter) StartParticipantCalls(stub func(string, string, string, string) error) { + fake.startParticipantMutex.Lock() + defer fake.startParticipantMutex.Unlock() + fake.StartParticipantStub = stub +} + +func (fake *FakeRouter) StartParticipantArgsForCall(i int) (string, string, string, string) { + fake.startParticipantMutex.RLock() + defer fake.startParticipantMutex.RUnlock() + argsForCall := fake.startParticipantArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *FakeRouter) StartParticipantReturns(result1 error) { + fake.startParticipantMutex.Lock() + defer fake.startParticipantMutex.Unlock() + fake.StartParticipantStub = nil + fake.startParticipantReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeRouter) StartParticipantReturnsOnCall(i int, result1 error) { + fake.startParticipantMutex.Lock() + defer fake.startParticipantMutex.Unlock() + fake.StartParticipantStub = nil + if fake.startParticipantReturnsOnCall == nil { + fake.startParticipantReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.startParticipantReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeRouter) Stop() { + fake.stopMutex.Lock() + fake.stopArgsForCall = append(fake.stopArgsForCall, struct { + }{}) + stub := fake.StopStub + fake.recordInvocation("Stop", []interface{}{}) + fake.stopMutex.Unlock() + if stub != nil { + fake.StopStub() + } +} + +func (fake *FakeRouter) StopCallCount() int { + fake.stopMutex.RLock() + defer fake.stopMutex.RUnlock() + return len(fake.stopArgsForCall) +} + +func (fake *FakeRouter) StopCalls(stub func()) { + fake.stopMutex.Lock() + defer fake.stopMutex.Unlock() + fake.StopStub = stub +} + +func (fake *FakeRouter) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.getNodeMutex.RLock() + defer fake.getNodeMutex.RUnlock() + fake.getNodeIdForRoomMutex.RLock() + defer fake.getNodeIdForRoomMutex.RUnlock() + fake.getRequestSinkMutex.RLock() + defer fake.getRequestSinkMutex.RUnlock() + fake.getResponseSourceMutex.RLock() + defer fake.getResponseSourceMutex.RUnlock() + fake.onNewParticipantMutex.RLock() + defer fake.onNewParticipantMutex.RUnlock() + fake.registerNodeMutex.RLock() + defer fake.registerNodeMutex.RUnlock() + fake.setRTCNodeMutex.RLock() + defer fake.setRTCNodeMutex.RUnlock() + fake.startMutex.RLock() + defer fake.startMutex.RUnlock() + fake.startParticipantMutex.RLock() + defer fake.startParticipantMutex.RUnlock() + fake.stopMutex.RLock() + defer fake.stopMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeRouter) 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.Router = new(FakeRouter) diff --git a/pkg/rtc/config.go b/pkg/rtc/config.go index a1c64be44..737bb8449 100644 --- a/pkg/rtc/config.go +++ b/pkg/rtc/config.go @@ -19,7 +19,9 @@ type ReceiverConfig struct { maxBufferTime int } -func NewWebRTCConfig(conf *config.RTCConfig, externalIP string) (*WebRTCConfig, error) { +type ExternalIP string + +func NewWebRTCConfig(conf *config.RTCConfig, externalIP ExternalIP) (*WebRTCConfig, error) { c := webrtc.Configuration{ SDPSemantics: webrtc.SDPSemanticsUnifiedPlan, } @@ -41,7 +43,7 @@ func NewWebRTCConfig(conf *config.RTCConfig, externalIP string) (*WebRTCConfig, }, } if conf.UseExternalIP { - s.SetNAT1To1IPs([]string{externalIP}, webrtc.ICECandidateTypeHost) + s.SetNAT1To1IPs([]string{string(externalIP)}, webrtc.ICECandidateTypeHost) } return &WebRTCConfig{ diff --git a/pkg/rtc/datatrack.go b/pkg/rtc/datatrack.go index 718c4f605..812649562 100644 --- a/pkg/rtc/datatrack.go +++ b/pkg/rtc/datatrack.go @@ -141,7 +141,7 @@ func (t *DataTrack) forwardWorker() { for _, sub := range t.subscribers { err := sub.SendMessage(msg) if err != nil { - logger.GetLogger().Errorw("could not send data message", + logger.Errorw("could not send data message", "err", err, "source", t.participantId, "dest", sub.participantId) diff --git a/pkg/rtc/manager.go b/pkg/rtc/manager.go deleted file mode 100644 index e603252a8..000000000 --- a/pkg/rtc/manager.go +++ /dev/null @@ -1,99 +0,0 @@ -package rtc - -import ( - "sync" - - "github.com/livekit/livekit-server/pkg/config" - "github.com/livekit/livekit-server/proto/livekit" -) - -// A RoomManager maintains active rooms that are hosted on the current node -type RoomManager struct { - rtcConf config.RTCConfig - externalIP string - - config WebRTCConfig - - rooms map[string]*Room - roomsByName map[string]*Room - roomLock sync.RWMutex -} - -func NewRoomManager(rtcConf config.RTCConfig, externalIP string) (m *RoomManager, err error) { - m = &RoomManager{ - rtcConf: rtcConf, - externalIP: externalIP, - rooms: make(map[string]*Room), - roomsByName: make(map[string]*Room), - roomLock: sync.RWMutex{}, - } - - wc, err := NewWebRTCConfig(&rtcConf, externalIP) - if err != nil { - return - } - m.config = *wc - return -} - -func (m *RoomManager) GetRoom(idOrName string) *Room { - m.roomLock.RLock() - defer m.roomLock.RUnlock() - rm := m.rooms[idOrName] - if rm == nil { - rm = m.roomsByName[idOrName] - } - return rm -} - -func (m *RoomManager) GetRoomWithConstraint(idOrName string, onlyName string) (*Room, error) { - if idOrName == "" { - idOrName = onlyName - } - if idOrName == "" { - return nil, ErrRoomIdMissing - } - - rm := m.GetRoom(idOrName) - if rm == nil { - return nil, ErrRoomNotFound - } - - if onlyName != "" && rm.Name != onlyName { - return nil, ErrPermissionDenied - } - return rm, nil -} - -func (m *RoomManager) CreateRoom(req *livekit.CreateRoomRequest) (*Room, error) { - if req.Name == "" { - return nil, ErrInvalidRoomName - } - r := NewRoomForRequest(req, &m.config) - m.roomLock.Lock() - defer m.roomLock.Unlock() - - if m.roomsByName[req.Name] != nil { - return nil, ErrInvalidRoomName - } - - m.rooms[r.Sid] = r - m.roomsByName[r.Name] = r - return r, nil -} - -func (m *RoomManager) DeleteRoom(idOrName string) error { - rm := m.GetRoom(idOrName) - if rm == nil { - return nil - } - m.roomLock.Lock() - defer m.roomLock.Unlock() - delete(m.rooms, rm.Sid) - delete(m.roomsByName, rm.Name) - return nil -} - -func (m *RoomManager) Config() *WebRTCConfig { - return &m.config -} diff --git a/pkg/rtc/manager_test.go b/pkg/rtc/manager_test.go deleted file mode 100644 index a60bb9f96..000000000 --- a/pkg/rtc/manager_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package rtc_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/livekit/livekit-server/pkg/config" - "github.com/livekit/livekit-server/pkg/rtc" - "github.com/livekit/livekit-server/proto/livekit" -) - -func TestRoomManager_CreateRoom(t *testing.T) { - man := newRoomManager(t) - - t.Run("creation and duplicates", func(t *testing.T) { - r := &livekit.CreateRoomRequest{Name: "basic"} - rm, err := man.CreateRoom(r) - assert.NoError(t, err) - assert.NotNil(t, rm) - - rm, err = man.CreateRoom(r) - assert.Equal(t, rtc.ErrInvalidRoomName, err) - assert.Nil(t, rm) - }) - - t.Run("name is required", func(t *testing.T) { - _, err := man.CreateRoom(&livekit.CreateRoomRequest{}) - assert.Equal(t, rtc.ErrInvalidRoomName, err) - }) -} - -func TestRoomManager_GetRoomByName(t *testing.T) { - man := newRoomManager(t) - _, err := man.CreateRoom(&livekit.CreateRoomRequest{ - Name: "hello", - }) - assert.NoError(t, err) - - rm := man.GetRoom("hello") - assert.Equal(t, "hello", rm.Name) -} - -func TestRoomManager_GetRoomWithConstraint(t *testing.T) { - man := newRoomManager(t) - rm, _ := man.CreateRoom(&livekit.CreateRoomRequest{ - Name: "hello", - }) - - t.Run("no constraint, get by id", func(t *testing.T) { - r, err := man.GetRoomWithConstraint(rm.Sid, "") - assert.NoError(t, err) - assert.Equal(t, r, rm) - }) - - t.Run("no constraint, get by name", func(t *testing.T) { - r, err := man.GetRoomWithConstraint(rm.Name, "") - assert.NoError(t, err) - assert.Equal(t, r, rm) - }) - - t.Run("no constraint, room doesn't exist", func(t *testing.T) { - _, err := man.GetRoomWithConstraint("wtf", "") - assert.Equal(t, rtc.ErrRoomNotFound, err) - }) - - t.Run("constraint, no name", func(t *testing.T) { - r, err := man.GetRoomWithConstraint("", rm.Name) - assert.NoError(t, err) - assert.Equal(t, r, rm) - }) - - t.Run("constraint does not match name", func(t *testing.T) { - _, err := man.GetRoomWithConstraint(rm.Name, "anotherroom") - assert.Equal(t, rtc.ErrPermissionDenied, err) - }) -} - -func newRoomManager(t *testing.T) *rtc.RoomManager { - man, err := rtc.NewRoomManager(config.RTCConfig{}, "1.2.3.4") - assert.NoError(t, err) - return man -} diff --git a/pkg/rtc/mediatrack.go b/pkg/rtc/mediatrack.go index a542d407a..4890b217a 100644 --- a/pkg/rtc/mediatrack.go +++ b/pkg/rtc/mediatrack.go @@ -152,13 +152,13 @@ func (t *MediaTrack) AddSubscriber(participant types.Participant) error { // however, if the dest participant has disconnected, then we can skip sender := transceiver.Sender() if sender != nil { - logger.GetLogger().Debugw("removing peerconnection track", + logger.Debugw("removing peerconnection track", "track", t.id, "srcParticipant", t.participantId, "destParticipant", participant.ID()) if err := participant.PeerConnection().RemoveTrack(sender); err != nil { if _, ok := err.(*rtcerr.InvalidStateError); !ok { - logger.GetLogger().Warnw("could not remove remoteTrack from forwarder", + logger.Warnw("could not remove remoteTrack from forwarder", "participant", participant.ID(), "err", err) } @@ -188,7 +188,7 @@ func (t *MediaTrack) RemoveSubscriber(participantId string) { } func (t *MediaTrack) RemoveAllSubscribers() { - logger.GetLogger().Debugw("removing all subscribers", "track", t.id) + logger.Debugw("removing all subscribers", "track", t.id) t.lock.RLock() defer t.lock.RUnlock() for _, dt := range t.downtracks { @@ -244,7 +244,7 @@ func (t *MediaTrack) forwardRTPWorker() { }() for pkt := range t.receiver.RTPChan() { - //logger.GetLogger().Debugw("read packet from remoteTrack", + //logger.Debugw("read packet from remoteTrack", // "participant", t.participantId, // "track", t.ID()) // when track is muted, it's "disabled" on the client side, and will still be sending black frames @@ -255,7 +255,7 @@ func (t *MediaTrack) forwardRTPWorker() { t.lock.RLock() for dstId, dt := range t.downtracks { - //logger.GetLogger().Debugw("read packet from remoteTrack", + //logger.Debugw("read packet from remoteTrack", // "srcParticipant", t.participantId, // "destParticipant", dstId, // "track", t.ID()) @@ -271,7 +271,7 @@ func (t *MediaTrack) forwardRTPWorker() { if delta < maxPLIFrequency { continue } - logger.GetLogger().Infow("keyframe required, sending PLI", + logger.Infow("keyframe required, sending PLI", "srcParticipant", t.participantId) rtcpPkts := []rtcp.Packet{ &rtcp.PictureLossIndication{SenderSSRC: uint32(t.ssrc), MediaSSRC: pkt.SSRC}, @@ -279,7 +279,7 @@ func (t *MediaTrack) forwardRTPWorker() { t.rtcpCh <- rtcpPkts t.lastPLI = time.Now() } else if err != nil { - logger.GetLogger().Warnw("could not forward packet to participant", + logger.Warnw("could not forward packet to participant", "src", t.participantId, "dest", dstId, "remoteTrack", t.id, @@ -294,7 +294,7 @@ func (t *MediaTrack) handleRTCP(dt *sfu.DownTrack, rtcpBuf []byte) { defer Recover() pkts, err := rtcp.Unmarshal(rtcpBuf) if err != nil { - logger.GetLogger().Warnw("could not decode RTCP packet", "err", err) + logger.Warnw("could not decode RTCP packet", "err", err) } var fwdPkts []rtcp.Packet @@ -322,7 +322,7 @@ func (t *MediaTrack) handleRTCP(dt *sfu.DownTrack, rtcpBuf []byte) { //log.Tracef("Slow link for sender %s, fraction packet lost %.2f", f.track.peerID, float64(p.Reports[0].FractionLost)/256) } case *rtcp.TransportLayerNack: - logger.GetLogger().Debugw("forwarder got nack", + logger.Debugw("forwarder got nack", "packet", p) var nackedPackets []uint16 for _, pair := range p.Nacks { diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index e084d0d70..3cd269faf 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -12,6 +12,7 @@ import ( "github.com/pkg/errors" "github.com/livekit/livekit-server/pkg/logger" + "github.com/livekit/livekit-server/pkg/routing" "github.com/livekit/livekit-server/pkg/rtc/types" "github.com/livekit/livekit-server/pkg/sfu" "github.com/livekit/livekit-server/pkg/utils" @@ -33,7 +34,7 @@ const ( type ParticipantImpl struct { id string peerConn types.PeerConnection - sigConn types.SignalConnection + responseSink routing.MessageSink receiverConfig ReceiverConfig ctx context.Context cancel context.CancelFunc @@ -69,19 +70,21 @@ func NewPeerConnection(conf *WebRTCConfig) (*webrtc.PeerConnection, error) { se.BufferFactory = bufferFactory.GetOrNew api := webrtc.NewAPI(webrtc.WithMediaEngine(me), webrtc.WithSettingEngine(se)) - return api.NewPeerConnection(conf.Configuration) + pc, err := api.NewPeerConnection(conf.Configuration) + return pc, err } -func NewParticipant(pc types.PeerConnection, sc types.SignalConnection, name string, receiverConfig ReceiverConfig) (*ParticipantImpl, error) { +func NewParticipant(participantId, name string, pc types.PeerConnection, rs routing.MessageSink, receiverConfig ReceiverConfig) (*ParticipantImpl, error) { + // TODO: check to ensure params are valid, id and name can't be empty me := &webrtc.MediaEngine{} me.RegisterDefaultCodecs() ctx, cancel := context.WithCancel(context.Background()) participant := &ParticipantImpl{ - id: utils.NewGuid(utils.ParticipantPrefix), + id: participantId, name: name, peerConn: pc, - sigConn: sc, + responseSink: rs, receiverConfig: receiverConfig, ctx: ctx, cancel: cancel, @@ -96,7 +99,6 @@ func NewParticipant(pc types.PeerConnection, sc types.SignalConnection, name str debouncedNegotiate: debounce.New(negotiationFrequency), } - log := logger.GetLogger() pc.OnTrack(participant.onMediaTrack) pc.OnICECandidate(func(c *webrtc.ICECandidate) { @@ -107,14 +109,14 @@ func NewParticipant(pc types.PeerConnection, sc types.SignalConnection, name str ci := c.ToJSON() // write candidate - logger.GetLogger().Debugw("sending ice candidates") - err := sc.WriteResponse(&livekit.SignalResponse{ + logger.Debugw("sending ice candidates") + err := rs.WriteMessage(&livekit.SignalResponse{ Message: &livekit.SignalResponse_Trickle{ Trickle: ToProtoTrickle(ci), }, }) if err != nil { - log.Errorw("could not send trickle", "err", err) + logger.Errorw("could not send trickle", "err", err) } if participant.onICECandidate != nil { @@ -123,7 +125,7 @@ func NewParticipant(pc types.PeerConnection, sc types.SignalConnection, name str }) pc.OnICEConnectionStateChange(func(state webrtc.ICEConnectionState) { - logger.GetLogger().Debugw("ICE connection state changed", "state", state.String()) + logger.Debugw("ICE connection state changed", "state", state.String()) if state == webrtc.ICEConnectionStateConnected { participant.updateState(livekit.ParticipantInfo_ACTIVE) } @@ -228,7 +230,7 @@ func (p *ParticipantImpl) Answer(sdp webrtc.SessionDescription) (answer webrtc.S } p.negotiationCond.L.Unlock() - err = p.sigConn.WriteResponse(&livekit.SignalResponse{ + err = p.responseSink.WriteMessage(&livekit.SignalResponse{ Message: &livekit.SignalResponse_Answer{ Answer: ToProtoSessionDescription(answer), }, @@ -252,7 +254,7 @@ func (p *ParticipantImpl) AddTrack(clientId, name string, trackType livekit.Trac } p.pendingTracks[clientId] = ti - p.sigConn.WriteResponse(&livekit.SignalResponse{ + p.responseSink.WriteMessage(&livekit.SignalResponse{ Message: &livekit.SignalResponse_TrackPublished{ TrackPublished: &livekit.TrackPublishedResponse{ Cid: clientId, @@ -266,7 +268,7 @@ func (p *ParticipantImpl) HandleAnswer(sdp webrtc.SessionDescription) error { if sdp.Type != webrtc.SDPTypeAnswer { return ErrUnexpectedOffer } - logger.GetLogger().Debugw("setting remote answer") + logger.Debugw("setting remote answer") if err := p.peerConn.SetRemoteDescription(sdp); err != nil { return errors.Wrap(err, "could not set remote description") } @@ -288,7 +290,7 @@ func (p *ParticipantImpl) HandleClientNegotiation() { } p.negotiationState = negotiationStateClient p.negotiationCond.L.Unlock() - p.sigConn.WriteResponse(&livekit.SignalResponse{ + p.responseSink.WriteMessage(&livekit.SignalResponse{ Message: &livekit.SignalResponse_Negotiate{ Negotiate: &livekit.NegotiationResponse{}, }, @@ -329,7 +331,7 @@ func (p *ParticipantImpl) AddSubscriber(op types.Participant) error { defer p.lock.RUnlock() for _, track := range p.publishedTracks { - logger.GetLogger().Debugw("subscribing to remoteTrack", + logger.Debugw("subscribing to remoteTrack", "srcParticipant", p.ID(), "dstParticipant", op.ID(), "remoteTrack", track.ID()) @@ -350,9 +352,9 @@ func (p *ParticipantImpl) RemoveSubscriber(participantId string) { } // signal connection methods -func (p *ParticipantImpl) SendJoinResponse(roomInfo *livekit.RoomInfo, otherParticipants []types.Participant) error { +func (p *ParticipantImpl) SendJoinResponse(roomInfo *livekit.Room, otherParticipants []types.Participant) error { // send Join response - return p.sigConn.WriteResponse(&livekit.SignalResponse{ + return p.responseSink.WriteMessage(&livekit.SignalResponse{ Message: &livekit.SignalResponse_Join{ Join: &livekit.JoinResponse{ Room: roomInfo, @@ -364,7 +366,7 @@ func (p *ParticipantImpl) SendJoinResponse(roomInfo *livekit.RoomInfo, otherPart } func (p *ParticipantImpl) SendParticipantUpdate(participants []*livekit.ParticipantInfo) error { - return p.sigConn.WriteResponse(&livekit.SignalResponse{ + return p.responseSink.WriteMessage(&livekit.SignalResponse{ Message: &livekit.SignalResponse_Update{ Update: &livekit.ParticipantUpdate{ Participants: participants, @@ -429,10 +431,10 @@ func (p *ParticipantImpl) negotiate() { } p.negotiationCond.L.Unlock() - logger.GetLogger().Debugw("starting negotiation", "participant", p.ID()) + logger.Debugw("starting negotiation", "participant", p.ID()) offer, err := p.peerConn.CreateOffer(nil) if err != nil { - logger.GetLogger().Errorw("could not create offer", "err", err) + logger.Errorw("could not create offer", "err", err) return } @@ -444,18 +446,18 @@ func (p *ParticipantImpl) negotiate() { err = p.peerConn.SetLocalDescription(offer) if err != nil { - logger.GetLogger().Errorw("could not set local description", "err", err) + logger.Errorw("could not set local description", "err", err) return } - logger.GetLogger().Debugw("sending available offer to participant") - err = p.sigConn.WriteResponse(&livekit.SignalResponse{ + logger.Debugw("sending available offer to participant") + err = p.responseSink.WriteMessage(&livekit.SignalResponse{ Message: &livekit.SignalResponse_Offer{ Offer: ToProtoSessionDescription(offer), }, }) if err != nil { - logger.GetLogger().Errorw("could not send offer to peer", + logger.Errorw("could not send offer to peer", "err", err) } } @@ -477,7 +479,7 @@ func (p *ParticipantImpl) updateState(state livekit.ParticipantInfo_State) { // when a new remoteTrack is created, creates a Track and adds it to room func (p *ParticipantImpl) onMediaTrack(track *webrtc.TrackRemote, rtpReceiver *webrtc.RTPReceiver) { - logger.GetLogger().Debugw("mediaTrack added", "participantId", p.ID(), "remoteTrack", track.ID()) + logger.Debugw("mediaTrack added", "participantId", p.ID(), "remoteTrack", track.ID()) ti := p.popPendingTrack(track.ID()) if ti == nil { @@ -496,7 +498,7 @@ func (p *ParticipantImpl) onDataChannel(dc *webrtc.DataChannel) { if dc.Label() == placeholderDataChannel { return } - logger.GetLogger().Debugw("dataChannel added", "participantId", p.ID(), "label", dc.Label()) + logger.Debugw("dataChannel added", "participantId", p.ID(), "label", dc.Label()) // data channels have numeric ids, so we use its label to identify ti := p.popPendingTrack(dc.Label()) @@ -515,7 +517,7 @@ func (p *ParticipantImpl) popPendingTrack(clientId string) *livekit.TrackInfo { defer p.lock.Unlock() ti := p.pendingTracks[clientId] if ti == nil { - logger.GetLogger().Errorw("track info not published prior to track", "clientId", clientId) + logger.Errorw("track info not published prior to track", "clientId", clientId) } else { delete(p.pendingTracks, clientId) } @@ -584,7 +586,7 @@ func (p *ParticipantImpl) downTracksRTCPWorker() { if err == io.EOF || err == io.ErrClosedPipe { return } - logger.GetLogger().Errorw("could not send downtrack reports", + logger.Errorw("could not send downtrack reports", "participant", p.id, "err", err) } @@ -598,10 +600,10 @@ func (p *ParticipantImpl) rtcpSendWorker() { // read from rtcpChan for pkts := range p.rtcpCh { //for _, pkt := range pkts { - // logger.GetLogger().Debugw("writing RTCP", "packet", pkt) + // logger.Debugw("writing RTCP", "packet", pkt) //} if err := p.peerConn.WriteRTCP(pkts); err != nil { - logger.GetLogger().Errorw("could not write RTCP to participant", + logger.Errorw("could not write RTCP to participant", "participant", p.id, "err", err) } diff --git a/pkg/rtc/participant_internal_test.go b/pkg/rtc/participant_internal_test.go index 23d3fbd19..c0fec8293 100644 --- a/pkg/rtc/participant_internal_test.go +++ b/pkg/rtc/participant_internal_test.go @@ -5,8 +5,10 @@ import ( "github.com/stretchr/testify/assert" + "github.com/livekit/livekit-server/pkg/routing/routingfakes" "github.com/livekit/livekit-server/pkg/rtc/types" "github.com/livekit/livekit-server/pkg/rtc/types/typesfakes" + "github.com/livekit/livekit-server/pkg/utils" "github.com/livekit/livekit-server/proto/livekit" ) @@ -67,6 +69,11 @@ func TestTrackPublishEvents(t *testing.T) { } func newParticipantForTest(name string) *ParticipantImpl { - p, _ := NewParticipant(&typesfakes.FakePeerConnection{}, &typesfakes.FakeSignalConnection{}, name, ReceiverConfig{}) + p, _ := NewParticipant( + utils.NewGuid(utils.ParticipantPrefix), + name, + &typesfakes.FakePeerConnection{}, + &routingfakes.FakeMessageSink{}, + ReceiverConfig{}) return p } diff --git a/pkg/rtc/receiver.go b/pkg/rtc/receiver.go index 79b41cbed..2642aba24 100644 --- a/pkg/rtc/receiver.go +++ b/pkg/rtc/receiver.go @@ -52,7 +52,7 @@ func NewReceiver(rtcpCh chan []rtcp.Packet, rtpReceiver *webrtc.RTPReceiver, tra r.rtcpReader.OnPacket(func(bytes []byte) { pkts, err := rtcp.Unmarshal(bytes) if err != nil { - logger.GetLogger().Warnw("could not unmarshal RTCP packet") + logger.Warnw("could not unmarshal RTCP packet") return } for _, pkt := range pkts { diff --git a/pkg/rtc/room.go b/pkg/rtc/room.go index 20606f437..c1fff42a6 100644 --- a/pkg/rtc/room.go +++ b/pkg/rtc/room.go @@ -2,13 +2,11 @@ package rtc import ( "sync" - "time" "github.com/thoas/go-funk" "github.com/livekit/livekit-server/pkg/logger" "github.com/livekit/livekit-server/pkg/rtc/types" - "github.com/livekit/livekit-server/pkg/utils" "github.com/livekit/livekit-server/proto/livekit" ) @@ -20,16 +18,10 @@ type Room struct { participants map[string]types.Participant } -func NewRoomForRequest(req *livekit.CreateRoomRequest, config *WebRTCConfig) *Room { +func NewRoom(room *livekit.Room, config WebRTCConfig) *Room { return &Room{ - Room: livekit.Room{ - Sid: utils.NewGuid(utils.RoomPrefix), - Name: req.Name, - EmptyTimeout: req.EmptyTimeout, - MaxParticipants: req.MaxParticipants, - CreationTime: time.Now().Unix(), - }, - config: *config, + Room: *room, + config: config, lock: sync.RWMutex{}, participants: make(map[string]types.Participant), } @@ -47,28 +39,14 @@ func (r *Room) GetParticipants() []types.Participant { return funk.Values(r.participants).([]types.Participant) } -func (r *Room) ToRoomInfo(node *livekit.Node) *livekit.RoomInfo { - ri := &livekit.RoomInfo{ - Sid: r.Sid, - Name: r.Name, - CreationTime: r.CreationTime, - } - if node != nil { - ri.NodeIp = node.Ip - } - return ri -} - func (r *Room) Join(participant types.Participant) error { r.lock.Lock() defer r.lock.Unlock() - log := logger.GetLogger() - // it's important to set this before connection, we don't want to miss out on any publishedTracks participant.OnTrackPublished(r.onTrackAdded) participant.OnStateChange(func(p types.Participant, oldState livekit.ParticipantInfo_State) { - log.Debugw("participant state changed", "state", p.State(), "participant", p.ID(), + logger.Debugw("participant state changed", "state", p.State(), "participant", p.ID(), "oldState", oldState) r.broadcastParticipantState(p) @@ -81,7 +59,7 @@ func (r *Room) Join(participant types.Participant) error { } if err := op.AddSubscriber(p); err != nil { // TODO: log error? or disconnect? - logger.GetLogger().Errorw("could not subscribe to participant", + logger.Errorw("could not subscribe to participant", "dstParticipant", p.ID(), "srcParticipant", op.ID()) } @@ -92,7 +70,7 @@ func (r *Room) Join(participant types.Participant) error { }) participant.OnTrackUpdated(r.onTrackUpdated) - log.Infow("new participant joined", + logger.Infow("new participant joined", "id", participant.ID(), "name", participant.Name(), "roomId", r.Sid) @@ -107,7 +85,7 @@ func (r *Room) Join(participant types.Participant) error { } } - return participant.SendJoinResponse(r.ToRoomInfo(nil), otherParticipants) + return participant.SendJoinResponse(&r.Room, otherParticipants) } func (r *Room) RemoveParticipant(id string) { @@ -145,12 +123,12 @@ func (r *Room) onTrackAdded(participant types.Participant, track types.Published // not fully joined. don't subscribe yet continue } - logger.GetLogger().Debugw("subscribing to new track", + logger.Debugw("subscribing to new track", "srcParticipant", participant.ID(), "remoteTrack", track.ID(), "dstParticipant", existingParticipant.ID()) if err := track.AddSubscriber(existingParticipant); err != nil { - logger.GetLogger().Errorw("could not subscribe to remoteTrack", + logger.Errorw("could not subscribe to remoteTrack", "srcParticipant", participant.ID(), "remoteTrack", track.ID(), "dstParticipant", existingParticipant.ID()) @@ -176,7 +154,7 @@ func (r *Room) broadcastParticipantState(p types.Participant) { err := op.SendParticipantUpdate(updates) if err != nil { - logger.GetLogger().Errorw("could not send update to participant", + logger.Errorw("could not send update to participant", "participant", p.ID(), "err", err) } diff --git a/pkg/rtc/room_test.go b/pkg/rtc/room_test.go index 9122caa15..dce876557 100644 --- a/pkg/rtc/room_test.go +++ b/pkg/rtc/room_test.go @@ -15,32 +15,6 @@ const ( numParticipants = 3 ) -func TestNewRoomForRequest(t *testing.T) { - req := &livekit.CreateRoomRequest{ - Name: "myroom", - EmptyTimeout: 120, - MaxParticipants: 50, - } - - rm := rtc.NewRoomForRequest(req, &rtc.WebRTCConfig{}) - assert.NotEmpty(t, rm.Sid) - assert.Equal(t, req.Name, rm.Name) - assert.Equal(t, req.EmptyTimeout, rm.EmptyTimeout) - assert.Equal(t, req.MaxParticipants, rm.MaxParticipants) -} - -func TestToRoomInfo(t *testing.T) { - rm := rtc.NewRoomForRequest(&livekit.CreateRoomRequest{ - Name: "myroom", - EmptyTimeout: 120, - MaxParticipants: 50, - }, &rtc.WebRTCConfig{}) - info := rm.ToRoomInfo(&livekit.Node{Ip: "0.0.0.0"}) - assert.Equal(t, rm.Sid, info.Sid) - assert.Equal(t, rm.Name, info.Name) - assert.Equal(t, "0.0.0.0", info.NodeIp) -} - func TestRoomJoin(t *testing.T) { t.Run("joining returns existing participant data", func(t *testing.T) { rm := newRoomWithParticipants(t, numParticipants) @@ -123,7 +97,10 @@ func TestNewTrack(t *testing.T) { } func newRoomWithParticipants(t *testing.T, num int) *rtc.Room { - rm := rtc.NewRoomForRequest(&livekit.CreateRoomRequest{}, &rtc.WebRTCConfig{}) + rm := rtc.NewRoom( + &livekit.Room{Name: "name"}, + rtc.WebRTCConfig{}, + ) for i := 0; i < num; i++ { participant := newMockParticipant("") err := rm.Join(participant) diff --git a/pkg/rtc/types/interfaces.go b/pkg/rtc/types/interfaces.go index 4d8b901f3..3e885edd0 100644 --- a/pkg/rtc/types/interfaces.go +++ b/pkg/rtc/types/interfaces.go @@ -20,12 +20,6 @@ type WebsocketClient interface { WriteControl(messageType int, data []byte, deadline time.Time) error } -//counterfeiter:generate . SignalConnection -type SignalConnection interface { - ReadRequest() (*livekit.SignalRequest, error) - WriteResponse(*livekit.SignalResponse) error -} - //counterfeiter:generate . PeerConnection type PeerConnection interface { OnICECandidate(f func(*webrtc.ICECandidate)) @@ -61,10 +55,11 @@ type Participant interface { AddTrack(clientId, name string, trackType livekit.TrackType) Answer(sdp webrtc.SessionDescription) (answer webrtc.SessionDescription, err error) HandleAnswer(sdp webrtc.SessionDescription) error + HandleClientNegotiation() AddICECandidate(candidate webrtc.ICECandidateInit) error AddSubscriber(op Participant) error RemoveSubscriber(peerId string) - SendJoinResponse(info *livekit.RoomInfo, otherParticipants []Participant) error + SendJoinResponse(info *livekit.Room, otherParticipants []Participant) error SendParticipantUpdate(participants []*livekit.ParticipantInfo) error SetTrackMuted(trackId string, muted bool) diff --git a/pkg/rtc/types/typesfakes/fake_participant.go b/pkg/rtc/types/typesfakes/fake_participant.go index 11dbc1cc9..6fbf159b4 100644 --- a/pkg/rtc/types/typesfakes/fake_participant.go +++ b/pkg/rtc/types/typesfakes/fake_participant.go @@ -81,6 +81,10 @@ type FakeParticipant struct { handleAnswerReturnsOnCall map[int]struct { result1 error } + HandleClientNegotiationStub func() + handleClientNegotiationMutex sync.RWMutex + handleClientNegotiationArgsForCall []struct { + } IDStub func() string iDMutex sync.RWMutex iDArgsForCall []struct { @@ -167,10 +171,10 @@ type FakeParticipant struct { removeSubscriberArgsForCall []struct { arg1 string } - SendJoinResponseStub func(*livekit.RoomInfo, []types.Participant) error + SendJoinResponseStub func(*livekit.Room, []types.Participant) error sendJoinResponseMutex sync.RWMutex sendJoinResponseArgsForCall []struct { - arg1 *livekit.RoomInfo + arg1 *livekit.Room arg2 []types.Participant } sendJoinResponseReturns struct { @@ -591,6 +595,30 @@ func (fake *FakeParticipant) HandleAnswerReturnsOnCall(i int, result1 error) { }{result1} } +func (fake *FakeParticipant) HandleClientNegotiation() { + fake.handleClientNegotiationMutex.Lock() + fake.handleClientNegotiationArgsForCall = append(fake.handleClientNegotiationArgsForCall, struct { + }{}) + stub := fake.HandleClientNegotiationStub + fake.recordInvocation("HandleClientNegotiation", []interface{}{}) + fake.handleClientNegotiationMutex.Unlock() + if stub != nil { + fake.HandleClientNegotiationStub() + } +} + +func (fake *FakeParticipant) HandleClientNegotiationCallCount() int { + fake.handleClientNegotiationMutex.RLock() + defer fake.handleClientNegotiationMutex.RUnlock() + return len(fake.handleClientNegotiationArgsForCall) +} + +func (fake *FakeParticipant) HandleClientNegotiationCalls(stub func()) { + fake.handleClientNegotiationMutex.Lock() + defer fake.handleClientNegotiationMutex.Unlock() + fake.HandleClientNegotiationStub = stub +} + func (fake *FakeParticipant) ID() string { fake.iDMutex.Lock() ret, specificReturn := fake.iDReturnsOnCall[len(fake.iDArgsForCall)] @@ -1081,7 +1109,7 @@ func (fake *FakeParticipant) RemoveSubscriberArgsForCall(i int) string { return argsForCall.arg1 } -func (fake *FakeParticipant) SendJoinResponse(arg1 *livekit.RoomInfo, arg2 []types.Participant) error { +func (fake *FakeParticipant) SendJoinResponse(arg1 *livekit.Room, arg2 []types.Participant) error { var arg2Copy []types.Participant if arg2 != nil { arg2Copy = make([]types.Participant, len(arg2)) @@ -1090,7 +1118,7 @@ func (fake *FakeParticipant) SendJoinResponse(arg1 *livekit.RoomInfo, arg2 []typ fake.sendJoinResponseMutex.Lock() ret, specificReturn := fake.sendJoinResponseReturnsOnCall[len(fake.sendJoinResponseArgsForCall)] fake.sendJoinResponseArgsForCall = append(fake.sendJoinResponseArgsForCall, struct { - arg1 *livekit.RoomInfo + arg1 *livekit.Room arg2 []types.Participant }{arg1, arg2Copy}) stub := fake.SendJoinResponseStub @@ -1112,13 +1140,13 @@ func (fake *FakeParticipant) SendJoinResponseCallCount() int { return len(fake.sendJoinResponseArgsForCall) } -func (fake *FakeParticipant) SendJoinResponseCalls(stub func(*livekit.RoomInfo, []types.Participant) error) { +func (fake *FakeParticipant) SendJoinResponseCalls(stub func(*livekit.Room, []types.Participant) error) { fake.sendJoinResponseMutex.Lock() defer fake.sendJoinResponseMutex.Unlock() fake.SendJoinResponseStub = stub } -func (fake *FakeParticipant) SendJoinResponseArgsForCall(i int) (*livekit.RoomInfo, []types.Participant) { +func (fake *FakeParticipant) SendJoinResponseArgsForCall(i int) (*livekit.Room, []types.Participant) { fake.sendJoinResponseMutex.RLock() defer fake.sendJoinResponseMutex.RUnlock() argsForCall := fake.sendJoinResponseArgsForCall[i] @@ -1394,6 +1422,8 @@ func (fake *FakeParticipant) Invocations() map[string][][]interface{} { defer fake.closeMutex.RUnlock() fake.handleAnswerMutex.RLock() defer fake.handleAnswerMutex.RUnlock() + fake.handleClientNegotiationMutex.RLock() + defer fake.handleClientNegotiationMutex.RUnlock() fake.iDMutex.RLock() defer fake.iDMutex.RUnlock() fake.isReadyMutex.RLock() diff --git a/pkg/rtc/types/typesfakes/fake_signal_connection.go b/pkg/rtc/types/typesfakes/fake_signal_connection.go deleted file mode 100644 index 6621f506e..000000000 --- a/pkg/rtc/types/typesfakes/fake_signal_connection.go +++ /dev/null @@ -1,182 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package typesfakes - -import ( - "sync" - - "github.com/livekit/livekit-server/pkg/rtc/types" - "github.com/livekit/livekit-server/proto/livekit" -) - -type FakeSignalConnection struct { - ReadRequestStub func() (*livekit.SignalRequest, error) - readRequestMutex sync.RWMutex - readRequestArgsForCall []struct { - } - readRequestReturns struct { - result1 *livekit.SignalRequest - result2 error - } - readRequestReturnsOnCall map[int]struct { - result1 *livekit.SignalRequest - result2 error - } - WriteResponseStub func(*livekit.SignalResponse) error - writeResponseMutex sync.RWMutex - writeResponseArgsForCall []struct { - arg1 *livekit.SignalResponse - } - writeResponseReturns struct { - result1 error - } - writeResponseReturnsOnCall map[int]struct { - result1 error - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *FakeSignalConnection) ReadRequest() (*livekit.SignalRequest, error) { - fake.readRequestMutex.Lock() - ret, specificReturn := fake.readRequestReturnsOnCall[len(fake.readRequestArgsForCall)] - fake.readRequestArgsForCall = append(fake.readRequestArgsForCall, struct { - }{}) - stub := fake.ReadRequestStub - fakeReturns := fake.readRequestReturns - fake.recordInvocation("ReadRequest", []interface{}{}) - fake.readRequestMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *FakeSignalConnection) ReadRequestCallCount() int { - fake.readRequestMutex.RLock() - defer fake.readRequestMutex.RUnlock() - return len(fake.readRequestArgsForCall) -} - -func (fake *FakeSignalConnection) ReadRequestCalls(stub func() (*livekit.SignalRequest, error)) { - fake.readRequestMutex.Lock() - defer fake.readRequestMutex.Unlock() - fake.ReadRequestStub = stub -} - -func (fake *FakeSignalConnection) ReadRequestReturns(result1 *livekit.SignalRequest, result2 error) { - fake.readRequestMutex.Lock() - defer fake.readRequestMutex.Unlock() - fake.ReadRequestStub = nil - fake.readRequestReturns = struct { - result1 *livekit.SignalRequest - result2 error - }{result1, result2} -} - -func (fake *FakeSignalConnection) ReadRequestReturnsOnCall(i int, result1 *livekit.SignalRequest, result2 error) { - fake.readRequestMutex.Lock() - defer fake.readRequestMutex.Unlock() - fake.ReadRequestStub = nil - if fake.readRequestReturnsOnCall == nil { - fake.readRequestReturnsOnCall = make(map[int]struct { - result1 *livekit.SignalRequest - result2 error - }) - } - fake.readRequestReturnsOnCall[i] = struct { - result1 *livekit.SignalRequest - result2 error - }{result1, result2} -} - -func (fake *FakeSignalConnection) WriteResponse(arg1 *livekit.SignalResponse) error { - fake.writeResponseMutex.Lock() - ret, specificReturn := fake.writeResponseReturnsOnCall[len(fake.writeResponseArgsForCall)] - fake.writeResponseArgsForCall = append(fake.writeResponseArgsForCall, struct { - arg1 *livekit.SignalResponse - }{arg1}) - stub := fake.WriteResponseStub - fakeReturns := fake.writeResponseReturns - fake.recordInvocation("WriteResponse", []interface{}{arg1}) - fake.writeResponseMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *FakeSignalConnection) WriteResponseCallCount() int { - fake.writeResponseMutex.RLock() - defer fake.writeResponseMutex.RUnlock() - return len(fake.writeResponseArgsForCall) -} - -func (fake *FakeSignalConnection) WriteResponseCalls(stub func(*livekit.SignalResponse) error) { - fake.writeResponseMutex.Lock() - defer fake.writeResponseMutex.Unlock() - fake.WriteResponseStub = stub -} - -func (fake *FakeSignalConnection) WriteResponseArgsForCall(i int) *livekit.SignalResponse { - fake.writeResponseMutex.RLock() - defer fake.writeResponseMutex.RUnlock() - argsForCall := fake.writeResponseArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *FakeSignalConnection) WriteResponseReturns(result1 error) { - fake.writeResponseMutex.Lock() - defer fake.writeResponseMutex.Unlock() - fake.WriteResponseStub = nil - fake.writeResponseReturns = struct { - result1 error - }{result1} -} - -func (fake *FakeSignalConnection) WriteResponseReturnsOnCall(i int, result1 error) { - fake.writeResponseMutex.Lock() - defer fake.writeResponseMutex.Unlock() - fake.WriteResponseStub = nil - if fake.writeResponseReturnsOnCall == nil { - fake.writeResponseReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.writeResponseReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *FakeSignalConnection) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.readRequestMutex.RLock() - defer fake.readRequestMutex.RUnlock() - fake.writeResponseMutex.RLock() - defer fake.writeResponseMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *FakeSignalConnection) 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 _ types.SignalConnection = new(FakeSignalConnection) diff --git a/pkg/rtc/utils.go b/pkg/rtc/utils.go index 3b2a8eb37..53d69b583 100644 --- a/pkg/rtc/utils.go +++ b/pkg/rtc/utils.go @@ -5,8 +5,11 @@ import ( "io" "strings" + "github.com/google/wire" "github.com/pion/webrtc/v3" + "go.uber.org/zap" + "github.com/livekit/livekit-server/pkg/config" "github.com/livekit/livekit-server/pkg/logger" "github.com/livekit/livekit-server/pkg/rtc/types" "github.com/livekit/livekit-server/proto/livekit" @@ -16,6 +19,15 @@ const ( trackIdSeparator = "|" ) +var RTCSet = wire.NewSet( + NewWebRTCConfig, + RTCConfigFromConfig, +) + +func RTCConfigFromConfig(conf *config.Config) *config.RTCConfig { + return &conf.RTC +} + func UnpackTrackId(packed string) (peerId string, trackId string) { parts := strings.Split(packed, trackIdSeparator) if len(parts) > 1 { @@ -118,6 +130,7 @@ func RecoverSilent() { func Recover() { if r := recover(); r != nil { - logger.GetLogger().Errorw("recovered panic", "err", r) + log := logger.Desugar().WithOptions(zap.AddCallerSkip(1)) + log.Error("recovered panic", zap.Any("error", r)) } } diff --git a/pkg/service/auth.go b/pkg/service/auth.go index 94ad20531..92ad945f0 100644 --- a/pkg/service/auth.go +++ b/pkg/service/auth.go @@ -21,7 +21,6 @@ const ( var ( ErrPermissionDenied = errors.New("permissions denied") - AuthRequired bool ) // authentication middleware @@ -91,9 +90,6 @@ func SetAuthorizationToken(r *http.Request, token string) { } func EnsureJoinPermission(ctx context.Context) (name string, err error) { - if !AuthRequired { - return "", nil - } claims := GetGrants(ctx) if claims == nil || claims.Video == nil { err = ErrPermissionDenied @@ -109,9 +105,6 @@ func EnsureJoinPermission(ctx context.Context) (name string, err error) { } func EnsureCreatePermission(ctx context.Context) error { - if !AuthRequired { - return nil - } claims := GetGrants(ctx) if claims == nil { return ErrPermissionDenied @@ -123,13 +116,25 @@ func EnsureCreatePermission(ctx context.Context) error { return ErrPermissionDenied } +func EnsureListPermission(ctx context.Context) error { + claims := GetGrants(ctx) + if claims == nil { + return ErrPermissionDenied + } + + if claims.Video.RoomList { + return nil + } + return ErrPermissionDenied +} + // wraps authentication errors around Twirp func twirpAuthError(err error) error { return twirp.NewError(twirp.Unauthenticated, err.Error()) } func handleError(w http.ResponseWriter, status int, msg string) { - logger.GetLogger().Debugw("error handling request", "error", msg, "status", status) + logger.Debugw("error handling request", "error", msg, "status", status) w.WriteHeader(status) w.Write([]byte(msg)) } diff --git a/pkg/service/errors.go b/pkg/service/errors.go new file mode 100644 index 000000000..eb5fdecf8 --- /dev/null +++ b/pkg/service/errors.go @@ -0,0 +1,7 @@ +package service + +import "errors" + +var ( + ErrRoomNotFound = errors.New("requested room does not exist") +) diff --git a/pkg/service/localroomstore.go b/pkg/service/localroomstore.go new file mode 100644 index 000000000..12b23b5a9 --- /dev/null +++ b/pkg/service/localroomstore.go @@ -0,0 +1,74 @@ +package service + +import ( + "sync" + + "github.com/thoas/go-funk" + + "github.com/livekit/livekit-server/proto/livekit" +) + +// encapsulates CRUD operations for room settings +type LocalRoomStore struct { + // map of roomId => room + rooms map[string]*livekit.Room + // map of roomName => roomId + roomIds map[string]string + lock sync.RWMutex + //CreateRoom(room *livekit.Room) error + //GetRoom(idOrName string) (*livekit.Room, error) + //DeleteRoom(idOrName string) error +} + +func NewLocalRoomStore() *LocalRoomStore { + return &LocalRoomStore{ + rooms: make(map[string]*livekit.Room), + roomIds: make(map[string]string), + lock: sync.RWMutex{}, + } +} + +func (p *LocalRoomStore) CreateRoom(room *livekit.Room) error { + p.lock.Lock() + p.rooms[room.Sid] = room + p.roomIds[room.Name] = room.Sid + p.lock.Unlock() + return nil +} + +func (p *LocalRoomStore) GetRoom(idOrName string) (*livekit.Room, error) { + p.lock.RLock() + defer p.lock.RUnlock() + // see if it's an id or name + if p.rooms[idOrName] == nil { + idOrName = p.roomIds[idOrName] + } + + room := p.rooms[idOrName] + if room == nil { + return nil, ErrRoomNotFound + } + return room, nil +} + +func (p *LocalRoomStore) ListRooms() ([]*livekit.Room, error) { + p.lock.RLock() + defer p.lock.RUnlock() + return funk.Values(p.rooms).([]*livekit.Room), nil +} + +func (p *LocalRoomStore) DeleteRoom(idOrName string) error { + room, err := p.GetRoom(idOrName) + if err == ErrRoomNotFound { + return nil + } else if err != nil { + return err + } + + p.lock.Lock() + defer p.lock.Unlock() + + delete(p.rooms, room.Sid) + delete(p.roomIds, room.Name) + return nil +} diff --git a/pkg/service/redisroomstore.go b/pkg/service/redisroomstore.go new file mode 100644 index 000000000..6d43c3366 --- /dev/null +++ b/pkg/service/redisroomstore.go @@ -0,0 +1 @@ +package service diff --git a/pkg/service/roomservice.go b/pkg/service/roomservice.go new file mode 100644 index 000000000..7b4ca5d49 --- /dev/null +++ b/pkg/service/roomservice.go @@ -0,0 +1,75 @@ +package service + +import ( + "context" + "time" + + "github.com/twitchtv/twirp" + + "github.com/livekit/livekit-server/pkg/utils" + "github.com/livekit/livekit-server/proto/livekit" +) + +// A rooms service that supports a single node +type RoomService struct { + roomProvider RoomStore +} + +func NewRoomService(rp RoomStore) (svc *RoomService, err error) { + svc = &RoomService{ + roomProvider: rp, + } + + return +} + +func (s *RoomService) CreateRoom(ctx context.Context, req *livekit.CreateRoomRequest) (rm *livekit.Room, err error) { + if err = EnsureCreatePermission(ctx); err != nil { + return nil, twirpAuthError(err) + } + + rm = &livekit.Room{ + Sid: utils.NewGuid(utils.RoomPrefix), + Name: req.Name, + EmptyTimeout: req.EmptyTimeout, + MaxParticipants: req.MaxParticipants, + CreationTime: time.Now().Unix(), + } + err = s.roomProvider.CreateRoom(rm) + if err != nil { + return + } + + return +} + +func (s *RoomService) ListRooms(ctx context.Context, req *livekit.ListRoomsRequest) (res *livekit.ListRoomsResponse, err error) { + err = EnsureListPermission(ctx) + if err != nil { + return nil, twirpAuthError(err) + } + + rooms, err := s.roomProvider.ListRooms() + if err != nil { + // TODO: translate error codes to twirp + return + } + + res = &livekit.ListRoomsResponse{ + Rooms: rooms, + } + return +} + +func (s *RoomService) DeleteRoom(ctx context.Context, req *livekit.DeleteRoomRequest) (res *livekit.DeleteRoomResponse, err error) { + if err = EnsureCreatePermission(ctx); err != nil { + return nil, twirpAuthError(err) + } + err = s.roomProvider.DeleteRoom(req.Room) + if err != nil { + err = twirp.WrapError(twirp.InternalError("could not delete room"), err) + return + } + res = &livekit.DeleteRoomResponse{} + return +} diff --git a/pkg/service/roomstore.go b/pkg/service/roomstore.go new file mode 100644 index 000000000..f5092fb72 --- /dev/null +++ b/pkg/service/roomstore.go @@ -0,0 +1,16 @@ +package service + +import ( + "github.com/livekit/livekit-server/proto/livekit" +) + +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate + +// encapsulates CRUD operations for room settings +//counterfeiter:generate . RoomStore +type RoomStore interface { + CreateRoom(room *livekit.Room) error + GetRoom(idOrName string) (*livekit.Room, error) + ListRooms() ([]*livekit.Room, error) + DeleteRoom(idOrName string) error +} diff --git a/pkg/service/rtc.go b/pkg/service/rtc.go deleted file mode 100644 index 07b7b4c7f..000000000 --- a/pkg/service/rtc.go +++ /dev/null @@ -1,221 +0,0 @@ -package service - -import ( - "encoding/json" - "io" - "net/http" - - "github.com/gorilla/websocket" - "github.com/pkg/errors" - - "github.com/livekit/livekit-server/pkg/config" - "github.com/livekit/livekit-server/pkg/logger" - "github.com/livekit/livekit-server/pkg/rtc" - "github.com/livekit/livekit-server/pkg/rtc/types" - "github.com/livekit/livekit-server/proto/livekit" -) - -type RTCService struct { - manager *rtc.RoomManager - upgrader websocket.Upgrader - isDev bool -} - -func NewRTCService(conf *config.Config, manager *rtc.RoomManager) *RTCService { - s := &RTCService{ - manager: manager, - upgrader: websocket.Upgrader{}, - isDev: conf.Development, - } - - // allow connections from any origin, since script may be hosted anywhere - // security is enforced by access tokens - s.upgrader.CheckOrigin = func(r *http.Request) bool { - return true - } - - return s -} - -func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) { - roomId := r.FormValue("room") - var pName string - if s.isDev { - r.FormValue("name") - } else { - claims := GetGrants(r.Context()) - // require a claim - if claims == nil || claims.Video == nil { - handleError(w, http.StatusUnauthorized, rtc.ErrPermissionDenied.Error()) - } - pName = claims.Identity - } - log := logger.GetLogger() - - onlyName, err := EnsureJoinPermission(r.Context()) - if err != nil { - handleError(w, http.StatusUnauthorized, err.Error()) - return - } - - room, err := s.manager.GetRoomWithConstraint(roomId, onlyName) - if err != nil { - // TODO: return errors/status correctly - handleError(w, http.StatusNotFound, err.Error()) - return - } - - // upgrade only once the basics are good to go - conn, err := s.upgrader.Upgrade(w, r, nil) - if err != nil { - logger.GetLogger().Warnw("could not upgrade to WS", - "err", err, - ) - handleError(w, http.StatusInternalServerError, err.Error()) - return - } - conn.SetCloseHandler(func(code int, text string) error { - log.Infow("websocket closed by remote") - return nil - }) - signalConn := rtc.NewWSSignalConnection(conn) - - pc, err := rtc.NewPeerConnection(s.manager.Config()) - if err != nil { - handleError(w, http.StatusInternalServerError, "could not create peerConnection: "+err.Error()) - return - } - participant, err := rtc.NewParticipant(pc, signalConn, pName, s.manager.Config().Receiver) - if err != nil { - handleError(w, http.StatusInternalServerError, "could not create participant: "+err.Error()) - return - } - - log.Infow("new client connected", - "roomId", roomId, - "name", pName, - "participant", participant.ID(), - ) - - if err := room.Join(participant); err != nil { - handleError(w, http.StatusInternalServerError, "could not join room: "+err.Error()) - return - } - - defer func() { - // remove peer from room upon disconnection - room.RemoveParticipant(participant.ID()) - participant.Close() - log.Infow("WS connection closed", "participant", participant.ID()) - }() - - // read connection and wait for commands - //ctx := context.Background() - for { - req, err := signalConn.ReadRequest() - if err == io.EOF { - // client disconnected from websocket - return - } else if err != nil { - return - } - - if req == nil { - continue - } - - switch msg := req.Message.(type) { - case *livekit.SignalRequest_Offer: - err = s.handleOffer(participant, msg.Offer) - if err != nil { - log.Errorw("could not handle join", "err", err, "participant", participant.ID()) - return - } - case *livekit.SignalRequest_AddTrack: - log.Debugw("publishing track", "participant", participant.ID(), - "track", msg.AddTrack.Cid) - participant.AddTrack(msg.AddTrack.Cid, msg.AddTrack.Name, msg.AddTrack.Type) - case *livekit.SignalRequest_Answer: - if participant.State() == livekit.ParticipantInfo_JOINING { - log.Errorw("cannot negotiate before peer offer", "participant", participant.ID()) - //conn.WriteJSON(jsonError(http.StatusNotAcceptable, "cannot negotiate before peer offer")) - return - } - sd := rtc.FromProtoSessionDescription(msg.Answer) - err = participant.HandleAnswer(sd) - if err != nil { - log.Errorw("could not handle answer", "participant", participant.ID(), "err", err) - //conn.WriteJSON( - // jsonError(http.StatusInternalServerError, "could not handle negotiate", err.Error())) - return - } - case *livekit.SignalRequest_Negotiate: - participant.HandleClientNegotiation() - case *livekit.SignalRequest_Trickle: - if participant.State() == livekit.ParticipantInfo_JOINING { - log.Errorw("cannot trickle before peer offer", "participant", participant.ID()) - //conn.WriteJSON(jsonError(http.StatusNotAcceptable, "cannot trickle before peer offer")) - return - } - - err = s.handleTrickle(participant, msg.Trickle) - if err != nil { - log.Errorw("could not handle trickle", "participant", participant.ID(), "err", err) - //conn.WriteJSON( - // jsonError(http.StatusInternalServerError, "could not handle trickle", err.Error())) - return - } - case *livekit.SignalRequest_Mute: - participant.SetTrackMuted(msg.Mute.Sid, msg.Mute.Muted) - } - } -} - -func (s *RTCService) handleOffer(participant types.Participant, offer *livekit.SessionDescription) error { - log := logger.GetLogger() - - _, err := participant.Answer(rtc.FromProtoSessionDescription(offer)) - if err != nil { - return errors.Wrap(err, "could not answer offer") - } - - log.Debugw("answered client offer") - return nil -} - -func (s *RTCService) handleTrickle(participant types.Participant, trickle *livekit.TrickleRequest) error { - candidateInit := rtc.FromProtoTrickle(trickle) - //logger.GetLogger().Debugw("adding peer candidate", "participant", participant.ID()) - if err := participant.AddICECandidate(candidateInit); err != nil { - return err - } - - return nil -} - -type errStruct struct { - StatusCode int `json:"statusCode"` - Error string `json:"error"` - Message string `json:"message,omitempty"` -} - -func writeJSONError(w http.ResponseWriter, code int, error ...string) { - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.Header().Set("X-Content-Type-Options", "nosniff") - w.WriteHeader(code) - - json.NewEncoder(w).Encode(jsonError(code, error...)) -} - -func jsonError(code int, error ...string) errStruct { - es := errStruct{ - StatusCode: code, - } - if len(error) > 0 { - es.Error = error[0] - } - if len(error) > 1 { - es.Message = error[1] - } - return es -} diff --git a/pkg/service/rtcrunner.go b/pkg/service/rtcrunner.go new file mode 100644 index 000000000..0bb09ad73 --- /dev/null +++ b/pkg/service/rtcrunner.go @@ -0,0 +1,166 @@ +package service + +import ( + "io" + "sync" + + "github.com/livekit/livekit-server/pkg/logger" + "github.com/livekit/livekit-server/pkg/routing" + "github.com/livekit/livekit-server/pkg/rtc" + "github.com/livekit/livekit-server/pkg/rtc/types" + "github.com/livekit/livekit-server/proto/livekit" +) + +// RTC runner manages the lifecycles of a WebRTC connection +// it creates a new goroutine for each participant it manages. + +type RTCRunner struct { + lock sync.RWMutex + roomProvider RoomStore + currentNode routing.LocalNode + router routing.Router + config *rtc.WebRTCConfig + rooms map[string]*rtc.Room +} + +func NewRTCRunner(rp RoomStore, router routing.Router, currentNode routing.LocalNode, config *rtc.WebRTCConfig) *RTCRunner { + return &RTCRunner{ + lock: sync.RWMutex{}, + roomProvider: rp, + config: config, + router: router, + currentNode: currentNode, + rooms: make(map[string]*rtc.Room), + } +} + +// starts WebRTC session when a new participant is connected +func (r *RTCRunner) StartSession(roomName, participantId, participantName string, requestSource routing.MessageSource, responseSink routing.MessageSink) { + room, err := r.getOrCreateRoom(roomName) + if err != nil { + logger.Errorw("could not create room", "error", err) + return + } + + logger.Debugw("starting RTC session", + "room", roomName, + "participant", participantName, + "num_participants", len(room.GetParticipants()), + ) + + pc, err := rtc.NewPeerConnection(r.config) + if err != nil { + logger.Errorw("could not create peerConnection", "error", err) + return + } + + participant, err := rtc.NewParticipant(participantId, participantName, pc, responseSink, r.config.Receiver) + if err != nil { + logger.Errorw("could not create participant", "error", err) + return + } + + // register participant to be on this server + if err = r.router.SetRTCNode(participantId, r.currentNode.Id); err != nil { + logger.Errorw("could not set RTC node", "error", err) + return + } + + // join room + if err := room.Join(participant); err != nil { + logger.Errorw("could not join room", "error", err) + return + } + + go r.sessionWorker(room, participant, requestSource) +} + +func (r *RTCRunner) getOrCreateRoom(roomName string) (*rtc.Room, error) { + r.lock.RLock() + room := r.rooms[roomName] + r.lock.RUnlock() + + if room != nil { + return room, nil + } + + // create new room, get details first + ri, err := r.roomProvider.GetRoom(roomName) + if err != nil { + return nil, err + } + + room = rtc.NewRoom(ri, *r.config) + r.lock.Lock() + r.rooms[roomName] = room + r.lock.Unlock() + + return room, nil +} + +func (r *RTCRunner) sessionWorker(room *rtc.Room, participant types.Participant, requestSource routing.MessageSource) { + defer func() { + logger.Debugw("RTC session finishing", + "participant", participant.Name(), + "room", room.Name, + ) + // remove peer from room when participant leaves room + room.RemoveParticipant(participant.ID()) + }() + defer rtc.Recover() + + for { + obj, err := requestSource.ReadMessage() + if err == io.EOF { + return + } + + req := obj.(*livekit.SignalRequest) + + switch msg := req.Message.(type) { + case *livekit.SignalRequest_Offer: + _, err := participant.Answer(rtc.FromProtoSessionDescription(msg.Offer)) + if err != nil { + logger.Errorw("could not handle join", "err", err, "participant", participant.ID()) + return + } + case *livekit.SignalRequest_AddTrack: + logger.Debugw("publishing track", "participant", participant.ID(), + "track", msg.AddTrack.Cid) + participant.AddTrack(msg.AddTrack.Cid, msg.AddTrack.Name, msg.AddTrack.Type) + case *livekit.SignalRequest_Answer: + if participant.State() == livekit.ParticipantInfo_JOINING { + logger.Errorw("cannot negotiate before peer offer", "participant", participant.ID()) + //conn.WriteJSON(jsonError(http.StatusNotAcceptable, "cannot negotiate before peer offer")) + return + } + sd := rtc.FromProtoSessionDescription(msg.Answer) + err = participant.HandleAnswer(sd) + if err != nil { + logger.Errorw("could not handle answer", "participant", participant.ID(), "err", err) + //conn.WriteJSON( + // jsonError(http.StatusInternalServerError, "could not handle negotiate", err.Error())) + return + } + case *livekit.SignalRequest_Negotiate: + participant.HandleClientNegotiation() + case *livekit.SignalRequest_Trickle: + if participant.State() == livekit.ParticipantInfo_JOINING { + logger.Errorw("cannot trickle before peer offer", "participant", participant.ID()) + //conn.WriteJSON(jsonError(http.StatusNotAcceptable, "cannot trickle before peer offer")) + return + } + + candidateInit := rtc.FromProtoTrickle(msg.Trickle) + //logger.Debugw("adding peer candidate", "participant", participant.ID()) + if err := participant.AddICECandidate(candidateInit); err != nil { + logger.Errorw("could not handle trickle", "participant", participant.ID(), "err", err) + //conn.WriteJSON( + // jsonError(http.StatusInternalServerError, "could not handle trickle", err.Error())) + return + } + case *livekit.SignalRequest_Mute: + participant.SetTrackMuted(msg.Mute.Sid, msg.Mute.Muted) + } + } +} diff --git a/pkg/service/rtcservice.go b/pkg/service/rtcservice.go new file mode 100644 index 000000000..61590b9d8 --- /dev/null +++ b/pkg/service/rtcservice.go @@ -0,0 +1,160 @@ +package service + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/gorilla/websocket" + + "github.com/livekit/livekit-server/pkg/config" + "github.com/livekit/livekit-server/pkg/logger" + "github.com/livekit/livekit-server/pkg/routing" + "github.com/livekit/livekit-server/pkg/rtc" + "github.com/livekit/livekit-server/pkg/utils" + "github.com/livekit/livekit-server/proto/livekit" +) + +type RTCService struct { + router routing.Router + roomStore RoomStore + upgrader websocket.Upgrader + currentNode routing.LocalNode + isDev bool +} + +func NewRTCService(conf *config.Config, roomStore RoomStore, router routing.Router, currentNode routing.LocalNode) *RTCService { + s := &RTCService{ + router: router, + roomStore: roomStore, + upgrader: websocket.Upgrader{}, + currentNode: currentNode, + isDev: conf.Development, + } + + // allow connections from any origin, since script may be hosted anywhere + // security is enforced by access tokens + s.upgrader.CheckOrigin = func(r *http.Request) bool { + return true + } + + return s +} + +func (s *RTCService) ServeHTTP(w http.ResponseWriter, r *http.Request) { + roomName := r.FormValue("room") + claims := GetGrants(r.Context()) + // require a claim + if claims == nil || claims.Video == nil { + handleError(w, http.StatusUnauthorized, rtc.ErrPermissionDenied.Error()) + } + pName := claims.Identity + + onlyName, err := EnsureJoinPermission(r.Context()) + if err != nil { + handleError(w, http.StatusUnauthorized, err.Error()) + return + } + if onlyName != "" { + roomName = onlyName + } + + rm, err := s.roomStore.GetRoom(roomName) + if err != nil { + handleError(w, http.StatusNotFound, err.Error()) + return + } + + // upgrade only once the basics are good to go + conn, err := s.upgrader.Upgrade(w, r, nil) + if err != nil { + logger.Warnw("could not upgrade to WS", + "err", err, + ) + handleError(w, http.StatusInternalServerError, err.Error()) + return + } + + sigConn := NewWSSignalConnection(conn) + + participantId := utils.NewGuid(utils.ParticipantPrefix) + err = s.router.StartParticipant(roomName, participantId, pName, s.currentNode.Id) + if err != nil { + handleError(w, http.StatusInternalServerError, "could not set signal node: "+err.Error()) + } + + logger.Infow("new client connected", + "room", rm.Sid, + "roomName", rm.Name, + "name", pName, + ) + + reqSink := s.router.GetRequestSink(participantId) + resSource := s.router.GetResponseSource(participantId) + + go func() { + for { + msg, err := resSource.ReadMessage() + if err == io.EOF { + return + } + res, ok := msg.(*livekit.SignalResponse) + if !ok { + logger.Errorw("unexpected message type", "type", fmt.Sprintf("%T", msg)) + continue + } + + if err = sigConn.WriteResponse(res); err != nil { + logger.Warnw("error writing to websocket", "error", err) + return + } + } + }() + + defer func() { + logger.Infow("WS connection closed", "participant", pName) + reqSink.Close() + }() + for { + req, err := sigConn.ReadRequest() + // normal closure + if err == io.EOF || websocket.IsCloseError(err, websocket.CloseAbnormalClosure, websocket.CloseGoingAway, websocket.CloseNormalClosure) { + return + } else if err != nil { + logger.Errorw("error reading from websocket", "error", err) + return + } + + if err = reqSink.WriteMessage(req); err != nil { + logger.Warnw("error writing to request sink", "error", err) + } + } +} + +type errStruct struct { + StatusCode int `json:"statusCode"` + Error string `json:"error"` + Message string `json:"message,omitempty"` +} + +func writeJSONError(w http.ResponseWriter, code int, error ...string) { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("X-Content-Type-Options", "nosniff") + w.WriteHeader(code) + + json.NewEncoder(w).Encode(jsonError(code, error...)) +} + +func jsonError(code int, error ...string) errStruct { + es := errStruct{ + StatusCode: code, + } + if len(error) > 0 { + es.Error = error[0] + } + if len(error) > 1 { + es.Message = error[1] + } + return es +} diff --git a/pkg/service/server.go b/pkg/service/server.go new file mode 100644 index 000000000..fec55d311 --- /dev/null +++ b/pkg/service/server.go @@ -0,0 +1,117 @@ +package service + +import ( + "context" + "errors" + "fmt" + "net" + "net/http" + "time" + + "github.com/urfave/negroni" + + "github.com/livekit/livekit-server/pkg/auth" + "github.com/livekit/livekit-server/pkg/config" + "github.com/livekit/livekit-server/pkg/logger" + "github.com/livekit/livekit-server/pkg/routing" + "github.com/livekit/livekit-server/proto/livekit" +) + +type LivekitServer struct { + config *config.Config + roomServer livekit.TwirpServer + rtcService *RTCService + httpServer *http.Server + router routing.Router + running bool + doneChan chan bool +} + +func NewLivekitServer(conf *config.Config, + roomService livekit.RoomService, + rtcService *RTCService, + keyProvider auth.KeyProvider, + router routing.Router, + runner *RTCRunner, +) (s *LivekitServer, err error) { + s = &LivekitServer{ + config: conf, + roomServer: livekit.NewRoomServiceServer(roomService), + rtcService: rtcService, + router: router, + } + + middlewares := []negroni.Handler{ + // always the first + negroni.NewRecovery(), + } + if keyProvider != nil { + middlewares = append(middlewares, NewAPIKeyAuthMiddleware(keyProvider)) + } + + mux := http.NewServeMux() + mux.Handle(s.roomServer.PathPrefix(), s.roomServer) + mux.Handle("/rtc", rtcService) + + s.httpServer = &http.Server{ + Addr: fmt.Sprintf(":%d", conf.Port), + Handler: configureMiddlewares(mux, middlewares...), + } + + // hook up router to the RTC Runner + router.OnNewParticipant(runner.StartSession) + + return +} + +func (s *LivekitServer) IsRunning() bool { + return s.running +} + +func (s *LivekitServer) Start() error { + if s.running { + return errors.New("already running") + } + + if err := s.router.Start(); err != nil { + return err + } + + s.doneChan = make(chan bool, 1) + + // ensure we could listen + ln, err := net.Listen("tcp", s.httpServer.Addr) + if err != nil { + return err + } + + go func() { + logger.Infow("starting LiveKit server", "address", s.httpServer.Addr) + s.httpServer.Serve(ln) + }() + + s.running = true + + <-s.doneChan + + // wait for shutdown + ctx, _ := context.WithTimeout(context.Background(), time.Second*5) + s.httpServer.Shutdown(ctx) + + return nil +} + +func (s *LivekitServer) Stop() { + s.running = false + s.router.Stop() + s.doneChan <- true +} + +func configureMiddlewares(handler http.Handler, middlewares ...negroni.Handler) *negroni.Negroni { + n := negroni.New() + for _, m := range middlewares { + n.Use(m) + } + n.UseHandler(handler) + return n +} diff --git a/pkg/service/service.go b/pkg/service/service.go deleted file mode 100644 index e97a34820..000000000 --- a/pkg/service/service.go +++ /dev/null @@ -1,147 +0,0 @@ -package service - -import ( - "context" - "errors" - "fmt" - "net" - "net/http" - "sync" - "time" - - "github.com/google/wire" - "github.com/urfave/negroni" - - "github.com/livekit/livekit-server/pkg/auth" - "github.com/livekit/livekit-server/pkg/config" - "github.com/livekit/livekit-server/pkg/logger" - "github.com/livekit/livekit-server/pkg/node" - "github.com/livekit/livekit-server/pkg/rtc" - "github.com/livekit/livekit-server/proto/livekit" -) - -var ServiceSet = wire.NewSet( - NewRoomService, - NewRTCService, - NewLivekitServer, - newRoomManagerWithNode, -) - -func NewRoomService(conf *config.Config, manager *rtc.RoomManager, localNode *node.Node) (livekit.RoomService, error) { - if conf.MultiNode { - return nil, fmt.Errorf("multinode is not supported") - } else { - return NewSimpleRoomService(manager, localNode) - } -} - -type LivekitServer struct { - config *config.Config - roomServer livekit.TwirpServer - rtcService *RTCService - roomHttp *http.Server - rtcHttp *http.Server - running bool - doneChan chan bool -} - -func newRoomManagerWithNode(conf *config.Config, localNode *node.Node) (*rtc.RoomManager, error) { - return rtc.NewRoomManager(conf.RTC, localNode.Ip) -} - -func NewLivekitServer(conf *config.Config, - roomService livekit.RoomService, - rtcService *RTCService, - keyProvider auth.KeyProvider) (s *LivekitServer, err error) { - s = &LivekitServer{ - config: conf, - roomServer: livekit.NewRoomServiceServer(roomService), - rtcService: rtcService, - } - - middlewares := make([]negroni.Handler, 0) - if keyProvider != nil { - middlewares = append(middlewares, NewAPIKeyAuthMiddleware(keyProvider)) - } - - s.roomHttp = &http.Server{ - Addr: fmt.Sprintf(":%d", conf.APIPort), - Handler: configureMiddlewares(s.roomServer, middlewares...), - } - - rtcHandler := http.NewServeMux() - rtcHandler.Handle("/rtc", rtcService) - s.rtcHttp = &http.Server{ - Addr: fmt.Sprintf(":%d", conf.RTCPort), - Handler: configureMiddlewares(rtcHandler, middlewares...), - } - - return -} - -func (s *LivekitServer) IsRunning() bool { - return s.running -} - -func (s *LivekitServer) Start() error { - if s.running { - return errors.New("already running") - } - s.doneChan = make(chan bool, 1) - - // ensure we could listen - roomLn, err := net.Listen("tcp", s.roomHttp.Addr) - if err != nil { - return err - } - - rtcAddr := fmt.Sprintf(":%d", s.config.RTCPort) - rtcLn, err := net.Listen("tcp", rtcAddr) - if err != nil { - return err - } - - go func() { - logger.GetLogger().Infow("starting Room service", "address", s.roomHttp.Addr) - s.roomHttp.Serve(roomLn) - }() - go func() { - logger.GetLogger().Infow("starting RTC service", "address", rtcAddr) - s.rtcHttp.Serve(rtcLn) - }() - - s.running = true - - <-s.doneChan - - // wait for shutdown - ctx, _ := context.WithTimeout(context.Background(), time.Second*5) - wg := sync.WaitGroup{} - wg.Add(2) - go func() { - defer wg.Done() - s.rtcHttp.Shutdown(ctx) - }() - go func() { - defer wg.Done() - s.roomHttp.Shutdown(ctx) - }() - wg.Wait() - - return nil -} - -func (s *LivekitServer) Stop() { - s.running = false - s.doneChan <- true -} - -func configureMiddlewares(handler http.Handler, middlewares ...negroni.Handler) *negroni.Negroni { - n := negroni.New() - n.Use(negroni.NewRecovery()) - for _, m := range middlewares { - n.Use(m) - } - n.UseHandler(handler) - return n -} diff --git a/pkg/service/servicefakes/fake_room_store.go b/pkg/service/servicefakes/fake_room_store.go new file mode 100644 index 000000000..8cd943b13 --- /dev/null +++ b/pkg/service/servicefakes/fake_room_store.go @@ -0,0 +1,335 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package servicefakes + +import ( + "sync" + + "github.com/livekit/livekit-server/pkg/service" + "github.com/livekit/livekit-server/proto/livekit" +) + +type FakeRoomStore struct { + CreateRoomStub func(*livekit.Room) error + createRoomMutex sync.RWMutex + createRoomArgsForCall []struct { + arg1 *livekit.Room + } + createRoomReturns struct { + result1 error + } + createRoomReturnsOnCall map[int]struct { + result1 error + } + DeleteRoomStub func(string) error + deleteRoomMutex sync.RWMutex + deleteRoomArgsForCall []struct { + arg1 string + } + deleteRoomReturns struct { + result1 error + } + deleteRoomReturnsOnCall map[int]struct { + result1 error + } + GetRoomStub func(string) (*livekit.Room, error) + getRoomMutex sync.RWMutex + getRoomArgsForCall []struct { + arg1 string + } + getRoomReturns struct { + result1 *livekit.Room + result2 error + } + getRoomReturnsOnCall map[int]struct { + result1 *livekit.Room + result2 error + } + ListRoomsStub func() ([]*livekit.Room, error) + listRoomsMutex sync.RWMutex + listRoomsArgsForCall []struct { + } + listRoomsReturns struct { + result1 []*livekit.Room + result2 error + } + listRoomsReturnsOnCall map[int]struct { + result1 []*livekit.Room + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeRoomStore) CreateRoom(arg1 *livekit.Room) error { + fake.createRoomMutex.Lock() + ret, specificReturn := fake.createRoomReturnsOnCall[len(fake.createRoomArgsForCall)] + fake.createRoomArgsForCall = append(fake.createRoomArgsForCall, struct { + arg1 *livekit.Room + }{arg1}) + stub := fake.CreateRoomStub + fakeReturns := fake.createRoomReturns + fake.recordInvocation("CreateRoom", []interface{}{arg1}) + fake.createRoomMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeRoomStore) CreateRoomCallCount() int { + fake.createRoomMutex.RLock() + defer fake.createRoomMutex.RUnlock() + return len(fake.createRoomArgsForCall) +} + +func (fake *FakeRoomStore) CreateRoomCalls(stub func(*livekit.Room) error) { + fake.createRoomMutex.Lock() + defer fake.createRoomMutex.Unlock() + fake.CreateRoomStub = stub +} + +func (fake *FakeRoomStore) CreateRoomArgsForCall(i int) *livekit.Room { + fake.createRoomMutex.RLock() + defer fake.createRoomMutex.RUnlock() + argsForCall := fake.createRoomArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeRoomStore) CreateRoomReturns(result1 error) { + fake.createRoomMutex.Lock() + defer fake.createRoomMutex.Unlock() + fake.CreateRoomStub = nil + fake.createRoomReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeRoomStore) CreateRoomReturnsOnCall(i int, result1 error) { + fake.createRoomMutex.Lock() + defer fake.createRoomMutex.Unlock() + fake.CreateRoomStub = nil + if fake.createRoomReturnsOnCall == nil { + fake.createRoomReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.createRoomReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeRoomStore) DeleteRoom(arg1 string) error { + fake.deleteRoomMutex.Lock() + ret, specificReturn := fake.deleteRoomReturnsOnCall[len(fake.deleteRoomArgsForCall)] + fake.deleteRoomArgsForCall = append(fake.deleteRoomArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.DeleteRoomStub + fakeReturns := fake.deleteRoomReturns + fake.recordInvocation("DeleteRoom", []interface{}{arg1}) + fake.deleteRoomMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeRoomStore) DeleteRoomCallCount() int { + fake.deleteRoomMutex.RLock() + defer fake.deleteRoomMutex.RUnlock() + return len(fake.deleteRoomArgsForCall) +} + +func (fake *FakeRoomStore) DeleteRoomCalls(stub func(string) error) { + fake.deleteRoomMutex.Lock() + defer fake.deleteRoomMutex.Unlock() + fake.DeleteRoomStub = stub +} + +func (fake *FakeRoomStore) DeleteRoomArgsForCall(i int) string { + fake.deleteRoomMutex.RLock() + defer fake.deleteRoomMutex.RUnlock() + argsForCall := fake.deleteRoomArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeRoomStore) DeleteRoomReturns(result1 error) { + fake.deleteRoomMutex.Lock() + defer fake.deleteRoomMutex.Unlock() + fake.DeleteRoomStub = nil + fake.deleteRoomReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeRoomStore) DeleteRoomReturnsOnCall(i int, result1 error) { + fake.deleteRoomMutex.Lock() + defer fake.deleteRoomMutex.Unlock() + fake.DeleteRoomStub = nil + if fake.deleteRoomReturnsOnCall == nil { + fake.deleteRoomReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.deleteRoomReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeRoomStore) GetRoom(arg1 string) (*livekit.Room, error) { + fake.getRoomMutex.Lock() + ret, specificReturn := fake.getRoomReturnsOnCall[len(fake.getRoomArgsForCall)] + fake.getRoomArgsForCall = append(fake.getRoomArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.GetRoomStub + fakeReturns := fake.getRoomReturns + fake.recordInvocation("GetRoom", []interface{}{arg1}) + fake.getRoomMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeRoomStore) GetRoomCallCount() int { + fake.getRoomMutex.RLock() + defer fake.getRoomMutex.RUnlock() + return len(fake.getRoomArgsForCall) +} + +func (fake *FakeRoomStore) GetRoomCalls(stub func(string) (*livekit.Room, error)) { + fake.getRoomMutex.Lock() + defer fake.getRoomMutex.Unlock() + fake.GetRoomStub = stub +} + +func (fake *FakeRoomStore) GetRoomArgsForCall(i int) string { + fake.getRoomMutex.RLock() + defer fake.getRoomMutex.RUnlock() + argsForCall := fake.getRoomArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeRoomStore) GetRoomReturns(result1 *livekit.Room, result2 error) { + fake.getRoomMutex.Lock() + defer fake.getRoomMutex.Unlock() + fake.GetRoomStub = nil + fake.getRoomReturns = struct { + result1 *livekit.Room + result2 error + }{result1, result2} +} + +func (fake *FakeRoomStore) GetRoomReturnsOnCall(i int, result1 *livekit.Room, result2 error) { + fake.getRoomMutex.Lock() + defer fake.getRoomMutex.Unlock() + fake.GetRoomStub = nil + if fake.getRoomReturnsOnCall == nil { + fake.getRoomReturnsOnCall = make(map[int]struct { + result1 *livekit.Room + result2 error + }) + } + fake.getRoomReturnsOnCall[i] = struct { + result1 *livekit.Room + result2 error + }{result1, result2} +} + +func (fake *FakeRoomStore) ListRooms() ([]*livekit.Room, error) { + fake.listRoomsMutex.Lock() + ret, specificReturn := fake.listRoomsReturnsOnCall[len(fake.listRoomsArgsForCall)] + fake.listRoomsArgsForCall = append(fake.listRoomsArgsForCall, struct { + }{}) + stub := fake.ListRoomsStub + fakeReturns := fake.listRoomsReturns + fake.recordInvocation("ListRooms", []interface{}{}) + fake.listRoomsMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeRoomStore) ListRoomsCallCount() int { + fake.listRoomsMutex.RLock() + defer fake.listRoomsMutex.RUnlock() + return len(fake.listRoomsArgsForCall) +} + +func (fake *FakeRoomStore) ListRoomsCalls(stub func() ([]*livekit.Room, error)) { + fake.listRoomsMutex.Lock() + defer fake.listRoomsMutex.Unlock() + fake.ListRoomsStub = stub +} + +func (fake *FakeRoomStore) ListRoomsReturns(result1 []*livekit.Room, result2 error) { + fake.listRoomsMutex.Lock() + defer fake.listRoomsMutex.Unlock() + fake.ListRoomsStub = nil + fake.listRoomsReturns = struct { + result1 []*livekit.Room + result2 error + }{result1, result2} +} + +func (fake *FakeRoomStore) ListRoomsReturnsOnCall(i int, result1 []*livekit.Room, result2 error) { + fake.listRoomsMutex.Lock() + defer fake.listRoomsMutex.Unlock() + fake.ListRoomsStub = nil + if fake.listRoomsReturnsOnCall == nil { + fake.listRoomsReturnsOnCall = make(map[int]struct { + result1 []*livekit.Room + result2 error + }) + } + fake.listRoomsReturnsOnCall[i] = struct { + result1 []*livekit.Room + result2 error + }{result1, result2} +} + +func (fake *FakeRoomStore) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.createRoomMutex.RLock() + defer fake.createRoomMutex.RUnlock() + fake.deleteRoomMutex.RLock() + defer fake.deleteRoomMutex.RUnlock() + fake.getRoomMutex.RLock() + defer fake.getRoomMutex.RUnlock() + fake.listRoomsMutex.RLock() + defer fake.listRoomsMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeRoomStore) 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 _ service.RoomStore = new(FakeRoomStore) diff --git a/pkg/service/simpleroom.go b/pkg/service/simpleroom.go deleted file mode 100644 index 36941e6e5..000000000 --- a/pkg/service/simpleroom.go +++ /dev/null @@ -1,69 +0,0 @@ -package service - -import ( - "context" - - "github.com/twitchtv/twirp" - - "github.com/livekit/livekit-server/pkg/node" - "github.com/livekit/livekit-server/pkg/rtc" - "github.com/livekit/livekit-server/proto/livekit" -) - -// A rooms service that supports a single node -type SimpleRoomService struct { - localNode *node.Node - - manager *rtc.RoomManager -} - -func NewSimpleRoomService(manager *rtc.RoomManager, localNode *node.Node) (svc *SimpleRoomService, err error) { - svc = &SimpleRoomService{ - localNode: localNode, - manager: manager, - } - - return -} - -func (s *SimpleRoomService) CreateRoom(ctx context.Context, req *livekit.CreateRoomRequest) (res *livekit.RoomInfo, err error) { - if err = EnsureCreatePermission(ctx); err != nil { - return nil, twirpAuthError(err) - } - room, err := s.manager.CreateRoom(req) - if err != nil { - return - } - - res = room.ToRoomInfo(&s.localNode.Node) - return -} - -func (s *SimpleRoomService) GetRoom(ctx context.Context, req *livekit.GetRoomRequest) (res *livekit.RoomInfo, err error) { - onlyName, err := EnsureJoinPermission(ctx) - if err != nil { - return nil, twirpAuthError(err) - } - - room, err := s.manager.GetRoomWithConstraint(req.Room, onlyName) - if err != nil { - // TODO: translate error codes to twirp - return - } - - res = room.ToRoomInfo(&s.localNode.Node) - return -} - -func (s *SimpleRoomService) DeleteRoom(ctx context.Context, req *livekit.DeleteRoomRequest) (res *livekit.DeleteRoomResponse, err error) { - if err = EnsureCreatePermission(ctx); err != nil { - return nil, twirpAuthError(err) - } - err = s.manager.DeleteRoom(req.Room) - if err != nil { - err = twirp.WrapError(twirp.InternalError("could not delete room"), err) - return - } - res = &livekit.DeleteRoomResponse{} - return -} diff --git a/pkg/service/utils.go b/pkg/service/utils.go new file mode 100644 index 000000000..34348ec81 --- /dev/null +++ b/pkg/service/utils.go @@ -0,0 +1,23 @@ +package service + +import ( + "github.com/google/wire" + + "github.com/livekit/livekit-server/pkg/routing" + "github.com/livekit/livekit-server/pkg/rtc" + "github.com/livekit/livekit-server/proto/livekit" +) + +var ServiceSet = wire.NewSet( + NewRoomService, + NewRTCService, + NewLivekitServer, + NewRTCRunner, + wire.Bind(new(livekit.RoomService), new(*RoomService)), + externalIpFromNode, +) + +// helper to construct RTCConfig +func externalIpFromNode(currentNode routing.LocalNode) rtc.ExternalIP { + return rtc.ExternalIP(currentNode.Ip) +} diff --git a/pkg/service/wire.go b/pkg/service/wire.go index c219275e1..a899e037e 100644 --- a/pkg/service/wire.go +++ b/pkg/service/wire.go @@ -7,13 +7,15 @@ import ( "github.com/livekit/livekit-server/pkg/auth" "github.com/livekit/livekit-server/pkg/config" - "github.com/livekit/livekit-server/pkg/node" + "github.com/livekit/livekit-server/pkg/routing" + "github.com/livekit/livekit-server/pkg/rtc" ) -func InitializeServer(conf *config.Config, keyProvider auth.KeyProvider) (*LivekitServer, error) { +func InitializeServer(conf *config.Config, keyProvider auth.KeyProvider, + roomStore RoomStore, router routing.Router, currentNode routing.LocalNode) (*LivekitServer, error) { wire.Build( - node.NodeSet, ServiceSet, + rtc.RTCSet, ) return &LivekitServer{}, nil } diff --git a/pkg/service/wire_gen.go b/pkg/service/wire_gen.go index f9761d13b..575fd093c 100644 --- a/pkg/service/wire_gen.go +++ b/pkg/service/wire_gen.go @@ -8,26 +8,26 @@ package service import ( "github.com/livekit/livekit-server/pkg/auth" "github.com/livekit/livekit-server/pkg/config" - "github.com/livekit/livekit-server/pkg/node" + "github.com/livekit/livekit-server/pkg/routing" + "github.com/livekit/livekit-server/pkg/rtc" ) // Injectors from wire.go: -func InitializeServer(conf *config.Config, keyProvider auth.KeyProvider) (*LivekitServer, error) { - nodeNode, err := node.NewLocalNode(conf) +func InitializeServer(conf *config.Config, keyProvider auth.KeyProvider, roomStore RoomStore, router routing.Router, currentNode routing.LocalNode) (*LivekitServer, error) { + roomService, err := NewRoomService(roomStore) if err != nil { return nil, err } - roomManager, err := newRoomManagerWithNode(conf, nodeNode) + rtcService := NewRTCService(conf, roomStore, router, currentNode) + rtcConfig := rtc.RTCConfigFromConfig(conf) + externalIP := externalIpFromNode(currentNode) + webRTCConfig, err := rtc.NewWebRTCConfig(rtcConfig, externalIP) if err != nil { return nil, err } - roomService, err := NewRoomService(conf, roomManager, nodeNode) - if err != nil { - return nil, err - } - rtcService := NewRTCService(conf, roomManager) - livekitServer, err := NewLivekitServer(conf, roomService, rtcService, keyProvider) + rtcRunner := NewRTCRunner(roomStore, router, currentNode, webRTCConfig) + livekitServer, err := NewLivekitServer(conf, roomService, rtcService, keyProvider, router, rtcRunner) if err != nil { return nil, err } diff --git a/pkg/rtc/wsprotocol.go b/pkg/service/wsprotocol.go similarity index 95% rename from pkg/rtc/wsprotocol.go rename to pkg/service/wsprotocol.go index 90aded6c6..57bc0e921 100644 --- a/pkg/rtc/wsprotocol.go +++ b/pkg/service/wsprotocol.go @@ -1,4 +1,4 @@ -package rtc +package service import ( "sync" @@ -54,7 +54,7 @@ func (c *WSSignalConnection) ReadRequest() (*livekit.SignalRequest, error) { err := protojson.Unmarshal(payload, msg) return msg, err default: - logger.GetLogger().Debugw("unsupported message", "message", messageType) + logger.Debugw("unsupported message", "message", messageType) return nil, nil } } diff --git a/pkg/sfu/README.md b/pkg/sfu/README.md index 27a6f529c..4c21f06a1 100644 --- a/pkg/sfu/README.md +++ b/pkg/sfu/README.md @@ -2,4 +2,4 @@ This package is largely files from the wonderful ion-sfu project. https://github.com/pion/ion-sfu -It's duplicated here since we needed to access a private method in various helper classes \ No newline at end of file +It's duplicated here with modifications to reference only classes that we need \ No newline at end of file diff --git a/pkg/sfu/errors.go b/pkg/sfu/errors.go index b5387103b..bbc8a6124 100644 --- a/pkg/sfu/errors.go +++ b/pkg/sfu/errors.go @@ -6,7 +6,7 @@ var ( errPeerConnectionInitFailed = errors.New("pc init failed") errPtNotSupported = errors.New("payload type not supported") errCreatingDataChannel = errors.New("failed to create data channel") - // router errors + // routing errors errNoReceiverFound = errors.New("no receiver found") // Helpers errors errShortPacket = errors.New("packet is not large enough") diff --git a/proto/livekit/model.pb.go b/proto/livekit/model.pb.go index 18177bbd2..6ad1e2a3a 100644 --- a/proto/livekit/model.pb.go +++ b/proto/livekit/model.pb.go @@ -127,7 +127,7 @@ func (x ParticipantInfo_State) Number() protoreflect.EnumNumber { // Deprecated: Use ParticipantInfo_State.Descriptor instead. func (ParticipantInfo_State) EnumDescriptor() ([]byte, []int) { - return file_model_proto_rawDescGZIP(), []int{4, 0} + return file_model_proto_rawDescGZIP(), []int{3, 0} } type Node struct { @@ -137,7 +137,7 @@ type Node struct { Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Ip string `protobuf:"bytes,2,opt,name=ip,proto3" json:"ip,omitempty"` - RtcPort uint32 `protobuf:"varint,3,opt,name=rtc_port,json=rtcPort,proto3" json:"rtc_port,omitempty"` + NumCpus uint32 `protobuf:"varint,3,opt,name=num_cpus,json=numCpus,proto3" json:"num_cpus,omitempty"` Stats *NodeStats `protobuf:"bytes,4,opt,name=stats,proto3" json:"stats,omitempty"` } @@ -187,9 +187,9 @@ func (x *Node) GetIp() string { return "" } -func (x *Node) GetRtcPort() uint32 { +func (x *Node) GetNumCpus() uint32 { if x != nil { - return x.RtcPort + return x.NumCpus } return 0 } @@ -336,77 +336,6 @@ func (x *Room) GetCreationTime() int64 { return 0 } -type RoomInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Sid string `protobuf:"bytes,1,opt,name=sid,proto3" json:"sid,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - NodeIp string `protobuf:"bytes,3,opt,name=node_ip,json=nodeIp,proto3" json:"node_ip,omitempty"` - CreationTime int64 `protobuf:"varint,4,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` -} - -func (x *RoomInfo) Reset() { - *x = RoomInfo{} - if protoimpl.UnsafeEnabled { - mi := &file_model_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RoomInfo) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RoomInfo) ProtoMessage() {} - -func (x *RoomInfo) ProtoReflect() protoreflect.Message { - mi := &file_model_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RoomInfo.ProtoReflect.Descriptor instead. -func (*RoomInfo) Descriptor() ([]byte, []int) { - return file_model_proto_rawDescGZIP(), []int{3} -} - -func (x *RoomInfo) GetSid() string { - if x != nil { - return x.Sid - } - return "" -} - -func (x *RoomInfo) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *RoomInfo) GetNodeIp() string { - if x != nil { - return x.NodeIp - } - return "" -} - -func (x *RoomInfo) GetCreationTime() int64 { - if x != nil { - return x.CreationTime - } - return 0 -} - type ParticipantInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -421,7 +350,7 @@ type ParticipantInfo struct { func (x *ParticipantInfo) Reset() { *x = ParticipantInfo{} if protoimpl.UnsafeEnabled { - mi := &file_model_proto_msgTypes[4] + mi := &file_model_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -434,7 +363,7 @@ func (x *ParticipantInfo) String() string { func (*ParticipantInfo) ProtoMessage() {} func (x *ParticipantInfo) ProtoReflect() protoreflect.Message { - mi := &file_model_proto_msgTypes[4] + mi := &file_model_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -447,7 +376,7 @@ func (x *ParticipantInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use ParticipantInfo.ProtoReflect.Descriptor instead. func (*ParticipantInfo) Descriptor() ([]byte, []int) { - return file_model_proto_rawDescGZIP(), []int{4} + return file_model_proto_rawDescGZIP(), []int{3} } func (x *ParticipantInfo) GetSid() string { @@ -493,7 +422,7 @@ type TrackInfo struct { func (x *TrackInfo) Reset() { *x = TrackInfo{} if protoimpl.UnsafeEnabled { - mi := &file_model_proto_msgTypes[5] + mi := &file_model_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -506,7 +435,7 @@ func (x *TrackInfo) String() string { func (*TrackInfo) ProtoMessage() {} func (x *TrackInfo) ProtoReflect() protoreflect.Message { - mi := &file_model_proto_msgTypes[5] + mi := &file_model_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -519,7 +448,7 @@ func (x *TrackInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use TrackInfo.ProtoReflect.Descriptor instead. func (*TrackInfo) Descriptor() ([]byte, []int) { - return file_model_proto_rawDescGZIP(), []int{5} + return file_model_proto_rawDescGZIP(), []int{4} } func (x *TrackInfo) GetSid() string { @@ -564,7 +493,7 @@ type DataMessage struct { func (x *DataMessage) Reset() { *x = DataMessage{} if protoimpl.UnsafeEnabled { - mi := &file_model_proto_msgTypes[6] + mi := &file_model_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -577,7 +506,7 @@ func (x *DataMessage) String() string { func (*DataMessage) ProtoMessage() {} func (x *DataMessage) ProtoReflect() protoreflect.Message { - mi := &file_model_proto_msgTypes[6] + mi := &file_model_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -590,7 +519,7 @@ func (x *DataMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage.ProtoReflect.Descriptor instead. func (*DataMessage) Descriptor() ([]byte, []int) { - return file_model_proto_rawDescGZIP(), []int{6} + return file_model_proto_rawDescGZIP(), []int{5} } func (m *DataMessage) GetValue() isDataMessage_Value { @@ -637,8 +566,8 @@ var file_model_proto_rawDesc = []byte{ 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x22, 0x6b, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x19, - 0x0a, 0x08, 0x72, 0x74, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x07, 0x72, 0x74, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x28, 0x0a, 0x05, 0x73, 0x74, 0x61, + 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x43, 0x70, 0x75, 0x73, 0x12, 0x28, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x22, 0x49, 0x0a, 0x09, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, @@ -656,13 +585,6 @@ var file_model_proto_rawDesc = []byte{ 0x78, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, - 0x6d, 0x65, 0x22, 0x6e, 0x0a, 0x08, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, - 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x70, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x70, 0x12, 0x23, 0x0a, - 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xd9, 0x01, 0x0a, 0x0f, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, @@ -710,22 +632,21 @@ func file_model_proto_rawDescGZIP() []byte { } var file_model_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_model_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_model_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_model_proto_goTypes = []interface{}{ (TrackType)(0), // 0: livekit.TrackType (ParticipantInfo_State)(0), // 1: livekit.ParticipantInfo.State (*Node)(nil), // 2: livekit.Node (*NodeStats)(nil), // 3: livekit.NodeStats (*Room)(nil), // 4: livekit.Room - (*RoomInfo)(nil), // 5: livekit.RoomInfo - (*ParticipantInfo)(nil), // 6: livekit.ParticipantInfo - (*TrackInfo)(nil), // 7: livekit.TrackInfo - (*DataMessage)(nil), // 8: livekit.DataMessage + (*ParticipantInfo)(nil), // 5: livekit.ParticipantInfo + (*TrackInfo)(nil), // 6: livekit.TrackInfo + (*DataMessage)(nil), // 7: livekit.DataMessage } var file_model_proto_depIdxs = []int32{ 3, // 0: livekit.Node.stats:type_name -> livekit.NodeStats 1, // 1: livekit.ParticipantInfo.state:type_name -> livekit.ParticipantInfo.State - 7, // 2: livekit.ParticipantInfo.tracks:type_name -> livekit.TrackInfo + 6, // 2: livekit.ParticipantInfo.tracks:type_name -> livekit.TrackInfo 0, // 3: livekit.TrackInfo.type:type_name -> livekit.TrackType 4, // [4:4] is the sub-list for method output_type 4, // [4:4] is the sub-list for method input_type @@ -777,18 +698,6 @@ func file_model_proto_init() { } } file_model_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RoomInfo); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_model_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ParticipantInfo); i { case 0: return &v.state @@ -800,7 +709,7 @@ func file_model_proto_init() { return nil } } - file_model_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_model_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TrackInfo); i { case 0: return &v.state @@ -812,7 +721,7 @@ func file_model_proto_init() { return nil } } - file_model_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_model_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DataMessage); i { case 0: return &v.state @@ -825,7 +734,7 @@ func file_model_proto_init() { } } } - file_model_proto_msgTypes[6].OneofWrappers = []interface{}{ + file_model_proto_msgTypes[5].OneofWrappers = []interface{}{ (*DataMessage_Text)(nil), (*DataMessage_Binary)(nil), } @@ -835,7 +744,7 @@ func file_model_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_model_proto_rawDesc, NumEnums: 2, - NumMessages: 7, + NumMessages: 6, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/livekit/room.pb.go b/proto/livekit/room.pb.go index ee25fcfd0..16f6cb243 100644 --- a/proto/livekit/room.pb.go +++ b/proto/livekit/room.pb.go @@ -89,16 +89,14 @@ func (x *CreateRoomRequest) GetMaxParticipants() uint32 { return 0 } -type GetRoomRequest struct { +type ListRoomsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - - Room string `protobuf:"bytes,1,opt,name=room,proto3" json:"room,omitempty"` } -func (x *GetRoomRequest) Reset() { - *x = GetRoomRequest{} +func (x *ListRoomsRequest) Reset() { + *x = ListRoomsRequest{} if protoimpl.UnsafeEnabled { mi := &file_room_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -106,13 +104,13 @@ func (x *GetRoomRequest) Reset() { } } -func (x *GetRoomRequest) String() string { +func (x *ListRoomsRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetRoomRequest) ProtoMessage() {} +func (*ListRoomsRequest) ProtoMessage() {} -func (x *GetRoomRequest) ProtoReflect() protoreflect.Message { +func (x *ListRoomsRequest) ProtoReflect() protoreflect.Message { mi := &file_room_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -124,16 +122,56 @@ func (x *GetRoomRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetRoomRequest.ProtoReflect.Descriptor instead. -func (*GetRoomRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use ListRoomsRequest.ProtoReflect.Descriptor instead. +func (*ListRoomsRequest) Descriptor() ([]byte, []int) { return file_room_proto_rawDescGZIP(), []int{1} } -func (x *GetRoomRequest) GetRoom() string { - if x != nil { - return x.Room +type ListRoomsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Rooms []*Room `protobuf:"bytes,1,rep,name=rooms,proto3" json:"rooms,omitempty"` +} + +func (x *ListRoomsResponse) Reset() { + *x = ListRoomsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_room_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } - return "" +} + +func (x *ListRoomsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListRoomsResponse) ProtoMessage() {} + +func (x *ListRoomsResponse) ProtoReflect() protoreflect.Message { + mi := &file_room_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListRoomsResponse.ProtoReflect.Descriptor instead. +func (*ListRoomsResponse) Descriptor() ([]byte, []int) { + return file_room_proto_rawDescGZIP(), []int{2} +} + +func (x *ListRoomsResponse) GetRooms() []*Room { + if x != nil { + return x.Rooms + } + return nil } type DeleteRoomRequest struct { @@ -147,7 +185,7 @@ type DeleteRoomRequest struct { func (x *DeleteRoomRequest) Reset() { *x = DeleteRoomRequest{} if protoimpl.UnsafeEnabled { - mi := &file_room_proto_msgTypes[2] + mi := &file_room_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -160,7 +198,7 @@ func (x *DeleteRoomRequest) String() string { func (*DeleteRoomRequest) ProtoMessage() {} func (x *DeleteRoomRequest) ProtoReflect() protoreflect.Message { - mi := &file_room_proto_msgTypes[2] + mi := &file_room_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -173,7 +211,7 @@ func (x *DeleteRoomRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteRoomRequest.ProtoReflect.Descriptor instead. func (*DeleteRoomRequest) Descriptor() ([]byte, []int) { - return file_room_proto_rawDescGZIP(), []int{2} + return file_room_proto_rawDescGZIP(), []int{3} } func (x *DeleteRoomRequest) GetRoom() string { @@ -192,7 +230,7 @@ type DeleteRoomResponse struct { func (x *DeleteRoomResponse) Reset() { *x = DeleteRoomResponse{} if protoimpl.UnsafeEnabled { - mi := &file_room_proto_msgTypes[3] + mi := &file_room_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -205,7 +243,7 @@ func (x *DeleteRoomResponse) String() string { func (*DeleteRoomResponse) ProtoMessage() {} func (x *DeleteRoomResponse) ProtoReflect() protoreflect.Message { - mi := &file_room_proto_msgTypes[3] + mi := &file_room_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -218,7 +256,7 @@ func (x *DeleteRoomResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteRoomResponse.ProtoReflect.Descriptor instead. func (*DeleteRoomResponse) Descriptor() ([]byte, []int) { - return file_room_proto_rawDescGZIP(), []int{3} + return file_room_proto_rawDescGZIP(), []int{4} } var File_room_proto protoreflect.FileDescriptor @@ -233,30 +271,33 @@ var file_room_proto_rawDesc = []byte{ 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x6d, 0x61, 0x78, 0x50, - 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x22, 0x24, 0x0a, 0x0e, 0x47, - 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, - 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6f, - 0x6d, 0x22, 0x27, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x32, 0xc8, 0x01, 0x0a, 0x0b, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x3b, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1a, - 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, - 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x6c, 0x69, 0x76, - 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, - 0x07, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x17, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, - 0x69, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x11, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x45, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, - 0x6f, 0x6d, 0x12, 0x1a, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, - 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, - 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, - 0x74, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x22, 0x12, 0x0a, 0x10, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x38, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x6f, + 0x6f, 0x6d, 0x52, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x22, 0x27, 0x0a, 0x11, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, + 0x6f, 0x6d, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xd1, 0x01, 0x0a, 0x0b, 0x52, 0x6f, 0x6f, + 0x6d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x1a, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x0d, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x6f, 0x6f, + 0x6d, 0x12, 0x42, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x12, 0x19, + 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, + 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x69, 0x76, 0x65, + 0x6b, 0x69, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x6d, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x6f, 0x6f, 0x6d, 0x12, 0x1a, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1b, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x31, 0x5a, 0x2f, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, + 0x69, 0x74, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -271,26 +312,28 @@ func file_room_proto_rawDescGZIP() []byte { return file_room_proto_rawDescData } -var file_room_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_room_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_room_proto_goTypes = []interface{}{ (*CreateRoomRequest)(nil), // 0: livekit.CreateRoomRequest - (*GetRoomRequest)(nil), // 1: livekit.GetRoomRequest - (*DeleteRoomRequest)(nil), // 2: livekit.DeleteRoomRequest - (*DeleteRoomResponse)(nil), // 3: livekit.DeleteRoomResponse - (*RoomInfo)(nil), // 4: livekit.RoomInfo + (*ListRoomsRequest)(nil), // 1: livekit.ListRoomsRequest + (*ListRoomsResponse)(nil), // 2: livekit.ListRoomsResponse + (*DeleteRoomRequest)(nil), // 3: livekit.DeleteRoomRequest + (*DeleteRoomResponse)(nil), // 4: livekit.DeleteRoomResponse + (*Room)(nil), // 5: livekit.Room } var file_room_proto_depIdxs = []int32{ - 0, // 0: livekit.RoomService.CreateRoom:input_type -> livekit.CreateRoomRequest - 1, // 1: livekit.RoomService.GetRoom:input_type -> livekit.GetRoomRequest - 2, // 2: livekit.RoomService.DeleteRoom:input_type -> livekit.DeleteRoomRequest - 4, // 3: livekit.RoomService.CreateRoom:output_type -> livekit.RoomInfo - 4, // 4: livekit.RoomService.GetRoom:output_type -> livekit.RoomInfo - 3, // 5: livekit.RoomService.DeleteRoom:output_type -> livekit.DeleteRoomResponse - 3, // [3:6] is the sub-list for method output_type - 0, // [0:3] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 5, // 0: livekit.ListRoomsResponse.rooms:type_name -> livekit.Room + 0, // 1: livekit.RoomService.CreateRoom:input_type -> livekit.CreateRoomRequest + 1, // 2: livekit.RoomService.ListRooms:input_type -> livekit.ListRoomsRequest + 3, // 3: livekit.RoomService.DeleteRoom:input_type -> livekit.DeleteRoomRequest + 5, // 4: livekit.RoomService.CreateRoom:output_type -> livekit.Room + 2, // 5: livekit.RoomService.ListRooms:output_type -> livekit.ListRoomsResponse + 4, // 6: livekit.RoomService.DeleteRoom:output_type -> livekit.DeleteRoomResponse + 4, // [4:7] is the sub-list for method output_type + 1, // [1:4] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_room_proto_init() } @@ -313,7 +356,7 @@ func file_room_proto_init() { } } file_room_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetRoomRequest); i { + switch v := v.(*ListRoomsRequest); i { case 0: return &v.state case 1: @@ -325,7 +368,7 @@ func file_room_proto_init() { } } file_room_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteRoomRequest); i { + switch v := v.(*ListRoomsResponse); i { case 0: return &v.state case 1: @@ -337,6 +380,18 @@ func file_room_proto_init() { } } file_room_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteRoomRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_room_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeleteRoomResponse); i { case 0: return &v.state @@ -355,7 +410,7 @@ func file_room_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_room_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 5, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/livekit/room.twirp.go b/proto/livekit/room.twirp.go index b57fa66da..9f44a1be7 100644 --- a/proto/livekit/room.twirp.go +++ b/proto/livekit/room.twirp.go @@ -45,9 +45,9 @@ const _ = twirp.TwirpPackageIsVersion7 type RoomService interface { // TODO: how do we secure room service? // should be accessible to only internal servers, not external - CreateRoom(context.Context, *CreateRoomRequest) (*RoomInfo, error) + CreateRoom(context.Context, *CreateRoomRequest) (*Room, error) - GetRoom(context.Context, *GetRoomRequest) (*RoomInfo, error) + ListRooms(context.Context, *ListRoomsRequest) (*ListRoomsResponse, error) DeleteRoom(context.Context, *DeleteRoomRequest) (*DeleteRoomResponse, error) } @@ -80,7 +80,7 @@ func NewRoomServiceProtobufClient(baseURL string, client HTTPClient, opts ...twi serviceURL += baseServicePath(clientOpts.PathPrefix(), "livekit", "RoomService") urls := [3]string{ serviceURL + "CreateRoom", - serviceURL + "GetRoom", + serviceURL + "ListRooms", serviceURL + "DeleteRoom", } @@ -92,13 +92,13 @@ func NewRoomServiceProtobufClient(baseURL string, client HTTPClient, opts ...twi } } -func (c *roomServiceProtobufClient) CreateRoom(ctx context.Context, in *CreateRoomRequest) (*RoomInfo, error) { +func (c *roomServiceProtobufClient) CreateRoom(ctx context.Context, in *CreateRoomRequest) (*Room, error) { ctx = ctxsetters.WithPackageName(ctx, "livekit") ctx = ctxsetters.WithServiceName(ctx, "RoomService") ctx = ctxsetters.WithMethodName(ctx, "CreateRoom") caller := c.callCreateRoom if c.interceptor != nil { - caller = func(ctx context.Context, req *CreateRoomRequest) (*RoomInfo, error) { + caller = func(ctx context.Context, req *CreateRoomRequest) (*Room, error) { resp, err := c.interceptor( func(ctx context.Context, req interface{}) (interface{}, error) { typedReq, ok := req.(*CreateRoomRequest) @@ -109,9 +109,9 @@ func (c *roomServiceProtobufClient) CreateRoom(ctx context.Context, in *CreateRo }, )(ctx, req) if resp != nil { - typedResp, ok := resp.(*RoomInfo) + typedResp, ok := resp.(*Room) if !ok { - return nil, twirp.InternalError("failed type assertion resp.(*RoomInfo) when calling interceptor") + return nil, twirp.InternalError("failed type assertion resp.(*Room) when calling interceptor") } return typedResp, err } @@ -121,8 +121,8 @@ func (c *roomServiceProtobufClient) CreateRoom(ctx context.Context, in *CreateRo return caller(ctx, in) } -func (c *roomServiceProtobufClient) callCreateRoom(ctx context.Context, in *CreateRoomRequest) (*RoomInfo, error) { - out := new(RoomInfo) +func (c *roomServiceProtobufClient) callCreateRoom(ctx context.Context, in *CreateRoomRequest) (*Room, error) { + out := new(Room) ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) if err != nil { twerr, ok := err.(twirp.Error) @@ -138,26 +138,26 @@ func (c *roomServiceProtobufClient) callCreateRoom(ctx context.Context, in *Crea return out, nil } -func (c *roomServiceProtobufClient) GetRoom(ctx context.Context, in *GetRoomRequest) (*RoomInfo, error) { +func (c *roomServiceProtobufClient) ListRooms(ctx context.Context, in *ListRoomsRequest) (*ListRoomsResponse, error) { ctx = ctxsetters.WithPackageName(ctx, "livekit") ctx = ctxsetters.WithServiceName(ctx, "RoomService") - ctx = ctxsetters.WithMethodName(ctx, "GetRoom") - caller := c.callGetRoom + ctx = ctxsetters.WithMethodName(ctx, "ListRooms") + caller := c.callListRooms if c.interceptor != nil { - caller = func(ctx context.Context, req *GetRoomRequest) (*RoomInfo, error) { + caller = func(ctx context.Context, req *ListRoomsRequest) (*ListRoomsResponse, error) { resp, err := c.interceptor( func(ctx context.Context, req interface{}) (interface{}, error) { - typedReq, ok := req.(*GetRoomRequest) + typedReq, ok := req.(*ListRoomsRequest) if !ok { - return nil, twirp.InternalError("failed type assertion req.(*GetRoomRequest) when calling interceptor") + return nil, twirp.InternalError("failed type assertion req.(*ListRoomsRequest) when calling interceptor") } - return c.callGetRoom(ctx, typedReq) + return c.callListRooms(ctx, typedReq) }, )(ctx, req) if resp != nil { - typedResp, ok := resp.(*RoomInfo) + typedResp, ok := resp.(*ListRoomsResponse) if !ok { - return nil, twirp.InternalError("failed type assertion resp.(*RoomInfo) when calling interceptor") + return nil, twirp.InternalError("failed type assertion resp.(*ListRoomsResponse) when calling interceptor") } return typedResp, err } @@ -167,8 +167,8 @@ func (c *roomServiceProtobufClient) GetRoom(ctx context.Context, in *GetRoomRequ return caller(ctx, in) } -func (c *roomServiceProtobufClient) callGetRoom(ctx context.Context, in *GetRoomRequest) (*RoomInfo, error) { - out := new(RoomInfo) +func (c *roomServiceProtobufClient) callListRooms(ctx context.Context, in *ListRoomsRequest) (*ListRoomsResponse, error) { + out := new(ListRoomsResponse) ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[1], in, out) if err != nil { twerr, ok := err.(twirp.Error) @@ -258,7 +258,7 @@ func NewRoomServiceJSONClient(baseURL string, client HTTPClient, opts ...twirp.C serviceURL += baseServicePath(clientOpts.PathPrefix(), "livekit", "RoomService") urls := [3]string{ serviceURL + "CreateRoom", - serviceURL + "GetRoom", + serviceURL + "ListRooms", serviceURL + "DeleteRoom", } @@ -270,13 +270,13 @@ func NewRoomServiceJSONClient(baseURL string, client HTTPClient, opts ...twirp.C } } -func (c *roomServiceJSONClient) CreateRoom(ctx context.Context, in *CreateRoomRequest) (*RoomInfo, error) { +func (c *roomServiceJSONClient) CreateRoom(ctx context.Context, in *CreateRoomRequest) (*Room, error) { ctx = ctxsetters.WithPackageName(ctx, "livekit") ctx = ctxsetters.WithServiceName(ctx, "RoomService") ctx = ctxsetters.WithMethodName(ctx, "CreateRoom") caller := c.callCreateRoom if c.interceptor != nil { - caller = func(ctx context.Context, req *CreateRoomRequest) (*RoomInfo, error) { + caller = func(ctx context.Context, req *CreateRoomRequest) (*Room, error) { resp, err := c.interceptor( func(ctx context.Context, req interface{}) (interface{}, error) { typedReq, ok := req.(*CreateRoomRequest) @@ -287,9 +287,9 @@ func (c *roomServiceJSONClient) CreateRoom(ctx context.Context, in *CreateRoomRe }, )(ctx, req) if resp != nil { - typedResp, ok := resp.(*RoomInfo) + typedResp, ok := resp.(*Room) if !ok { - return nil, twirp.InternalError("failed type assertion resp.(*RoomInfo) when calling interceptor") + return nil, twirp.InternalError("failed type assertion resp.(*Room) when calling interceptor") } return typedResp, err } @@ -299,8 +299,8 @@ func (c *roomServiceJSONClient) CreateRoom(ctx context.Context, in *CreateRoomRe return caller(ctx, in) } -func (c *roomServiceJSONClient) callCreateRoom(ctx context.Context, in *CreateRoomRequest) (*RoomInfo, error) { - out := new(RoomInfo) +func (c *roomServiceJSONClient) callCreateRoom(ctx context.Context, in *CreateRoomRequest) (*Room, error) { + out := new(Room) ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) if err != nil { twerr, ok := err.(twirp.Error) @@ -316,26 +316,26 @@ func (c *roomServiceJSONClient) callCreateRoom(ctx context.Context, in *CreateRo return out, nil } -func (c *roomServiceJSONClient) GetRoom(ctx context.Context, in *GetRoomRequest) (*RoomInfo, error) { +func (c *roomServiceJSONClient) ListRooms(ctx context.Context, in *ListRoomsRequest) (*ListRoomsResponse, error) { ctx = ctxsetters.WithPackageName(ctx, "livekit") ctx = ctxsetters.WithServiceName(ctx, "RoomService") - ctx = ctxsetters.WithMethodName(ctx, "GetRoom") - caller := c.callGetRoom + ctx = ctxsetters.WithMethodName(ctx, "ListRooms") + caller := c.callListRooms if c.interceptor != nil { - caller = func(ctx context.Context, req *GetRoomRequest) (*RoomInfo, error) { + caller = func(ctx context.Context, req *ListRoomsRequest) (*ListRoomsResponse, error) { resp, err := c.interceptor( func(ctx context.Context, req interface{}) (interface{}, error) { - typedReq, ok := req.(*GetRoomRequest) + typedReq, ok := req.(*ListRoomsRequest) if !ok { - return nil, twirp.InternalError("failed type assertion req.(*GetRoomRequest) when calling interceptor") + return nil, twirp.InternalError("failed type assertion req.(*ListRoomsRequest) when calling interceptor") } - return c.callGetRoom(ctx, typedReq) + return c.callListRooms(ctx, typedReq) }, )(ctx, req) if resp != nil { - typedResp, ok := resp.(*RoomInfo) + typedResp, ok := resp.(*ListRoomsResponse) if !ok { - return nil, twirp.InternalError("failed type assertion resp.(*RoomInfo) when calling interceptor") + return nil, twirp.InternalError("failed type assertion resp.(*ListRoomsResponse) when calling interceptor") } return typedResp, err } @@ -345,8 +345,8 @@ func (c *roomServiceJSONClient) GetRoom(ctx context.Context, in *GetRoomRequest) return caller(ctx, in) } -func (c *roomServiceJSONClient) callGetRoom(ctx context.Context, in *GetRoomRequest) (*RoomInfo, error) { - out := new(RoomInfo) +func (c *roomServiceJSONClient) callListRooms(ctx context.Context, in *ListRoomsRequest) (*ListRoomsResponse, error) { + out := new(ListRoomsResponse) ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[1], in, out) if err != nil { twerr, ok := err.(twirp.Error) @@ -495,8 +495,8 @@ func (s *roomServiceServer) ServeHTTP(resp http.ResponseWriter, req *http.Reques case "CreateRoom": s.serveCreateRoom(ctx, resp, req) return - case "GetRoom": - s.serveGetRoom(ctx, resp, req) + case "ListRooms": + s.serveListRooms(ctx, resp, req) return case "DeleteRoom": s.serveDeleteRoom(ctx, resp, req) @@ -544,7 +544,7 @@ func (s *roomServiceServer) serveCreateRoomJSON(ctx context.Context, resp http.R handler := s.RoomService.CreateRoom if s.interceptor != nil { - handler = func(ctx context.Context, req *CreateRoomRequest) (*RoomInfo, error) { + handler = func(ctx context.Context, req *CreateRoomRequest) (*Room, error) { resp, err := s.interceptor( func(ctx context.Context, req interface{}) (interface{}, error) { typedReq, ok := req.(*CreateRoomRequest) @@ -555,9 +555,9 @@ func (s *roomServiceServer) serveCreateRoomJSON(ctx context.Context, resp http.R }, )(ctx, req) if resp != nil { - typedResp, ok := resp.(*RoomInfo) + typedResp, ok := resp.(*Room) if !ok { - return nil, twirp.InternalError("failed type assertion resp.(*RoomInfo) when calling interceptor") + return nil, twirp.InternalError("failed type assertion resp.(*Room) when calling interceptor") } return typedResp, err } @@ -566,7 +566,7 @@ func (s *roomServiceServer) serveCreateRoomJSON(ctx context.Context, resp http.R } // Call service method - var respContent *RoomInfo + var respContent *Room func() { defer ensurePanicResponses(ctx, resp, s.hooks) respContent, err = handler(ctx, reqContent) @@ -577,7 +577,7 @@ func (s *roomServiceServer) serveCreateRoomJSON(ctx context.Context, resp http.R return } if respContent == nil { - s.writeError(ctx, resp, twirp.InternalError("received a nil *RoomInfo and nil error while calling CreateRoom. nil responses are not supported")) + s.writeError(ctx, resp, twirp.InternalError("received a nil *Room and nil error while calling CreateRoom. nil responses are not supported")) return } @@ -626,7 +626,7 @@ func (s *roomServiceServer) serveCreateRoomProtobuf(ctx context.Context, resp ht handler := s.RoomService.CreateRoom if s.interceptor != nil { - handler = func(ctx context.Context, req *CreateRoomRequest) (*RoomInfo, error) { + handler = func(ctx context.Context, req *CreateRoomRequest) (*Room, error) { resp, err := s.interceptor( func(ctx context.Context, req interface{}) (interface{}, error) { typedReq, ok := req.(*CreateRoomRequest) @@ -637,9 +637,9 @@ func (s *roomServiceServer) serveCreateRoomProtobuf(ctx context.Context, resp ht }, )(ctx, req) if resp != nil { - typedResp, ok := resp.(*RoomInfo) + typedResp, ok := resp.(*Room) if !ok { - return nil, twirp.InternalError("failed type assertion resp.(*RoomInfo) when calling interceptor") + return nil, twirp.InternalError("failed type assertion resp.(*Room) when calling interceptor") } return typedResp, err } @@ -648,7 +648,7 @@ func (s *roomServiceServer) serveCreateRoomProtobuf(ctx context.Context, resp ht } // Call service method - var respContent *RoomInfo + var respContent *Room func() { defer ensurePanicResponses(ctx, resp, s.hooks) respContent, err = handler(ctx, reqContent) @@ -659,7 +659,7 @@ func (s *roomServiceServer) serveCreateRoomProtobuf(ctx context.Context, resp ht return } if respContent == nil { - s.writeError(ctx, resp, twirp.InternalError("received a nil *RoomInfo and nil error while calling CreateRoom. nil responses are not supported")) + s.writeError(ctx, resp, twirp.InternalError("received a nil *Room and nil error while calling CreateRoom. nil responses are not supported")) return } @@ -683,7 +683,7 @@ func (s *roomServiceServer) serveCreateRoomProtobuf(ctx context.Context, resp ht callResponseSent(ctx, s.hooks) } -func (s *roomServiceServer) serveGetRoom(ctx context.Context, resp http.ResponseWriter, req *http.Request) { +func (s *roomServiceServer) serveListRooms(ctx context.Context, resp http.ResponseWriter, req *http.Request) { header := req.Header.Get("Content-Type") i := strings.Index(header, ";") if i == -1 { @@ -691,9 +691,9 @@ func (s *roomServiceServer) serveGetRoom(ctx context.Context, resp http.Response } switch strings.TrimSpace(strings.ToLower(header[:i])) { case "application/json": - s.serveGetRoomJSON(ctx, resp, req) + s.serveListRoomsJSON(ctx, resp, req) case "application/protobuf": - s.serveGetRoomProtobuf(ctx, resp, req) + s.serveListRoomsProtobuf(ctx, resp, req) default: msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")) twerr := badRouteError(msg, req.Method, req.URL.Path) @@ -701,38 +701,38 @@ func (s *roomServiceServer) serveGetRoom(ctx context.Context, resp http.Response } } -func (s *roomServiceServer) serveGetRoomJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) { +func (s *roomServiceServer) serveListRoomsJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) { var err error - ctx = ctxsetters.WithMethodName(ctx, "GetRoom") + ctx = ctxsetters.WithMethodName(ctx, "ListRooms") ctx, err = callRequestRouted(ctx, s.hooks) if err != nil { s.writeError(ctx, resp, err) return } - reqContent := new(GetRoomRequest) + reqContent := new(ListRoomsRequest) unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true} if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil { s.writeError(ctx, resp, malformedRequestError("the json request could not be decoded")) return } - handler := s.RoomService.GetRoom + handler := s.RoomService.ListRooms if s.interceptor != nil { - handler = func(ctx context.Context, req *GetRoomRequest) (*RoomInfo, error) { + handler = func(ctx context.Context, req *ListRoomsRequest) (*ListRoomsResponse, error) { resp, err := s.interceptor( func(ctx context.Context, req interface{}) (interface{}, error) { - typedReq, ok := req.(*GetRoomRequest) + typedReq, ok := req.(*ListRoomsRequest) if !ok { - return nil, twirp.InternalError("failed type assertion req.(*GetRoomRequest) when calling interceptor") + return nil, twirp.InternalError("failed type assertion req.(*ListRoomsRequest) when calling interceptor") } - return s.RoomService.GetRoom(ctx, typedReq) + return s.RoomService.ListRooms(ctx, typedReq) }, )(ctx, req) if resp != nil { - typedResp, ok := resp.(*RoomInfo) + typedResp, ok := resp.(*ListRoomsResponse) if !ok { - return nil, twirp.InternalError("failed type assertion resp.(*RoomInfo) when calling interceptor") + return nil, twirp.InternalError("failed type assertion resp.(*ListRoomsResponse) when calling interceptor") } return typedResp, err } @@ -741,7 +741,7 @@ func (s *roomServiceServer) serveGetRoomJSON(ctx context.Context, resp http.Resp } // Call service method - var respContent *RoomInfo + var respContent *ListRoomsResponse func() { defer ensurePanicResponses(ctx, resp, s.hooks) respContent, err = handler(ctx, reqContent) @@ -752,7 +752,7 @@ func (s *roomServiceServer) serveGetRoomJSON(ctx context.Context, resp http.Resp return } if respContent == nil { - s.writeError(ctx, resp, twirp.InternalError("received a nil *RoomInfo and nil error while calling GetRoom. nil responses are not supported")) + s.writeError(ctx, resp, twirp.InternalError("received a nil *ListRoomsResponse and nil error while calling ListRooms. nil responses are not supported")) return } @@ -779,9 +779,9 @@ func (s *roomServiceServer) serveGetRoomJSON(ctx context.Context, resp http.Resp callResponseSent(ctx, s.hooks) } -func (s *roomServiceServer) serveGetRoomProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) { +func (s *roomServiceServer) serveListRoomsProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) { var err error - ctx = ctxsetters.WithMethodName(ctx, "GetRoom") + ctx = ctxsetters.WithMethodName(ctx, "ListRooms") ctx, err = callRequestRouted(ctx, s.hooks) if err != nil { s.writeError(ctx, resp, err) @@ -793,28 +793,28 @@ func (s *roomServiceServer) serveGetRoomProtobuf(ctx context.Context, resp http. s.writeError(ctx, resp, wrapInternal(err, "failed to read request body")) return } - reqContent := new(GetRoomRequest) + reqContent := new(ListRoomsRequest) if err = proto.Unmarshal(buf, reqContent); err != nil { s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded")) return } - handler := s.RoomService.GetRoom + handler := s.RoomService.ListRooms if s.interceptor != nil { - handler = func(ctx context.Context, req *GetRoomRequest) (*RoomInfo, error) { + handler = func(ctx context.Context, req *ListRoomsRequest) (*ListRoomsResponse, error) { resp, err := s.interceptor( func(ctx context.Context, req interface{}) (interface{}, error) { - typedReq, ok := req.(*GetRoomRequest) + typedReq, ok := req.(*ListRoomsRequest) if !ok { - return nil, twirp.InternalError("failed type assertion req.(*GetRoomRequest) when calling interceptor") + return nil, twirp.InternalError("failed type assertion req.(*ListRoomsRequest) when calling interceptor") } - return s.RoomService.GetRoom(ctx, typedReq) + return s.RoomService.ListRooms(ctx, typedReq) }, )(ctx, req) if resp != nil { - typedResp, ok := resp.(*RoomInfo) + typedResp, ok := resp.(*ListRoomsResponse) if !ok { - return nil, twirp.InternalError("failed type assertion resp.(*RoomInfo) when calling interceptor") + return nil, twirp.InternalError("failed type assertion resp.(*ListRoomsResponse) when calling interceptor") } return typedResp, err } @@ -823,7 +823,7 @@ func (s *roomServiceServer) serveGetRoomProtobuf(ctx context.Context, resp http. } // Call service method - var respContent *RoomInfo + var respContent *ListRoomsResponse func() { defer ensurePanicResponses(ctx, resp, s.hooks) respContent, err = handler(ctx, reqContent) @@ -834,7 +834,7 @@ func (s *roomServiceServer) serveGetRoomProtobuf(ctx context.Context, resp http. return } if respContent == nil { - s.writeError(ctx, resp, twirp.InternalError("received a nil *RoomInfo and nil error while calling GetRoom. nil responses are not supported")) + s.writeError(ctx, resp, twirp.InternalError("received a nil *ListRoomsResponse and nil error while calling ListRooms. nil responses are not supported")) return } @@ -1595,23 +1595,25 @@ func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error) } var twirpFileDescriptor0 = []byte{ - // 288 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x4f, 0x4b, 0xc3, 0x40, - 0x10, 0xc5, 0x89, 0x8a, 0xc5, 0xa9, 0x55, 0xbb, 0x08, 0x86, 0x78, 0x29, 0x51, 0xb0, 0x1e, 0x4c, - 0x50, 0xf1, 0xe4, 0xcd, 0x3f, 0x88, 0x37, 0x89, 0x9e, 0xbc, 0x94, 0x6d, 0x1c, 0x75, 0x31, 0x9b, - 0x89, 0x9b, 0x49, 0xac, 0xdf, 0xd0, 0x8f, 0x25, 0xf9, 0xd7, 0x46, 0xd3, 0xd3, 0xce, 0xfe, 0xe6, - 0x2d, 0xf3, 0xde, 0x2c, 0x80, 0x21, 0xd2, 0x5e, 0x62, 0x88, 0x49, 0xf4, 0x22, 0x95, 0xe3, 0x87, - 0x62, 0xa7, 0xaf, 0xe9, 0x05, 0xa3, 0x8a, 0xba, 0x5f, 0x30, 0xbc, 0x36, 0x28, 0x19, 0x03, 0x22, - 0x1d, 0xe0, 0x67, 0x86, 0x29, 0x0b, 0x01, 0x6b, 0xb1, 0xd4, 0x68, 0x5b, 0x23, 0x6b, 0xbc, 0x11, - 0x94, 0xb5, 0x38, 0x80, 0x01, 0xea, 0x84, 0xbf, 0x27, 0xac, 0x34, 0x52, 0xc6, 0xf6, 0xca, 0xc8, - 0x1a, 0x0f, 0x82, 0xcd, 0x12, 0x3e, 0x55, 0x4c, 0x1c, 0xc3, 0x8e, 0x96, 0xb3, 0x49, 0x22, 0x0d, - 0xab, 0x50, 0x25, 0x32, 0xe6, 0xd4, 0x5e, 0x2d, 0x75, 0xdb, 0x5a, 0xce, 0x1e, 0x5a, 0xd8, 0x3d, - 0x84, 0xad, 0x3b, 0xe4, 0x7f, 0x53, 0x0b, 0xbb, 0xcd, 0xd4, 0xa2, 0x76, 0x8f, 0x60, 0x78, 0x83, - 0x11, 0x76, 0xec, 0x75, 0x84, 0xbb, 0x20, 0xda, 0xc2, 0x34, 0xa1, 0x38, 0xc5, 0xb3, 0x1f, 0x0b, - 0xfa, 0x05, 0x78, 0x44, 0x93, 0xab, 0x10, 0xc5, 0x25, 0xc0, 0x22, 0xad, 0x70, 0xbc, 0x7a, 0x25, - 0x5e, 0x67, 0x05, 0xce, 0x70, 0xde, 0x2b, 0xe8, 0x7d, 0xfc, 0x4a, 0xe2, 0x02, 0x7a, 0xb5, 0x63, - 0xb1, 0x37, 0xef, 0xfe, 0xcd, 0xb0, 0xec, 0xd9, 0x2d, 0xc0, 0xc2, 0x59, 0x6b, 0x66, 0x27, 0x97, - 0xb3, 0xbf, 0xb4, 0x57, 0x45, 0xb9, 0x3a, 0x7d, 0xf6, 0xdf, 0x14, 0xbf, 0x67, 0x53, 0x2f, 0x24, - 0xed, 0xd7, 0xc2, 0xe6, 0x3c, 0x49, 0xd1, 0xe4, 0x68, 0xfc, 0xf2, 0x4f, 0x1b, 0x38, 0x5d, 0x2f, - 0xaf, 0xe7, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x9f, 0xf2, 0xc7, 0x37, 0x06, 0x02, 0x00, 0x00, + // 311 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x92, 0x3f, 0x4f, 0xf3, 0x30, + 0x10, 0xc6, 0x95, 0xb7, 0x2f, 0xa0, 0x5e, 0xa9, 0x68, 0x2d, 0x86, 0x60, 0x96, 0x2a, 0x0c, 0x94, + 0x81, 0x54, 0x94, 0x01, 0xe6, 0x02, 0x1b, 0x03, 0x0a, 0x4c, 0x2c, 0x95, 0x1b, 0x4e, 0x60, 0x11, + 0xc7, 0xc1, 0x76, 0x42, 0xf9, 0x98, 0x7c, 0x23, 0x64, 0xe7, 0x4f, 0x03, 0xe9, 0xe4, 0xf3, 0xf3, + 0x9c, 0xfc, 0xdc, 0xef, 0x64, 0x00, 0x25, 0xa5, 0x08, 0x33, 0x25, 0x8d, 0x24, 0x7b, 0x09, 0x2f, + 0xf0, 0x9d, 0x1b, 0x3a, 0x10, 0xf2, 0x05, 0x93, 0x52, 0x0d, 0x3e, 0x61, 0x7c, 0xa3, 0x90, 0x19, + 0x8c, 0xa4, 0x14, 0x11, 0x7e, 0xe4, 0xa8, 0x0d, 0x21, 0xf0, 0x3f, 0x65, 0x02, 0x7d, 0x6f, 0xe2, + 0x4d, 0xfb, 0x91, 0xab, 0xc9, 0x09, 0x0c, 0x51, 0x64, 0xe6, 0x6b, 0x69, 0xb8, 0x40, 0x99, 0x1b, + 0xff, 0xdf, 0xc4, 0x9b, 0x0e, 0xa3, 0x7d, 0x27, 0x3e, 0x95, 0x1a, 0x39, 0x83, 0x91, 0x60, 0xeb, + 0x65, 0xc6, 0x94, 0xe1, 0x31, 0xcf, 0x58, 0x6a, 0xb4, 0xdf, 0x73, 0x7d, 0x07, 0x82, 0xad, 0x1f, + 0x5a, 0x72, 0x40, 0x60, 0x74, 0xcf, 0xb5, 0xb1, 0xb1, 0xba, 0xca, 0x0d, 0xae, 0x61, 0xdc, 0xd2, + 0x74, 0x26, 0x53, 0x6d, 0x83, 0x77, 0x2c, 0x85, 0xf6, 0xbd, 0x49, 0x6f, 0x3a, 0x98, 0x0f, 0xc3, + 0x8a, 0x23, 0x74, 0x13, 0x97, 0x5e, 0x70, 0x0a, 0xe3, 0x5b, 0x4c, 0xb0, 0x83, 0x61, 0xdd, 0x1a, + 0xc3, 0xd6, 0xc1, 0x21, 0x90, 0x76, 0x63, 0x99, 0x31, 0xff, 0xf6, 0x60, 0x60, 0x85, 0x47, 0x54, + 0x05, 0x8f, 0x91, 0x5c, 0x01, 0x6c, 0xb6, 0x42, 0x68, 0x13, 0xd9, 0x59, 0x15, 0xfd, 0x3d, 0x0e, + 0x59, 0x40, 0xbf, 0x21, 0x20, 0x47, 0x8d, 0xf7, 0x97, 0x94, 0xd2, 0x6d, 0x56, 0x05, 0x7c, 0x07, + 0xb0, 0x19, 0xb1, 0x15, 0xde, 0x01, 0xa4, 0xc7, 0x5b, 0xbd, 0xf2, 0x99, 0xc5, 0xc5, 0xf3, 0xec, + 0x95, 0x9b, 0xb7, 0x7c, 0x15, 0xc6, 0x52, 0xcc, 0xaa, 0xc6, 0xfa, 0x3c, 0xd7, 0xa8, 0x0a, 0x54, + 0x33, 0xf7, 0x09, 0x6a, 0x71, 0xb5, 0xeb, 0xae, 0x97, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xe4, + 0x3c, 0x6a, 0xb4, 0x37, 0x02, 0x00, 0x00, } diff --git a/proto/livekit/rtc.pb.go b/proto/livekit/rtc.pb.go index 3bfada4a0..b3f723961 100644 --- a/proto/livekit/rtc.pb.go +++ b/proto/livekit/rtc.pb.go @@ -530,7 +530,7 @@ type JoinResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Room *RoomInfo `protobuf:"bytes,1,opt,name=room,proto3" json:"room,omitempty"` + Room *Room `protobuf:"bytes,1,opt,name=room,proto3" json:"room,omitempty"` Participant *ParticipantInfo `protobuf:"bytes,2,opt,name=participant,proto3" json:"participant,omitempty"` OtherParticipants []*ParticipantInfo `protobuf:"bytes,3,rep,name=other_participants,json=otherParticipants,proto3" json:"other_participants,omitempty"` } @@ -567,7 +567,7 @@ func (*JoinResponse) Descriptor() ([]byte, []int) { return file_rtc_proto_rawDescGZIP(), []int{6} } -func (x *JoinResponse) GetRoom() *RoomInfo { +func (x *JoinResponse) GetRoom() *Room { if x != nil { return x.Room } @@ -851,39 +851,38 @@ var file_rtc_proto_rawDesc = []byte{ 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x22, 0x14, 0x0a, 0x12, 0x4e, 0x65, 0x67, 0x6f, 0x74, - 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xba, 0x01, - 0x0a, 0x0c, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, - 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, - 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x12, 0x3a, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, - 0x70, 0x61, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x69, 0x76, + 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb6, 0x01, + 0x0a, 0x0c, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, + 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6c, + 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x04, 0x72, 0x6f, 0x6f, + 0x6d, 0x12, 0x3a, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, + 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x12, 0x47, 0x0a, + 0x12, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, + 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x69, 0x76, 0x65, + 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x11, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, + 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x22, 0x54, 0x0a, 0x16, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, + 0x69, 0x64, 0x12, 0x28, 0x0a, 0x05, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x63, + 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x22, 0x15, 0x0a, 0x13, + 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x0a, 0x12, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, + 0x03, 0x73, 0x64, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x64, 0x70, 0x22, + 0x51, 0x0a, 0x11, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, - 0x74, 0x12, 0x47, 0x0a, 0x12, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, - 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, - 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, - 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x11, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x50, 0x61, - 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x22, 0x54, 0x0a, 0x16, 0x54, 0x72, - 0x61, 0x63, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x28, 0x0a, 0x05, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, - 0x54, 0x72, 0x61, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x74, 0x72, 0x61, 0x63, 0x6b, - 0x22, 0x15, 0x0a, 0x13, 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x0a, 0x12, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x64, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x73, 0x64, 0x70, 0x22, 0x51, 0x0a, 0x11, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, - 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, - 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, - 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, - 0x70, 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, - 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2f, 0x6c, 0x69, 0x76, - 0x65, 0x6b, 0x69, 0x74, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, + 0x74, 0x73, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, + 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x69, + 0x76, 0x65, 0x6b, 0x69, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -912,7 +911,7 @@ var file_rtc_proto_goTypes = []interface{}{ (*SessionDescription)(nil), // 9: livekit.SessionDescription (*ParticipantUpdate)(nil), // 10: livekit.ParticipantUpdate (TrackType)(0), // 11: livekit.TrackType - (*RoomInfo)(nil), // 12: livekit.RoomInfo + (*Room)(nil), // 12: livekit.Room (*ParticipantInfo)(nil), // 13: livekit.ParticipantInfo (*TrackInfo)(nil), // 14: livekit.TrackInfo } @@ -931,7 +930,7 @@ var file_rtc_proto_depIdxs = []int32{ 7, // 11: livekit.SignalResponse.track_published:type_name -> livekit.TrackPublishedResponse 8, // 12: livekit.SignalResponse.negotiate:type_name -> livekit.NegotiationResponse 11, // 13: livekit.AddTrackRequest.type:type_name -> livekit.TrackType - 12, // 14: livekit.JoinResponse.room:type_name -> livekit.RoomInfo + 12, // 14: livekit.JoinResponse.room:type_name -> livekit.Room 13, // 15: livekit.JoinResponse.participant:type_name -> livekit.ParticipantInfo 13, // 16: livekit.JoinResponse.other_participants:type_name -> livekit.ParticipantInfo 14, // 17: livekit.TrackPublishedResponse.track:type_name -> livekit.TrackInfo diff --git a/proto/model.proto b/proto/model.proto index 0436ceb98..0e07c563d 100644 --- a/proto/model.proto +++ b/proto/model.proto @@ -6,7 +6,7 @@ option go_package = "github.com/livekit/livekit-server/proto/livekit"; message Node { string id = 1; string ip = 2; - uint32 rtc_port = 3; + uint32 num_cpus = 3; NodeStats stats = 4; } @@ -24,13 +24,6 @@ message Room { int64 creation_time = 5; } -message RoomInfo { - string sid = 1; - string name = 2; - string node_ip = 3; - int64 creation_time = 4; -} - message ParticipantInfo { enum State { // websocket' connected, but not offered yet diff --git a/proto/room.proto b/proto/room.proto index 3475fa51f..9dc6d0c6d 100644 --- a/proto/room.proto +++ b/proto/room.proto @@ -10,8 +10,8 @@ import "model.proto"; service RoomService { // TODO: how do we secure room service? // should be accessible to only internal servers, not external - rpc CreateRoom(CreateRoomRequest) returns (RoomInfo); - rpc GetRoom(GetRoomRequest) returns (RoomInfo); + rpc CreateRoom(CreateRoomRequest) returns (Room); + rpc ListRooms(ListRoomsRequest) returns (ListRoomsResponse); rpc DeleteRoom(DeleteRoomRequest) returns (DeleteRoomResponse); } @@ -22,8 +22,11 @@ message CreateRoomRequest { uint32 max_participants = 3; } -message GetRoomRequest { - string room = 1; +message ListRoomsRequest { +} + +message ListRoomsResponse { + repeated Room rooms = 1; } message DeleteRoomRequest { diff --git a/proto/rtc.proto b/proto/rtc.proto index 458421def..cf3bfd1b5 100644 --- a/proto/rtc.proto +++ b/proto/rtc.proto @@ -59,7 +59,7 @@ message NegotiationRequest { } message JoinResponse { - RoomInfo room = 1; + Room room = 1; ParticipantInfo participant = 2; repeated ParticipantInfo other_participants = 3; } diff --git a/test/integration_helpers.go b/test/integration_helpers.go index c84a76e5f..3c20f9da1 100644 --- a/test/integration_helpers.go +++ b/test/integration_helpers.go @@ -13,6 +13,7 @@ import ( "github.com/livekit/livekit-server/cmd/cli/client" "github.com/livekit/livekit-server/pkg/auth" "github.com/livekit/livekit-server/pkg/config" + "github.com/livekit/livekit-server/pkg/routing" "github.com/livekit/livekit-server/pkg/service" "github.com/livekit/livekit-server/proto/livekit" ) @@ -43,12 +44,12 @@ func waitForServerToStart(s *service.LivekitServer) { } } -func withTimeout(t *testing.T, f func() bool) { +func withTimeout(t *testing.T, description string, f func() bool) { ctx, _ := context.WithTimeout(context.Background(), time.Second) for { select { case <-ctx.Done(): - t.Fatal("timed out") + t.Fatal("timed out: " + description) case <-time.After(10 * time.Millisecond): if f() { return @@ -76,19 +77,28 @@ func createServer() *service.LivekitServer { if err != nil { panic(fmt.Sprintf("could not create config: %v", err)) } - s, err := service.InitializeServer(serverConfig, &StaticKeyProvider{}) + + currentNode, err := routing.NewLocalNode(serverConfig) + if err != nil { + panic(err) + } + + // local routing and store + router := routing.NewLocalRouter(currentNode) + roomStore := service.NewLocalRoomStore() + s, err := service.InitializeServer(serverConfig, &StaticKeyProvider{}, roomStore, router, currentNode) if err != nil { panic(fmt.Sprintf("could not create server: %v", err)) } - roomClient = livekit.NewRoomServiceJSONClient(fmt.Sprintf("http://localhost:%d", serverConfig.APIPort), &http.Client{}) + roomClient = livekit.NewRoomServiceJSONClient(fmt.Sprintf("http://localhost:%d", serverConfig.Port), &http.Client{}) return s } // creates a client and runs against server func createClient(name string) *client.RTCClient { token := joinToken(testRoom, name) - ws, err := client.NewWebSocketConn(fmt.Sprintf("ws://localhost:%d", serverConfig.RTCPort), token) + ws, err := client.NewWebSocketConn(fmt.Sprintf("ws://localhost:%d", serverConfig.Port), token) if err != nil { panic(err) } diff --git a/test/integration_test.go b/test/integration_test.go index e100b33eb..d9244a2c3 100644 --- a/test/integration_test.go +++ b/test/integration_test.go @@ -10,7 +10,6 @@ import ( "github.com/twitchtv/twirp" "github.com/livekit/livekit-server/pkg/logger" - "github.com/livekit/livekit-server/pkg/service" "github.com/livekit/livekit-server/proto/livekit" ) @@ -20,7 +19,7 @@ func TestClientCouldConnect(t *testing.T) { waitUntilConnected(t, c1, c2) // ensure they both see each other - withTimeout(t, func() bool { + withTimeout(t, "c1 and c2 could connect", func() bool { if len(c1.RemoteParticipants()) == 0 || len(c2.RemoteParticipants()) == 0 { return false } @@ -45,7 +44,7 @@ func TestSinglePublisher(t *testing.T) { // a new client joins and should get the initial stream c3 := createClient("c3") - withTimeout(t, func() bool { + withTimeout(t, "c2 should receive two tracks", func() bool { if len(c2.SubscribedTracks()) == 0 { return false } @@ -61,7 +60,7 @@ func TestSinglePublisher(t *testing.T) { // ensure that new client that has joined also received tracks waitUntilConnected(t, c3) - withTimeout(t, func() bool { + withTimeout(t, "c2 should receive two tracks", func() bool { if len(c3.SubscribedTracks()) == 0 { return false } @@ -76,7 +75,6 @@ func TestSinglePublisher(t *testing.T) { func TestMain(m *testing.M) { logger.InitDevelopment() s := createServer() - service.AuthRequired = true go func() { s.Start() }() @@ -86,7 +84,7 @@ func TestMain(m *testing.M) { // create test room token := createRoomToken() header := make(http.Header) - logger.GetLogger().Debugw("auth token", "token", token) + logger.Debugw("auth token", "token", token) header.Set("Authorization", "Bearer "+token) tctx, err := twirp.WithHTTPRequestHeaders(context.Background(), header) if err != nil {