openvidu SDKs: support for updateConnection

pull/550/head
pabloFuente 2020-10-08 19:31:47 +02:00
parent f2c37f29a5
commit 08fcdbdb15
9 changed files with 809 additions and 288 deletions

View File

@ -20,6 +20,10 @@ package io.openvidu.java.client;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
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#getActiveConnections()}
@ -28,35 +32,52 @@ public class Connection {
private String connectionId; private String connectionId;
private long createdAt; private long createdAt;
private OpenViduRole role;
private String token;
private String location; private String location;
private String platform; private String platform;
private String serverData;
private String clientData; private String clientData;
private Token token;
protected Map<String, Publisher> publishers; protected Map<String, Publisher> publishers = new ConcurrentHashMap<>();
protected List<String> subscribers; protected List<String> subscribers = new ArrayList<>();
protected Connection(String connectionId, long createdAt, OpenViduRole role, String token, String location, protected Connection(JsonObject json) {
String platform, String serverData, String clientData, Map<String, Publisher> publishers, JsonArray jsonArrayPublishers = json.get("publishers").getAsJsonArray();
List<String> subscribers) { jsonArrayPublishers.forEach(publisher -> {
this.connectionId = connectionId; JsonObject pubJson = publisher.getAsJsonObject();
this.createdAt = createdAt; JsonObject mediaOptions = pubJson.get("mediaOptions").getAsJsonObject();
this.role = role; Publisher pub = new Publisher(pubJson.get("streamId").getAsString(), pubJson.get("createdAt").getAsLong(),
this.token = token; mediaOptions.get("hasAudio").getAsBoolean(), mediaOptions.get("hasVideo").getAsBoolean(),
this.location = location; mediaOptions.get("audioActive"), mediaOptions.get("videoActive"), mediaOptions.get("frameRate"),
this.platform = platform; mediaOptions.get("typeOfVideo"), mediaOptions.get("videoDimensions"));
this.serverData = serverData; this.publishers.put(pub.getStreamId(), pub);
this.clientData = clientData; });
this.publishers = publishers;
this.subscribers = subscribers; JsonArray jsonArraySubscribers = json.get("subscribers").getAsJsonArray();
jsonArraySubscribers.forEach(subscriber -> {
this.subscribers.add((subscriber.getAsJsonObject()).get("streamId").getAsString());
});
this.connectionId = json.get("connectionId").getAsString();
this.createdAt = json.get("createdAt").getAsLong();
this.location = json.get("location").getAsString();
this.platform = json.get("platform").getAsString();
this.clientData = json.get("clientData").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);
} }
/** /**
* Returns the identifier of the connection. You can call * Returns the identifier of the connection. You can call methods
* {@link io.openvidu.java.client.Session#forceDisconnect(String)} passing this * {@link io.openvidu.java.client.Session#forceDisconnect(String)} or
* property as parameter * {@link io.openvidu.java.client.Session#updateConnection(String, TokenOptions)}
* passing this property as parameter
*/ */
public String getConnectionId() { public String getConnectionId() {
return connectionId; return connectionId;
@ -74,21 +95,41 @@ public class Connection {
* Returns the role of the connection * Returns the role of the connection
*/ */
public OpenViduRole getRole() { public OpenViduRole getRole() {
return role; return this.token.getRole();
} }
/** /**
* Returns the token associated to the connection * Returns the data associated to the connection on the server-side. This value
* is set with {@link io.openvidu.java.client.TokenOptions.Builder#data(String)}
* when calling {@link io.openvidu.java.client.Session#generateToken()}
*/
public String getServerData() {
return this.token.getData();
}
/**
* Whether the streams published by this Connection will be recorded or not.
* This only affects <a href=
* "https://docs.openvidu.io/en/stable/advanced-features/recording#selecting-streams-to-be-recorded"
* target="_blank">INDIVIDUAL recording</a>.
*/
public boolean record() {
return this.token.record();
}
/**
* Returns the token string associated to the connection
*/ */
public String getToken() { public String getToken() {
return token; return this.token.getToken();
} }
/** /**
* <a href="https://docs.openvidu.io/en/stable/openvidu-pro/" target="_blank" style="display: * <a href="https://docs.openvidu.io/en/stable/openvidu-pro/" target="_blank"
* inline-block; background-color: rgb(0, 136, 170); color: white; font-weight: * style="display: inline-block; background-color: rgb(0, 136, 170); color:
* bold; padding: 0px 5px; margin-right: 5px; border-radius: 3px; font-size: * white; font-weight: bold; padding: 0px 5px; margin-right: 5px; border-radius:
* 13px; line-height:21px; font-family: Montserrat, sans-serif">PRO</a> * 3px; font-size: 13px; line-height:21px; font-family: Montserrat,
* sans-serif">PRO</a>
* *
* Returns the geo location of the connection, with the following format: * Returns the geo location of the connection, with the following format:
* <code>"CITY, COUNTRY"</code> (<code>"unknown"</code> if it wasn't possible to * <code>"CITY, COUNTRY"</code> (<code>"unknown"</code> if it wasn't possible to
@ -106,20 +147,11 @@ public class Connection {
return platform; return platform;
} }
/**
* Returns the data associated to the connection on the server-side. This value
* is set with {@link io.openvidu.java.client.TokenOptions.Builder#data(String)}
* when calling {@link io.openvidu.java.client.Session#generateToken()}
*/
public String getServerData() {
return serverData;
}
/** /**
* Returns the data associated to the connection on the client-side. This value * Returns the data associated to the connection on the client-side. This value
* is set with second parameter of method * is set with second parameter of method <a href=
* <a href="https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/session.html#connect" target * "https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/session.html#connect"
* ="_blank">Session.connect</a> in OpenVidu Browser * target ="_blank">Session.connect</a> in OpenVidu Browser
*/ */
public String getClientData() { public String getClientData() {
return clientData; return clientData;
@ -147,6 +179,16 @@ public class Connection {
return this.subscribers; return this.subscribers;
} }
/**
* For now only properties data, role and record can be updated
*/
protected void overrideTokenOptions(TokenOptions tokenOptions) {
TokenOptions.Builder modifiableTokenOptions = new TokenOptions.Builder().role(tokenOptions.getRole())
.record(tokenOptions.record());
modifiableTokenOptions.data(this.token.getData());
this.token.overrideTokenOptions(modifiableTokenOptions.build());
}
protected void setSubscribers(List<String> subscribers) { protected void setSubscribers(List<String> subscribers) {
this.subscribers = subscribers; this.subscribers = subscribers;
} }

View File

@ -29,6 +29,7 @@ import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
@ -70,7 +71,7 @@ public class Session {
} }
/** /**
* Gets the unique identifier of the Session * Gets the unique identifier of the Session.
* *
* @return The sessionId * @return The sessionId
*/ */
@ -80,78 +81,112 @@ public class Session {
/** /**
* Timestamp when this session was created, in UTC milliseconds (ms since Jan 1, * Timestamp when this session was created, in UTC milliseconds (ms since Jan 1,
* 1970, 00:00:00 UTC) * 1970, 00:00:00 UTC).
*/ */
public long createdAt() { public long createdAt() {
return this.createdAt; return this.createdAt;
} }
/** /**
* Gets a new token associated to Session object with default values for * @deprecated Use {@link Session#createToken() Session.createToken()} instead
* {@link io.openvidu.java.client.TokenOptions}. This always translates into a * to get a {@link io.openvidu.java.client.Token} object.
* new request to OpenVidu Server
* *
* @return The generated token * @return The generated token String
* *
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
* @throws OpenViduHttpException * @throws OpenViduHttpException
*/ */
@Deprecated
public String generateToken() throws OpenViduJavaClientException, OpenViduHttpException { public String generateToken() throws OpenViduJavaClientException, OpenViduHttpException {
return this.generateToken(new TokenOptions.Builder().role(OpenViduRole.PUBLISHER).build()); return createToken().getToken();
} }
/** /**
* Gets a new token associated to Session object configured with * @deprecated Use
* <code>tokenOptions</code>. This always translates into a new request to * {@link Session#createToken(io.openvidu.java.client.TokenOptions)
* OpenVidu Server * Session.createToken(TokenOptions)} instead to get a
* {@link io.openvidu.java.client.Token} object.
* *
* @return The generated token * @return The generated token String
* *
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
* @throws OpenViduHttpException * @throws OpenViduHttpException
*/ */
@Deprecated
public String generateToken(TokenOptions tokenOptions) throws OpenViduJavaClientException, OpenViduHttpException { public String generateToken(TokenOptions tokenOptions) throws OpenViduJavaClientException, OpenViduHttpException {
return createToken(tokenOptions).getToken();
}
/**
* Gets a new token object associated to Session object with default values for
* {@link io.openvidu.java.client.TokenOptions}. The token string value to send
* to the client side can be retrieved with
* {@link io.openvidu.java.client.Token#getToken() Token.getToken()}. <br>
* <br>
* You can use method {@link io.openvidu.java.client.Token#getConnectionId()
* Token.getConnectionId()} to get the connection identifier that will be given
* to the user consuming the token. With <code>connectionId</code> you can call
* the following methods without having to fetch and search for the actual
* {@link io.openvidu.java.client.Connection Connection} object:
* <ul>
* <li>Call {@link io.openvidu.java.client.Session#forceDisconnect(String)
* 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)
* 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
* dynamically change the connection options on the fly.</li>
* </ul>
*
* @return The generated {@link io.openvidu.java.client.Token Token} object.
*
* @throws OpenViduJavaClientException
* @throws OpenViduHttpException
*/
public Token createToken() throws OpenViduJavaClientException, OpenViduHttpException {
return createToken(new TokenOptions.Builder().data("").role(OpenViduRole.PUBLISHER).record(true).build());
}
/**
* Gets a new token object associated to Session object configured with
* <code>tokenOptions</code>. The token string value to send to the client side
* can be retrieved with {@link io.openvidu.java.client.Token#getToken()
* Token.getToken()}. <br>
* <br>
* You can use method {@link io.openvidu.java.client.Token#getConnectionId()
* Token.getConnectionId()} to get the connection identifier that will be given
* to the user consuming the token. With <code>connectionId</code> you can call
* the following methods without having to fetch and search for the actual
* {@link io.openvidu.java.client.Connection Connection} object:
* <ul>
* <li>Call {@link io.openvidu.java.client.Session#forceDisconnect(String)
* 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)
* 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
* dynamically change the user connection options on the fly.</li>
* </ul>
*
* @return The generated {@link io.openvidu.java.client.Token Token} object.
*
* @throws OpenViduJavaClientException
* @throws OpenViduHttpException
*/
public Token createToken(TokenOptions tokenOptions) throws OpenViduJavaClientException, OpenViduHttpException {
if (!this.hasSessionId()) { if (!this.hasSessionId()) {
this.getSessionId(); this.getSessionId();
} }
HttpPost request = new HttpPost(this.openVidu.hostname + OpenVidu.API_TOKENS); HttpPost request = new HttpPost(this.openVidu.hostname + OpenVidu.API_TOKENS);
JsonObject json = new JsonObject();
json.addProperty("session", this.sessionId);
json.addProperty("role", tokenOptions.getRole().name());
json.addProperty("data", tokenOptions.getData());
if (tokenOptions.getKurentoOptions() != null) {
JsonObject kurentoOptions = new JsonObject();
if (tokenOptions.getKurentoOptions().getVideoMaxRecvBandwidth() != null) {
kurentoOptions.addProperty("videoMaxRecvBandwidth",
tokenOptions.getKurentoOptions().getVideoMaxRecvBandwidth());
}
if (tokenOptions.getKurentoOptions().getVideoMinRecvBandwidth() != null) {
kurentoOptions.addProperty("videoMinRecvBandwidth",
tokenOptions.getKurentoOptions().getVideoMinRecvBandwidth());
}
if (tokenOptions.getKurentoOptions().getVideoMaxSendBandwidth() != null) {
kurentoOptions.addProperty("videoMaxSendBandwidth",
tokenOptions.getKurentoOptions().getVideoMaxSendBandwidth());
}
if (tokenOptions.getKurentoOptions().getVideoMinSendBandwidth() != null) {
kurentoOptions.addProperty("videoMinSendBandwidth",
tokenOptions.getKurentoOptions().getVideoMinSendBandwidth());
}
if (tokenOptions.getKurentoOptions().getAllowedFilters().length > 0) {
JsonArray allowedFilters = new JsonArray();
for (String filter : tokenOptions.getKurentoOptions().getAllowedFilters()) {
allowedFilters.add(filter);
}
kurentoOptions.add("allowedFilters", allowedFilters);
}
json.add("kurentoOptions", kurentoOptions);
}
StringEntity params; StringEntity params;
try { try {
params = new StringEntity(json.toString()); params = new StringEntity(tokenOptions.toJsonObject(sessionId).toString());
} catch (UnsupportedEncodingException e1) { } catch (UnsupportedEncodingException e1) {
throw new OpenViduJavaClientException(e1.getMessage(), e1.getCause()); throw new OpenViduJavaClientException(e1.getMessage(), e1.getCause());
} }
@ -169,8 +204,8 @@ public class Session {
try { try {
int statusCode = response.getStatusLine().getStatusCode(); int statusCode = response.getStatusLine().getStatusCode();
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) { if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
String token = httpResponseToJson(response).get("id").getAsString(); Token token = new Token(httpResponseToJson(response));
log.info("Returning a TOKEN: {}", token); log.info("Returning a TOKEN: {}", token.getToken());
return token; return token;
} else { } else {
throw new OpenViduHttpException(statusCode); throw new OpenViduHttpException(statusCode);
@ -182,7 +217,7 @@ public class Session {
/** /**
* Gracefully closes the Session: unpublishes all streams and evicts every * Gracefully closes the Session: unpublishes all streams and evicts every
* participant * participant.
* *
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
* @throws OpenViduHttpException * @throws OpenViduHttpException
@ -217,15 +252,17 @@ public class Session {
* connections to the Session * connections to the Session
* ({@link io.openvidu.java.client.Session#getActiveConnections()}) and use * ({@link io.openvidu.java.client.Session#getActiveConnections()}) and use
* those values to call * those values to call
* {@link io.openvidu.java.client.Session#forceDisconnect(Connection)} or * {@link io.openvidu.java.client.Session#forceDisconnect(Connection)},
* {@link io.openvidu.java.client.Session#forceUnpublish(Publisher)}. <br> * {@link io.openvidu.java.client.Session#forceUnpublish(Publisher)} or
* {@link io.openvidu.java.client.Session#updateConnection(String, TokenOptions)}.<br>
* <br>
* *
* To update every Session object owned by OpenVidu object, call * To update all Session objects owned by OpenVidu object at once, call
* {@link io.openvidu.java.client.OpenVidu#fetch()} * {@link io.openvidu.java.client.OpenVidu#fetch()}.
* *
* @return true if the Session status has changed with respect to the server, * @return true if the Session status has changed with respect to the server,
* false if not. This applies to any property or sub-property of the * false if not. This applies to any property or sub-property of the
* object * object.
* *
* @throws OpenViduHttpException * @throws OpenViduHttpException
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
@ -263,11 +300,19 @@ public class Session {
* OpenVidu Browser will trigger the proper events on the client-side * OpenVidu Browser will trigger the proper events on the client-side
* (<code>streamDestroyed</code>, <code>connectionDestroyed</code>, * (<code>streamDestroyed</code>, <code>connectionDestroyed</code>,
* <code>sessionDisconnected</code>) with reason set to * <code>sessionDisconnected</code>) with reason set to
* "forceDisconnectByServer" <br> * <code>"forceDisconnectByServer"</code>. <br>
* <br>
* *
* You can get <code>connection</code> parameter with * You can get <code>connection</code> parameter with
* {@link io.openvidu.java.client.Session#fetch()} and then * {@link io.openvidu.java.client.Session#fetch()} and then
* {@link io.openvidu.java.client.Session#getActiveConnections()} * {@link io.openvidu.java.client.Session#getActiveConnections()}.<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
* changes consequence of the execution of this method applied in the local
* objects.
* *
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
* @throws OpenViduHttpException * @throws OpenViduHttpException
@ -278,15 +323,34 @@ public class Session {
/** /**
* Forces the user with Connection <code>connectionId</code> to leave the * Forces the user with Connection <code>connectionId</code> to leave the
* session. OpenVidu Browser will trigger the proper events on the client-side * session, or invalidates the {@link Token} associated with that
* <code>connectionId</code> if no user has used it yet. <br>
* <br>
*
* In the first case you can get <code>connectionId</code> parameter from
* {@link io.openvidu.java.client.Connection#getConnectionId()
* Connection.getConnectionId()}. Connection objects can be listed with
* {@link io.openvidu.java.client.Session#getActiveConnections()
* Session.getActiveConnections()} (remember to use first
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} to fetch the
* current active connections from OpenVidu Server). As a result, OpenVidu
* Browser will trigger the proper events on the client-side
* (<code>streamDestroyed</code>, <code>connectionDestroyed</code>, * (<code>streamDestroyed</code>, <code>connectionDestroyed</code>,
* <code>sessionDisconnected</code>) with reason set to * <code>sessionDisconnected</code>) with reason set to
* "forceDisconnectByServer" <br> * <code>"forceDisconnectByServer"</code>. <br>
* <br>
* *
* You can get <code>connectionId</code> parameter with * In the second case you can get <code>connectionId</code> parameter from a
* {@link io.openvidu.java.client.Session#fetch()} (use * {@link Token} with {@link Token#getConnectionId()}. As a result, the token
* {@link io.openvidu.java.client.Connection#getConnectionId()} to get the * will be invalidated and no user will be able to connect to the session with
* `connectionId` you want) * it. <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
* changes consequence of the execution of this method applied in the local
* objects.
* *
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
* @throws OpenViduHttpException * @throws OpenViduHttpException
@ -336,14 +400,22 @@ public class Session {
/** /**
* Forces some user to unpublish a Stream. OpenVidu Browser will trigger the * Forces some user to unpublish a Stream. OpenVidu Browser will trigger the
* proper events on the client-side (<code>streamDestroyed</code>) with reason * proper events on the client-side (<code>streamDestroyed</code>) with reason
* set to "forceUnpublishByServer".<br> * set to <code>"forceUnpublishByServer"</code>. <br>
* <br>
* *
* You can get <code>publisher</code> parameter with * You can get <code>publisher</code> parameter with
* {@link io.openvidu.java.client.Session#getActiveConnections()} and then for * {@link io.openvidu.java.client.Session#getActiveConnections()} and then for
* each Connection you can call * each Connection you can call
* {@link io.openvidu.java.client.Connection#getPublishers()}. Remember to call * {@link io.openvidu.java.client.Connection#getPublishers()}. Remember to call
* {@link io.openvidu.java.client.Session#fetch()} before to fetch the current * {@link io.openvidu.java.client.Session#fetch()} before to fetch the current
* actual properties of the Session from OpenVidu Server * actual properties of the Session from OpenVidu Server.<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
* changes consequence of the execution of this method applied in the local
* objects.
* *
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
* @throws OpenViduHttpException * @throws OpenViduHttpException
@ -355,7 +427,8 @@ public class Session {
/** /**
* Forces some user to unpublish a Stream. OpenVidu Browser will trigger the * Forces some user to unpublish a Stream. OpenVidu Browser will trigger the
* proper events on the client-side (<code>streamDestroyed</code>) with reason * proper events on the client-side (<code>streamDestroyed</code>) with reason
* set to "forceUnpublishByServer". <br> * set to <code>"forceUnpublishByServer"</code>. <br>
* <br>
* *
* You can get <code>streamId</code> parameter with * You can get <code>streamId</code> parameter with
* {@link io.openvidu.java.client.Session#getActiveConnections()} and then for * {@link io.openvidu.java.client.Session#getActiveConnections()} and then for
@ -364,7 +437,14 @@ public class Session {
* {@link io.openvidu.java.client.Publisher#getStreamId()}) will give you the * {@link io.openvidu.java.client.Publisher#getStreamId()}) will give you the
* <code>streamId</code>. Remember to call * <code>streamId</code>. Remember to call
* {@link io.openvidu.java.client.Session#fetch()} before to fetch the current * {@link io.openvidu.java.client.Session#fetch()} before to fetch the current
* actual properties of the Session from OpenVidu Server * actual properties of the Session from OpenVidu Server.<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
* changes consequence of the execution of this method applied in the local
* objects.
* *
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
* @throws OpenViduHttpException * @throws OpenViduHttpException
@ -401,6 +481,94 @@ public class Session {
} }
} }
/**
* Updates the properties of a Connection. These properties are the ones defined
* by the {@link io.openvidu.java.client.TokenOptions} parameter when generating
* the token used to create the Connection. These are the properties that can be
* updated:
* <ul>
* <li>{@link io.openvidu.java.client.TokenOptions.Builder#role(OpenViduRole)
* TokenOptions.Builder.role(OpenViduRole)}</li>
* <li>{@link io.openvidu.java.client.TokenOptions.Builder#record(boolean)
* TokenOptions.Builder.record(boolean)}</li>
* </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
* 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 tokenOptions A new TokenOptions object with the updated values to
* apply
*
* @return The updated {@link io.openvidu.java.client.Connection Connection}
* object
*
* @throws OpenViduJavaClientException
* @throws OpenViduHttpException
*/
public Connection updateConnection(String connectionId, TokenOptions tokenOptions)
throws OpenViduJavaClientException, OpenViduHttpException {
HttpPatch request = new HttpPatch(
this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection/" + connectionId);
StringEntity params;
try {
params = new StringEntity(tokenOptions.toJsonObject(this.sessionId).toString());
} catch (UnsupportedEncodingException e1) {
throw new OpenViduJavaClientException(e1.getMessage(), e1.getCause());
}
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
request.setEntity(params);
HttpResponse response;
try {
response = this.openVidu.httpClient.execute(request);
} catch (IOException e) {
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
}
try {
int statusCode = response.getStatusLine().getStatusCode();
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
log.info("Connection {} updated", connectionId);
} else if ((statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
log.info("Properties of Connection {} remain the same", connectionId);
} else {
throw new OpenViduHttpException(statusCode);
}
// Update the actual Connection object with the new options
Connection existingConnection = this.activeConnections.get(connectionId);
if (existingConnection == null) {
// The updated Connection is not available in local map
Connection newConnection = new Connection(httpResponseToJson(response));
this.activeConnections.put(connectionId, newConnection);
return newConnection;
} else {
// The updated Connection was available in local map
existingConnection.overrideTokenOptions(tokenOptions);
return existingConnection;
}
} finally {
EntityUtils.consumeQuietly(response.getEntity());
}
}
/** /**
* Returns the list of active connections to the session. <strong>This value * Returns the list of active connections to the session. <strong>This value
* will remain unchanged since the last time method * will remain unchanged since the last time method
@ -408,38 +576,37 @@ public class Session {
* Exceptions to this rule are: * Exceptions to this rule are:
* <ul> * <ul>
* <li>Calling {@link io.openvidu.java.client.Session#forceUnpublish(String)} * <li>Calling {@link io.openvidu.java.client.Session#forceUnpublish(String)}
* updates each affected Connection status</li> * automatically updates each affected local Connection object.</li>
* <li>Calling {@link io.openvidu.java.client.Session#forceDisconnect(String)} * <li>Calling {@link io.openvidu.java.client.Session#forceDisconnect(String)}
* updates each affected Connection status</li> * automatically updates each affected local Connection object.</li>
* <li>Calling
* {@link io.openvidu.java.client.Session#updateConnection(String, TokenOptions)}
* automatically updates the attributes of the affected local Connection
* object.</li>
* </ul> * </ul>
* <br> * <br>
* To get the list of active connections with their current actual value, you * 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 * must call first {@link io.openvidu.java.client.Session#fetch()} and then
* {@link io.openvidu.java.client.Session#getActiveConnections()} * {@link io.openvidu.java.client.Session#getActiveConnections()}.
*/ */
public List<Connection> getActiveConnections() { public List<Connection> getActiveConnections() {
return new ArrayList<>(this.activeConnections.values()); return new ArrayList<>(this.activeConnections.values());
} }
/** /**
* Returns whether the session is being recorded or not * Returns whether the session is being recorded or not.
*/ */
public boolean isBeingRecorded() { public boolean isBeingRecorded() {
return this.recording; return this.recording;
} }
/** /**
* Returns the properties defining the session * Returns the properties defining the session.
*/ */
public SessionProperties getProperties() { public SessionProperties getProperties() {
return this.properties; return this.properties;
} }
@Override
public String toString() {
return this.sessionId;
}
private boolean hasSessionId() { private boolean hasSessionId() {
return (this.sessionId != null && !this.sessionId.isEmpty()); return (this.sessionId != null && !this.sessionId.isEmpty());
} }
@ -528,35 +695,9 @@ public class Session {
this.properties = builder.build(); this.properties = builder.build();
JsonArray jsonArrayConnections = (json.get("connections").getAsJsonObject()).get("content").getAsJsonArray(); JsonArray jsonArrayConnections = (json.get("connections").getAsJsonObject()).get("content").getAsJsonArray();
this.activeConnections.clear(); this.activeConnections.clear();
jsonArrayConnections.forEach(connection -> { jsonArrayConnections.forEach(connectionJsonElement -> {
JsonObject con = connection.getAsJsonObject(); Connection connectionObj = new Connection(connectionJsonElement.getAsJsonObject());
this.activeConnections.put(connectionObj.getConnectionId(), connectionObj);
Map<String, Publisher> publishers = new ConcurrentHashMap<>();
JsonArray jsonArrayPublishers = con.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"));
publishers.put(pub.getStreamId(), pub);
});
List<String> subscribers = new ArrayList<>();
JsonArray jsonArraySubscribers = con.get("subscribers").getAsJsonArray();
jsonArraySubscribers.forEach(subscriber -> {
subscribers.add((subscriber.getAsJsonObject()).get("streamId").getAsString());
});
Connection c = new Connection(con.get("connectionId").getAsString(), con.get("createdAt").getAsLong(),
OpenViduRole.valueOf(con.get("role").getAsString()),
(con.has("token") ? con.get("token").getAsString() : null), con.get("location").getAsString(),
con.get("platform").getAsString(), con.get("serverData").getAsString(),
con.get("clientData").getAsString(), publishers, subscribers);
this.activeConnections.put(con.get("connectionId").getAsString(), c);
}); });
return this; return this;
} }

View File

@ -0,0 +1,127 @@
package io.openvidu.java.client;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
public class Token {
private String token;
private String connectionId;
private TokenOptions tokenOptions;
protected Token(String token, String connectionId, TokenOptions tokenOptions) {
this.token = token;
this.connectionId = connectionId;
this.tokenOptions = tokenOptions;
}
protected Token(JsonObject json) {
this.token = json.get("token").getAsString();
this.connectionId = json.get("connectionId").getAsString();
OpenViduRole role = OpenViduRole.valueOf(json.get("role").getAsString());
String data = json.get("data").getAsString();
Boolean record = json.get("record").getAsBoolean();
KurentoOptions kurentoOptions = null;
if (json.has("kurentoOptions")) {
JsonObject kurentoOptionsJson = json.get("kurentoOptions").getAsJsonObject();
Integer videoMaxRecvBandwidth = null;
Integer videoMinRecvBandwidth = null;
Integer videoMaxSendBandwidth = null;
Integer videoMinSendBandwidth = null;
String[] allowedFilters = null;
if (kurentoOptionsJson.has("videoMaxRecvBandwidth")) {
videoMaxRecvBandwidth = kurentoOptionsJson.get("videoMaxRecvBandwidth").getAsInt();
}
if (kurentoOptionsJson.has("videoMinRecvBandwidth")) {
videoMinRecvBandwidth = kurentoOptionsJson.get("videoMinRecvBandwidth").getAsInt();
}
if (kurentoOptionsJson.has("videoMaxSendBandwidth")) {
videoMaxSendBandwidth = kurentoOptionsJson.get("videoMaxSendBandwidth").getAsInt();
}
if (kurentoOptionsJson.has("videoMinSendBandwidth")) {
videoMinSendBandwidth = kurentoOptionsJson.get("videoMinSendBandwidth").getAsInt();
}
if (kurentoOptionsJson.has("allowedFilters")) {
JsonArray filters = kurentoOptionsJson.get("allowedFilters").getAsJsonArray();
allowedFilters = new String[filters.size()];
for (int i = 0; i < filters.size(); i++) {
allowedFilters[i] = filters.get(i).getAsString();
}
}
kurentoOptions = new KurentoOptions(videoMaxRecvBandwidth, videoMinRecvBandwidth, videoMaxSendBandwidth,
videoMinSendBandwidth, allowedFilters);
}
this.tokenOptions = new TokenOptions(role, data, record, kurentoOptions);
}
/**
* Returns the token string value that must be sent to clients. They need to use
* it to connect to the session.
*/
public String getToken() {
return this.token;
}
/**
* Returns the connection identifier that will be associated to the user
* consuming this token. This means that the future
* {@link io.openvidu.java.client.Connection Connection} object created with
* this token will have as <code>connectionId</code> this string. In other
* words, method {@link io.openvidu.java.client.Connection#getConnectionId()
* Connection.getConnectionId()} will return this same value.
*
* With <code>connectionId</code> you can call the following methods without
* having to fetch and search for the actual
* {@link io.openvidu.java.client.Connection Connection} object:
* <ul>
* <li>Call {@link io.openvidu.java.client.Session#forceDisconnect(String)
* 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)
* 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
* dynamically change the connection options on the fly.</li>
* </ul>
*
*/
public String getConnectionId() {
return this.connectionId;
}
/**
* Returns the role assigned to this token.
*/
public OpenViduRole getRole() {
return this.tokenOptions.getRole();
}
/**
* Returns the secure (server-side) metadata assigned to this token.
*/
public String getData() {
return this.tokenOptions.getData();
}
/**
* Whether the streams published by the participant owning this token will be
* recorded or not. This only affects <a href=
* "https://docs.openvidu.io/en/stable/advanced-features/recording#selecting-streams-to-be-recorded"
* target="_blank">INDIVIDUAL recording</a>.
*/
public Boolean record() {
return this.tokenOptions.record();
}
protected void overrideTokenOptions(TokenOptions tokenOptions) {
this.tokenOptions = tokenOptions;
}
}

View File

@ -17,13 +17,18 @@
package io.openvidu.java.client; package io.openvidu.java.client;
import com.google.gson.JsonArray;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
/** /**
* See {@link io.openvidu.java.client.Session#generateToken(TokenOptions)} * See {@link io.openvidu.java.client.Session#generateToken(TokenOptions)}
*/ */
public class TokenOptions { public class TokenOptions {
private String data;
private OpenViduRole role; private OpenViduRole role;
private String data;
private Boolean record;
private KurentoOptions kurentoOptions; private KurentoOptions kurentoOptions;
/** /**
@ -33,15 +38,24 @@ public class TokenOptions {
*/ */
public static class Builder { public static class Builder {
private String data = "";
private OpenViduRole role = OpenViduRole.PUBLISHER; private OpenViduRole role = OpenViduRole.PUBLISHER;
private String data;
private Boolean record = true;
private KurentoOptions kurentoOptions; private KurentoOptions kurentoOptions;
/** /**
* Builder for {@link io.openvidu.java.client.TokenOptions} * Builder for {@link io.openvidu.java.client.TokenOptions}.
*/ */
public TokenOptions build() { public TokenOptions build() {
return new TokenOptions(this.data, this.role, this.kurentoOptions); return new TokenOptions(this.role, this.data, this.record, this.kurentoOptions);
}
/**
* Call this method to set the role assigned to this token.
*/
public Builder role(OpenViduRole role) {
this.role = role;
return this;
} }
/** /**
@ -72,16 +86,19 @@ public class TokenOptions {
} }
/** /**
* Call this method to set the role assigned to this token * Call this method to flag the streams published by the participant owning this
* token to be recorded or not. This only affects <a href=
* "https://docs.openvidu.io/en/stable/advanced-features/recording#selecting-streams-to-be-recorded"
* target="_blank">INDIVIDUAL recording</a>. If not set by default will be true.
*/ */
public Builder role(OpenViduRole role) { public Builder record(boolean record) {
this.role = role; this.record = record;
return this; return this;
} }
/** /**
* Call this method to set a {@link io.openvidu.java.client.KurentoOptions} * Call this method to set a {@link io.openvidu.java.client.KurentoOptions}
* object for this token * object for this token.
*/ */
public Builder kurentoOptions(KurentoOptions kurentoOptions) { public Builder kurentoOptions(KurentoOptions kurentoOptions) {
this.kurentoOptions = kurentoOptions; this.kurentoOptions = kurentoOptions;
@ -90,31 +107,79 @@ public class TokenOptions {
} }
private TokenOptions(String data, OpenViduRole role, KurentoOptions kurentoOptions) { TokenOptions(OpenViduRole role, String data, Boolean record, KurentoOptions kurentoOptions) {
this.data = data;
this.role = role; this.role = role;
this.data = data;
this.record = record;
this.kurentoOptions = kurentoOptions; this.kurentoOptions = kurentoOptions;
} }
/** /**
* Returns the secure (server-side) metadata assigned to this token * Returns the role assigned to this token.
*/
public String getData() {
return this.data;
}
/**
* Returns the role assigned to this token
*/ */
public OpenViduRole getRole() { public OpenViduRole getRole() {
return this.role; return this.role;
} }
/** /**
* Returns the Kurento options assigned to this token * Returns the secure (server-side) metadata assigned to this token.
*/ */
public KurentoOptions getKurentoOptions() { public String getData() {
return this.kurentoOptions; return this.data;
}
/**
* Whether the streams published by the participant owning this token will be
* recorded or not. This only affects <a href=
* "https://docs.openvidu.io/en/stable/advanced-features/recording#selecting-streams-to-be-recorded"
* target="_blank">INDIVIDUAL recording</a>.
*/
public Boolean record() {
return this.record;
}
protected JsonObject toJsonObject(String sessionId) {
JsonObject json = new JsonObject();
json.addProperty("session", sessionId);
if (getRole() != null) {
json.addProperty("role", getRole().name());
} else {
json.add("role", JsonNull.INSTANCE);
}
if (getData() != null) {
json.addProperty("data", getData());
} else {
json.add("data", JsonNull.INSTANCE);
}
if (record() != null) {
json.addProperty("record", record());
} else {
json.add("record", JsonNull.INSTANCE);
}
if (this.kurentoOptions != null) {
JsonObject kurentoOptions = new JsonObject();
if (this.kurentoOptions.getVideoMaxRecvBandwidth() != null) {
kurentoOptions.addProperty("videoMaxRecvBandwidth", this.kurentoOptions.getVideoMaxRecvBandwidth());
}
if (this.kurentoOptions.getVideoMinRecvBandwidth() != null) {
kurentoOptions.addProperty("videoMinRecvBandwidth", this.kurentoOptions.getVideoMinRecvBandwidth());
}
if (this.kurentoOptions.getVideoMaxSendBandwidth() != null) {
kurentoOptions.addProperty("videoMaxSendBandwidth", this.kurentoOptions.getVideoMaxSendBandwidth());
}
if (this.kurentoOptions.getVideoMinSendBandwidth() != null) {
kurentoOptions.addProperty("videoMinSendBandwidth", this.kurentoOptions.getVideoMinSendBandwidth());
}
if (this.kurentoOptions.getAllowedFilters().length > 0) {
JsonArray allowedFilters = new JsonArray();
for (String filter : this.kurentoOptions.getAllowedFilters()) {
allowedFilters.add(filter);
}
kurentoOptions.add("allowedFilters", allowedFilters);
}
json.add("kurentoOptions", kurentoOptions);
}
return json;
} }
} }

View File

@ -17,6 +17,7 @@
import { OpenViduRole } from './OpenViduRole'; import { OpenViduRole } from './OpenViduRole';
import { Publisher } from './Publisher'; import { Publisher } from './Publisher';
import { TokenOptions } from './TokenOptions';
/** /**
* See [[Session.activeConnections]] * See [[Session.activeConnections]]
@ -24,7 +25,8 @@ import { Publisher } from './Publisher';
export class Connection { export class Connection {
/** /**
* Identifier of the connection. You can call [[Session.forceDisconnect]] passing this property as parameter * Identifier of the connection. You can call methods [[Session.forceDisconnect]]
* or [[Session.updateConnection]] passing this property as parameter
*/ */
connectionId: string; connectionId: string;
@ -38,6 +40,16 @@ export class Connection {
*/ */
role: OpenViduRole; role: OpenViduRole;
/**
* Data associated to the connection on the server-side. This value is set with property [[TokenOptions.data]] when calling [[Session.generateToken]]
*/
serverData: string;
/**
* Whether to record the streams published by the participant owning this token or not. This only affects [INDIVIDUAL recording](/en/stable/advanced-features/recording#selecting-streams-to-be-recorded)
*/
record: boolean;
/** /**
* Token associated to the connection * Token associated to the connection
*/ */
@ -54,11 +66,6 @@ export class Connection {
*/ */
platform: string; platform: string;
/**
* Data associated to the connection on the server-side. This value is set with property [[TokenOptions.data]] when calling [[Session.generateToken]]
*/
serverData: string;
/** /**
* Data associated to the connection on the client-side. This value is set with second parameter of method * Data associated to the connection on the client-side. This value is set with second parameter of method
* [Session.connect](/en/stable/api/openvidu-browser/classes/session.html#connect) in OpenVidu Browser * [Session.connect](/en/stable/api/openvidu-browser/classes/session.html#connect) in OpenVidu Browser
@ -80,18 +87,26 @@ export class Connection {
/** /**
* @hidden * @hidden
*/ */
constructor(connectionId: string, createdAt: number, role: OpenViduRole, token: string, location: string, platform: string, serverData: string, clientData: string, constructor(json) {
publishers: Publisher[], subscribers: string[]) { if (json.publishers != null) {
this.connectionId = connectionId; json.publishers.forEach(publisher => {
this.createdAt = createdAt; this.publishers.push(new Publisher(publisher));
this.role = role; });
this.token = token; }
this.location = location; if (json.subscribers != null) {
this.platform = platform; json.subscribers.forEach(subscriber => {
this.serverData = serverData; this.subscribers.push(subscriber.streamId);
this.clientData = clientData; });
this.publishers = publishers; }
this.subscribers = subscribers; this.connectionId = json.connectionId;
this.createdAt = json.createdAt;
this.role = json.role;
this.serverData = json.serverData;
this.record = json.record;
this.token = json.token;
this.location = json.location;
this.platform = json.platform;
this.clientData = json.clientData;
} }
/** /**
@ -102,10 +117,11 @@ export class Connection {
this.connectionId === other.connectionId && this.connectionId === other.connectionId &&
this.createdAt === other.createdAt && this.createdAt === other.createdAt &&
this.role === other.role && this.role === other.role &&
this.serverData === other.serverData &&
this.record === other.record &&
this.token === other.token && this.token === other.token &&
this.location === other.location && this.location === other.location &&
this.platform === other.platform && this.platform === other.platform &&
this.serverData === other.serverData &&
this.clientData === other.clientData && this.clientData === other.clientData &&
this.subscribers.length === other.subscribers.length && this.subscribers.length === other.subscribers.length &&
this.publishers.length === other.publishers.length); this.publishers.length === other.publishers.length);
@ -125,4 +141,17 @@ export class Connection {
return false; return false;
} }
} }
/**
* @hidden
*/
overrideTokenOptions(tokenOptions: TokenOptions): void {
if (tokenOptions.role != null) {
this.role = tokenOptions.role;
}
if (tokenOptions.record != null) {
this.record = tokenOptions.record
}
}
} }

View File

@ -15,16 +15,16 @@
* *
*/ */
import axios from 'axios'; import axios, { AxiosError } from 'axios';
import { Connection } from './Connection'; import { Connection } from './Connection';
import { MediaMode } from './MediaMode'; import { MediaMode } from './MediaMode';
import { OpenVidu } from './OpenVidu'; import { OpenVidu } from './OpenVidu';
import { OpenViduRole } from './OpenViduRole';
import { Publisher } from './Publisher'; import { Publisher } from './Publisher';
import { Recording } from './Recording'; import { Recording } from './Recording';
import { RecordingLayout } from './RecordingLayout'; import { RecordingLayout } from './RecordingLayout';
import { RecordingMode } from './RecordingMode'; import { RecordingMode } from './RecordingMode';
import { SessionProperties } from './SessionProperties'; import { SessionProperties } from './SessionProperties';
import { Token } from './Token';
import { TokenOptions } from './TokenOptions'; import { TokenOptions } from './TokenOptions';
@ -49,8 +49,9 @@ export class Session {
* Array of active connections to the session. This property always initialize as an empty array and * 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: * **will remain unchanged since the last time method [[Session.fetch]] was called**. Exceptions to this rule are:
* *
* - Calling [[Session.forceUnpublish]] also automatically updates each affected Connection status * - Calling [[Session.forceUnpublish]] automatically updates each affected local Connection object.
* - Calling [[Session.forceDisconnect]] automatically updates each affected Connection status * - 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 * To get the array of active connections with their current actual value, you must call [[Session.fetch]] before consulting
* property [[activeConnections]] * property [[activeConnections]]
@ -93,12 +94,36 @@ export class Session {
} }
/** /**
* Gets a new token associated to Session object * @deprecated Use [[Session.createToken]] instead to get a [[Token]] object.
* *
* @returns A Promise that is resolved to the _token_ if success and rejected with an Error object if not * @returns A Promise that is resolved to the generated _token_ string if success and rejected with an Error object if not
*/ */
public generateToken(tokenOptions?: TokenOptions): Promise<string> { public generateToken(tokenOptions?: TokenOptions): Promise<string> {
return new Promise<string>((resolve, reject) => { return new Promise<string>((resolve, reject) => {
this.createToken(tokenOptions).then(token => resolve(token.token)).catch(error => reject(error));
});
}
/**
* Gets a new token object associated to Session object configured with
* `tokenOptions`. The token string value to send to the client side
* is available at [[Token.token]] property.
*
* Property [[Token.connectionId]] provides the connection identifier that will be given
* to the user consuming the token. With `connectionId` you can call
* the following methods without having to fetch and search for the actual
* [[Connection]] object:
*
* - Call [[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.
* - Call [[Session.updateConnection]] to update the [[Connection]] options. And this is
* valid for unused tokens, but also for already used tokens, so you can
* dynamically change the user connection options on the fly.
*
* @returns A Promise that is resolved to the generated [[Token]] object if success and rejected with an Error object if not
*/
public createToken(tokenOptions?: TokenOptions): Promise<Token> {
return new Promise<Token>((resolve, reject) => {
const data = JSON.stringify({ const data = JSON.stringify({
session: this.sessionId, session: this.sessionId,
@ -120,26 +145,13 @@ export class Session {
.then(res => { .then(res => {
if (res.status === 200) { if (res.status === 200) {
// SUCCESS response from openvidu-server. Resolve token // SUCCESS response from openvidu-server. Resolve token
resolve(res.data.id); resolve(new Token(res.data));
} else { } else {
// ERROR response from openvidu-server. Resolve HTTP status // ERROR response from openvidu-server. Resolve HTTP status
reject(new Error(res.status.toString())); reject(new Error(res.status.toString()));
} }
}).catch(error => { }).catch(error => {
if (error.response) { this.handleError(error, reject);
// The request was made and the server responded with a status code (not 2xx)
reject(new Error(error.response.status.toString()));
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error(error.request);
reject(new Error(error.request));
} else {
// Something happened in setting up the request that triggered an Error
console.error('Error', error.message);
reject(new Error(error.message));
}
}); });
}); });
} }
@ -171,29 +183,17 @@ export class Session {
reject(new Error(res.status.toString())); reject(new Error(res.status.toString()));
} }
}).catch(error => { }).catch(error => {
if (error.response) { this.handleError(error, reject);
// The request was made and the server responded with a status code (not 2xx)
reject(new Error(error.response.status.toString()));
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error(error.request);
reject(new Error(error.request));
} else {
// Something happened in setting up the request that triggered an Error
console.error('Error', error.message);
reject(new Error(error.message));
}
}); });
}); });
} }
/** /**
* 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 * 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]] or [[Session.forceUnpublish]]. * connections of the Session ([[Session.activeConnections]]) and use those values to call [[Session.forceDisconnect]], [[Session.forceUnpublish]] or
* [[Session.updateConnection]].
* *
* To update every Session object owned by OpenVidu object, call [[OpenVidu.fetch]] * To update all Session objects owned by OpenVidu object at once, call [[OpenVidu.fetch]]
* *
* @returns A promise resolved to true if the Session status has changed with respect to the server, or to false if not. * @returns A promise resolved to true if the Session status has changed with respect to the server, or to false if not.
* This applies to any property or sub-property of the Session object * This applies to any property or sub-property of the Session object
@ -223,30 +223,26 @@ export class Session {
reject(new Error(res.status.toString())); reject(new Error(res.status.toString()));
} }
}).catch(error => { }).catch(error => {
if (error.response) { this.handleError(error, reject);
// The request was made and the server responded with a status code (not 2xx)
reject(new Error(error.response.status.toString()));
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error(error.request);
reject(new Error(error.request));
} else {
// Something happened in setting up the request that triggered an Error
console.error('Error', error.message);
reject(new Error(error.message));
}
}); });
}); });
} }
/** /**
* Forces the user with Connection `connectionId` to leave the session. OpenVidu Browser will trigger the proper events on the client-side * Forces the user with Connection `connectionId` to leave the session, or invalidates the [[Token]] associated with that
* (`streamDestroyed`, `connectionDestroyed`, `sessionDisconnected`) with reason set to `"forceDisconnectByServer"` * `connectionId` if no user has used it yet.
* *
* You can get `connection` parameter from [[Session.activeConnections]] array ([[Connection.connectionId]] for getting each `connectionId` property). * In the first case you can get `connection` parameter from [[Session.activeConnections]] array (remember to call [[Session.fetch]] before
* Remember to call [[Session.fetch]] before to fetch the current actual properties of the Session from OpenVidu Server * 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.
*
* 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.
*
* @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 user was successfully disconnected and rejected with an Error object if not
*/ */
@ -302,20 +298,7 @@ export class Session {
} }
}) })
.catch(error => { .catch(error => {
if (error.response) { this.handleError(error, reject);
// The request was made and the server responded with a status code (not 2xx)
reject(new Error(error.response.status.toString()));
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error(error.request);
reject(new Error(error.request));
} else {
// Something happened in setting up the request that triggered an Error
console.error('Error', error.message);
reject(new Error(error.message));
}
}); });
}); });
} }
@ -327,6 +310,9 @@ export class Session {
* You can get `publisher` parameter from [[Connection.publishers]] array ([[Publisher.streamId]] for getting each `streamId` property). * 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]] 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.
*
* @returns A Promise that is resolved if the stream was successfully unpublished and rejected with an Error object if not * @returns A Promise that is resolved if the stream was successfully unpublished and rejected with an Error object if not
*/ */
public forceUnpublish(publisher: string | Publisher): Promise<any> { public forceUnpublish(publisher: string | Publisher): Promise<any> {
@ -367,20 +353,70 @@ export class Session {
reject(new Error(res.status.toString())); reject(new Error(res.status.toString()));
} }
}).catch(error => { }).catch(error => {
if (error.response) { this.handleError(error, reject);
// The request was made and the server responded with a status code (not 2xx) });
reject(new Error(error.response.status.toString())); });
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error(error.request);
reject(new Error(error.request));
} else {
// Something happened in setting up the request that triggered an Error
console.error('Error', error.message);
reject(new Error(error.message));
} }
/**
* Updates the properties of a Connection. These properties are the ones defined
* by the [[TokenOptions]] parameter when generating the token used to create the Connection.
* These are the properties that can be updated:
*
* - [[TokenOptions.role]]
* - [[TokenOptions.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.
*
* @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 tokenOptions A new [[TokenOptions]] object with the updated values to apply
*
* @returns A Promise that is resolved to the updated [[Connection]] object if the operation was
* successful and rejected with an Error object if not
*/
public updateConnection(connectionId: string, tokenOptions: TokenOptions): Promise<Connection> {
return new Promise<any>((resolve, reject) => {
axios.patch(
this.ov.host + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection/" + connectionId,
tokenOptions,
{
headers: {
'Authorization': this.ov.basicAuth,
'Content-Type': 'application/json'
}
}
)
.then(res => {
if (res.status === 200) {
console.log('Connection ' + connectionId + ' updated');
} else if (res.status === 204) {
console.log('Properties of Connection ' + connectionId + ' remain the same');
} else {
// ERROR response from openvidu-server. Resolve HTTP status
reject(new Error(res.status.toString()));
return;
}
// Update the actual Connection object with the new options
const existingConnection: Connection = this.activeConnections.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);
resolve(newConnection);
} else {
// The updated Connection was available in local map
existingConnection.overrideTokenOptions(tokenOptions);
resolve(existingConnection);
}
}).catch(error => {
this.handleError(error, reject);
}); });
}); });
} }
@ -478,28 +514,8 @@ export class Session {
} }
this.activeConnections = []; this.activeConnections = [];
json.connections.content.forEach(connection => { json.connections.content.forEach(jsonConnection => this.activeConnections.push(new Connection(jsonConnection)));
const publishers: Publisher[] = [];
connection.publishers.forEach(publisher => {
publishers.push(new Publisher(publisher));
});
const subscribers: string[] = [];
connection.subscribers.forEach(subscriber => {
subscribers.push(subscriber.streamId);
});
this.activeConnections.push(
new Connection(
connection.connectionId,
connection.createdAt,
connection.role,
connection.token,
connection.location,
connection.platform,
connection.serverData,
connection.clientData,
publishers,
subscribers));
});
// Order connections by time of creation // Order connections by time of creation
this.activeConnections.sort((c1, c2) => (c1.createdAt > c2.createdAt) ? 1 : ((c2.createdAt > c1.createdAt) ? -1 : 0)); this.activeConnections.sort((c1, c2) => (c1.createdAt > c2.createdAt) ? 1 : ((c2.createdAt > c1.createdAt) ? -1 : 0));
return this; return this;
@ -539,4 +555,24 @@ export class Session {
} }
} }
/**
* @hidden
*/
private handleError(error: AxiosError, reject: (reason?: any) => void) {
if (error.response) {
// The request was made and the server responded with a status code (not 2xx)
reject(new Error(error.response.status.toString()));
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error(error.request);
reject(new Error(error.request));
} else {
// Something happened in setting up the request that triggered an Error
console.error('Error', error.message);
reject(new Error(error.message));
}
}
} }

View File

@ -0,0 +1,81 @@
/*
* (C) Copyright 2017-2020 OpenVidu (https://openvidu.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import { TokenOptions } from './TokenOptions';
export class Token {
/**
* The token string value that must be sent to clients. They need to use it to connect to the session.
*/
token: string;
/**
* The connection identifier that will be associated to the user
* consuming this token. This means that the future [[Connection]] object created with
* this token will have as [[Connection.connectionId]] this same value.
*
* With `connectionId` you can call the following methods without
* having to fetch and search for the actual [[Connection]] object:
*
* - Call [[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.
* - Call [[Session.updateConnection]] to update the [[Connection]] options. And this is
* valid for unused tokens, but also for already used tokens, so you can
* dynamically change the connection options on the fly.
*/
connectionId: string;
/**
* The [[TokenOptions]] assigned to this token.
*/
tokenOptions: TokenOptions;
/**
* @hidden
*/
constructor(json) {
this.token = json.token;
this.connectionId = json.connectionId;
let possibleKurentoOptions;
if (!!json.kurentoOptions) {
possibleKurentoOptions = {};
if (json.kurentoOptions.videoMaxRecvBandwidth != null) {
possibleKurentoOptions['videoMaxRecvBandwidth'] = json.kurentoOptions.videoMaxRecvBandwidth;
}
if (json.kurentoOptions.videoMinRecvBandwidth != null) {
possibleKurentoOptions['videoMinRecvBandwidth'] = json.kurentoOptions.videoMinRecvBandwidth;
}
if (json.kurentoOptions.videoMaxSendBandwidth != null) {
possibleKurentoOptions['videoMaxSendBandwidth'] = json.kurentoOptions.videoMaxSendBandwidth;
}
if (json.kurentoOptions.videoMinSendBandwidth != null) {
possibleKurentoOptions['videoMinSendBandwidth'] = json.kurentoOptions.videoMinSendBandwidth;
}
if (json.kurentoOptions.allowedFilters != null) {
possibleKurentoOptions['allowedFilters'] = json.kurentoOptions.allowedFilters;
}
}
this.tokenOptions = {
role: json.role,
data: json.data,
record: json.record,
kurentoOptions: possibleKurentoOptions
};
}
}

View File

@ -44,7 +44,6 @@ export interface TokenOptions {
*/ */
record?: boolean; record?: boolean;
/** /**
* **WARNING**: experimental option. This interface may change in the near future * **WARNING**: experimental option. This interface may change in the near future
* *

View File

@ -3,6 +3,7 @@ export * from './OpenViduRole';
export * from './Session'; export * from './Session';
export * from './SessionProperties'; export * from './SessionProperties';
export * from './TokenOptions'; export * from './TokenOptions';
export * from './Token';
export * from './MediaMode'; export * from './MediaMode';
export * from './RecordingLayout'; export * from './RecordingLayout';
export * from './RecordingMode'; export * from './RecordingMode';