diff --git a/go.mod b/go.mod index 08f66b8d7..26a3e6a59 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/google/wire v0.5.0 github.com/gorilla/websocket v1.4.2 github.com/hashicorp/golang-lru v0.5.4 - github.com/livekit/protocol v0.13.5-0.20220721030958-86da2252193b + github.com/livekit/protocol v0.13.5-0.20220721052645-5eea37b737f6 github.com/livekit/rtcscore-go v0.0.0-20220524203225-dfd1ba40744a github.com/mackerelio/go-osstat v0.2.1 github.com/magefile/mage v1.13.0 diff --git a/go.sum b/go.sum index 1e4b1179c..4934e35ec 100644 --- a/go.sum +++ b/go.sum @@ -235,8 +235,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lithammer/shortuuid/v3 v3.0.7 h1:trX0KTHy4Pbwo/6ia8fscyHoGA+mf1jWbPJVuvyJQQ8= github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts= -github.com/livekit/protocol v0.13.5-0.20220721030958-86da2252193b h1:7p5M5WoTFDyIvxcB+r2aqMYKU8tFYf8MA52vXY15naI= -github.com/livekit/protocol v0.13.5-0.20220721030958-86da2252193b/go.mod h1:Qd/Dn4BkJfZQy/IjtEeUOGXARrR7l09WDkg5SY8thkw= +github.com/livekit/protocol v0.13.5-0.20220721052645-5eea37b737f6 h1:+8Uw5Ron7LU1nXMn7lfwB91G0fGpjqMlRHvxdyE/JUk= +github.com/livekit/protocol v0.13.5-0.20220721052645-5eea37b737f6/go.mod h1:Qd/Dn4BkJfZQy/IjtEeUOGXARrR7l09WDkg5SY8thkw= github.com/livekit/rtcscore-go v0.0.0-20220524203225-dfd1ba40744a h1:cENjhGfslLSDV07gt8ASy47Wd12Q0kBS7hsdunyQ62I= github.com/livekit/rtcscore-go v0.0.0-20220524203225-dfd1ba40744a/go.mod h1:116ych8UaEs9vfIE8n6iZCZ30iagUFTls0vRmC+Ix5U= github.com/mackerelio/go-osstat v0.2.1 h1:5AeAcBEutEErAOlDz6WCkEvm6AKYgHTUQrfwm5RbeQc= diff --git a/pkg/service/interfaces.go b/pkg/service/interfaces.go index b36e254dc..47146215f 100644 --- a/pkg/service/interfaces.go +++ b/pkg/service/interfaces.go @@ -29,9 +29,9 @@ type ObjectStore interface { //counterfeiter:generate . ServiceStore type ServiceStore interface { LoadRoom(ctx context.Context, name livekit.RoomName) (*livekit.Room, error) - // ListRooms returns currently active rooms. if names is not nil, it'll filter and return + // ListRooms returns currently active rooms. if names and/or sids is not nil, it'll filter and return // only rooms that match - ListRooms(ctx context.Context, names []livekit.RoomName) ([]*livekit.Room, error) + ListRooms(ctx context.Context, names []livekit.RoomName, sids []livekit.RoomID) ([]*livekit.Room, error) LoadParticipant(ctx context.Context, roomName livekit.RoomName, identity livekit.ParticipantIdentity) (*livekit.ParticipantInfo, error) ListParticipants(ctx context.Context, roomName livekit.RoomName) ([]*livekit.ParticipantInfo, error) diff --git a/pkg/service/localstore.go b/pkg/service/localstore.go index 9f9e86e21..463e82172 100644 --- a/pkg/service/localstore.go +++ b/pkg/service/localstore.go @@ -50,12 +50,12 @@ func (s *LocalStore) LoadRoom(_ context.Context, name livekit.RoomName) (*liveki return room, nil } -func (s *LocalStore) ListRooms(_ context.Context, names []livekit.RoomName) ([]*livekit.Room, error) { +func (s *LocalStore) ListRooms(_ context.Context, names []livekit.RoomName, sids []livekit.RoomID) ([]*livekit.Room, error) { s.lock.RLock() defer s.lock.RUnlock() rooms := make([]*livekit.Room, 0, len(s.rooms)) for _, r := range s.rooms { - if names == nil || funk.Contains(names, livekit.RoomName(r.Name)) { + if (names == nil && sids == nil) || funk.Contains(names, livekit.RoomName(r.Name)) || funk.Contains(sids, livekit.RoomID(r.Sid)) { rooms = append(rooms, r) } } diff --git a/pkg/service/redisstore.go b/pkg/service/redisstore.go index eab293abe..fc851094d 100644 --- a/pkg/service/redisstore.go +++ b/pkg/service/redisstore.go @@ -6,6 +6,7 @@ import ( "github.com/go-redis/redis/v8" "github.com/pkg/errors" + "github.com/thoas/go-funk" "google.golang.org/protobuf/proto" "github.com/livekit/protocol/livekit" @@ -76,37 +77,25 @@ func (s *RedisStore) LoadRoom(_ context.Context, name livekit.RoomName) (*liveki return &room, nil } -func (s *RedisStore) ListRooms(_ context.Context, names []livekit.RoomName) ([]*livekit.Room, error) { +func (s *RedisStore) ListRooms(_ context.Context, names []livekit.RoomName, sids []livekit.RoomID) ([]*livekit.Room, error) { var items []string var err error - if names == nil { - items, err = s.rc.HVals(s.ctx, RoomsKey).Result() - if err != nil && err != redis.Nil { - return nil, errors.Wrap(err, "could not get rooms") - } - } else { - roomNames := livekit.RoomNamesAsStrings(names) - var results []interface{} - results, err = s.rc.HMGet(s.ctx, RoomsKey, roomNames...).Result() - if err != nil && err != redis.Nil { - return nil, errors.Wrap(err, "could not get rooms by names") - } - for _, r := range results { - if item, ok := r.(string); ok { - items = append(items, item) - } - } + items, err = s.rc.HVals(s.ctx, RoomsKey).Result() + if err != nil && err != redis.Nil { + return nil, errors.Wrap(err, "could not get rooms") } rooms := make([]*livekit.Room, 0, len(items)) - for _, item := range items { room := livekit.Room{} err := proto.Unmarshal([]byte(item), &room) if err != nil { return nil, err } - rooms = append(rooms, &room) + + if (names == nil && sids == nil) || funk.Contains(names, livekit.RoomName(room.Name)) || funk.Contains(sids, livekit.RoomID(room.Sid)) { + rooms = append(rooms, &room) + } } return rooms, nil } diff --git a/pkg/service/roommanager.go b/pkg/service/roommanager.go index b5c6bfeb0..dfdcbb374 100644 --- a/pkg/service/roommanager.go +++ b/pkg/service/roommanager.go @@ -114,7 +114,7 @@ func (r *RoomManager) DeleteRoom(ctx context.Context, roomName livekit.RoomName) func (r *RoomManager) CleanupRooms() error { // cleanup rooms that have been left for over a day ctx := context.Background() - rooms, err := r.roomStore.ListRooms(ctx, nil) + rooms, err := r.roomStore.ListRooms(ctx, nil, nil) if err != nil { return err } diff --git a/pkg/service/roomservice.go b/pkg/service/roomservice.go index d5bad1c24..c32ec28d9 100644 --- a/pkg/service/roomservice.go +++ b/pkg/service/roomservice.go @@ -61,7 +61,11 @@ func (s *RoomService) ListRooms(ctx context.Context, req *livekit.ListRoomsReque if len(req.Names) > 0 { names = livekit.StringsAsRoomNames(req.Names) } - rooms, err := s.roomStore.ListRooms(ctx, names) + var sids []livekit.RoomID + if len(req.RoomSids) > 0 { + sids = livekit.StringsAsRoomIDs(req.RoomSids) + } + rooms, err := s.roomStore.ListRooms(ctx, names, sids) if err != nil { // TODO: translate error codes to twirp return diff --git a/pkg/service/servicefakes/fake_object_store.go b/pkg/service/servicefakes/fake_object_store.go index 39ff2a54d..302eea499 100644 --- a/pkg/service/servicefakes/fake_object_store.go +++ b/pkg/service/servicefakes/fake_object_store.go @@ -76,11 +76,12 @@ type FakeObjectStore struct { result1 []*livekit.ParticipantInfo result2 error } - ListRoomsStub func(context.Context, []livekit.RoomName) ([]*livekit.Room, error) + ListRoomsStub func(context.Context, []livekit.RoomName, []livekit.RoomID) ([]*livekit.Room, error) listRoomsMutex sync.RWMutex listRoomsArgsForCall []struct { arg1 context.Context arg2 []livekit.RoomName + arg3 []livekit.RoomID } listRoomsReturns struct { result1 []*livekit.Room @@ -531,24 +532,30 @@ func (fake *FakeObjectStore) ListParticipantsReturnsOnCall(i int, result1 []*liv }{result1, result2} } -func (fake *FakeObjectStore) ListRooms(arg1 context.Context, arg2 []livekit.RoomName) ([]*livekit.Room, error) { +func (fake *FakeObjectStore) ListRooms(arg1 context.Context, arg2 []livekit.RoomName, arg3 []livekit.RoomID) ([]*livekit.Room, error) { var arg2Copy []livekit.RoomName if arg2 != nil { arg2Copy = make([]livekit.RoomName, len(arg2)) copy(arg2Copy, arg2) } + var arg3Copy []livekit.RoomID + if arg3 != nil { + arg3Copy = make([]livekit.RoomID, len(arg3)) + copy(arg3Copy, arg3) + } fake.listRoomsMutex.Lock() ret, specificReturn := fake.listRoomsReturnsOnCall[len(fake.listRoomsArgsForCall)] fake.listRoomsArgsForCall = append(fake.listRoomsArgsForCall, struct { arg1 context.Context arg2 []livekit.RoomName - }{arg1, arg2Copy}) + arg3 []livekit.RoomID + }{arg1, arg2Copy, arg3Copy}) stub := fake.ListRoomsStub fakeReturns := fake.listRoomsReturns - fake.recordInvocation("ListRooms", []interface{}{arg1, arg2Copy}) + fake.recordInvocation("ListRooms", []interface{}{arg1, arg2Copy, arg3Copy}) fake.listRoomsMutex.Unlock() if stub != nil { - return stub(arg1, arg2) + return stub(arg1, arg2, arg3) } if specificReturn { return ret.result1, ret.result2 @@ -562,17 +569,17 @@ func (fake *FakeObjectStore) ListRoomsCallCount() int { return len(fake.listRoomsArgsForCall) } -func (fake *FakeObjectStore) ListRoomsCalls(stub func(context.Context, []livekit.RoomName) ([]*livekit.Room, error)) { +func (fake *FakeObjectStore) ListRoomsCalls(stub func(context.Context, []livekit.RoomName, []livekit.RoomID) ([]*livekit.Room, error)) { fake.listRoomsMutex.Lock() defer fake.listRoomsMutex.Unlock() fake.ListRoomsStub = stub } -func (fake *FakeObjectStore) ListRoomsArgsForCall(i int) (context.Context, []livekit.RoomName) { +func (fake *FakeObjectStore) ListRoomsArgsForCall(i int) (context.Context, []livekit.RoomName, []livekit.RoomID) { fake.listRoomsMutex.RLock() defer fake.listRoomsMutex.RUnlock() argsForCall := fake.listRoomsArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } func (fake *FakeObjectStore) ListRoomsReturns(result1 []*livekit.Room, result2 error) { diff --git a/pkg/service/servicefakes/fake_service_store.go b/pkg/service/servicefakes/fake_service_store.go index 5c0bd4544..3c9b280af 100644 --- a/pkg/service/servicefakes/fake_service_store.go +++ b/pkg/service/servicefakes/fake_service_store.go @@ -50,11 +50,12 @@ type FakeServiceStore struct { result1 []*livekit.ParticipantInfo result2 error } - ListRoomsStub func(context.Context, []livekit.RoomName) ([]*livekit.Room, error) + ListRoomsStub func(context.Context, []livekit.RoomName, []livekit.RoomID) ([]*livekit.Room, error) listRoomsMutex sync.RWMutex listRoomsArgsForCall []struct { arg1 context.Context arg2 []livekit.RoomName + arg3 []livekit.RoomID } listRoomsReturns struct { result1 []*livekit.Room @@ -327,24 +328,30 @@ func (fake *FakeServiceStore) ListParticipantsReturnsOnCall(i int, result1 []*li }{result1, result2} } -func (fake *FakeServiceStore) ListRooms(arg1 context.Context, arg2 []livekit.RoomName) ([]*livekit.Room, error) { +func (fake *FakeServiceStore) ListRooms(arg1 context.Context, arg2 []livekit.RoomName, arg3 []livekit.RoomID) ([]*livekit.Room, error) { var arg2Copy []livekit.RoomName if arg2 != nil { arg2Copy = make([]livekit.RoomName, len(arg2)) copy(arg2Copy, arg2) } + var arg3Copy []livekit.RoomID + if arg3 != nil { + arg3Copy = make([]livekit.RoomID, len(arg3)) + copy(arg3Copy, arg3) + } fake.listRoomsMutex.Lock() ret, specificReturn := fake.listRoomsReturnsOnCall[len(fake.listRoomsArgsForCall)] fake.listRoomsArgsForCall = append(fake.listRoomsArgsForCall, struct { arg1 context.Context arg2 []livekit.RoomName - }{arg1, arg2Copy}) + arg3 []livekit.RoomID + }{arg1, arg2Copy, arg3Copy}) stub := fake.ListRoomsStub fakeReturns := fake.listRoomsReturns - fake.recordInvocation("ListRooms", []interface{}{arg1, arg2Copy}) + fake.recordInvocation("ListRooms", []interface{}{arg1, arg2Copy, arg3Copy}) fake.listRoomsMutex.Unlock() if stub != nil { - return stub(arg1, arg2) + return stub(arg1, arg2, arg3) } if specificReturn { return ret.result1, ret.result2 @@ -358,17 +365,17 @@ func (fake *FakeServiceStore) ListRoomsCallCount() int { return len(fake.listRoomsArgsForCall) } -func (fake *FakeServiceStore) ListRoomsCalls(stub func(context.Context, []livekit.RoomName) ([]*livekit.Room, error)) { +func (fake *FakeServiceStore) ListRoomsCalls(stub func(context.Context, []livekit.RoomName, []livekit.RoomID) ([]*livekit.Room, error)) { fake.listRoomsMutex.Lock() defer fake.listRoomsMutex.Unlock() fake.ListRoomsStub = stub } -func (fake *FakeServiceStore) ListRoomsArgsForCall(i int) (context.Context, []livekit.RoomName) { +func (fake *FakeServiceStore) ListRoomsArgsForCall(i int) (context.Context, []livekit.RoomName, []livekit.RoomID) { fake.listRoomsMutex.RLock() defer fake.listRoomsMutex.RUnlock() argsForCall := fake.listRoomsArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } func (fake *FakeServiceStore) ListRoomsReturns(result1 []*livekit.Room, result2 error) { diff --git a/test/scenarios.go b/test/scenarios.go index d5c7878e0..91bde898e 100644 --- a/test/scenarios.go +++ b/test/scenarios.go @@ -202,11 +202,11 @@ func roomServiceListRoom(t *testing.T) { createCtx := contextWithToken(createRoomToken()) listCtx := contextWithToken(listRoomToken()) // create rooms - _, err := roomClient.CreateRoom(createCtx, &livekit.CreateRoomRequest{ + testRm, err := roomClient.CreateRoom(createCtx, &livekit.CreateRoomRequest{ Name: testRoom, }) require.NoError(t, err) - _, err = roomClient.CreateRoom(contextWithToken(createRoomToken()), &livekit.CreateRoomRequest{ + yourRm, err := roomClient.CreateRoom(contextWithToken(createRoomToken()), &livekit.CreateRoomRequest{ Name: "yourroom", }) require.NoError(t, err) @@ -216,7 +216,7 @@ func roomServiceListRoom(t *testing.T) { require.NoError(t, err) require.Len(t, res.Rooms, 2) }) - t.Run("list specific rooms", func(t *testing.T) { + t.Run("list specific rooms by name", func(t *testing.T) { res, err := roomClient.ListRooms(listCtx, &livekit.ListRoomsRequest{ Names: []string{"yourroom"}, }) @@ -224,4 +224,29 @@ func roomServiceListRoom(t *testing.T) { require.Len(t, res.Rooms, 1) require.Equal(t, "yourroom", res.Rooms[0].Name) }) + t.Run("list specific rooms by sid", func(t *testing.T) { + res, err := roomClient.ListRooms(listCtx, &livekit.ListRoomsRequest{ + RoomSids: []string{testRm.Sid}, + }) + require.NoError(t, err) + require.Len(t, res.Rooms, 1) + require.Equal(t, testRm.Sid, res.Rooms[0].Sid) + }) + t.Run("list specific rooms by name and sid overlap", func(t *testing.T) { + res, err := roomClient.ListRooms(listCtx, &livekit.ListRoomsRequest{ + Names: []string{testRoom}, + RoomSids: []string{testRm.Sid}, + }) + require.NoError(t, err) + require.Len(t, res.Rooms, 1) + require.Equal(t, testRm.Sid, res.Rooms[0].Sid) + }) + t.Run("list specific rooms by name and sid non-overlap", func(t *testing.T) { + res, err := roomClient.ListRooms(listCtx, &livekit.ListRoomsRequest{ + Names: []string{testRoom}, + RoomSids: []string{yourRm.Sid}, + }) + require.NoError(t, err) + require.Len(t, res.Rooms, 2) + }) }