OpenVidu SDKs: getConnection and getConnections

pull/553/head
pabloFuente 2020-10-15 13:16:29 +02:00
parent bf6defc4de
commit 0463230e9d
6 changed files with 116 additions and 77 deletions

View File

@ -26,7 +26,7 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
/**
* See {@link io.openvidu.java.client.Session#getActiveConnections()}
* See {@link io.openvidu.java.client.Session#getConnections()}
*/
public class Connection {

View File

@ -537,7 +537,7 @@ public class OpenVidu {
* @throws OpenViduJavaClientException
*/
public boolean fetch() throws OpenViduJavaClientException, OpenViduHttpException {
HttpGet request = new HttpGet(this.hostname + API_SESSIONS);
HttpGet request = new HttpGet(this.hostname + API_SESSIONS + "?pendingConnections=true");
HttpResponse response;
try {

View File

@ -19,7 +19,6 @@ package io.openvidu.java.client;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -49,7 +48,7 @@ public class Session {
private long createdAt;
private OpenVidu openVidu;
private SessionProperties properties;
private Map<String, Connection> activeConnections = new ConcurrentHashMap<>();
private Map<String, Connection> connections = new ConcurrentHashMap<>();
private boolean recording = false;
protected Session(OpenVidu openVidu) throws OpenViduJavaClientException, OpenViduHttpException {
@ -165,7 +164,7 @@ public class Session {
* Session.forceDisconnect()} to invalidate the token if no client has used it
* yet or force the connected client to leave the session if it has.</li>
* <li>Call
* {@link io.openvidu.java.client.Session#updateConnection(String, TokenOptions)
* {@link io.openvidu.java.client.Session#updateConnection(String, ConnectionOptions)
* Session.updateConnection()} to update the
* {@link io.openvidu.java.client.Connection Connection} options. And this is
* valid for unused tokens, but also for already used tokens, so you can
@ -254,7 +253,7 @@ public class Session {
* those values to call
* {@link io.openvidu.java.client.Session#forceDisconnect(Connection)},
* {@link io.openvidu.java.client.Session#forceUnpublish(Publisher)} or
* {@link io.openvidu.java.client.Session#updateConnection(String, TokenOptions)}.<br>
* {@link io.openvidu.java.client.Session#updateConnection(String, ConnectionOptions)}.<br>
* <br>
*
* To update all Session objects owned by OpenVidu object at once, call
@ -269,7 +268,8 @@ public class Session {
*/
public boolean fetch() throws OpenViduJavaClientException, OpenViduHttpException {
final String beforeJSON = this.toJson();
HttpGet request = new HttpGet(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId);
HttpGet request = new HttpGet(
this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "?pendingConnections=true");
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
HttpResponse response;
@ -371,13 +371,13 @@ public class Session {
int statusCode = response.getStatusLine().getStatusCode();
if ((statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
// Remove connection from activeConnections map
Connection connectionClosed = this.activeConnections.remove(connectionId);
Connection connectionClosed = this.connections.remove(connectionId);
// Remove every Publisher of the closed connection from every subscriber list of
// other connections
if (connectionClosed != null) {
for (Publisher publisher : connectionClosed.getPublishers()) {
String streamId = publisher.getStreamId();
for (Connection connection : this.activeConnections.values()) {
for (Connection connection : this.connections.values()) {
connection.setSubscribers(connection.getSubscribers().stream()
.filter(subscriber -> !streamId.equals(subscriber)).collect(Collectors.toList()));
}
@ -464,7 +464,7 @@ public class Session {
try {
int statusCode = response.getStatusLine().getStatusCode();
if ((statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
for (Connection connection : this.activeConnections.values()) {
for (Connection connection : this.connections.values()) {
// Try to remove the Publisher from the Connection publishers collection
if (connection.publishers.remove(streamId) != null) {
continue;
@ -493,21 +493,14 @@ public class Session {
* </ul>
* <br>
*
* The <code>connectionId</code> parameter can be obtained from a Connection
* object with {@link io.openvidu.java.client.Connection#getConnectionId()
* Connection.getConnectionId()}, in which case the updated properties will
* modify an active Connection. But <code>connectionId</code> can also be
* obtained from a Token with {@link Token#getConnectionId()}, which allows
* modifying a still not used token.<br>
* <br>
*
* This method automatically updates the properties of the local affected
* objects. This means that there is no need to call
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} to see the
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} or
* {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()} to see the
* changes consequence of the execution of this method applied in the local
* objects.
*
* @param connectionId The Connection (or a still not used Token) to modify
* @param connectionId The Connection to modify
* @param connectionOptions A ConnectionOptions object with the new values to
* apply
*
@ -551,12 +544,12 @@ public class Session {
JsonObject json = httpResponseToJson(response);
// Update the actual Connection object with the new options
Connection existingConnection = this.activeConnections.get(connectionId);
Connection existingConnection = this.connections.get(connectionId);
if (existingConnection == null) {
// The updated Connection is not available in local map
Connection newConnection = new Connection(json);
this.activeConnections.put(connectionId, newConnection);
this.connections.put(connectionId, newConnection);
return newConnection;
} else {
// The updated Connection was available in local map
@ -570,27 +563,55 @@ public class Session {
}
/**
* Returns the list of active connections to the session. <strong>This value
* will remain unchanged since the last time method
* {@link io.openvidu.java.client.Session#fetch()} was called</strong>.
* Exceptions to this rule are:
* Returns a Connection of the Session. This method only returns the local
* available object and does not query OpenVidu Server. To get the current
* actual value you must call first
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} or
* {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()}.
*/
public Connection getConnection(String id) {
return this.connections.get(id);
}
/**
* Returns all the Connections of the Session. This method only returns the
* local available objects and does not query OpenVidu Server. To get the
* current actual value you must call first
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} or
* {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()}.
*/
public List<Connection> getConnections() {
return this.connections.values().stream().collect(Collectors.toList());
}
/**
* Returns the list of active Connections of the Session. These are the
* Connections returning <code>active</code> in response to
* {@link io.openvidu.java.client.Connection#getStatus()}. This method only
* returns the local available objects and does not query OpenVidu Server.
* <strong>The list of active Connections will remain unchanged since the last
* time method {@link io.openvidu.java.client.Session#fetch() Session.fetch()}
* or {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()} was
* called</strong>. Exceptions to this rule are:
* <ul>
* <li>Calling {@link io.openvidu.java.client.Session#forceUnpublish(String)}
* automatically updates each affected local Connection object.</li>
* <li>Calling {@link io.openvidu.java.client.Session#forceDisconnect(String)}
* automatically updates each affected local Connection object.</li>
* <li>Calling
* {@link io.openvidu.java.client.Session#updateConnection(String, TokenOptions)}
* {@link io.openvidu.java.client.Session#updateConnection(String, ConnectionOptions)}
* automatically updates the attributes of the affected local Connection
* object.</li>
* </ul>
* <br>
* To get the list of active connections with their current actual value, you
* must call first {@link io.openvidu.java.client.Session#fetch()} and then
* {@link io.openvidu.java.client.Session#getActiveConnections()}.
* must call first {@link io.openvidu.java.client.Session#fetch()
* Session.fetch()} or {@link io.openvidu.java.client.OpenVidu#fetch()
* OpenVidu.fetch()}.
*/
public List<Connection> getActiveConnections() {
return new ArrayList<>(this.activeConnections.values());
return this.connections.values().stream().filter(con -> "active".equals(con.getStatus()))
.collect(Collectors.toList());
}
/**
@ -694,10 +715,10 @@ public class Session {
}
this.properties = builder.build();
JsonArray jsonArrayConnections = (json.get("connections").getAsJsonObject()).get("content").getAsJsonArray();
this.activeConnections.clear();
this.connections.clear();
jsonArrayConnections.forEach(connectionJsonElement -> {
Connection connectionObj = new Connection(connectionJsonElement.getAsJsonObject());
this.activeConnections.put(connectionObj.getConnectionId(), connectionObj);
this.connections.put(connectionObj.getConnectionId(), connectionObj);
});
return this;
}
@ -714,9 +735,9 @@ public class Session {
json.addProperty("defaultRecordingLayout", this.properties.defaultRecordingLayout().name());
json.addProperty("defaultCustomLayout", this.properties.defaultCustomLayout());
JsonObject connections = new JsonObject();
connections.addProperty("numberOfElements", this.getActiveConnections().size());
connections.addProperty("numberOfElements", this.getConnections().size());
JsonArray jsonArrayConnections = new JsonArray();
this.getActiveConnections().forEach(con -> {
this.getConnections().forEach(con -> {
jsonArrayConnections.add(con.toJson());
});
connections.add("content", jsonArrayConnections);

View File

@ -20,7 +20,7 @@ import { Publisher } from './Publisher';
import { ConnectionOptions } from './ConnectionOptions';
/**
* See [[Session.activeConnections]]
* See [[Session.connections]]
*/
export class Connection {

View File

@ -419,7 +419,7 @@ export class OpenVidu {
public fetch(): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
axios.get(
this.host + OpenVidu.API_SESSIONS,
this.host + OpenVidu.API_SESSIONS + '?pendingConnections=true',
{
headers: {
Authorization: this.basicAuth

View File

@ -47,15 +47,25 @@ export class Session {
properties: SessionProperties;
/**
* Array of active connections to the session. This property always initialize as an empty array and
* **will remain unchanged since the last time method [[Session.fetch]] was called**. Exceptions to this rule are:
* Array of Connections to the Session. This property always initialize as an empty array and
* **will remain unchanged since the last time method [[Session.fetch]] or [[OpenVidu.fetch]] was called**.
* Exceptions to this rule are:
*
* - Calling [[Session.forceUnpublish]] automatically updates each affected local Connection object.
* - Calling [[Session.forceDisconnect]] automatically updates each affected local Connection object.
* - Calling [[Session.updateConnection]] automatically updates the attributes of the affected local Connection object.
*
* To get the array of active connections with their current actual value, you must call [[Session.fetch]] before consulting
* property [[activeConnections]]
* To get the array of Connections with their current actual value, you must call [[Session.fetch]] or [[OpenVidu.fetch]]
* before consulting property [[connections]]
*/
connections: Connection[] = [];
/**
* Array containing the active Connections of the Session. It is a subset of [[Session.connections]] array containing only
* those Connections with property [[Connection.status]] to `active`.
*
* To get the array of active Connections with their current actual value, you must call [[Session.fetch]] or [[OpenVidu.fetch]]
* before consulting property [[activeConnections]]
*/
activeConnections: Connection[] = [];
@ -190,9 +200,9 @@ export class Session {
}
/**
* Updates every property of the Session with the current status it has in OpenVidu Server. This is especially useful for accessing the list of active
* connections of the Session ([[Session.activeConnections]]) and use those values to call [[Session.forceDisconnect]], [[Session.forceUnpublish]] or
* [[Session.updateConnection]].
* Updates every property of the Session with the current status it has in OpenVidu Server. This is especially useful for accessing the list of
* Connections of the Session ([[Session.connections]], [[Session.activeConnections]]) and use those values to call [[Session.forceDisconnect]],
* [[Session.forceUnpublish]] or [[Session.updateConnection]].
*
* To update all Session objects owned by OpenVidu object at once, call [[OpenVidu.fetch]]
*
@ -203,7 +213,7 @@ export class Session {
return new Promise<boolean>((resolve, reject) => {
const beforeJSON: string = JSON.stringify(this, this.removeCircularOpenViduReference);
axios.get(
this.ov.host + OpenVidu.API_SESSIONS + '/' + this.sessionId,
this.ov.host + OpenVidu.API_SESSIONS + '/' + this.sessionId + '?pendingConnections=true',
{
headers: {
'Authorization': this.ov.basicAuth,
@ -230,22 +240,14 @@ export class Session {
}
/**
* Forces the user with Connection `connectionId` to leave the session, or invalidates the [[Token]] associated with that
* `connectionId` if no user has used it yet.
*
* In the first case you can get `connection` parameter from [[Session.activeConnections]] array (remember to call [[Session.fetch]] before
* to fetch the current actual properties of the Session from OpenVidu Server). As a result, OpenVidu Browser will trigger the proper
* events on the client-side (`streamDestroyed`, `connectionDestroyed`, `sessionDisconnected`) with reason set to `"forceDisconnectByServer"`.
*
* In the second case you can get `connectionId` parameter with [[Token.connectionId]]. As a result, the token will be invalidated
* and no user will be able to connect to the session with it.
* Removes a Connection from the Session.
*
* This method automatically updates the properties of the local affected objects. This means that there is no need to call
* [[Session.fetch]] to see the changes consequence of the execution of this method applied in the local objects.
* [[Session.fetch]] or [[OpenVidu.fetch]] to see the changes consequence of the execution of this method applied in the local objects.
*
* @param connection The Connection object to disconnect from the session, or its `connectionId` property
*
* @returns A Promise that is resolved if the user was successfully disconnected and rejected with an Error object if not
* @returns A Promise that is resolved if the Connection was successfully removed from the Session and rejected with an Error object if not
*/
public forceDisconnect(connection: string | Connection): Promise<any> {
return new Promise<any>((resolve, reject) => {
@ -261,9 +263,9 @@ export class Session {
.then(res => {
if (res.status === 204) {
// SUCCESS response from openvidu-server
// Remove connection from activeConnections array
// Remove connection from connections array
let connectionClosed;
this.activeConnections = this.activeConnections.filter(con => {
this.connections = this.connections.filter(con => {
if (con.connectionId !== connectionId) {
return true;
} else {
@ -274,7 +276,7 @@ export class Session {
// Remove every Publisher of the closed connection from every subscriber list of other connections
if (!!connectionClosed) {
connectionClosed.publishers.forEach(publisher => {
this.activeConnections.forEach(con => {
this.connections.forEach(con => {
con.subscribers = con.subscribers.filter(subscriber => {
// tslint:disable:no-string-literal
if (!!subscriber['streamId']) {
@ -289,8 +291,9 @@ export class Session {
});
});
} else {
console.warn("The closed connection wasn't fetched in OpenVidu Java Client. No changes in the collection of active connections of the Session");
console.warn("The closed connection wasn't fetched in OpenVidu Node Client. No changes in the collection of active connections of the Session");
}
this.updateActiveConnectionsArray();
console.log("Connection '" + connectionId + "' closed");
resolve();
} else {
@ -309,10 +312,10 @@ export class Session {
* OpenVidu Browser will trigger the proper events on the client-side (`streamDestroyed`) with reason set to `"forceUnpublishByServer"`.
*
* You can get `publisher` parameter from [[Connection.publishers]] array ([[Publisher.streamId]] for getting each `streamId` property).
* Remember to call [[Session.fetch]] before to fetch the current actual properties of the Session from OpenVidu Server
* Remember to call [[Session.fetch]] or [[OpenVidu.fetch]] before to fetch the current actual properties of the Session from OpenVidu Server
*
* This method automatically updates the properties of the local affected objects. This means that there is no need to call
* [[Session.fetch]] to see the changes consequence of the execution of this method applied in the local objects.
* [[Session.fetch]] or [[OpenVidu.fetch]] to see the changes consequence of the execution of this method applied in the local objects.
*
* @returns A Promise that is resolved if the stream was successfully unpublished and rejected with an Error object if not
*/
@ -331,7 +334,7 @@ export class Session {
.then(res => {
if (res.status === 204) {
// SUCCESS response from openvidu-server
this.activeConnections.forEach(connection => {
this.connections.forEach(connection => {
// Try to remove the Publisher from the Connection publishers collection
connection.publishers = connection.publishers.filter(pub => pub.streamId !== streamId);
// Try to remove the Publisher from the Connection subscribers collection
@ -347,6 +350,7 @@ export class Session {
}
}
});
this.updateActiveConnectionsArray();
console.log("Stream '" + streamId + "' unpublished");
resolve();
} else {
@ -366,16 +370,10 @@ export class Session {
* - [[ConnectionOptions.role]]
* - [[ConnectionOptions.record]]
*
* The `connectionId` parameter can be obtained from a Connection object with
* [[Connection.connectionId]], in which case the updated properties will
* modify an active Connection. But `connectionId` can also be obtained from a
* Token with [[Token.connectionId]], which allows modifying a still not used token.
*
* This method automatically updates the properties of the local affected objects. This means that there is no need to call
* [[Session.fetch]] to see the changes consequence of the execution of this method applied in the local objects.
* [[Session.fetch]] or [[OpenVidu.fetch]] to see the changes consequence of the execution of this method applied in the local objects.
*
* @param connectionId The [[Connection.connectionId]] property of the Connection object to modify,
* or the [[Token.connectionId]] property of a still not used token to modify
* @param connectionId The [[Connection.connectionId]] of the Connection object to modify
* @param connectionOptions A new [[ConnectionOptions]] object with the updated values to apply
*
* @returns A Promise that is resolved to the updated [[Connection]] object if the operation was
@ -404,15 +402,17 @@ export class Session {
return;
}
// Update the actual Connection object with the new options
const existingConnection: Connection = this.activeConnections.find(con => con.connectionId === connectionId);
const existingConnection: Connection = this.connections.find(con => con.connectionId === connectionId);
if (!existingConnection) {
// The updated Connection is not available in local map
const newConnection: Connection = new Connection(res.data);
this.activeConnections.push(newConnection);
this.connections.push(newConnection);
this.updateActiveConnectionsArray();
resolve(newConnection);
} else {
// The updated Connection was available in local map
existingConnection.overrideConnectionOptions(connectionOptions);
this.updateActiveConnectionsArray();
resolve(existingConnection);
}
}).catch(error => {
@ -513,11 +513,17 @@ export class Session {
this.properties.defaultCustomLayout = defaultCustomLayout;
}
this.connections = [];
this.activeConnections = [];
json.connections.content.forEach(jsonConnection => this.activeConnections.push(new Connection(jsonConnection)));
json.connections.content.forEach(jsonConnection => {
const con = new Connection(jsonConnection);
this.connections.push(con);
});
// Order connections by time of creation
this.activeConnections.sort((c1, c2) => (c1.createdAt > c2.createdAt) ? 1 : ((c2.createdAt > c1.createdAt) ? -1 : 0));
this.connections.sort((c1, c2) => (c1.createdAt > c2.createdAt) ? 1 : ((c2.createdAt > c1.createdAt) ? -1 : 0));
// Populate activeConnections array
this.updateActiveConnectionsArray();
return this;
}
@ -529,13 +535,13 @@ export class Session {
this.sessionId === other.sessionId &&
this.createdAt === other.createdAt &&
this.recording === other.recording &&
this.activeConnections.length === other.activeConnections.length &&
this.connections.length === other.connections.length &&
JSON.stringify(this.properties) === JSON.stringify(other.properties)
);
if (equals) {
let i = 0;
while (equals && i < this.activeConnections.length) {
equals = this.activeConnections[i].equalTo(other.activeConnections[i]);
while (equals && i < this.connections.length) {
equals = this.connections[i].equalTo(other.connections[i]);
i++;
}
return equals;
@ -555,6 +561,18 @@ export class Session {
}
}
/**
* @hidden
*/
private updateActiveConnectionsArray() {
this.activeConnections = [];
this.connections.forEach(con => {
if (con.status === 'active') {
this.activeConnections.push(con);
}
});
}
/**
* @hidden
*/