Skip to content

Commit 4d35ed1

Browse files
authored
🐛Ensure locked state is shown when RTC_MAX_NUMBER_OF_USERS is set (ITISFoundation#8181)
1 parent b585dbf commit 4d35ed1

File tree

2 files changed

+47
-21
lines changed

2 files changed

+47
-21
lines changed

services/web/server/src/simcore_service_webserver/projects/_projects_service.py

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,10 @@ async def patch_project_and_notify_users(
204204
new_partial_project_data=patch_project_data,
205205
)
206206

207-
project_document, document_version = (
208-
await create_project_document_and_increment_version(app, project_uuid)
209-
)
207+
(
208+
project_document,
209+
document_version,
210+
) = await create_project_document_and_increment_version(app, project_uuid)
210211
await notify_project_document_updated(
211212
app=app,
212213
project_id=project_uuid,
@@ -1665,10 +1666,15 @@ async def _get_project_share_state(
16651666
4. If the same user is using the project with a valid socket id (meaning a tab is currently active) then the project is Locked and OPENED.
16661667
5. If the same user is using the project with NO socket id (meaning there is no current tab active) then the project is Unlocked and OPENED. which means the user can open it again.
16671668
"""
1669+
app_settings = get_application_settings(app)
16681670
prj_locked_state = await get_project_locked_state(
16691671
get_redis_lock_manager_client_sdk(app), project_uuid
16701672
)
1671-
app_settings = get_application_settings(app)
1673+
with managed_resource(user_id, None, app) as rt:
1674+
user_sessions_with_project = await rt.find_users_of_resource(
1675+
app, PROJECT_ID_KEY, project_uuid
1676+
)
1677+
16721678
if prj_locked_state:
16731679
_logger.debug(
16741680
"project [%s] is currently locked: %s",
@@ -1684,7 +1690,17 @@ async def _get_project_share_state(
16841690
ProjectStatus.CLONING,
16851691
ProjectStatus.EXPORTING,
16861692
ProjectStatus.MAINTAINING,
1687-
],
1693+
]
1694+
or (
1695+
(
1696+
app_settings.WEBSERVER_REALTIME_COLLABORATION.RTC_MAX_NUMBER_OF_USERS
1697+
is not None
1698+
)
1699+
and (
1700+
len(user_sessions_with_project)
1701+
< app_settings.WEBSERVER_REALTIME_COLLABORATION.RTC_MAX_NUMBER_OF_USERS
1702+
)
1703+
),
16881704
current_user_groupids=(
16891705
[
16901706
await users_service.get_user_primary_group_id(
@@ -1695,6 +1711,7 @@ async def _get_project_share_state(
16951711
else []
16961712
),
16971713
)
1714+
# "old" behavior to remove once RTC is fully implemented
16981715
return ProjectShareState(
16991716
status=prj_locked_state.status,
17001717
locked=prj_locked_state.value,
@@ -1709,29 +1726,27 @@ async def _get_project_share_state(
17091726
),
17101727
)
17111728

1712-
# let's now check if anyone has the project in use somehow
1713-
with managed_resource(user_id, None, app) as rt:
1714-
user_sessions_with_project = await rt.find_users_of_resource(
1715-
app, PROJECT_ID_KEY, project_uuid
1716-
)
1717-
set_user_ids = {user_session.user_id for user_session in user_sessions_with_project}
1718-
1719-
if not set_user_ids:
1729+
if not user_sessions_with_project:
17201730
# no one has the project, so it is unlocked and closed.
17211731
_logger.debug("project [%s] is not in use", f"{project_uuid=}")
17221732
return ProjectShareState(
17231733
status=ProjectStatus.CLOSED, locked=False, current_user_groupids=[]
17241734
)
17251735

1736+
# let's now check if anyone has the project in use somehow
1737+
active_user_ids = {
1738+
user_session.user_id for user_session in user_sessions_with_project
1739+
}
1740+
17261741
_logger.debug(
17271742
"project [%s] might be used by the following users: [%s]",
17281743
f"{project_uuid=}",
1729-
f"{set_user_ids=}",
1744+
f"{active_user_ids=}",
17301745
)
17311746

17321747
if app_settings.WEBSERVER_REALTIME_COLLABORATION is None: # noqa: SIM102
17331748
# let's check if the project is opened by the same user, maybe already opened or closed in a orphaned session
1734-
if set_user_ids.issubset(
1749+
if active_user_ids.issubset(
17351750
{user_id}
17361751
) and not await _user_has_another_active_session(
17371752
user_sessions_with_project, app
@@ -1740,27 +1755,38 @@ async def _get_project_share_state(
17401755
_logger.debug(
17411756
"project [%s] is in use by the same user [%s] that is currently disconnected, so it is unlocked for this specific user and opened",
17421757
f"{project_uuid=}",
1743-
f"{set_user_ids=}",
1758+
f"{active_user_ids=}",
17441759
)
17451760
return ProjectShareState(
17461761
status=ProjectStatus.OPENED,
17471762
locked=False,
17481763
current_user_groupids=await limited_gather(
17491764
*[
17501765
users_service.get_user_primary_group_id(app, user_id=uid)
1751-
for uid in set_user_ids
1766+
for uid in active_user_ids
17521767
],
17531768
limit=10,
17541769
),
17551770
)
17561771

1772+
# compute lock state
1773+
if app_settings.WEBSERVER_REALTIME_COLLABORATION is None:
1774+
locked = True
1775+
elif app_settings.WEBSERVER_REALTIME_COLLABORATION.RTC_MAX_NUMBER_OF_USERS is None:
1776+
locked = False
1777+
else:
1778+
locked = (
1779+
len(user_sessions_with_project)
1780+
>= app_settings.WEBSERVER_REALTIME_COLLABORATION.RTC_MAX_NUMBER_OF_USERS
1781+
)
1782+
17571783
return ProjectShareState(
17581784
status=ProjectStatus.OPENED,
1759-
locked=bool(app_settings.WEBSERVER_REALTIME_COLLABORATION is None),
1785+
locked=locked,
17601786
current_user_groupids=await limited_gather(
17611787
*[
17621788
users_service.get_user_primary_group_id(app, user_id=uid)
1763-
for uid in set_user_ids
1789+
for uid in active_user_ids
17641790
],
17651791
limit=10,
17661792
),

services/web/server/tests/unit/with_dbs/02/test_projects_states_handlers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,7 +1501,7 @@ async def test_open_shared_project_multiple_users(
15011501
other_users: list[
15021502
tuple[UserInfoDict, TestClient, str, socketio.AsyncClient, _SocketHandlers]
15031503
] = []
1504-
for _ in range(1, max_number_of_user_sessions):
1504+
for user_session in range(1, max_number_of_user_sessions):
15051505
client_i = client_on_running_server_factory()
15061506

15071507
# user i logs in
@@ -1521,7 +1521,7 @@ async def test_open_shared_project_multiple_users(
15211521
opened_project_state = opened_project_state.model_copy(
15221522
update={
15231523
"share_state": ProjectShareStateOutputSchema(
1524-
locked=False,
1524+
locked=(not user_session < max_number_of_user_sessions - 1),
15251525
status=ProjectStatus.OPENED,
15261526
current_user_groupids=[
15271527
*opened_project_state.share_state.current_user_groupids,

0 commit comments

Comments
 (0)