Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/im/lib/controller/ |
Upload File : |
<?php namespace Bitrix\Im\Controller; use Bitrix\Call\NotifyService; use Bitrix\Im\Call\CallUser; use Bitrix\Im\Call\Integration\EntityType; use Bitrix\Im\Call\Registry; use Bitrix\Im\Call\Util; use Bitrix\Im\Common; use Bitrix\Im\V2\Call\CallFactory; use Bitrix\Im\V2\Chat\ChatFactory; use Bitrix\Main\Application; use Bitrix\Main\Engine; use Bitrix\Main\Error; use Bitrix\Main\Loader; use Bitrix\Main\Type\DateTime; use Bitrix\Main\Localization\Loc; use Bitrix\Call\Settings; use Bitrix\Call\Integration\AI\CallAISettings; class Call extends Engine\Controller { protected const LOCK_TTL = 10; // in seconds /** * @restMethod im.call.create * @param int $type * @param string $provider * @param string $entityType * @param string $entityId * @param bool $joinExisting * @return array|null * */ public function createAction(int $type, string $provider, string $entityType, string $entityId, bool $joinExisting = false): ?array { Loader::includeModule('call'); $currentUserId = $this->getCurrentUser()->getId(); $call = null; $lockName = static::getLockNameWithEntityId($entityType, $entityId, $currentUserId); if (!Application::getConnection()->lock($lockName, 3)) { if ($joinExisting) { $call = CallFactory::searchActive($type, $provider, $entityType, $entityId); } if (!$call) { $this->addError(new Error("Could not get exclusive lock", "could_not_lock")); return null; } } if (!$call && $joinExisting) { $call = CallFactory::searchActive($type, $provider, $entityType, $entityId); } if (!$call && ($provider == \Bitrix\Im\Call\Call::PROVIDER_PLAIN)) { $opponentActiveCalls = CallFactory::getUserActiveCalls((int)$entityId); if (!empty($opponentActiveCalls)) { $chat = ChatFactory::getInstance()->getPrivateChat($currentUserId, (int)$entityId); if ($chat->getId() > 0) { $notifyService = NotifyService::getInstance(); $notifyService->sendOpponentBusyMessage($currentUserId, (int)$entityId); } $this->addError(new Error('User is currently busy on another call', 'user_is_busy')); Application::getConnection()->unlock($lockName); return null; } } $isNew = false; try { if ($call) { if ($call->hasErrors()) { $this->addErrors($call->getErrors()); Application::getConnection()->unlock($lockName); return null; } if (!$call->getAssociatedEntity()->checkAccess($currentUserId)) { if ($call instanceof \Bitrix\Call\Call\PlainCall) { $chat = ChatFactory::getInstance()->getPrivateChat($currentUserId, (int)$entityId); if ($chat->getId() > 0) { $notifyService = NotifyService::getInstance(); $notifyService->sendOpponentBusyMessage($currentUserId, (int)$entityId); } $this->addError(new Error('User is currently busy on another call', 'user_is_busy')); Application::getConnection()->unlock($lockName); return null; } $this->addError(new Error('You can not access this call', 'access_denied')); Application::getConnection()->unlock($lockName); return null; } if (!$call->hasUser($currentUserId)) { $addedUser = $call->addUser($currentUserId); if (!$addedUser) { $this->addError(new Error("User limit reached", "user_limit_reached")); Application::getConnection()->unlock($lockName); return null; } } } else { $isNew = true; try { $call = CallFactory::createWithEntity( type: $type, provider: $provider, entityType: $entityType, entityId: $entityId, initiatorId: $currentUserId, scheme: \Bitrix\Im\Call\Call::SCHEME_CLASSIC, ); } catch (\Throwable $e) { $this->addError(new Error($e->getMessage(), $e->getCode())); Application::getConnection()->unlock($lockName); return null; } if ($call->hasErrors()) { $this->addErrors($call->getErrors()); Application::getConnection()->unlock($lockName); return null; } if (!$call->getAssociatedEntity()->canStartCall($currentUserId)) { $this->addError(new Error("You can not create this call", 'access_denied')); Application::getConnection()->unlock($lockName); return null; } $initiator = $call->getUser($currentUserId); $initiator->update([ 'STATE' => CallUser::STATE_READY, 'LAST_SEEN' => new DateTime(), 'FIRST_JOINED' => new DateTime() ]); } } catch(\Exception $e) { $this->addError(new Error( "Can't initiate a call. Server error. (" . ($status ?? "") . ")", "call_init_error") ); Application::getConnection()->unlock($lockName); return null; } Application::getConnection()->unlock($lockName); return $this->formatCallResponse($call, 0, $isNew); } /** * @param \Bitrix\Im\Call\Call $call * @param bool $isNew * @return array{call: array, connectionData: array, users: array, userData: array, publicChannels: array, logToken: string, isNew: bool} */ protected function formatCallResponse(\Bitrix\Im\Call\Call $call, int $initiatorId = 0, bool $isNew = false): array { $currentUserId = $this->getCurrentUser()->getId(); $users = $call->getUsers(); $publicChannels = Loader::includeModule('pull') ? \Bitrix\Pull\Channel::getPublicIds([ 'TYPE' => \CPullChannel::TYPE_PRIVATE, 'USERS' => $users, 'JSON' => true ]) : [] ; $response = [ 'call' => $call->toArray($initiatorId), 'connectionData' => $call->getConnectionData($currentUserId), 'users' => $users, 'userData' => $call->prepareUserData($users), 'publicChannels' => $publicChannels, 'logToken' => $call->getLogToken($currentUserId), ]; if ($isNew) { $response['isNew'] = $isNew; } if (Settings::isAIServiceEnabled()) { $response['ai'] = [ 'serviceEnabled' => Settings::isAIServiceEnabled(), 'settingsEnabled' => CallAISettings::isEnableBySettings(), 'recordingMinUsers' => CallAISettings::getRecordMinUsers(), 'agreementAccepted' => CallAISettings::isAgreementAccepted(), 'tariffAvailable' => CallAISettings::isTariffAvailable(), 'baasAvailable' => CallAISettings::isBaasServiceHasPackage(), ]; } return $response; } /** * @restMethod im.call.createChild * @param int $parentId * @param string $newProvider * @param int[] $newUsers * @return array|null */ public function createChildCallAction(int $parentId, string $newProvider, array $newUsers): ?array { $parentCall = Registry::getCallWithId($parentId); if (!$parentCall) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($parentCall, $currentUserId)) { $this->addError(new Error("You do not have access to the parent call", "access_denied")); return null; } $childCall = $parentCall->makeClone($newProvider); if ($childCall->hasErrors()) { $this->addErrors($childCall->getErrors()); return null; } $initiator = $childCall->getUser($currentUserId); $initiator->updateState(CallUser::STATE_READY); $initiator->updateLastSeen(new DateTime()); foreach ($newUsers as $userId) { if (!$childCall->hasUser($userId)) { $childCall->addUser($userId)?->updateState(CallUser::STATE_CALLING); } } $users = $childCall->getUsers(); return [ 'call' => $childCall->toArray(), 'connectionData' => $childCall->getConnectionData($currentUserId), 'users' => $users, 'userData' => $childCall->prepareUserData($users), 'logToken' => $childCall->getLogToken($currentUserId) ]; } /** * @restMethod im.call.tryJoinCall * @param int $type * @param string $provider * @param string $entityType * @param string $entityId * @return array|null */ public function tryJoinCallAction($type, $provider, $entityType, $entityId): ?array { $call = CallFactory::searchActive($type, $provider, $entityType, $entityId); if (!$call) { return ['success' => false]; } if ($call->hasErrors()) { $this->addErrors($call->getErrors()); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$call->getAssociatedEntity()->checkAccess($currentUserId)) { $this->addError(new Error("You can not access this call", 'access_denied')); return null; } if (!$call->hasUser($currentUserId)) { $addedUser = $call->addUser($currentUserId); if (!$addedUser) { $this->addError(new Error("User limit reached", "user_limit_reached")); return null; } $call->getSignaling()->sendUsersJoined($currentUserId, [$currentUserId]); } return array_merge( ['success' => true], $this->formatCallResponse($call) ); } /** * @restMethod im.call.interrupt * @param int $callId * @return array|null */ public function interruptAction(int $callId): ?array { $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { $this->addError(new Error("You do not have access to the parent call", "access_denied")); return null; } $call->setActionUserId($currentUserId)->finish(); return [ 'call' => $call->toArray($currentUserId), 'connectionData' => $call->getConnectionData($currentUserId), 'logToken' => $call->getLogToken($currentUserId) ]; } /** * @restMethod im.call.get * @param int $callId * @return array|null */ public function getAction(int $callId): ?array { $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { $this->addError(new Error("You do not have access to the parent call", "access_denied")); return null; } return $this->formatCallResponse($call, $currentUserId); } /** * @restMethod im.call.invite * @param int $callId * @param int[] $userIds * @param string $video * @param string $show * @param string $legacyMobile * @param string $repeated * @return true|null */ public function inviteAction(int $callId, array $userIds, $video = "N", $show = "Y", $legacyMobile = "N", $repeated = "N"): ?bool { $isVideo = ($video === "Y"); $isShow = ($show === "Y"); $isLegacyMobile = ($legacyMobile === "Y"); $isRepeated = ($repeated === "Y"); $userIds = array_map('intVal', $userIds); $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { return null; } if ($call->hasErrors()) { $this->addErrors($call->getErrors()); return null; } $call->getUser($currentUserId)->update([ 'LAST_SEEN' => new DateTime(), 'IS_MOBILE' => ($isLegacyMobile ? 'Y' : 'N') ]); $lockName = static::getLockNameWithCallId('invite', $callId); if (!Application::getConnection()->lock($lockName, static::LOCK_TTL)) { $this->addError(new Error("Could not get exclusive lock", "could_not_lock")); return null; } $this->inviteUsers($call, $userIds, $isLegacyMobile, $isVideo, $isShow, $isRepeated); Application::getConnection()->unlock($lockName); return true; } protected function inviteUsers(\Bitrix\Im\Call\Call $call, $userIds, $isLegacyMobile, $isVideo, $isShow, $isRepeated): void { $usersToInvite = []; $existingUsers = []; foreach ($userIds as $userId) { $userId = (int)$userId; if (!$userId) { continue; } if (!$call->hasUser($userId)) { if (!$call->addUser($userId)) { continue; } } else if ($isRepeated === false && $call->getAssociatedEntity()) { $existingUsers[] = $userId; } $usersToInvite[] = $userId; $callUser = $call->getUser($userId); if($callUser->getState() != CallUser::STATE_READY) { $callUser->updateState(CallUser::STATE_CALLING); } } if (!empty($existingUsers)) { $call->getAssociatedEntity()->onExistingUsersInvite($existingUsers); } if (count($usersToInvite) === 0) { $this->addError(new Error("No users to invite", "empty_users")); return; } $sendPush = $isRepeated !== true; // send invite to the ones being invited. $call->inviteUsers( $this->getCurrentUser()->getId(), $usersToInvite, $isLegacyMobile, $isVideo, $sendPush ); // send userInvited to everyone else. $allUsers = $call->getUsers(); $otherUsers = array_diff($allUsers, $userIds); $call->getSignaling()->sendUsersInvited( $this->getCurrentUser()->getId(), $otherUsers, $usersToInvite, $isShow ); if ($call->getState() === \Bitrix\Im\Call\Call::STATE_NEW) { $call->updateState(\Bitrix\Im\Call\Call::STATE_INVITING); } } /** * @restMethod im.call.cancel * @param int $callId * @return void|null */ public function cancelAction(int $callId) { $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { return null; } } /** * @restMethod im.call.answer * @param int $callId * @param int $callInstanceId * @param string $legacyMobile * @return void|null */ public function answerAction(int $callId, $callInstanceId, $legacyMobile = "N") { $isLegacyMobile = $legacyMobile === "Y"; $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { return null; } $callUser = $call->getUser($currentUserId); if ($callUser) { $lockName = static::getLockNameWithCallId('user'.$currentUserId, $callId); if (!Application::getConnection()->lock($lockName, static::LOCK_TTL)) { $this->addError(new Error("Could not get exclusive lock", "could_not_lock")); return null; } $callUser->update([ 'STATE' => CallUser::STATE_READY, 'LAST_SEEN' => new DateTime(), 'FIRST_JOINED' => $callUser->getFirstJoined() ?: new DateTime(), 'IS_MOBILE' => $isLegacyMobile ? 'Y' : 'N', ]); Application::getConnection()->unlock($lockName); } $call->getSignaling()->sendAnswer($currentUserId, $callInstanceId, $isLegacyMobile); } /** * @restMethod im.call.decline * @param int $callId * @param int $callInstanceId * @param int $code * @return void|null */ public function declineAction(int $callId, $callInstanceId, int $code = 603) { $currentUserId = $this->getCurrentUser()->getId(); $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } if (!$this->checkCallAccess($call, $currentUserId)) { return null; } $callUser = $call->getUser($currentUserId); if (!$callUser) { $this->addError(new Error("User is not part of the call", "unknown_call_user")); return null; } if ($callUser->getState() === CallUser::STATE_READY) { $this->addError(new Error("Can not decline in {$callUser->getState()} user state", "wrong_user_state")); return null; } $lockName = static::getLockNameWithCallId('user'.$currentUserId, $callId); if (!Application::getConnection()->lock($lockName, static::LOCK_TTL)) { $this->addError(new Error("Could not get exclusive lock", "could_not_lock")); return null; } if ($code === 486) { $callUser->updateState(CallUser::STATE_BUSY); } else { $callUser->updateState(CallUser::STATE_DECLINED); } $callUser->updateLastSeen(new DateTime()); Application::getConnection()->unlock($lockName); $userIds = $call->getUsers(); $call->getSignaling()->sendHangup($currentUserId, $userIds, $callInstanceId, $code); if (!$call->hasActiveUsers()) { $call->setActionUserId($currentUserId)->finish(); } } /** * @restMethod im.call.ping * @param int $callId * @param int $requestId * @param bool $retransmit * @return bool */ public function pingAction(int $callId, $requestId, $retransmit = true) { $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { return null; } $callUser = $call->getUser($currentUserId); if ($callUser) { $callUser->updateLastSeen(new DateTime()); if ($callUser->getState() == CallUser::STATE_UNAVAILABLE) { $callUser->updateState(CallUser::STATE_IDLE); } } if ( is_bool($retransmit) && $retransmit===true || is_string($retransmit) && in_array($retransmit, ['true', 'Y', '1'], true) ) { $call->getSignaling()->sendPing($currentUserId, $requestId); } return true; } /** * @restMethod im.call.onShareScreen * @param int $callId * @return void|null */ public function onShareScreenAction(int $callId) { $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { return null; } $callUser = $call->getUser($currentUserId); if ($callUser) { $callUser->update([ 'SHARED_SCREEN' => 'Y' ]); } } /** * @restMethod im.call.onStartRecord * @param int $callId * @return void|null */ public function onStartRecordAction(int $callId) { $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { return null; } $callUser = $call->getUser($currentUserId); if ($callUser) { $callUser->update([ 'RECORDED' => 'Y' ]); } } /** * @restMethod im.call.negotiationNeeded * @param int $callId * @param int $userId * @param bool $restart * @return void|null */ public function negotiationNeededAction(int $callId, int $userId, $restart = false) { $restart = (bool)$restart; $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { return null; } $callUser = $call->getUser($currentUserId); if ($callUser) { $callUser->updateLastSeen(new DateTime()); } $call->getSignaling()->sendNegotiationNeeded($currentUserId, $userId, $restart); } /** * @restMethod im.call.connectionOffer * @param int $callId * @param int $userId * @param int $connectionId * @param string $sdp * @param string $userAgent * @return void|null */ public function connectionOfferAction(int $callId, int $userId, $connectionId, $sdp, $userAgent) { $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { return null; } $callUser = $call->getUser($currentUserId); if ($callUser) { $callUser->updateLastSeen(new DateTime()); } $call->getSignaling()->sendConnectionOffer($currentUserId, $userId, $connectionId, $sdp, $userAgent); } /** * @restMethod im.call.connectionAnswer * @param int $callId * @param int $userId * @param int $connectionId * @param string $sdp * @param string $userAgent * @return void|null */ public function connectionAnswerAction(int $callId, int $userId, $connectionId, $sdp, $userAgent) { $currentUserId = $this->getCurrentUser()->getId(); $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } if (!$this->checkCallAccess($call, $currentUserId)) { return null; } $callUser = $call->getUser($currentUserId); if ($callUser) { $callUser->updateLastSeen(new DateTime()); } $call->getSignaling()->sendConnectionAnswer($currentUserId, $userId, $connectionId, $sdp, $userAgent); } /** * @restMethod im.call.iceCandidate * @param int $callId * @param int $userId * @param int $connectionId * @param array $candidates * @return void|null */ public function iceCandidateAction(int $callId, int $userId, $connectionId, array $candidates) { // mobile can alter key order, so we recover it ksort($candidates); $currentUserId = $this->getCurrentUser()->getId(); $call = Registry::getCallWithId($callId); if (!$this->checkCallAccess($call, $currentUserId)) { return null; } $callUser = $call->getUser($currentUserId); if ($callUser) { $callUser->updateLastSeen(new DateTime()); } $call->getSignaling()->sendIceCandidates($currentUserId, $userId, $connectionId, $candidates); } /** * @restMethod im.call.hangup * @param int $callId * @param int $callInstanceId * @param bool $retransmit * @return void|null */ public function hangupAction(int $callId, $callInstanceId, $retransmit = true) { $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { return null; } $lockName = static::getLockNameWithCallId('user'.$currentUserId, $callId); if (!Application::getConnection()->lock($lockName, static::LOCK_TTL)) { $this->addError(new Error("Could not get exclusive lock", "could_not_lock")); return null; } $callUser = $call->getUser($currentUserId); if ($callUser) { $callUser->updateState(CallUser::STATE_IDLE); $callUser->updateLastSeen(new DateTime()); } if ( is_bool($retransmit) && $retransmit===true || is_string($retransmit) && in_array($retransmit, ['true', 'Y', '1'], true) ) { $userIds = $call->getUsers(); $call->getSignaling()->sendHangup($currentUserId, $userIds, $callInstanceId); } Application::getConnection()->unlock($lockName); if (!$call->hasActiveUsers()) { $call->setActionUserId($currentUserId)->finish(); } } /** * @restMethod im.call.finish * @param int $callId * @return void|null */ public function finishAction(int $callId): ?array { $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { $this->addError(new Error("You do not have access to the parent call", "access_denied")); return null; } $call->setActionUserId($currentUserId)->finish(); return [ 'call' => $call->toArray($currentUserId), 'connectionData' => $call->getConnectionData($currentUserId), 'logToken' => $call->getLogToken($currentUserId) ]; } /** * @restMethod im.call.getUsers * @param int $callId * @param int[] $userIds * @return null|array */ public function getUsersAction(int $callId, array $userIds = []) { $call = Registry::getCallWithId($callId); if (!$call) { $this->addError(new Error(Loc::getMessage("IM_REST_CALL_ERROR_CALL_NOT_FOUND"), "call_not_found")); return null; } $currentUserId = $this->getCurrentUser()->getId(); if (!$this->checkCallAccess($call, $currentUserId)) { $this->addError(new Error("You do not have access to the call", "access_denied")); return null; } if (empty($userIds)) { $allowedUserIds = $call->getUsers(); } else { $allowedUserIds = array_filter($userIds, function($userId) use ($call, $currentUserId) { return $userId == $currentUserId || $call->hasUser($userId); }); } if (empty($allowedUserIds)) { $this->addError(new Error("Users are not part of the call", "access_denied")); return null; } return $call->prepareUserData($allowedUserIds); } /** * @restMethod im.call.getUserState * @param int $callId * @param int $userId * @return null|array */ public function getUserStateAction(int $callId, int $userId = 0) { $currentUserId = (int)$this->getCurrentUser()->getId(); $call = Registry::getCallWithId($callId); if (!$call || !$this->checkCallAccess($call, $currentUserId)) { $this->addError(new Error("Call is not found or you do not have access to the call", "access_denied")); return null; } if ($userId === 0) { $userId = $currentUserId; } $callUser = $call->getUser($userId); if (!$callUser) { $this->addError(new Error("User is not part of the call", "unknown_call_user")); return null; } return $callUser->toArray(); } /** * @restMethod im.call.getCallLimits * @return array */ public function getCallLimitsAction(): array { return [ 'callServerEnabled' => \Bitrix\Im\Call\Call::isCallServerEnabled(), 'maxParticipants' => \Bitrix\Im\Call\Call::getMaxParticipants(), ]; } /** * @restMethod im.call.reportConnectionStatus * @param int $callId * @param bool $connectionStatus * @return void */ public function reportConnectionStatusAction(int $callId, bool $connectionStatus): void { AddEventToStatFile('im', 'call_connection', $callId, ($connectionStatus ? 'Y' : 'N')); } protected function checkCallAccess(\Bitrix\Im\Call\Call $call, $userId) { if (!$call->checkAccess($userId)) { $this->addError(new Error("You don't have access to the call " . $call->getId() . "; (current user id: " . $userId . ")", 'access_denied')); return false; } return true; } protected static function getLockNameWithEntityId(string $entityType, $entityId, $currentUserId): string { if ($entityType === EntityType::CHAT && (Common::isChatId($entityId) || (int)$entityId > 0)) { $chatId = \Bitrix\Im\Dialog::getChatId($entityId, $currentUserId); return "call_entity_{$entityType}_{$chatId}"; } return "call_entity_{$entityType}_{$entityId}"; } protected static function getLockNameWithCallId(string $prefix, $callId): string { //TODO: int|string after switching to php 8 if (is_string($callId) || is_numeric($callId)) { return "{$prefix}_call_{$callId}"; } return ''; } public function configureActions(): array { return [ 'getUsers' => [ '+prefilters' => [new Engine\ActionFilter\CloseSession()], ], 'reportConnectionStatus' => [ '+prefilters' => [new Engine\ActionFilter\CloseSession()], ], ]; } }