unrhodecode/rhodecode/apps/channelstream/views.py
2025-01-13 17:47:37 +01:00

169 lines
6.5 KiB
Python

# Copyright (C) 2010-2024 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import logging
import uuid
from pyramid.httpexceptions import HTTPBadRequest, HTTPForbidden, HTTPBadGateway
from rhodecode.apps._base import BaseAppView
from rhodecode.lib.channelstream import (
channelstream_request,
get_channelstream_server_url,
ChannelstreamConnectionException,
ChannelstreamPermissionException,
check_channel_permissions,
get_connection_validators,
get_user_data,
parse_channels_info,
update_history_from_logs,
USER_STATE_PUBLIC_KEYS,
)
from rhodecode.lib.auth import NotAnonymous
log = logging.getLogger(__name__)
class ChannelstreamView(BaseAppView):
def load_default_context(self):
c = self._get_local_tmpl_context()
self.channelstream_config = self.request.registry.rhodecode_plugins["channelstream"]
if not self.channelstream_config.get("enabled"):
log.warning("Channelstream plugin is disabled")
raise HTTPBadRequest()
return c
@NotAnonymous()
def channelstream_connect(self):
"""handle authorization of users trying to connect"""
self.load_default_context()
try:
json_body = self.request.json_body
except Exception:
log.exception("Failed to decode json from request")
raise HTTPBadRequest()
try:
channels = check_channel_permissions(
json_body.get("channels"), get_connection_validators(self.request.registry)
)
except ChannelstreamPermissionException:
log.error("Incorrect permissions for requested channels")
raise HTTPForbidden()
user = self._rhodecode_user
if user.user_id:
user_data = get_user_data(user.user_id)
else:
user_data = {
"id": None,
"username": None,
"first_name": None,
"last_name": None,
"icon_link": None,
"display_name": None,
"display_link": None,
}
# user_data['permissions'] = self._rhodecode_user.permissions_safe
payload = {
"username": user.username,
"user_state": user_data,
"conn_id": str(uuid.uuid4()),
"channels": channels,
"channel_configs": {},
"state_public_keys": USER_STATE_PUBLIC_KEYS,
"info": {"exclude_channels": ["broadcast"]},
}
filtered_channels = [channel for channel in channels if channel != "broadcast"]
for channel in filtered_channels:
payload["channel_configs"][channel] = {
"notify_presence": True,
"history_size": 100,
"store_history": True,
"broadcast_presence_with_user_lists": True,
}
# connect user to server
channelstream_url = get_channelstream_server_url(self.channelstream_config, "/connect")
try:
connect_result = channelstream_request(self.channelstream_config, payload, "/connect")
except ChannelstreamConnectionException:
log.exception(f"Channelstream service at {channelstream_url} is down")
return HTTPBadGateway()
channel_info = connect_result.get("channels_info")
if not channel_info:
raise HTTPBadRequest()
connect_result["channels"] = channels
connect_result["channels_info"] = parse_channels_info(channel_info, include_channel_info=filtered_channels)
update_history_from_logs(self.channelstream_config, filtered_channels, connect_result)
return connect_result
@NotAnonymous()
def channelstream_subscribe(self):
"""can be used to subscribe specific connection to other channels"""
self.load_default_context()
try:
json_body = self.request.json_body
except Exception:
log.exception("Failed to decode json from request")
raise HTTPBadRequest()
try:
channels = check_channel_permissions(
json_body.get("channels"), get_connection_validators(self.request.registry)
)
except ChannelstreamPermissionException:
log.error("Incorrect permissions for requested channels")
raise HTTPForbidden()
payload = {
"conn_id": json_body.get("conn_id", ""),
"channels": channels,
"channel_configs": {},
"info": {"exclude_channels": ["broadcast"]},
}
filtered_channels = [chan for chan in channels if chan != "broadcast"]
for channel in filtered_channels:
payload["channel_configs"][channel] = {
"notify_presence": True,
"history_size": 100,
"store_history": True,
"broadcast_presence_with_user_lists": True,
}
channelstream_url = get_channelstream_server_url(self.channelstream_config, "/subscribe")
try:
connect_result = channelstream_request(self.channelstream_config, payload, "/subscribe")
except ChannelstreamConnectionException:
log.exception(f"Channelstream service at {channelstream_url} is down")
return HTTPBadGateway()
channel_info = connect_result.get("channels_info")
if not channel_info:
raise HTTPBadRequest()
# include_channel_info will limit history only to new channel
# to not overwrite histories on other channels in client
connect_result["channels_info"] = parse_channels_info(channel_info, include_channel_info=filtered_channels)
update_history_from_logs(self.channelstream_config, filtered_channels, connect_result)
return connect_result