diff --git a/src/main/java/im/rosetta/Boot.java b/src/main/java/im/rosetta/Boot.java index 7be744e..3b85bc3 100644 --- a/src/main/java/im/rosetta/Boot.java +++ b/src/main/java/im/rosetta/Boot.java @@ -1,5 +1,6 @@ package im.rosetta; +import im.rosetta.calls.CallManager; import im.rosetta.client.ClientManager; import im.rosetta.client.OnlineManager; import im.rosetta.event.EventManager; @@ -82,6 +83,7 @@ public class Boot { private OnlineManager onlineManager; private BufferCleanupService bufferCleanupService; private ForwardUnitService forwardUnitService; + private CallManager callManager; /** * Конструктор по умолчанию, использует порт 3000 для сервера @@ -104,7 +106,8 @@ public class Boot { port, 30 ), packetManager, this.serverAdapter); - this.clientManager = new ClientManager(server); + this.clientManager = new ClientManager(this.server); + this.callManager = new CallManager(this.clientManager); /** * Каждые сколько дней будет очищаться буфер (это влияет на синхронизацию сообщений, так * как при синхронизации клиент запрашивает пакеты из буфера за последние 7 дней, если этот параметр будет меньше, @@ -228,8 +231,8 @@ public class Boot { this.packetManager.registerExecutor(22, new Executor22GroupBan()); this.packetManager.registerExecutor(24, new Executor24DeviceResolve(this.clientManager, this.eventManager, this.packetManager)); this.packetManager.registerExecutor(25, new Executor25Sync(this.packetManager)); - this.packetManager.registerExecutor(26, new Executor26SignalPeer(this.clientManager, this.forwardUnitService)); - this.packetManager.registerExecutor(27, new Executor27WebRTC(this.forwardUnitService)); + this.packetManager.registerExecutor(26, new Executor26SignalPeer(this.clientManager, this.forwardUnitService, this.callManager)); + this.packetManager.registerExecutor(27, new Executor27WebRTC(this.callManager)); this.packetManager.registerExecutor(28, new Executor28IceServers(this.forwardUnitService)); } diff --git a/src/main/java/im/rosetta/calls/CallManager.java b/src/main/java/im/rosetta/calls/CallManager.java new file mode 100644 index 0000000..7140702 --- /dev/null +++ b/src/main/java/im/rosetta/calls/CallManager.java @@ -0,0 +1,109 @@ +package im.rosetta.calls; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import im.rosetta.client.ClientManager; +import im.rosetta.packet.Packet26SignalPeer; +import im.rosetta.packet.runtime.NetworkSignalType; +import io.orprotocol.ProtocolException; +import io.orprotocol.client.Client; +import io.orprotocol.packet.Packet; + +public class CallManager { + + private List callSessions = new ArrayList<>(); + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + private static final long RINGING_TIMEOUT = 10 * 1000; // 1 минута + private ClientManager clientManager; + + + public CallManager(ClientManager clientManager) { + this.clientManager = clientManager; + scheduler.scheduleAtFixedRate(this::cleanupCallSessions, 0, 30, TimeUnit.SECONDS); + } + + public void cleanupCallSessions() { + /** + * Такая конструкция нужна для избежания ConcurrentModificationException, + * так как мы не можем удалять элементы из списка, по которому проходим в цикле, + * поэтому мы сначала собираем сессии звонков, которые нужно удалить, а потом + * удаляем их из основного списка + */ + List sessionsToRemove = new ArrayList<>(); + for (CallSession session : this.callSessions) { + if (session.shouldRemove()) { + /** + * Отправляем всем в сессии что звонок завершился, так как он устарел, и удаляем сессию из списка активных сессий + */ + Packet26SignalPeer rtout = new Packet26SignalPeer(); + rtout.setSignalType(NetworkSignalType.RINGING_TIMEOUT); + Packet26SignalPeer endCallPacket = new Packet26SignalPeer(); + endCallPacket.setSignalType(NetworkSignalType.END_CALL); + endCallPacket.setJoinToken(session.getJoinToken()); + endCallPacket.setCallId(session.getCallId()); + + try { + session.sendPacket(rtout, null); + this.sendPacketToRinging(session, endCallPacket); + } catch (ProtocolException e) { + e.printStackTrace(); + } + sessionsToRemove.add(session); + } + } + for (CallSession session : sessionsToRemove) { + this.callSessions.remove(session); + } + } + + public CallSession createCall(String callId, String joinToken) { + CallSession session = new CallSession(callId, joinToken, RINGING_TIMEOUT); + this.callSessions.add(session); + return session; + } + + public CallSession getCallSession(String callId, String joinToken) { + for (CallSession session : this.callSessions) { + if (session.getCallId().equals(callId) && session.getJoinToken().equals(joinToken)) { + return session; + } + } + return null; + } + + public boolean isBusy(String publicKey) { + for (CallSession session : this.callSessions) { + if (session.clients.containsKey(publicKey)) { + return true; + } + if(session.ringing.containsKey(publicKey)) { + return true; + } + } + return false; + } + + public void sendPacketToRinging(CallSession session, Packet packet) throws ProtocolException { + for (String publicKey : session.ringing.keySet()) { + this.clientManager.sendPacketToAuthorizedPK(publicKey, packet); + } + } + + public CallSession getCallSession(Client client) { + for (CallSession session : this.callSessions) { + if (session.clients.containsValue(client)) { + return session; + } + } + return null; + } + + public void removeSession(CallSession session) { + this.callSessions.remove(session); + } + +} diff --git a/src/main/java/im/rosetta/calls/CallSession.java b/src/main/java/im/rosetta/calls/CallSession.java new file mode 100644 index 0000000..d15b5d9 --- /dev/null +++ b/src/main/java/im/rosetta/calls/CallSession.java @@ -0,0 +1,110 @@ +package im.rosetta.calls; + +import java.util.HashMap; + +import io.g365sfu.Room; +import io.orprotocol.ProtocolException; +import io.orprotocol.client.Client; +import io.orprotocol.packet.Packet; + +public class CallSession { + + public String callId; + public String joinToken; + public Long createdAt; + public Long ringingTimeout; + /** + * Клиенты которым сейчас идет дозвон (публичные ключи) + * Клиенты в этом списке не могут принимать другие звонки, так как они уже заняты дозвоном, + * но они еще не в звонке, так как не приняли звонок + * + * Клиенты удаляются из этого списка, когда они принимают звонок или отклоняют его, тогда они либо переходят в звонок, либо становятся свободными для других звонков + */ + public HashMap ringing; + /** + * Клиенты, которые уже приняли звонок и находятся в звонке (публичные ключи) и их сокеты + * pk -> client + */ + public HashMap clients; + /** + * Если звонок активен у него появляется комната, иначе комната null + */ + public Room room; + + + public CallSession(String callId, String joinToken, Long ringingTimeout) { + this.callId = callId; + this.joinToken = joinToken; + this.clients = new HashMap<>(); + this.ringing = new HashMap<>(); + this.createdAt = System.currentTimeMillis(); + this.ringingTimeout = ringingTimeout; + } + + public void joinCall(String publicKey, Client client) { + if(this.ringing.containsKey(publicKey)) { + this.ringing.remove(publicKey); + } + this.clients.put(publicKey, client); + } + + /** + * Получаем публичный ключ клиента по его сокету, чтобы понимать, кто отправляет сигналы в рамках звонка + * @param client Сокет клиента, для которого нужно получить публичный ключ + * @return Публичный ключ клиента, или null если клиент не найден в сессии звонка + */ + public String getPublicKey(Client client) { + for (String publicKey : this.clients.keySet()) { + if (this.clients.get(publicKey).equals(client)) { + return publicKey; + } + } + return null; + } + + public String getCallId() { + return this.callId; + } + + public String getJoinToken() { + return this.joinToken; + } + + public void addRinging(String publicKey) { + this.ringing.put(publicKey, System.currentTimeMillis()); + } + + public void setRoom(Room room) { + this.room = room; + } + + public Room getRoom() { + return this.room; + } + + /** + * Отправляем пакет всем участникам звонка, кроме исключенного клиента (обычно отправителя) + * @param packet Пакет для отправки + * @param excludeClient Клиент, которому не нужно отправлять пакет (обычно отправитель) + * @throws ProtocolException Если произошла ошибка при отправке пакета клиенту + */ + public void sendPacket(Packet packet, Client excludeClient) throws ProtocolException { + for (Client client : this.clients.values()) { + if (!client.equals(excludeClient)) { + client.send(packet); + } + } + } + + /** + * Проверяем, нужно ли удалять сессию звонка. + * Сессию звонка нужно удалять, если в ней меньше 2 клиентов и при этом нет клиентов в состоянии дозвона, + * или если сессия была создана более 1 минуты назад, так как это значит, что клиенты не ответили на звонок и он устарел + * @return true, если сессию звонка нужно удалять, false иначе + */ + public boolean shouldRemove() { + return this.clients.size() <= 1 && (this.ringing.size() == 0 || System.currentTimeMillis() - this.createdAt > this.ringingTimeout); + } + + +} diff --git a/src/main/java/im/rosetta/executors/Executor26SignalPeer.java b/src/main/java/im/rosetta/executors/Executor26SignalPeer.java index c4371f6..c7f442b 100644 --- a/src/main/java/im/rosetta/executors/Executor26SignalPeer.java +++ b/src/main/java/im/rosetta/executors/Executor26SignalPeer.java @@ -6,6 +6,8 @@ import java.util.Set; import java.util.UUID; import im.rosetta.Failures; +import im.rosetta.calls.CallManager; +import im.rosetta.calls.CallSession; import im.rosetta.client.ClientManager; import im.rosetta.client.tags.ECIAuthentificate; import im.rosetta.packet.Packet26SignalPeer; @@ -33,16 +35,18 @@ public class Executor26SignalPeer extends PacketExecutor { */ private Set authentificatedTypes = new HashSet<>(){{ add(NetworkSignalType.CALL); - /** - * Так как комнату создает звонящий, то комнату может создать только - * авторизованный пользователь - */ - add(NetworkSignalType.CREATE_ROOM); }}; - public Executor26SignalPeer(ClientManager clientManager, ForwardUnitService fus) { + /** + * Менеджер звонков, который реализует весь необхоимый функционал для управления звонками, + * например проверку занятости пользователя, и тд + */ + private CallManager callManager; + + public Executor26SignalPeer(ClientManager clientManager, ForwardUnitService fus, CallManager callManager) { this.clientManager = clientManager; this.fus = fus; + this.callManager = callManager; } @Override @@ -72,42 +76,123 @@ public class Executor26SignalPeer extends PacketExecutor { /** * Инициируется звонок от src к dst, проверяем, что dst не занят другим звонком, если занят, то отправляем сигнал END_CALL_BECAUSE_BUSY обратно src */ - Room room = this.fus.getRoomByParticipantId(packet.getDst()); - if(room != null) { + if(this.callManager.isBusy(dst) || this.callManager.isBusy(src)) { /** * Получатель сигнала уже находится в другой комнате, значит он занят другим звонком, отправляем сигнал END_CALL_BECAUSE_BUSY обратно src */ Packet26SignalPeer responsePacket = new Packet26SignalPeer(); responsePacket.setSignalType(NetworkSignalType.END_CALL_BECAUSE_BUSY); - this.clientManager.sendPacketToAuthorizedPK(packet.getSrc(), responsePacket); + client.send(responsePacket); return; } + /** + * Генерируем CallID и JoinToken + */ + String callId = UUID.randomUUID().toString(); + String joinToken = UUID.randomUUID().toString(); + packet.setJoinToken(joinToken); + packet.setCallId(callId); + /** + * Создаем сессию звонка и добавляем в нее звонящего + */ + CallSession session = this.callManager.createCall(callId, joinToken); + session.joinCall(src, client); + /** + * Добавляем dst в ringing, чтобы пометить, что ему поступает звонок + */ + session.addRinging(dst); /** * Получатель сигнала не занят, отправляем ему пуш уведомление о входящем звонке и сигнал CALL для инициализации звонка */ pushNotifyDispatcher.sendPush(dst, new HashMap<>(){{ put("type", PushType.CALL); put("dialog", src); - put("callId", UUID.randomUUID().toString()); + put("callId", callId); + put("joinToken", joinToken); }}); - } - if(type == NetworkSignalType.CREATE_ROOM){ /** - * Создается комната для звонка + * Отправляем сигнал CALL всем авторизованным устройствам вызываемого абонента */ - 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); + this.clientManager.sendPacketToAuthorizedPK(dst, packet); return; } - - this.clientManager.sendPacketToAuthorizedPK(packet.getDst(), packet); + if(type == NetworkSignalType.ACCEPT){ + String callId = packet.getCallId(); + String joinToken = packet.getJoinToken(); + CallSession session = this.callManager.getCallSession(callId, joinToken); + if(session == null) { + /** + * Сессии звонка нет + */ + client.disconnect(Failures.DATA_MISSMATCH); + return; + } + Room room = this.fus.createRoom(); + session.setRoom(room); + session.joinCall(src, client); + for(String participant : session.clients.keySet()) { + room.addParticipant(participant); + } + session.sendPacket(packet, client); + return; + } + if(type == NetworkSignalType.KEY_EXCHANGE){ + /** + * Ретранслируем ключи в рамках сессии + */ + CallSession session = this.callManager.getCallSession(client); + if(session == null) { + /** + * Сессии звонка нет + */ + client.disconnect(Failures.DATA_MISSMATCH); + return; + } + /** + * Обмениваемся ключами в рамках сессии, ретранслируя их всем участникам сессии, кроме отправителя + */ + session.sendPacket(packet, client); + return; + } + if(type == NetworkSignalType.END_CALL) { + /** + * Ретранслируем сигнал окончания звонка всем участникам сессии, кроме отправителя, и удаляем сессию + */ + /** + * Сначала получаем сессию по сокету отправителя пакета, если не находим, то пробуем найти сессию по callId и joinToken из пакета, если не находим, + * то отключаем клиента от сервера, так как он отправляет некорректные данные + */ + CallSession session = this.callManager.getCallSession(client); + if(session == null) { + String callId = packet.getCallId(); + String joinToken = packet.getJoinToken(); + session = this.callManager.getCallSession(callId, joinToken); + } + if(session == null) { + /** + * Сессии звонка нет + */ + client.disconnect(Failures.DATA_MISSMATCH); + return; + } + session.sendPacket(packet, client); + this.callManager.removeSession(session); + return; + } + if(type == NetworkSignalType.ACTIVE) { + /** + * Клиент сообщил, что прошел стадию обмена ключами и звонок активен + */ + CallSession session = this.callManager.getCallSession(client); + if(session == null) { + /** + * Сессии звонка нет + */ + client.disconnect(Failures.DATA_MISSMATCH); + return; + } + session.sendPacket(packet, null); + } } } diff --git a/src/main/java/im/rosetta/executors/Executor27WebRTC.java b/src/main/java/im/rosetta/executors/Executor27WebRTC.java index c3572df..6fbeafe 100644 --- a/src/main/java/im/rosetta/executors/Executor27WebRTC.java +++ b/src/main/java/im/rosetta/executors/Executor27WebRTC.java @@ -1,13 +1,10 @@ package im.rosetta.executors; -import java.util.HashSet; - import im.rosetta.Failures; -import im.rosetta.database.repository.DeviceRepository; +import im.rosetta.calls.CallManager; +import im.rosetta.calls.CallSession; import im.rosetta.packet.Packet27WebRTC; import im.rosetta.packet.runtime.NetworkWebRTCType; -import im.rosetta.service.services.DeviceService; -import im.rosetta.service.services.ForwardUnitService; import io.g365sfu.Room; import io.orprotocol.ProtocolException; import io.orprotocol.client.Client; @@ -15,38 +12,45 @@ import io.orprotocol.packet.PacketExecutor; public class Executor27WebRTC extends PacketExecutor { - private ForwardUnitService fus; - private final DeviceRepository deviceRepository = new DeviceRepository(); - private final DeviceService deviceService = new DeviceService(deviceRepository); + private CallManager callManager; - public Executor27WebRTC(ForwardUnitService fus) { - this.fus = fus; + public Executor27WebRTC(CallManager callManager) { + this.callManager = callManager; } @Override public void onPacketReceived(Packet27WebRTC packet, Client client) throws Exception, ProtocolException { - String publicKey = packet.getPublicKey(); - String deviceId = packet.getDeviceId(); - - HashSet publicKeys = this.deviceService.getPublicKeysByDeviceId(deviceId); - if(!publicKeys.contains(publicKey)) { + /** + * Получаем, в какой сессии находится этот сокет + */ + CallSession session = this.callManager.getCallSession(client); + if(session == null) { /** - * Если публичный ключ, который отправил пакет, не связан с deviceId, с которого был отправлен пакет, то отключаем клиента от сервера, так как это может быть попыткой подделки пакета + * Если сессия не найдена, то мы не будем обрабатывать сигналы для звонка + * и просто отключим клиента от сервера. */ client.disconnect(Failures.DATA_MISSMATCH); return; } - - /** - * Так как в комнатах Participants это публичные ключи пользователей, то мы можем - * найти комнату, в которой находится пользователь, по его публичному ключу - */ - Room room = this.fus.getRoomByParticipantId(publicKey); - + Room room = session.getRoom(); if(room == null) { /** - * Если комната не найдена, то мы не будем обрабатывать сигналы для звонка - * и просто отключим клиента от сервера. + * Звонок еще не активен, а значит комнаты еще нет. Нельзя обменяться WebRTC сигналами пока комнаты еще нет. + */ + client.disconnect(Failures.DATA_MISSMATCH); + return; + } + /** + * Получаем публичный ключ, которым представился клиент, в рамках сессии звонка. + * Мы не делаем это через ECIAuthentificate, так как в рамках звонка клиент может не быть авторизован, но при этом он уже находится в сессии звонка, и мы можем идентифицировать его по публичному ключу, + * который он указал при присоединении к звонку используя joinToken. + * Так что, несмотря на то, что клиент может быть не авторизован, мы все равно можем достоверно знать его публичный ключ + */ + String publicKey = session.getPublicKey(client); + if(publicKey == null) { + /** + * Избыточная проверка, так как если клиент находится в сессии, то он должен быть в списке клиентов сессии, + * но на всякий случай проверим это, чтобы избежать возможных ошибок */ client.disconnect(Failures.DATA_MISSMATCH); return; diff --git a/src/main/java/im/rosetta/packet/Packet26SignalPeer.java b/src/main/java/im/rosetta/packet/Packet26SignalPeer.java index ffb37a1..bd58e30 100644 --- a/src/main/java/im/rosetta/packet/Packet26SignalPeer.java +++ b/src/main/java/im/rosetta/packet/Packet26SignalPeer.java @@ -29,16 +29,18 @@ public class Packet26SignalPeer extends Packet { * Тип сигнала */ private NetworkSignalType signalType; - /** - * Идентификатор комнаты, в которой происходит звонок, заполняется если тип сигнала CREATE_ROOM, иначе null + * callId и joinToken нужны для того, чтобы идентифицировать сессию звонка. Так как roomId это только ID комнаты на sfu */ - private String roomId; + private String callId; + private String joinToken; @Override public void read(Stream stream) { this.signalType = NetworkSignalType.fromCode(stream.readInt8()); - if(this.signalType == NetworkSignalType.END_CALL_BECAUSE_BUSY || this.signalType == NetworkSignalType.END_CALL_BECAUSE_PEER_DISCONNECTED) { + if(this.signalType == NetworkSignalType.END_CALL_BECAUSE_BUSY + || this.signalType == NetworkSignalType.END_CALL_BECAUSE_PEER_DISCONNECTED + || this.signalType == NetworkSignalType.RINGING_TIMEOUT) { return; } this.src = stream.readString(); @@ -46,8 +48,9 @@ public class Packet26SignalPeer extends Packet { if (signalType == NetworkSignalType.KEY_EXCHANGE) { this.sharedPublic = stream.readString(); } - if(signalType == NetworkSignalType.CREATE_ROOM) { - this.roomId = stream.readString(); + if(signalType == NetworkSignalType.CALL || signalType == NetworkSignalType.ACCEPT || signalType == NetworkSignalType.END_CALL) { + this.callId = stream.readString(); + this.joinToken = stream.readString(); } } @@ -56,7 +59,9 @@ public class Packet26SignalPeer extends Packet { Stream stream = new Stream(); stream.writeInt16(this.packetId); stream.writeInt8(this.signalType.getCode()); - if(this.signalType == NetworkSignalType.END_CALL_BECAUSE_BUSY || this.signalType == NetworkSignalType.END_CALL_BECAUSE_PEER_DISCONNECTED) { + if(this.signalType == NetworkSignalType.END_CALL_BECAUSE_BUSY + || this.signalType == NetworkSignalType.END_CALL_BECAUSE_PEER_DISCONNECTED + || this.signalType == NetworkSignalType.RINGING_TIMEOUT) { return stream; } stream.writeString(this.src); @@ -64,8 +69,9 @@ public class Packet26SignalPeer extends Packet { if (signalType == NetworkSignalType.KEY_EXCHANGE) { stream.writeString(this.sharedPublic); } - if(signalType == NetworkSignalType.CREATE_ROOM) { - stream.writeString(this.roomId); + if(signalType == NetworkSignalType.CALL || signalType == NetworkSignalType.ACCEPT || signalType == NetworkSignalType.END_CALL) { + stream.writeString(this.callId); + stream.writeString(this.joinToken); } return stream; } @@ -134,20 +140,35 @@ public class Packet26SignalPeer extends Packet { public void setSignalType(NetworkSignalType signalType) { this.signalType = signalType; } + /** + * Получить идентификатор сессии звонка, если тип сигнала CALL или ACCEPT + * @return идентификатор сессии звонка, если тип сигнала CALL или ACCEPT, иначе null + */ + public String getCallId() { + return callId; + } /** - * Получить идентификатор созданной комнаты, если тип сигнала CREATE_ROOM - * @return идентификатор комнаты, если тип сигнала CREATE_ROOM, иначе null + * Установить идентификатор сессии звонка, если тип сигнала CALL или ACCEPT + * @param callId идентификатор сессии звонка, если тип сигнала CALL или ACCEPT */ - public String getRoomId() { - return roomId; + public void setCallId(String callId) { + this.callId = callId; } - /** - * Установить идентификатор комнаты, в которой происходит звонок, если тип сигнала CREATE_ROOM - * @param roomId идентификатор комнаты, если тип сигнала CREATE_ROOM + /** + * Получить токен для присоединения к сессии звонка, если тип сигнала CALL или ACCEPT + * @return токен для присоединения к сессии звонка, если тип сигнала CALL или ACCEPT, иначе null */ - public void setRoomId(String roomId) { - this.roomId = roomId; + public String getJoinToken() { + return joinToken; + } + + /** + * Установить токен для присоединения к сессии звонка, если тип сигнала CALL или ACCEPT + * @param joinToken токен для присоединения к сессии звонка, если тип сигнала CALL или ACCEPT + */ + public void setJoinToken(String joinToken) { + this.joinToken = joinToken; } } diff --git a/src/main/java/im/rosetta/packet/Packet27WebRTC.java b/src/main/java/im/rosetta/packet/Packet27WebRTC.java index 95dcad1..877ce2f 100644 --- a/src/main/java/im/rosetta/packet/Packet27WebRTC.java +++ b/src/main/java/im/rosetta/packet/Packet27WebRTC.java @@ -13,21 +13,11 @@ public class Packet27WebRTC extends Packet { * Тип сообщения WebRTC */ private NetworkWebRTCType type; - /** - * Публичный ключ участника комнаты, который отправил этот пакет - */ - private String publicKey; - /** - * Device ID участника комнаты, который отправил этот пакет - */ - private String deviceId; @Override public void read(Stream stream) { this.type = NetworkWebRTCType.fromCode(stream.readInt8()); this.sdpOrCandidate = stream.readString(); - this.publicKey = stream.readString(); - this.deviceId = stream.readString(); } @Override @@ -36,8 +26,6 @@ public class Packet27WebRTC extends Packet { steram.writeInt16(this.packetId); steram.writeInt8(this.type.getCode()); steram.writeString(this.sdpOrCandidate); - steram.writeString(this.publicKey); - steram.writeString(this.deviceId); return steram; } @@ -72,36 +60,4 @@ public class Packet27WebRTC extends Packet { public void setType(NetworkWebRTCType type) { this.type = type; } - - /** - * Получить публичный ключ участника комнаты, который отправил этот пакет - * @return публичный ключ участника комнаты, который отправил этот пакет - */ - public String getPublicKey() { - return publicKey; - } - - /** - * Установить публичный ключ участника комнаты, который отправил этот пакет - * @param publicKey публичный ключ участника комнаты, который отправил этот пакет - */ - public void setPublicKey(String publicKey) { - this.publicKey = publicKey; - } - - /** - * Получить device ID участника комнаты, который отправил этот пакет - * @return device ID участника комнаты, который отправил этот пакет - */ - public String getDeviceId() { - return deviceId; - } - - /** - * Установить device ID участника комнаты, который отправил этот пакет - * @param deviceId device ID участника комнаты, который отправил этот пакет - */ - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } } diff --git a/src/main/java/im/rosetta/packet/runtime/NetworkSignalType.java b/src/main/java/im/rosetta/packet/runtime/NetworkSignalType.java index 7ee79bd..7c529ff 100644 --- a/src/main/java/im/rosetta/packet/runtime/NetworkSignalType.java +++ b/src/main/java/im/rosetta/packet/runtime/NetworkSignalType.java @@ -21,9 +21,9 @@ public enum NetworkSignalType { */ END_CALL(3), /** - * Создание комнаты + * Активная стадия звонка, значит комната уже создана на SFU */ - CREATE_ROOM(4), + ACTIVE(4), /** * Обрыв связи с пиром */ @@ -31,7 +31,16 @@ public enum NetworkSignalType { /** * Не удалось дозвониться - пользователь занят другим звонком */ - END_CALL_BECAUSE_BUSY(6); + END_CALL_BECAUSE_BUSY(6), + /** + * Принятие звонка + */ + ACCEPT(7), + /** + * Таймаут на этапе дозвона, если пользователь не ответил на звонок в течение определенного времени, то звонок считается неуспешным и вызывающей + * стороне отправляется этот сигнал, а сессия звонка удаляется, так как она уже не актуальна + */ + RINGING_TIMEOUT(8); private final int code; diff --git a/src/main/java/io/orprotocol/Server.java b/src/main/java/io/orprotocol/Server.java index dfa705a..f446c08 100644 --- a/src/main/java/io/orprotocol/Server.java +++ b/src/main/java/io/orprotocol/Server.java @@ -150,6 +150,7 @@ public class Server extends WebSocketServer { } } catch (Exception e) { client.disconnect(ServerFailures.BAD_PACKET); + e.printStackTrace(); } } diff --git a/src/main/java/io/orprotocol/client/Client.java b/src/main/java/io/orprotocol/client/Client.java index 2879b38..90e72fe 100644 --- a/src/main/java/io/orprotocol/client/Client.java +++ b/src/main/java/io/orprotocol/client/Client.java @@ -239,17 +239,18 @@ public class Client { * @param client клиент * @return true если это один и тот же клиент, false если нет */ - public boolean equals(Client client) { - if(client == null){ - return false; - } - if(!(client instanceof Client)){ - return false; - } - if(!client.getClientId().equals(this.clientId)){ - return false; - } - return true; + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + + Client client = (Client) obj; + return this.clientId != null && this.clientId.equals(client.clientId); + } + + @Override + public int hashCode() { + return this.clientId == null ? 0 : this.clientId.hashCode(); } }