diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/Connection.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/Connection.java index 27a8879d..aa5e9565 100644 --- a/openvidu-java-client/src/main/java/io/openvidu/java/client/Connection.java +++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/Connection.java @@ -18,8 +18,10 @@ package io.openvidu.java.client; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import com.google.gson.JsonArray; @@ -42,50 +44,7 @@ public class Connection { protected List subscribers = new ArrayList<>(); protected Connection(JsonObject json) { - // These properties may be null - if (!json.get("publishers").isJsonNull()) { - JsonArray jsonArrayPublishers = json.get("publishers").getAsJsonArray(); - jsonArrayPublishers.forEach(publisher -> { - JsonObject pubJson = publisher.getAsJsonObject(); - JsonObject mediaOptions = pubJson.get("mediaOptions").getAsJsonObject(); - Publisher pub = new Publisher(pubJson.get("streamId").getAsString(), - pubJson.get("createdAt").getAsLong(), mediaOptions.get("hasAudio").getAsBoolean(), - mediaOptions.get("hasVideo").getAsBoolean(), mediaOptions.get("audioActive"), - mediaOptions.get("videoActive"), mediaOptions.get("frameRate"), mediaOptions.get("typeOfVideo"), - mediaOptions.get("videoDimensions")); - this.publishers.put(pub.getStreamId(), pub); - }); - } - - if (!json.get("subscribers").isJsonNull()) { - JsonArray jsonArraySubscribers = json.get("subscribers").getAsJsonArray(); - jsonArraySubscribers.forEach(subscriber -> { - this.subscribers.add((subscriber.getAsJsonObject()).get("streamId").getAsString()); - }); - } - if (!json.get("createdAt").isJsonNull()) { - this.createdAt = json.get("createdAt").getAsLong(); - } - if (!json.get("location").isJsonNull()) { - this.location = json.get("location").getAsString(); - } - if (!json.get("platform").isJsonNull()) { - this.platform = json.get("platform").getAsString(); - } - if (!json.get("clientData").isJsonNull()) { - this.clientData = json.get("clientData").getAsString(); - } - - // These properties won't ever be null - this.connectionId = json.get("connectionId").getAsString(); - this.status = json.get("status").getAsString(); - String token = json.has("token") ? json.get("token").getAsString() : null; - OpenViduRole role = OpenViduRole.valueOf(json.get("role").getAsString()); - String data = json.get("serverData").getAsString(); - Boolean record = json.get("record").getAsBoolean(); - - TokenOptions tokenOptions = new TokenOptions(role, data, record, null); - this.token = new Token(token, this.connectionId, tokenOptions); + this.resetWithJson(json); } /** @@ -248,4 +207,81 @@ public class Connection { this.subscribers = subscribers; } + protected Connection resetWithJson(JsonObject json) { + + if (!json.get("publishers").isJsonNull()) { + JsonArray jsonArrayPublishers = json.get("publishers").getAsJsonArray(); + + // 1. Set to store fetched publishers and later remove closed ones + Set fetchedPublisherIds = new HashSet<>(); + jsonArrayPublishers.forEach(publisherJsonElement -> { + + JsonObject publisherJson = publisherJsonElement.getAsJsonObject(); + Publisher publisherObj = new Publisher(publisherJson); + String id = publisherObj.getStreamId(); + fetchedPublisherIds.add(id); + + // 2. Update existing Publisher + this.publishers.computeIfPresent(id, (pId, p) -> { + p = p.resetWithJson(publisherJson); + return p; + }); + + // 3. Add new Publisher + this.publishers.computeIfAbsent(id, pId -> { + return publisherObj; + }); + }); + + // 4. Remove closed connections from local collection + this.publishers.entrySet().removeIf(entry -> !fetchedPublisherIds.contains(entry.getValue().getStreamId())); + } + + if (!json.get("subscribers").isJsonNull()) { + JsonArray jsonArraySubscribers = json.get("subscribers").getAsJsonArray(); + + // 1. Array to store fetched Subscribers and later remove closed ones + Set fetchedSubscriberIds = new HashSet<>(); + jsonArraySubscribers.forEach(subscriber -> { + + String sub = subscriber.getAsJsonObject().get("streamId").getAsString(); + fetchedSubscriberIds.add(sub); + + if (!this.subscribers.contains(sub)) { + // 2. Add new Subscriber + this.subscribers.add(sub); + } + }); + + // 3. Remove closed Subscribers from local collection + this.subscribers.removeIf(subId -> !fetchedSubscriberIds.contains(subId)); + } + + if (!json.get("createdAt").isJsonNull()) { + this.createdAt = json.get("createdAt").getAsLong(); + } + if (!json.get("location").isJsonNull()) { + this.location = json.get("location").getAsString(); + } + if (!json.get("platform").isJsonNull()) { + this.platform = json.get("platform").getAsString(); + } + if (!json.get("clientData").isJsonNull()) { + this.clientData = json.get("clientData").getAsString(); + } + + // These properties won't ever be null + this.connectionId = json.get("connectionId").getAsString(); + this.status = json.get("status").getAsString(); + String token = json.has("token") ? json.get("token").getAsString() : null; + OpenViduRole role = OpenViduRole.valueOf(json.get("role").getAsString()); + String data = json.get("serverData").getAsString(); + Boolean record = json.get("record").getAsBoolean(); + + TokenOptions tokenOptions = new TokenOptions(role, data, record, null); + this.token = new Token(token, this.connectionId, tokenOptions); + + return this; + } + } diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/OpenVidu.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/OpenVidu.java index 005c6430..0e1a660f 100644 --- a/openvidu-java-client/src/main/java/io/openvidu/java/client/OpenVidu.java +++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/OpenVidu.java @@ -31,7 +31,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; import javax.net.ssl.SSLContext; @@ -549,44 +548,55 @@ public class OpenVidu { try { int statusCode = response.getStatusLine().getStatusCode(); if ((statusCode == org.apache.http.HttpStatus.SC_OK)) { + JsonObject jsonSessions = httpResponseToJson(response); JsonArray jsonArraySessions = jsonSessions.get("content").getAsJsonArray(); - // Set to store fetched sessionIds and later remove closed sessions - Set fetchedSessionIds = new HashSet<>(); // Boolean to store if any Session has changed final boolean[] hasChanged = { false }; - jsonArraySessions.forEach(session -> { - String sessionId = (session.getAsJsonObject()).get("sessionId").getAsString(); - fetchedSessionIds.add(sessionId); - this.activeSessions.computeIfPresent(sessionId, (sId, s) -> { + + // 1. Set to store fetched sessionIds and later remove closed ones + Set fetchedSessionIds = new HashSet<>(); + jsonArraySessions.forEach(sessionJsonElement -> { + + JsonObject sessionJson = sessionJsonElement.getAsJsonObject(); + final Session sessionObj = new Session(this, sessionJson); + String id = sessionObj.getSessionId(); + fetchedSessionIds.add(id); + + // 2. Update existing Session + this.activeSessions.computeIfPresent(id, (sId, s) -> { String beforeJSON = s.toJson(); - s = s.resetSessionWithJson(session.getAsJsonObject()); + s = s.resetWithJson(sessionJson); String afterJSON = s.toJson(); boolean changed = !beforeJSON.equals(afterJSON); hasChanged[0] = hasChanged[0] || changed; - log.info("Available session '{}' info fetched. Any change: {}", sessionId, changed); + log.info("Available session '{}' info fetched. Any change: {}", id, changed); return s; }); - this.activeSessions.computeIfAbsent(sessionId, sId -> { - log.info("New session '{}' fetched", sessionId); + + // 3. Add new Session + this.activeSessions.computeIfAbsent(id, sId -> { + log.info("New session '{}' fetched", id); hasChanged[0] = true; - return new Session(this, session.getAsJsonObject()); + return sessionObj; }); }); - // Remove closed sessions from activeSessions map - this.activeSessions = this.activeSessions.entrySet().stream().filter(entry -> { + // 4. Remove closed sessions from local collection + this.activeSessions.entrySet().removeIf(entry -> { if (fetchedSessionIds.contains(entry.getKey())) { - return true; + return false; } else { log.info("Removing closed session {}", entry.getKey()); hasChanged[0] = true; - return false; + return true; } - }).collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())); + }); + log.info("Active sessions info fetched: {}", this.activeSessions.keySet()); return hasChanged[0]; + } else { throw new OpenViduHttpException(statusCode); } diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/Publisher.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/Publisher.java index 89030b51..7eeefe0e 100644 --- a/openvidu-java-client/src/main/java/io/openvidu/java/client/Publisher.java +++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/Publisher.java @@ -17,16 +17,15 @@ package io.openvidu.java.client; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; /** * See {@link io.openvidu.java.client.Connection#getPublishers()}. * *
- * This is a backend representation of a published media stream (see - * OpenVidu - * Browser Stream class). + * This is a backend representation of a published media stream (see OpenVidu Browser Stream class). */ public class Publisher { @@ -40,36 +39,18 @@ public class Publisher { private String typeOfVideo; private String videoDimensions; - protected Publisher(String streamId, long createdAt, boolean hasAudio, boolean hasVideo, JsonElement audioActive, - JsonElement videoActive, JsonElement frameRate, JsonElement typeOfVideo, JsonElement videoDimensions) { - this.streamId = streamId; - this.createdAt = createdAt; - this.hasAudio = hasAudio; - this.hasVideo = hasVideo; - if (audioActive != null && !audioActive.isJsonNull()) { - this.audioActive = audioActive.getAsBoolean(); - } - if (videoActive != null && !videoActive.isJsonNull()) { - this.videoActive = videoActive.getAsBoolean(); - } - if (frameRate != null && !frameRate.isJsonNull()) { - this.frameRate = frameRate.getAsInt(); - } - if (typeOfVideo != null && !typeOfVideo.isJsonNull()) { - this.typeOfVideo = typeOfVideo.getAsString(); - } - if (videoDimensions != null && !videoDimensions.isJsonNull()) { - this.videoDimensions = videoDimensions.getAsString(); - } + protected Publisher(JsonObject json) { + this.resetWithJson(json); } /** - * Returns the unique identifier of the - * Stream associated to this Publisher. Each Publisher is paired - * with only one Stream, so you can identify each Publisher by its - * Stream.streamId + * Returns the unique identifier of the Stream associated to this Publisher. Each Publisher is + * paired with only one Stream, so you can identify each Publisher by its + * Stream.streamId */ public String getStreamId() { return streamId; @@ -84,56 +65,70 @@ public class Publisher { } /** - * See properties of Stream object in OpenVidu Browser library to find out more + * See properties of Stream object in OpenVidu Browser library to find out + * more */ public boolean hasVideo() { return this.hasVideo; } /** - * See properties of Stream object in OpenVidu Browser library to find out more + * See properties of Stream object in OpenVidu Browser library to find out + * more */ public boolean hasAudio() { return this.hasAudio; } /** - * See properties of Stream object in OpenVidu Browser library to find out more + * See properties of Stream object in OpenVidu Browser library to find out + * more */ public Boolean isAudioActive() { return this.audioActive; } /** - * See properties of Stream object in OpenVidu Browser library to find out more + * See properties of Stream object in OpenVidu Browser library to find out + * more */ public Boolean isVideoActive() { return this.videoActive; } /** - * See properties of Stream object in OpenVidu Browser library to find out more + * See properties of Stream object in OpenVidu Browser library to find out + * more */ public Integer getFrameRate() { return this.frameRate; } /** - * See properties of Stream object in OpenVidu Browser library to find out more + * See properties of Stream object in OpenVidu Browser library to find out + * more */ public String getTypeOfVideo() { return this.typeOfVideo; } /** - * See properties of Stream object in OpenVidu Browser library to find out more + * See properties of Stream object in OpenVidu Browser library to find out + * more */ public String getVideoDimensions() { return this.videoDimensions; @@ -152,4 +147,32 @@ public class Publisher { return json; } + protected Publisher resetWithJson(JsonObject json) { + this.streamId = json.get("streamId").getAsString(); + this.createdAt = json.get("createdAt").getAsLong(); + + if (json.has("mediaOptions") && !json.get("mediaOptions").isJsonNull()) { + JsonObject mediaOptions = json.get("mediaOptions").getAsJsonObject(); + this.hasAudio = mediaOptions.get("hasAudio").getAsBoolean(); + this.hasVideo = mediaOptions.get("hasVideo").getAsBoolean(); + if (mediaOptions.has("audioActive") && !mediaOptions.get("audioActive").isJsonNull()) { + this.audioActive = mediaOptions.get("audioActive").getAsBoolean(); + } + if (mediaOptions.has("videoActive") && !mediaOptions.get("videoActive").isJsonNull()) { + this.videoActive = mediaOptions.get("videoActive").getAsBoolean(); + } + if (mediaOptions.has("frameRate") && !mediaOptions.get("frameRate").isJsonNull()) { + this.frameRate = mediaOptions.get("frameRate").getAsInt(); + } + if (mediaOptions.has("typeOfVideo") && !mediaOptions.get("typeOfVideo").isJsonNull()) { + this.typeOfVideo = mediaOptions.get("typeOfVideo").getAsString(); + } + if (mediaOptions.has("videoDimensions") && !mediaOptions.get("videoDimensions").isJsonNull()) { + this.videoDimensions = mediaOptions.get("videoDimensions").getAsString(); + } + } + + return this; + } + } diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java index 75eef6da..e1ef12b4 100644 --- a/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java +++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java @@ -19,8 +19,10 @@ package io.openvidu.java.client; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @@ -66,7 +68,7 @@ public class Session { protected Session(OpenVidu openVidu, JsonObject json) { this.openVidu = openVidu; - this.resetSessionWithJson(json); + this.resetWithJson(json); } /** @@ -282,7 +284,7 @@ public class Session { try { int statusCode = response.getStatusLine().getStatusCode(); if ((statusCode == org.apache.http.HttpStatus.SC_OK)) { - this.resetSessionWithJson(httpResponseToJson(response)); + this.resetWithJson(httpResponseToJson(response)); final String afterJSON = this.toJson(); boolean hasChanged = !beforeJSON.equals(afterJSON); log.info("Session info fetched for session '{}'. Any change: {}", this.sessionId, hasChanged); @@ -694,7 +696,7 @@ public class Session { this.recording = recording; } - protected Session resetSessionWithJson(JsonObject json) { + protected Session resetWithJson(JsonObject json) { this.sessionId = json.get("sessionId").getAsString(); this.createdAt = json.get("createdAt").getAsLong(); this.recording = json.get("recording").getAsBoolean(); @@ -708,18 +710,37 @@ public class Session { if (json.has("defaultCustomLayout")) { builder.defaultCustomLayout(json.get("defaultCustomLayout").getAsString()); } - if (this.properties != null && this.properties.customSessionId() != null) { - builder.customSessionId(this.properties.customSessionId()); - } else if (json.has("customSessionId")) { + if (json.has("customSessionId")) { builder.customSessionId(json.get("customSessionId").getAsString()); } + this.properties = builder.build(); JsonArray jsonArrayConnections = (json.get("connections").getAsJsonObject()).get("content").getAsJsonArray(); - this.connections.clear(); + + // 1. Set to store fetched connections and later remove closed ones + Set fetchedConnectionIds = new HashSet<>(); jsonArrayConnections.forEach(connectionJsonElement -> { - Connection connectionObj = new Connection(connectionJsonElement.getAsJsonObject()); - this.connections.put(connectionObj.getConnectionId(), connectionObj); + + JsonObject connectionJson = connectionJsonElement.getAsJsonObject(); + Connection connectionObj = new Connection(connectionJson); + String id = connectionObj.getConnectionId(); + fetchedConnectionIds.add(id); + + // 2. Update existing Connection + this.connections.computeIfPresent(id, (cId, c) -> { + c = c.resetWithJson(connectionJson); + return c; + }); + + // 3. Add new Connection + this.connections.computeIfAbsent(id, cId -> { + return connectionObj; + }); }); + + // 4. Remove closed connections from local collection + this.connections.entrySet() + .removeIf(entry -> !fetchedConnectionIds.contains(entry.getValue().getConnectionId())); return this; } diff --git a/openvidu-node-client/src/Connection.ts b/openvidu-node-client/src/Connection.ts index 928f2665..5bd0df9b 100644 --- a/openvidu-node-client/src/Connection.ts +++ b/openvidu-node-client/src/Connection.ts @@ -100,21 +100,13 @@ export class Connection { * @hidden */ constructor(json) { - // These properties may be null - if (json.publishers != null) { - json.publishers.forEach(publisher => { - this.publishers.push(new Publisher(publisher)); - }); - } - if (json.subscribers != null) { - json.subscribers.forEach(subscriber => { - this.subscribers.push(subscriber.streamId); - }); - } - this.createdAt = json.createdAt; - this.location = json.location; - this.platform = json.platform; - this.clientData = json.clientData; + this.resetWithJson(json); + } + + /** + * @hidden + */ + resetWithJson(json): Connection { // These properties won't ever be null this.connectionId = json.connectionId; @@ -123,6 +115,62 @@ export class Connection { this.role = json.role; this.serverData = json.serverData; this.record = json.record; + + // These properties may be null + if (json.publishers != null) { + + // 1. Array to store fetched Publishers and later remove closed ones + const fetchedPublisherIds: string[] = []; + json.publishers.forEach(jsonPublisher => { + + const publisherObj: Publisher = new Publisher(jsonPublisher); + fetchedPublisherIds.push(publisherObj.streamId); + let storedPublisher = this.publishers.find(c => c.streamId === publisherObj.streamId); + + if (!!storedPublisher) { + // 2. Update existing Publisher + storedPublisher.resetWithJson(jsonPublisher); + } else { + // 3. Add new Publisher + this.publishers.push(publisherObj); + } + }); + + // 4. Remove closed Publishers from local collection + for (var i = this.publishers.length - 1; i >= 0; --i) { + if (!fetchedPublisherIds.includes(this.publishers[i].streamId)) { + this.publishers.splice(i, 1); + } + } + + } + + if (json.subscribers != null) { + + // 1. Array to store fetched Subscribers and later remove closed ones + const fetchedSubscriberIds: string[] = []; + json.subscribers.forEach(jsonSubscriber => { + fetchedSubscriberIds.push(jsonSubscriber.streamId) + if (this.subscribers.indexOf(jsonSubscriber.streamId) === -1) { + // 2. Add new Subscriber + this.subscribers.push(jsonSubscriber.streamId); + } + }); + + // 3. Remove closed Subscribers from local collection + for (var i = this.subscribers.length - 1; i >= 0; --i) { + if (!fetchedSubscriberIds.includes(this.subscribers[i])) { + this.subscribers.splice(i, 1); + } + } + } + + this.createdAt = json.createdAt; + this.location = json.location; + this.platform = json.platform; + this.clientData = json.clientData; + + return this; } /** diff --git a/openvidu-node-client/src/OpenVidu.ts b/openvidu-node-client/src/OpenVidu.ts index 5e21a6c1..6979352b 100644 --- a/openvidu-node-client/src/OpenVidu.ts +++ b/openvidu-node-client/src/OpenVidu.ts @@ -429,47 +429,44 @@ export class OpenVidu { .then(res => { if (res.status === 200) { - // Array to store fetched sessionIds and later remove closed sessions - const fetchedSessionIds: string[] = []; // Boolean to store if any Session has changed let hasChanged = false; - res.data.content.forEach(session => { - fetchedSessionIds.push(session.sessionId); - let sessionIndex = -1; - let storedSession = this.activeSessions.find((s, index) => { - if (s.sessionId === session.sessionId) { - sessionIndex = index; - return true; - } else { - return false; - } - }); + // 1. Array to store fetched sessionIds and later remove closed ones + const fetchedSessionIds: string[] = []; + res.data.content.forEach(jsonSession => { + + const fetchedSession: Session = new Session(this, jsonSession); + fetchedSessionIds.push(fetchedSession.sessionId); + let storedSession = this.activeSessions.find(s => s.sessionId === fetchedSession.sessionId); + if (!!storedSession) { - const fetchedSession: Session = new Session(this).resetSessionWithJson(session); + + // 2. Update existing Session const changed: boolean = !storedSession.equalTo(fetchedSession); - if (changed) { - storedSession = fetchedSession; - this.activeSessions[sessionIndex] = storedSession; - } + storedSession.resetWithJson(jsonSession); console.log("Available session '" + storedSession.sessionId + "' info fetched. Any change: " + changed); hasChanged = hasChanged || changed; + } else { - this.activeSessions.push(new Session(this, session)); - console.log("New session '" + session.sessionId + "' info fetched"); + + // 3. Add new Session + this.activeSessions.push(fetchedSession); + console.log("New session '" + fetchedSession.sessionId + "' info fetched"); hasChanged = true; } }); - // Remove closed sessions from activeSessions array - this.activeSessions = this.activeSessions.filter(session => { - if (fetchedSessionIds.includes(session.sessionId)) { - return true; - } else { - console.log("Removing closed session '" + session.sessionId + "'"); + + // 4. Remove closed sessions from local collection + for (var i = this.activeSessions.length - 1; i >= 0; --i) { + let sessionId = this.activeSessions[i].sessionId; + if (!fetchedSessionIds.includes(sessionId)) { + console.log("Removing closed session '" + sessionId + "'"); hasChanged = true; - return false; + this.activeSessions.splice(i, 1); } - }); + } + console.log('Active sessions info fetched: ', fetchedSessionIds); resolve(hasChanged); } else { @@ -505,26 +502,9 @@ export class OpenVidu { const addWebRtcStatsToConnections = (connection: Connection, connectionsExtendedInfo: any) => { const connectionExtended = connectionsExtendedInfo.find(c => c.connectionId === connection.connectionId); if (!!connectionExtended) { - const publisherArray = []; connection.publishers.forEach(pub => { const publisherExtended = connectionExtended.publishers.find(p => p.streamId === pub.streamId); - const pubAux = {}; - // Standard properties - pubAux['streamId'] = pub.streamId; - pubAux['createdAt'] = pub.createdAt; - const mediaOptions = { - audioActive: pub.audioActive, - videoActive: pub.videoActive, - hasAudio: pub.hasAudio, - hasVideo: pub.hasVideo, - typeOfVideo: pub.typeOfVideo, - frameRate: pub.frameRate, - videoDimensions: pub.videoDimensions - }; - pubAux['mediaOptions'] = mediaOptions; - const newPublisher = new Publisher(pubAux); - // WebRtc properties - newPublisher['webRtc'] = { + pub['webRtc'] = { kms: { events: publisherExtended.events, localCandidate: publisherExtended.localCandidate, @@ -536,11 +516,10 @@ export class OpenVidu { remoteSdp: publisherExtended.remoteSdp } }; - newPublisher['localCandidatePair'] = parseRemoteCandidatePair(newPublisher['webRtc'].kms.remoteCandidate); + pub['localCandidatePair'] = parseRemoteCandidatePair(pub['webRtc'].kms.remoteCandidate); if (!!publisherExtended.serverStats) { - newPublisher['webRtc'].kms.serverStats = publisherExtended.serverStats; + pub['webRtc'].kms.serverStats = publisherExtended.serverStats; } - publisherArray.push(newPublisher); }); const subscriberArray = []; connection.subscribers.forEach(sub => { @@ -569,7 +548,6 @@ export class OpenVidu { } subscriberArray.push(subAux); }); - connection.publishers = publisherArray; connection.subscribers = subscriberArray; } }; @@ -601,68 +579,64 @@ export class OpenVidu { .then(res => { if (res.status === 200) { - // Array to store fetched sessionIds and later remove closed sessions - const fetchedSessionIds: string[] = []; // Global changes let globalChanges = false; // Collection of sessionIds telling whether each one of them has changed or not const sessionChanges: ObjMap = {}; - res.data.content.forEach(session => { - fetchedSessionIds.push(session.sessionId); - let sessionIndex = -1; - let storedSession = this.activeSessions.find((s, index) => { - if (s.sessionId === session.sessionId) { - sessionIndex = index; - return true; - } else { - return false; - } - }); - if (!!storedSession) { - const fetchedSession: Session = new Session(this).resetSessionWithJson(session); - fetchedSession.activeConnections.forEach(connection => { - addWebRtcStatsToConnections(connection, session.connections.content); - }); + // 1. Array to store fetched sessionIds and later remove closed ones + const fetchedSessionIds: string[] = []; + res.data.content.forEach(jsonSession => { + const fetchedSession: Session = new Session(this, jsonSession); + fetchedSession.connections.forEach(connection => { + addWebRtcStatsToConnections(connection, jsonSession.connections.content); + }); + fetchedSessionIds.push(fetchedSession.sessionId); + let storedSession = this.activeSessions.find(s => s.sessionId === fetchedSession.sessionId); + + if (!!storedSession) { + + // 2. Update existing Session let changed = !storedSession.equalTo(fetchedSession); if (!changed) { // Check if server webrtc information has changed in any Publisher object (Session.equalTo does not check Publisher.webRtc auxiliary object) - fetchedSession.activeConnections.forEach((connection, index1) => { + fetchedSession.connections.forEach((connection, index1) => { for (let index2 = 0; (index2 < connection['publishers'].length && !changed); index2++) { - changed = changed || JSON.stringify(connection['publishers'][index2]['webRtc']) !== JSON.stringify(storedSession.activeConnections[index1]['publishers'][index2]['webRtc']); + changed = changed || JSON.stringify(connection['publishers'][index2]['webRtc']) !== JSON.stringify(storedSession.connections[index1]['publishers'][index2]['webRtc']); } }); } - if (changed) { - storedSession = fetchedSession; - this.activeSessions[sessionIndex] = storedSession; - } + storedSession.resetWithJson(jsonSession); + storedSession.connections.forEach(connection => { + addWebRtcStatsToConnections(connection, jsonSession.connections.content); + }); console.log("Available session '" + storedSession.sessionId + "' info fetched. Any change: " + changed); sessionChanges[storedSession.sessionId] = changed; globalChanges = globalChanges || changed; + } else { - const newSession = new Session(this, session); - newSession.activeConnections.forEach(connection => { - addWebRtcStatsToConnections(connection, session.connections.content); - }); - this.activeSessions.push(newSession); - console.log("New session '" + session.sessionId + "' info fetched"); - sessionChanges[session.sessionId] = true; + + // 3. Add new Session + this.activeSessions.push(fetchedSession); + console.log("New session '" + fetchedSession.sessionId + "' info fetched"); + sessionChanges[fetchedSession.sessionId] = true; globalChanges = true; + } }); - // Remove closed sessions from activeSessions array - this.activeSessions = this.activeSessions.filter(session => { - if (fetchedSessionIds.includes(session.sessionId)) { - return true; - } else { - console.log("Removing closed session '" + session.sessionId + "'"); - sessionChanges[session.sessionId] = true; + + // 4. Remove closed sessions from local collection + for (var i = this.activeSessions.length - 1; i >= 0; --i) { + let sessionId = this.activeSessions[i].sessionId; + if (!fetchedSessionIds.includes(sessionId)) { + console.log("Removing closed session '" + sessionId + "'"); + sessionChanges[sessionId] = true; globalChanges = true; - return false; + this.activeSessions.splice(i, 1); } - }); + } + console.log('Active sessions info fetched: ', fetchedSessionIds); resolve({ changes: globalChanges, sessionChanges }); } else { diff --git a/openvidu-node-client/src/Publisher.ts b/openvidu-node-client/src/Publisher.ts index d88a009a..fa3ce8d2 100644 --- a/openvidu-node-client/src/Publisher.ts +++ b/openvidu-node-client/src/Publisher.ts @@ -74,6 +74,13 @@ export class Publisher { * @hidden */ constructor(json) { + this.resetWithJson(json); + } + + /** + * @hidden + */ + resetWithJson(json): Publisher { this.streamId = json.streamId; this.createdAt = json.createdAt; this.hasAudio = json.mediaOptions.hasAudio; @@ -83,6 +90,7 @@ export class Publisher { this.frameRate = json.mediaOptions.frameRate; this.typeOfVideo = json.mediaOptions.typeOfVideo; this.videoDimensions = json.mediaOptions.videoDimensions; + return this; } /** diff --git a/openvidu-node-client/src/Session.ts b/openvidu-node-client/src/Session.ts index 6fac15ac..10711654 100644 --- a/openvidu-node-client/src/Session.ts +++ b/openvidu-node-client/src/Session.ts @@ -82,7 +82,7 @@ export class Session { // Defined parameter if (!!propertiesOrJson.sessionId) { // Parameter is a JSON representation of Session ('sessionId' property always defined) - this.resetSessionWithJson(propertiesOrJson); + this.resetWithJson(propertiesOrJson); } else { // Parameter is a SessionProperties object this.properties = propertiesOrJson; @@ -224,7 +224,7 @@ export class Session { .then(res => { if (res.status === 200) { // SUCCESS response from openvidu-server - this.resetSessionWithJson(res.data); + this.resetWithJson(res.data); const afterJSON: string = JSON.stringify(this, this.removeCircularOpenViduReference); const hasChanged: boolean = !(beforeJSON === afterJSON); console.log("Session info fetched for session '" + this.sessionId + "'. Any change: " + hasChanged); @@ -488,42 +488,57 @@ export class Session { /** * @hidden */ - public resetSessionWithJson(json): Session { + public resetWithJson(json): Session { this.sessionId = json.sessionId; this.createdAt = json.createdAt; this.recording = json.recording; - let customSessionId: string; - let defaultCustomLayout: string; - if (!!this.properties) { - customSessionId = this.properties.customSessionId; - defaultCustomLayout = !!json.defaultCustomLayout ? json.defaultCustomLayout : this.properties.defaultCustomLayout; - } this.properties = { + customSessionId: json.customSessionId, mediaMode: json.mediaMode, recordingMode: json.recordingMode, defaultOutputMode: json.defaultOutputMode, - defaultRecordingLayout: json.defaultRecordingLayout + defaultRecordingLayout: json.defaultRecordingLayout, + defaultCustomLayout: json.defaultCustomLayout }; - if (!!customSessionId) { - this.properties.customSessionId = customSessionId; - } else if (!!json.customSessionId) { - this.properties.customSessionId = json.customSessionId; + if (json.defaultRecordingLayout == null) { + delete this.properties.defaultRecordingLayout; } - if (!!defaultCustomLayout) { - this.properties.defaultCustomLayout = defaultCustomLayout; + if (json.customSessionId == null) { + delete this.properties.customSessionId; + } + if (json.defaultCustomLayout == null) { + delete this.properties.defaultCustomLayout; } - this.connections = []; - this.activeConnections = []; + // 1. Array to store fetched connections and later remove closed ones + const fetchedConnectionIds: string[] = []; json.connections.content.forEach(jsonConnection => { - const con = new Connection(jsonConnection); - this.connections.push(con); + + const connectionObj: Connection = new Connection(jsonConnection); + fetchedConnectionIds.push(connectionObj.connectionId); + let storedConnection = this.connections.find(c => c.connectionId === connectionObj.connectionId); + + if (!!storedConnection) { + // 2. Update existing Connection + storedConnection.resetWithJson(jsonConnection); + } else { + // 3. Add new Connection + this.connections.push(connectionObj); + } }); + // 4. Remove closed sessions from local collection + for (var i = this.connections.length - 1; i >= 0; --i) { + if (!fetchedConnectionIds.includes(this.connections[i].connectionId)) { + this.connections.splice(i, 1); + } + } + // Order connections by time of creation this.connections.sort((c1, c2) => (c1.createdAt > c2.createdAt) ? 1 : ((c2.createdAt > c1.createdAt) ? -1 : 0)); // Populate activeConnections array this.updateActiveConnectionsArray(); + return this; }