package im.rosetta.executors; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.UUID; import im.rosetta.Failures; import im.rosetta.client.ClientManager; import im.rosetta.client.tags.ECIAuthentificate; import im.rosetta.packet.Packet26SignalPeer; import im.rosetta.packet.runtime.NetworkSignalType; import im.rosetta.service.dispatch.push.PushNotifyDispatcher; import im.rosetta.service.dispatch.runtime.PushType; import im.rosetta.service.services.ForwardUnitService; import io.g365sfu.Room; import io.orprotocol.ProtocolException; import io.orprotocol.client.Client; import io.orprotocol.packet.PacketExecutor; /** * Используется в Peer To Peer звонках, в групповых звонках другой сигналинг */ public class Executor26SignalPeer extends PacketExecutor { private ClientManager clientManager; private ForwardUnitService fus; private PushNotifyDispatcher pushNotifyDispatcher = new PushNotifyDispatcher(); /** * Сигналы, которые может выполнять только авторизованный пользователь, * все сигналы, которые не входят в этот перечень, будут доступны для * исполнения без авторизации. */ private Set authentificatedTypes = new HashSet<>(){{ add(NetworkSignalType.CALL); /** * Так как комнату создает звонящий, то комнату может создать только * авторизованный пользователь */ add(NetworkSignalType.CREATE_ROOM); }}; public Executor26SignalPeer(ClientManager clientManager, ForwardUnitService fus) { this.clientManager = clientManager; this.fus = fus; } @Override public void onPacketReceived(Packet26SignalPeer packet, Client client) throws Exception, ProtocolException { String src = packet.getSrc(); String dst = packet.getDst(); ECIAuthentificate eciAuthentificate = client.getTag(ECIAuthentificate.class); NetworkSignalType type = packet.getSignalType(); if ((eciAuthentificate == null || !eciAuthentificate.hasAuthorized()) && this.authentificatedTypes.contains(type)) { /** * Если клиент не авторизован, то мы не будем обрабатывать его сигналы на инициализацию звонка и создание комнаты * и просто отключим его от сервера. */ client.disconnect(Failures.HANDSHAKE_NOT_COMPLETED); return; } if(!src.equals(eciAuthentificate.getPublicKey()) && authentificatedTypes.contains(type)) { /** * Если src в пакете не совпадает с авторизованным PK клиента, то это может означать, что клиент пытается * отправить сигнал от другого пользователя, отключаем его от сервера. */ client.disconnect(Failures.DATA_MISSMATCH); return; } if(type == NetworkSignalType.CALL) { /** * Инициируется звонок от src к dst, проверяем, что dst не занят другим звонком, если занят, то отправляем сигнал END_CALL_BECAUSE_BUSY обратно src */ Room room = this.fus.getRoomByParticipantId(packet.getDst()); if(room != null) { /** * Получатель сигнала уже находится в другой комнате, значит он занят другим звонком, отправляем сигнал END_CALL_BECAUSE_BUSY обратно src */ Packet26SignalPeer responsePacket = new Packet26SignalPeer(); responsePacket.setSignalType(NetworkSignalType.END_CALL_BECAUSE_BUSY); this.clientManager.sendPacketToAuthorizedPK(packet.getSrc(), responsePacket); return; } /** * Получатель сигнала не занят, отправляем ему пуш уведомление о входящем звонке и сигнал CALL для инициализации звонка */ pushNotifyDispatcher.sendPush(dst, new HashMap<>(){{ put("type", PushType.CALL); put("dialog", src); put("callId", UUID.randomUUID().toString()); }}); } if(type == NetworkSignalType.CREATE_ROOM){ /** * Создается комната для звонка */ Room room = this.fus.createRoom(); room.addParticipant(packet.getSrc()); room.addParticipant(packet.getDst()); packet.setRoomId(room.getRoomId()); /** * Результат создания комнаты транслируем обоим участникам, чтобы они могли начать обмен WebRTC SDP, и тд */ this.clientManager.sendPacketToAuthorizedPK(packet.getSrc(), packet); this.clientManager.sendPacketToAuthorizedPK(packet.getDst(), packet); return; } this.clientManager.sendPacketToAuthorizedPK(packet.getDst(), packet); } }