mirror of https://github.com/OpenVidu/openvidu.git
openvidu-java-client: refactoring to use Java HttpClient. Allow custom client
parent
836fa84cd1
commit
b78b127447
|
@ -63,11 +63,6 @@
|
||||||
</distributionManagement>
|
</distributionManagement>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
|
||||||
<artifactId>httpclient</artifactId>
|
|
||||||
<version>4.5.13</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
|
@ -106,6 +101,7 @@
|
||||||
<version>${version.javadoc.plugin}</version>
|
<version>${version.javadoc.plugin}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<show>public</show>
|
<show>public</show>
|
||||||
|
<excludePackageNames>io.openvidu.java.client.utils</excludePackageNames>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
@ -142,6 +138,7 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<show>public</show>
|
<show>public</show>
|
||||||
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
|
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
|
||||||
|
<excludePackageNames>io.openvidu.java.client.utils</excludePackageNames>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
|
|
|
@ -17,19 +17,23 @@
|
||||||
|
|
||||||
package io.openvidu.java.client;
|
package io.openvidu.java.client;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
|
||||||
import org.apache.commons.validator.routines.DomainValidator;
|
|
||||||
import org.apache.commons.validator.routines.InetAddressValidator;
|
|
||||||
|
|
||||||
import javax.crypto.Mac;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
import org.apache.commons.validator.routines.DomainValidator;
|
||||||
|
import org.apache.commons.validator.routines.InetAddressValidator;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See
|
* See
|
||||||
|
@ -42,23 +46,28 @@ public class IceServerProperties {
|
||||||
private String credential;
|
private String credential;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the defined ICE Server url for this {@link IceServerProperties} object.
|
* Returns the defined ICE Server url for this {@link IceServerProperties}
|
||||||
|
* object.
|
||||||
*/
|
*/
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Username to be used for TURN connections at the defined {@link IceServerProperties#getUrl()}
|
* Returns the Username to be used for TURN connections at the defined
|
||||||
* and {@link IceServerProperties#getCredential()} for this {@link IceServerProperties} object.
|
* {@link IceServerProperties#getUrl()} and
|
||||||
|
* {@link IceServerProperties#getCredential()} for this
|
||||||
|
* {@link IceServerProperties} object.
|
||||||
*/
|
*/
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the credential to be used for TURN connections at the defined {@link IceServerProperties#getUrl()}
|
* Returns the credential to be used for TURN connections at the defined
|
||||||
* and {@link IceServerProperties#getUsername()} for this {@link IceServerProperties} object.
|
* {@link IceServerProperties#getUrl()} and
|
||||||
|
* {@link IceServerProperties#getUsername()} for this
|
||||||
|
* {@link IceServerProperties} object.
|
||||||
*/
|
*/
|
||||||
public String getCredential() {
|
public String getCredential() {
|
||||||
return credential;
|
return credential;
|
||||||
|
@ -97,11 +106,15 @@ public class IceServerProperties {
|
||||||
private boolean ignoreEmptyUrl = false;
|
private boolean ignoreEmptyUrl = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the url for the ICE Server you want to use.
|
* Set the url for the ICE Server you want to use. It should follow a valid
|
||||||
* It should follow a valid format:
|
* format:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7065#section-3.1" target="_blank">https://datatracker.ietf.org/doc/html/rfc7065#section-3.1</a></li>
|
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7065#section-3.1"
|
||||||
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7064#section-3.1" target="_blank">https://datatracker.ietf.org/doc/html/rfc7064#section-3.1</a></li>
|
* target=
|
||||||
|
* "_blank">https://datatracker.ietf.org/doc/html/rfc7065#section-3.1</a></li>
|
||||||
|
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7064#section-3.1"
|
||||||
|
* target=
|
||||||
|
* "_blank">https://datatracker.ietf.org/doc/html/rfc7064#section-3.1</a></li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public IceServerProperties.Builder url(String url) {
|
public IceServerProperties.Builder url(String url) {
|
||||||
|
@ -110,8 +123,8 @@ public class IceServerProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a username for the ICE Server you want to use.
|
* Set a username for the ICE Server you want to use. This parameter should be
|
||||||
* This parameter should be defined only for TURN, not for STUN ICE Servers.
|
* defined only for TURN, not for STUN ICE Servers.
|
||||||
*/
|
*/
|
||||||
public IceServerProperties.Builder username(String userName) {
|
public IceServerProperties.Builder username(String userName) {
|
||||||
this.username = userName;
|
this.username = userName;
|
||||||
|
@ -119,8 +132,8 @@ public class IceServerProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a credential for the ICE Server you want to use.
|
* Set a credential for the ICE Server you want to use. This parameter should be
|
||||||
* This parameter should be defined only for TURN, not for STUN ICE Servers.
|
* defined only for TURN, not for STUN ICE Servers.
|
||||||
*/
|
*/
|
||||||
public IceServerProperties.Builder credential(String credential) {
|
public IceServerProperties.Builder credential(String credential) {
|
||||||
this.credential = credential;
|
this.credential = credential;
|
||||||
|
@ -130,11 +143,17 @@ public class IceServerProperties {
|
||||||
/**
|
/**
|
||||||
* Secret for TURN authentication based on:
|
* Secret for TURN authentication based on:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li><a href="https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00" target="_blank">https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00</a></li>
|
* <li><a href="https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00"
|
||||||
* <li><a href="https://www.ietf.org/proceedings/87/slides/slides-87-behave-10.pdf" target="_blank">https://www.ietf.org/proceedings/87/slides/slides-87-behave-10.pdf</a></li>
|
* target=
|
||||||
|
* "_blank">https://tools.ietf.org/html/draft-uberti-behave-turn-rest-00</a></li>
|
||||||
|
* <li><a href=
|
||||||
|
* "https://www.ietf.org/proceedings/87/slides/slides-87-behave-10.pdf" target=
|
||||||
|
* "_blank">https://www.ietf.org/proceedings/87/slides/slides-87-behave-10.pdf</a></li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* This will generate credentials valid for 24 hours which is the recommended value. You need to setup in your TURN service this same secret value
|
* This will generate credentials valid for 24 hours which is the recommended
|
||||||
* which uses HMAC SHA1 as encryption algorithm. A TURN implementation which by default uses this is COTURN with static-auth-secret parameter.
|
* value. You need to setup in your TURN service this same secret value which
|
||||||
|
* uses HMAC SHA1 as encryption algorithm. A TURN implementation which by
|
||||||
|
* default uses this is COTURN with static-auth-secret parameter.
|
||||||
*/
|
*/
|
||||||
public IceServerProperties.Builder staticAuthSecret(String staticAuthSecret) {
|
public IceServerProperties.Builder staticAuthSecret(String staticAuthSecret) {
|
||||||
this.staticAuthSecret = staticAuthSecret;
|
this.staticAuthSecret = staticAuthSecret;
|
||||||
|
@ -147,19 +166,24 @@ public class IceServerProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
public IceServerProperties.Builder clone() {
|
public IceServerProperties.Builder clone() {
|
||||||
return new Builder().url(this.url)
|
return new Builder().url(this.url).username(this.username).credential(this.credential)
|
||||||
.username(this.username)
|
|
||||||
.credential(this.credential)
|
|
||||||
.staticAuthSecret(this.staticAuthSecret);
|
.staticAuthSecret(this.staticAuthSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder for {@link io.openvidu.java.client.RecordingProperties}
|
* Builder for {@link io.openvidu.java.client.RecordingProperties}
|
||||||
|
*
|
||||||
* @throws IllegalArgumentException if the defined properties does not follows
|
* @throws IllegalArgumentException if the defined properties does not follows
|
||||||
* common STUN/TURN RFCs:
|
* common STUN/TURN RFCs:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7065#section-3.1" target="_blank">https://datatracker.ietf.org/doc/html/rfc7065#section-3.1</a></li>
|
* <li><a href=
|
||||||
* <li><a href="https://datatracker.ietf.org/doc/html/rfc7064#section-3.1" target="_blank">https://datatracker.ietf.org/doc/html/rfc7064#section-3.1</a></li>
|
* "https://datatracker.ietf.org/doc/html/rfc7065#section-3.1"
|
||||||
|
* target=
|
||||||
|
* "_blank">https://datatracker.ietf.org/doc/html/rfc7065#section-3.1</a></li>
|
||||||
|
* <li><a href=
|
||||||
|
* "https://datatracker.ietf.org/doc/html/rfc7064#section-3.1"
|
||||||
|
* target=
|
||||||
|
* "_blank">https://datatracker.ietf.org/doc/html/rfc7064#section-3.1</a></li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public IceServerProperties build() throws IllegalArgumentException {
|
public IceServerProperties build() throws IllegalArgumentException {
|
||||||
|
@ -172,7 +196,8 @@ public class IceServerProperties {
|
||||||
throw new IllegalArgumentException("Error while generating credentials: " + e.getMessage());
|
throw new IllegalArgumentException("Error while generating credentials: " + e.getMessage());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("ignoreEmptyUrl=true can only be used with staticAuthSecret defined");
|
throw new IllegalArgumentException(
|
||||||
|
"ignoreEmptyUrl=true can only be used with staticAuthSecret defined");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.url == null) {
|
if (this.url == null) {
|
||||||
|
@ -182,7 +207,8 @@ public class IceServerProperties {
|
||||||
if (this.url.startsWith("turn")) {
|
if (this.url.startsWith("turn")) {
|
||||||
if (this.staticAuthSecret != null) {
|
if (this.staticAuthSecret != null) {
|
||||||
if (this.username != null || this.credential != null) {
|
if (this.username != null || this.credential != null) {
|
||||||
throw new IllegalArgumentException("You can't define username or credential if staticAuthSecret is defined");
|
throw new IllegalArgumentException(
|
||||||
|
"You can't define username or credential if staticAuthSecret is defined");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.generateTURNCredentials();
|
this.generateTURNCredentials();
|
||||||
|
@ -207,20 +233,14 @@ public class IceServerProperties {
|
||||||
final String UDP_TRANSPORT_SUFFIX = "?transport=udp";
|
final String UDP_TRANSPORT_SUFFIX = "?transport=udp";
|
||||||
|
|
||||||
// Protocols which accepts transport=tcp and transport=udp
|
// Protocols which accepts transport=tcp and transport=udp
|
||||||
final Set<String> TURN_PROTOCOLS = new HashSet<>(Arrays.asList(
|
final Set<String> TURN_PROTOCOLS = new HashSet<>(Arrays.asList("turn", "turns"));
|
||||||
"turn",
|
final Set<String> STUN_PROTOCOLS = new HashSet<>(Arrays.asList("stun", "stuns"));
|
||||||
"turns"
|
|
||||||
));
|
|
||||||
final Set<String> STUN_PROTOCOLS = new HashSet<>(Arrays.asList(
|
|
||||||
"stun",
|
|
||||||
"stuns"
|
|
||||||
));
|
|
||||||
|
|
||||||
// Fails if no colons
|
// Fails if no colons
|
||||||
int firstColonPos = uri.indexOf(':');
|
int firstColonPos = uri.indexOf(':');
|
||||||
if (firstColonPos == -1) {
|
if (firstColonPos == -1) {
|
||||||
throw new IllegalArgumentException("Not a valid TURN/STUN uri provided. " +
|
throw new IllegalArgumentException(
|
||||||
"No colons found in: '" + uri + "'");
|
"Not a valid TURN/STUN uri provided. " + "No colons found in: '" + uri + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get protocol and check
|
// Get protocol and check
|
||||||
|
@ -238,11 +258,13 @@ public class IceServerProperties {
|
||||||
// Only Turn uses transport arg
|
// Only Turn uses transport arg
|
||||||
String rawTransportType = uri.substring(qmarkPos);
|
String rawTransportType = uri.substring(qmarkPos);
|
||||||
hostAndPort = uri.substring(firstColonPos + 1, qmarkPos);
|
hostAndPort = uri.substring(firstColonPos + 1, qmarkPos);
|
||||||
if (!TCP_TRANSPORT_SUFFIX.equals(rawTransportType) && !UDP_TRANSPORT_SUFFIX.equals(rawTransportType)) {
|
if (!TCP_TRANSPORT_SUFFIX.equals(rawTransportType)
|
||||||
// If other argument rather than transport is specified, it is a wrong query for a STUN/TURN uri
|
&& !UDP_TRANSPORT_SUFFIX.equals(rawTransportType)) {
|
||||||
throw new IllegalArgumentException("Wrong value specified in STUN/TURN uri: '"
|
// If other argument rather than transport is specified, it is a wrong query for
|
||||||
+ uri + "'. " + "Unique valid arguments after '?' are '"
|
// a STUN/TURN uri
|
||||||
+ TCP_TRANSPORT_SUFFIX + "' or '" + UDP_TRANSPORT_SUFFIX);
|
throw new IllegalArgumentException("Wrong value specified in STUN/TURN uri: '" + uri + "'. "
|
||||||
|
+ "Unique valid arguments after '?' are '" + TCP_TRANSPORT_SUFFIX + "' or '"
|
||||||
|
+ UDP_TRANSPORT_SUFFIX);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("STUN uri can't have any '?' query param");
|
throw new IllegalArgumentException("STUN uri can't have any '?' query param");
|
||||||
|
@ -263,13 +285,14 @@ public class IceServerProperties {
|
||||||
// If Ipv4 and port defined
|
// If Ipv4 and port defined
|
||||||
String[] splittedHostAndPort = hostAndPort.split(":");
|
String[] splittedHostAndPort = hostAndPort.split(":");
|
||||||
if (splittedHostAndPort.length != 2) {
|
if (splittedHostAndPort.length != 2) {
|
||||||
throw new IllegalArgumentException("Host or port are not correctly " +
|
throw new IllegalArgumentException(
|
||||||
"defined in STUN/TURN uri: '" + uri + "'");
|
"Host or port are not correctly " + "defined in STUN/TURN uri: '" + uri + "'");
|
||||||
}
|
}
|
||||||
String host = splittedHostAndPort[0];
|
String host = splittedHostAndPort[0];
|
||||||
String port = splittedHostAndPort[1];
|
String port = splittedHostAndPort[1];
|
||||||
|
|
||||||
// Check if host is defined. Valid Host (Domain or IP) will be done at server side
|
// Check if host is defined. Valid Host (Domain or IP) will be done at server
|
||||||
|
// side
|
||||||
checkHostAndPort(uri, host, port);
|
checkHostAndPort(uri, host, port);
|
||||||
} else {
|
} else {
|
||||||
// If portColon is found and Ipv6
|
// If portColon is found and Ipv6
|
||||||
|
@ -277,7 +300,8 @@ public class IceServerProperties {
|
||||||
String auxPort = hostAndPort.substring(endIpv6Index + 1);
|
String auxPort = hostAndPort.substring(endIpv6Index + 1);
|
||||||
if (auxPort.startsWith(":")) {
|
if (auxPort.startsWith(":")) {
|
||||||
if (auxPort.length() == 1) {
|
if (auxPort.length() == 1) {
|
||||||
throw new IllegalArgumentException("Host or port are not correctly defined in STUN/TURN uri: " + uri);
|
throw new IllegalArgumentException(
|
||||||
|
"Host or port are not correctly defined in STUN/TURN uri: " + uri);
|
||||||
}
|
}
|
||||||
// If port is defined
|
// If port is defined
|
||||||
// Get port without colon and check host and port
|
// Get port without colon and check host and port
|
||||||
|
@ -286,7 +310,8 @@ public class IceServerProperties {
|
||||||
checkHostAndPort(uri, host, port);
|
checkHostAndPort(uri, host, port);
|
||||||
} else if (auxPort.length() > 0) {
|
} else if (auxPort.length() > 0) {
|
||||||
// If auxPort = 0, no port is defined
|
// If auxPort = 0, no port is defined
|
||||||
throw new IllegalArgumentException("Port is not specified correctly after IPv6 in uri: '" + uri + "'");
|
throw new IllegalArgumentException(
|
||||||
|
"Port is not specified correctly after IPv6 in uri: '" + uri + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -311,7 +336,8 @@ public class IceServerProperties {
|
||||||
Inet6Address.getByName(host).getHostAddress();
|
Inet6Address.getByName(host).getHostAddress();
|
||||||
return;
|
return;
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
throw new IllegalArgumentException("Is not a valid Internet Address (IP or Domain Name): '" + host + "'");
|
throw new IllegalArgumentException(
|
||||||
|
"Is not a valid Internet Address (IP or Domain Name): '" + host + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +349,8 @@ public class IceServerProperties {
|
||||||
try {
|
try {
|
||||||
int parsedPort = Integer.parseInt(port);
|
int parsedPort = Integer.parseInt(port);
|
||||||
if (parsedPort <= 0 || parsedPort > 65535) {
|
if (parsedPort <= 0 || parsedPort > 65535) {
|
||||||
throw new IllegalArgumentException("The port defined in '" + uri + "' is not a valid port number (0-65535)");
|
throw new IllegalArgumentException(
|
||||||
|
"The port defined in '" + uri + "' is not a valid port number (0-65535)");
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
throw new IllegalArgumentException("The port defined in '" + uri + "' is not a number (0-65535)");
|
throw new IllegalArgumentException("The port defined in '" + uri + "' is not a number (0-65535)");
|
||||||
|
@ -335,19 +362,17 @@ public class IceServerProperties {
|
||||||
this.checkPort(uri, port);
|
this.checkPort(uri, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void generateTURNCredentials() throws NoSuchAlgorithmException, InvalidKeyException {
|
private void generateTURNCredentials() throws NoSuchAlgorithmException, InvalidKeyException {
|
||||||
// 1. Generate random username
|
// 1. Generate random username
|
||||||
char[] ALPHANUMERIC =("abcdefghijklmnopqrstuvwxyzABCDEFGHIJK" +
|
char[] ALPHANUMERIC = ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJK" + "LMNOPQRSTUVWXYZ0123456789").toCharArray();
|
||||||
"LMNOPQRSTUVWXYZ0123456789").toCharArray();
|
|
||||||
int MAX_LENGTH = 8;
|
int MAX_LENGTH = 8;
|
||||||
StringBuilder randomUsername = new StringBuilder();
|
StringBuilder randomUsername = new StringBuilder();
|
||||||
for(int i =0; i < MAX_LENGTH; i++) {
|
for (int i = 0; i < MAX_LENGTH; i++) {
|
||||||
int index = new SecureRandom().nextInt(ALPHANUMERIC.length);
|
int index = new SecureRandom().nextInt(ALPHANUMERIC.length);
|
||||||
randomUsername.append(ALPHANUMERIC[index]);
|
randomUsername.append(ALPHANUMERIC[index]);
|
||||||
}
|
}
|
||||||
// 2. Get unix timestamp adding 24 hours to define max credential valid time
|
// 2. Get unix timestamp adding 24 hours to define max credential valid time
|
||||||
String unixTimestamp = Long.toString((System.currentTimeMillis() / 1000) + 24*3600);
|
String unixTimestamp = Long.toString((System.currentTimeMillis() / 1000) + 24 * 3600);
|
||||||
|
|
||||||
// 3. Generate TURN username
|
// 3. Generate TURN username
|
||||||
String username = unixTimestamp + ":" + randomUsername;
|
String username = unixTimestamp + ":" + randomUsername;
|
||||||
|
@ -356,7 +381,7 @@ public class IceServerProperties {
|
||||||
SecretKeySpec signingKey = new SecretKeySpec(staticAuthSecret.getBytes(), "HmacSHA1");
|
SecretKeySpec signingKey = new SecretKeySpec(staticAuthSecret.getBytes(), "HmacSHA1");
|
||||||
Mac mac = Mac.getInstance("HmacSHA1");
|
Mac mac = Mac.getInstance("HmacSHA1");
|
||||||
mac.init(signingKey);
|
mac.init(signingKey);
|
||||||
String credential = new String(Base64.encodeBase64(mac.doFinal(username.getBytes())));
|
String credential = new String(Base64.getEncoder().encode(mac.doFinal(username.getBytes())));
|
||||||
|
|
||||||
// Set credentials in builder
|
// Set credentials in builder
|
||||||
this.username = username;
|
this.username = username;
|
||||||
|
|
|
@ -18,55 +18,49 @@
|
||||||
package io.openvidu.java.client;
|
package io.openvidu.java.client;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpClient.Builder;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
import java.security.KeyManagementException;
|
import java.security.KeyManagementException;
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLEngine;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.X509ExtendedTrustManager;
|
||||||
|
|
||||||
import org.apache.http.HttpHeaders;
|
|
||||||
import org.apache.http.HttpResponse;
|
|
||||||
import org.apache.http.ParseException;
|
|
||||||
import org.apache.http.auth.AuthScope;
|
|
||||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
|
||||||
import org.apache.http.client.CredentialsProvider;
|
|
||||||
import org.apache.http.client.HttpClient;
|
|
||||||
import org.apache.http.client.config.RequestConfig;
|
|
||||||
import org.apache.http.client.methods.HttpDelete;
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
|
||||||
import org.apache.http.client.methods.HttpPost;
|
|
||||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
|
||||||
import org.apache.http.entity.StringEntity;
|
|
||||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
|
||||||
import org.apache.http.ssl.SSLContextBuilder;
|
|
||||||
import org.apache.http.ssl.TrustStrategy;
|
|
||||||
import org.apache.http.util.EntityUtils;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonSyntaxException;
|
|
||||||
|
|
||||||
public class OpenVidu {
|
public class OpenVidu {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(OpenVidu.class);
|
private static final Logger log = LoggerFactory.getLogger(OpenVidu.class);
|
||||||
|
|
||||||
private String secret;
|
|
||||||
protected String hostname;
|
protected String hostname;
|
||||||
protected HttpClient httpClient;
|
protected HttpClient httpClient;
|
||||||
protected Map<String, Session> activeSessions = new ConcurrentHashMap<>();
|
protected Map<String, Session> activeSessions = new ConcurrentHashMap<>();
|
||||||
|
protected long requestTimeout = 30000;
|
||||||
|
protected Map<String, String> headers = new HashMap<>();
|
||||||
|
|
||||||
protected final static String API_PATH = "openvidu/api";
|
protected final static String API_PATH = "openvidu/api";
|
||||||
protected final static String API_SESSIONS = API_PATH + "/sessions";
|
protected final static String API_SESSIONS = API_PATH + "/sessions";
|
||||||
|
@ -75,49 +69,149 @@ public class OpenVidu {
|
||||||
protected final static String API_RECORDINGS_START = API_RECORDINGS + "/start";
|
protected final static String API_RECORDINGS_START = API_RECORDINGS + "/start";
|
||||||
protected final static String API_RECORDINGS_STOP = API_RECORDINGS + "/stop";
|
protected final static String API_RECORDINGS_STOP = API_RECORDINGS + "/stop";
|
||||||
|
|
||||||
|
private String defaultBasicAuth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param hostname URL where your instance of OpenVidu Server is up an running.
|
* @param hostname URL where your OpenVidu deployment is up an running. It must
|
||||||
* It must be the full URL (e.g.
|
* be the full URL (e.g. <code>https://12.34.56.78:1234/</code>)
|
||||||
* <code>https://12.34.56.78:1234/</code>)
|
|
||||||
*
|
*
|
||||||
* @param secret Secret used on OpenVidu Server initialization
|
* @param secret Secret configured in your OpenVidu deployment
|
||||||
*/
|
*/
|
||||||
public OpenVidu(String hostname, String secret) {
|
public OpenVidu(String hostname, String secret) {
|
||||||
|
|
||||||
this.hostname = hostname;
|
testHostname(hostname);
|
||||||
|
setDefaultBasicAuth(secret);
|
||||||
|
|
||||||
|
this.hostname = hostname;
|
||||||
if (!this.hostname.endsWith("/")) {
|
if (!this.hostname.endsWith("/")) {
|
||||||
this.hostname += "/";
|
this.hostname += "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
this.secret = secret;
|
|
||||||
|
|
||||||
TrustStrategy trustStrategy = new TrustStrategy() {
|
|
||||||
@Override
|
|
||||||
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CredentialsProvider provider = new BasicCredentialsProvider();
|
|
||||||
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("OPENVIDUAPP", this.secret);
|
|
||||||
provider.setCredentials(AuthScope.ANY, credentials);
|
|
||||||
|
|
||||||
SSLContext sslContext;
|
SSLContext sslContext;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sslContext = new SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build();
|
sslContext = SSLContext.getInstance("TLS");
|
||||||
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
|
sslContext.init(null, new TrustManager[] { new X509ExtendedTrustManager() {
|
||||||
|
public X509Certificate[] getAcceptedIssuers() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type,
|
||||||
|
final Socket a_socket) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type,
|
||||||
|
final Socket a_socket) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type,
|
||||||
|
final SSLEngine a_engine) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type,
|
||||||
|
final SSLEngine a_engine) {
|
||||||
|
}
|
||||||
|
} }, null);
|
||||||
|
} catch (KeyManagementException | NoSuchAlgorithmException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestConfig.Builder requestBuilder = RequestConfig.custom();
|
Builder b = HttpClient.newBuilder();
|
||||||
requestBuilder = requestBuilder.setConnectTimeout(30000);
|
b.sslContext(sslContext);
|
||||||
requestBuilder = requestBuilder.setConnectionRequestTimeout(30000);
|
b.connectTimeout(Duration.ofSeconds(30));
|
||||||
|
this.httpClient = b.build();
|
||||||
|
}
|
||||||
|
|
||||||
this.httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestBuilder.build())
|
/**
|
||||||
.setConnectionTimeToLive(30, TimeUnit.SECONDS).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
|
* @param hostname URL where your OpenVidu deployment is up an running. It
|
||||||
.setSSLContext(sslContext).setDefaultCredentialsProvider(provider).build();
|
* must be the full URL (e.g.
|
||||||
|
* <code>https://12.34.56.78:1234/</code>)
|
||||||
|
* @param httpClient Object of class <a target="_blank" href=
|
||||||
|
* "https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html">java.net.http.HttpClient</a>.
|
||||||
|
* This overrides the internal HTTP client in use. This method
|
||||||
|
* allows you to custom configure the HTTP client to your
|
||||||
|
* needs. This may be interesting for many reasons, including:
|
||||||
|
* <ul>
|
||||||
|
* <li>Adding proxy configuration</li>
|
||||||
|
* <li>Customizing the SSLContext</li>
|
||||||
|
* <li>Modifying the connection timeout</li>
|
||||||
|
* <li>Adding a cookie handler</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public OpenVidu(String hostname, String secret, HttpClient httpClient) {
|
||||||
|
|
||||||
|
testHostname(hostname);
|
||||||
|
setDefaultBasicAuth(secret);
|
||||||
|
|
||||||
|
this.hostname = hostname;
|
||||||
|
if (!this.hostname.endsWith("/")) {
|
||||||
|
this.hostname += "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder b = HttpClient.newBuilder();
|
||||||
|
if (httpClient.authenticator().isPresent()) {
|
||||||
|
log.warn(
|
||||||
|
"The provided HttpClient contains a custom java.net.Authenticator. OpenVidu deployments require all HTTP requests to have an Authorization header with Basic Auth, with username \"OPENVIDUAPP\" and password your OpenVidu deployment's secret (configuration parameter OPENVIDU_SECRET). The default Authenticator adds this header. Make sure that your custom Authenticator does so as well or that you add it explicitly via OpenVidu#setRequestHeaders, or you will receive 401 responses");
|
||||||
|
b.authenticator(httpClient.authenticator().get());
|
||||||
|
}
|
||||||
|
if (httpClient.connectTimeout().isPresent()) {
|
||||||
|
b.connectTimeout(httpClient.connectTimeout().get());
|
||||||
|
}
|
||||||
|
if (httpClient.cookieHandler().isPresent()) {
|
||||||
|
b.cookieHandler(httpClient.cookieHandler().get());
|
||||||
|
}
|
||||||
|
if (httpClient.executor().isPresent()) {
|
||||||
|
b.executor(httpClient.executor().get());
|
||||||
|
}
|
||||||
|
if (httpClient.proxy().isPresent()) {
|
||||||
|
b.proxy(httpClient.proxy().get());
|
||||||
|
}
|
||||||
|
b.followRedirects(httpClient.followRedirects());
|
||||||
|
b.sslContext(httpClient.sslContext());
|
||||||
|
b.sslParameters(httpClient.sslParameters());
|
||||||
|
b.version(httpClient.version());
|
||||||
|
|
||||||
|
this.httpClient = b.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current request timeout configured for all requests.
|
||||||
|
*/
|
||||||
|
public long getRequestTimeout() {
|
||||||
|
return this.requestTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the request timeout for all HTTP requests. This is the same as setting
|
||||||
|
* the <a target="_blank" href=
|
||||||
|
* "https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpRequest.html#timeout()">HttpRequest.timeout()</a>
|
||||||
|
* property for all requests. The default value is 30000 ms.
|
||||||
|
*
|
||||||
|
* @param requestTimeout Timeout in milliseconds
|
||||||
|
*/
|
||||||
|
public void setRequestTimeout(long requestTimeout) {
|
||||||
|
this.requestTimeout = requestTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current collection of custom headers configured for all requests.
|
||||||
|
*/
|
||||||
|
public Map<String, String> getRequestHeaders() {
|
||||||
|
return this.headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets custom HTTP headers for all requests. Will override any previous value.
|
||||||
|
*
|
||||||
|
* @param headers Header names and values
|
||||||
|
*/
|
||||||
|
public void setRequestHeaders(Map<String, String> headers) {
|
||||||
|
this.headers = headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -183,23 +277,20 @@ public class OpenVidu {
|
||||||
public Recording startRecording(String sessionId, RecordingProperties properties)
|
public Recording startRecording(String sessionId, RecordingProperties properties)
|
||||||
throws OpenViduJavaClientException, OpenViduHttpException {
|
throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
|
|
||||||
HttpPost request = new HttpPost(this.hostname + API_RECORDINGS_START);
|
try {
|
||||||
|
|
||||||
JsonObject json = properties.toJson();
|
JsonObject json = properties.toJson();
|
||||||
json.addProperty("session", sessionId);
|
json.addProperty("session", sessionId);
|
||||||
|
|
||||||
StringEntity params = new StringEntity(json.toString(), "UTF-8");
|
HttpRequest request = addHeaders(
|
||||||
|
HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(json.toString()))
|
||||||
|
.uri(new URI(this.hostname + API_RECORDINGS_START))
|
||||||
|
.setHeader("Content-Type", "application/json").timeout(Duration.ofMillis(requestTimeout)))
|
||||||
|
.build();
|
||||||
|
|
||||||
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
|
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
request.setEntity(params);
|
|
||||||
|
|
||||||
HttpResponse response = null;
|
if ((response.statusCode() == HttpURLConnection.HTTP_OK)) {
|
||||||
try {
|
Recording r = new Recording(Utils.httpResponseToJson(response));
|
||||||
response = this.httpClient.execute(request);
|
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
|
|
||||||
Recording r = new Recording(httpResponseToJson(response));
|
|
||||||
Session activeSession = this.activeSessions.get(r.getSessionId());
|
Session activeSession = this.activeSessions.get(r.getSessionId());
|
||||||
if (activeSession != null) {
|
if (activeSession != null) {
|
||||||
activeSession.setIsBeingRecorded(true);
|
activeSession.setIsBeingRecorded(true);
|
||||||
|
@ -210,15 +301,11 @@ public class OpenVidu {
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,14 +375,16 @@ public class OpenVidu {
|
||||||
* API</a>)
|
* API</a>)
|
||||||
*/
|
*/
|
||||||
public Recording stopRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException {
|
public Recording stopRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
HttpPost request = new HttpPost(this.hostname + API_RECORDINGS_STOP + "/" + recordingId);
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
|
||||||
response = this.httpClient.execute(request);
|
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
try {
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
|
HttpRequest request = addHeaders(HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.noBody())
|
||||||
Recording r = new Recording(httpResponseToJson(response));
|
.uri(new URI(this.hostname + API_RECORDINGS_STOP + "/" + recordingId))
|
||||||
|
.timeout(Duration.ofMillis(requestTimeout))).build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||||
|
Recording r = new Recording(Utils.httpResponseToJson(response));
|
||||||
Session activeSession = this.activeSessions.get(r.getSessionId());
|
Session activeSession = this.activeSessions.get(r.getSessionId());
|
||||||
if (activeSession != null) {
|
if (activeSession != null) {
|
||||||
activeSession.setIsBeingRecorded(false);
|
activeSession.setIsBeingRecorded(false);
|
||||||
|
@ -306,14 +395,10 @@ public class OpenVidu {
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,24 +416,22 @@ public class OpenVidu {
|
||||||
* API</a>)
|
* API</a>)
|
||||||
*/
|
*/
|
||||||
public Recording getRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException {
|
public Recording getRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
HttpGet request = new HttpGet(this.hostname + API_RECORDINGS + "/" + recordingId);
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
try {
|
||||||
response = this.httpClient.execute(request);
|
HttpRequest request = addHeaders(
|
||||||
|
HttpRequest.newBuilder().GET().uri(new URI(this.hostname + API_RECORDINGS + "/" + recordingId))
|
||||||
|
.timeout(Duration.ofMillis(requestTimeout)))
|
||||||
|
.build();
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
|
|
||||||
return new Recording(httpResponseToJson(response));
|
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||||
|
return new Recording(Utils.httpResponseToJson(response));
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
} catch (IOException e) {
|
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,30 +444,26 @@ public class OpenVidu {
|
||||||
* @throws OpenViduHttpException
|
* @throws OpenViduHttpException
|
||||||
*/
|
*/
|
||||||
public List<Recording> listRecordings() throws OpenViduJavaClientException, OpenViduHttpException {
|
public List<Recording> listRecordings() throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
HttpGet request = new HttpGet(this.hostname + API_RECORDINGS);
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
|
||||||
response = this.httpClient.execute(request);
|
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
try {
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
|
HttpRequest request = addHeaders(HttpRequest.newBuilder().GET().uri(new URI(this.hostname + API_RECORDINGS))
|
||||||
|
.timeout(Duration.ofMillis(requestTimeout))).build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||||
List<Recording> recordings = new ArrayList<>();
|
List<Recording> recordings = new ArrayList<>();
|
||||||
JsonObject json = httpResponseToJson(response);
|
JsonObject json = Utils.httpResponseToJson(response);
|
||||||
JsonArray array = json.get("items").getAsJsonArray();
|
JsonArray array = json.get("items").getAsJsonArray();
|
||||||
array.forEach(item -> {
|
array.forEach(item -> {
|
||||||
recordings.add(new Recording(item.getAsJsonObject()));
|
recordings.add(new Recording(item.getAsJsonObject()));
|
||||||
});
|
});
|
||||||
return recordings;
|
return recordings;
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
} catch (IOException e) {
|
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,22 +484,20 @@ public class OpenVidu {
|
||||||
* API</a>)
|
* API</a>)
|
||||||
*/
|
*/
|
||||||
public void deleteRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException {
|
public void deleteRecording(String recordingId) throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
HttpDelete request = new HttpDelete(this.hostname + API_RECORDINGS + "/" + recordingId);
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
try {
|
||||||
response = this.httpClient.execute(request);
|
HttpRequest request = addHeaders(
|
||||||
|
HttpRequest.newBuilder().DELETE().uri(new URI(this.hostname + API_RECORDINGS + "/" + recordingId))
|
||||||
|
.timeout(Duration.ofMillis(requestTimeout)))
|
||||||
|
.build();
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
if (!(statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
|
|
||||||
throw new OpenViduHttpException(statusCode);
|
if (response.statusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
|
||||||
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
} catch (IOException e) {
|
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,16 +565,17 @@ public class OpenVidu {
|
||||||
* @throws OpenViduJavaClientException
|
* @throws OpenViduJavaClientException
|
||||||
*/
|
*/
|
||||||
public boolean fetch() throws OpenViduJavaClientException, OpenViduHttpException {
|
public boolean fetch() throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
HttpGet request = new HttpGet(this.hostname + API_SESSIONS + "?pendingConnections=true");
|
|
||||||
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
try {
|
||||||
response = this.httpClient.execute(request);
|
HttpRequest request = addHeaders(HttpRequest.newBuilder().GET()
|
||||||
|
.uri(new URI(this.hostname + API_SESSIONS + "?pendingConnections=true"))
|
||||||
|
.timeout(Duration.ofMillis(requestTimeout))).build();
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
|
|
||||||
|
|
||||||
JsonObject jsonSessions = httpResponseToJson(response);
|
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||||
|
|
||||||
|
JsonObject jsonSessions = Utils.httpResponseToJson(response);
|
||||||
JsonArray jsonArraySessions = jsonSessions.get("content").getAsJsonArray();
|
JsonArray jsonArraySessions = jsonSessions.get("content").getAsJsonArray();
|
||||||
|
|
||||||
// Boolean to store if any Session has changed
|
// Boolean to store if any Session has changed
|
||||||
|
@ -546,26 +624,35 @@ public class OpenVidu {
|
||||||
return hasChanged[0];
|
return hasChanged[0];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonObject httpResponseToJson(HttpResponse response) throws OpenViduJavaClientException {
|
protected HttpRequest.Builder addHeaders(HttpRequest.Builder builder) {
|
||||||
|
// HTTP header names are case insensitive
|
||||||
|
Map<String, String> headersLowerCase = new HashMap<>();
|
||||||
|
this.headers.forEach((k, v) -> headersLowerCase.put(k.toLowerCase(), v));
|
||||||
|
if (!headersLowerCase.containsKey("authorization")) {
|
||||||
|
// There is no custom Authorization header. Add default Basic Auth for OpenVidu
|
||||||
|
headersLowerCase.put("authorization", this.defaultBasicAuth);
|
||||||
|
}
|
||||||
|
headersLowerCase.forEach((k, v) -> builder.setHeader(k, v));
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testHostname(String hostnameStr) {
|
||||||
try {
|
try {
|
||||||
JsonObject json = new Gson().fromJson(EntityUtils.toString(response.getEntity(), "UTF-8"),
|
new URL(hostnameStr);
|
||||||
JsonObject.class);
|
} catch (MalformedURLException e) {
|
||||||
return json;
|
throw new RuntimeException("The hostname \"" + hostnameStr + "\" is not a valid URL: " + e.getMessage());
|
||||||
} catch (JsonSyntaxException | ParseException | IOException e) {
|
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setDefaultBasicAuth(String secret) {
|
||||||
|
this.defaultBasicAuth = "Basic " + Base64.getEncoder().encodeToString(("OPENVIDUAPP:" + secret).getBytes());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,7 @@ public class Recording {
|
||||||
* URL of the recording. You can access the file from there. It is
|
* URL of the recording. You can access the file from there. It is
|
||||||
* <code>null</code> until recording reaches "ready" or "failed" status. If
|
* <code>null</code> until recording reaches "ready" or "failed" status. If
|
||||||
* <a href="https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/">
|
* <a href="https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/">
|
||||||
* OpenVidu Server configuration </a> property
|
* OpenVidu configuration </a> property
|
||||||
* <code>OPENVIDU_RECORDING_PUBLIC_ACCESS</code> is false, this path will be
|
* <code>OPENVIDU_RECORDING_PUBLIC_ACCESS</code> is false, this path will be
|
||||||
* secured with OpenVidu credentials
|
* secured with OpenVidu credentials
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -22,7 +22,6 @@ import java.util.Map;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import io.openvidu.java.client.Recording.OutputMode;
|
import io.openvidu.java.client.Recording.OutputMode;
|
||||||
import io.openvidu.java.client.utils.FormatChecker;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See
|
* See
|
||||||
|
@ -559,7 +558,7 @@ public class RecordingProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nameParam != null && !nameParam.isEmpty()) {
|
if (nameParam != null && !nameParam.isEmpty()) {
|
||||||
if (!FormatChecker.isValidRecordingName(nameParam)) {
|
if (!Utils.isValidRecordingName(nameParam)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Parameter 'name' is wrong. Must be an alphanumeric string [a-zA-Z0-9_-~]+");
|
"Parameter 'name' is wrong. Must be an alphanumeric string [a-zA-Z0-9_-~]+");
|
||||||
}
|
}
|
||||||
|
@ -620,7 +619,7 @@ public class RecordingProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolutionParam != null) {
|
if (resolutionParam != null) {
|
||||||
if (!FormatChecker.isAcceptableRecordingResolution(resolutionParam)) {
|
if (!Utils.isAcceptableRecordingResolution(resolutionParam)) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Wrong 'resolution' parameter. Acceptable values from 100 to 1999 for both width and height");
|
"Wrong 'resolution' parameter. Acceptable values from 100 to 1999 for both width and height");
|
||||||
}
|
}
|
||||||
|
@ -630,7 +629,7 @@ public class RecordingProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frameRateParam != null) {
|
if (frameRateParam != null) {
|
||||||
if (!FormatChecker.isAcceptableRecordingFrameRate(frameRateParam.intValue())) {
|
if (!Utils.isAcceptableRecordingFrameRate(frameRateParam.intValue())) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Wrong 'frameRate' parameter. Acceptable values are within range [1,120]");
|
"Wrong 'frameRate' parameter. Acceptable values are within range [1,120]");
|
||||||
}
|
}
|
||||||
|
@ -640,7 +639,7 @@ public class RecordingProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shmSizeParam != null) {
|
if (shmSizeParam != null) {
|
||||||
if (!FormatChecker.isAcceptableRecordingShmSize(shmSizeParam)) {
|
if (!Utils.isAcceptableRecordingShmSize(shmSizeParam)) {
|
||||||
throw new IllegalStateException("Wrong 'shmSize' parameter. Must be 134217728 (128 MB) minimum");
|
throw new IllegalStateException("Wrong 'shmSize' parameter. Must be 134217728 (128 MB) minimum");
|
||||||
}
|
}
|
||||||
shmSizeFinal = shmSizeParam;
|
shmSizeFinal = shmSizeParam;
|
||||||
|
|
|
@ -18,6 +18,12 @@
|
||||||
package io.openvidu.java.client;
|
package io.openvidu.java.client;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -25,14 +31,6 @@ import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.http.HttpHeaders;
|
|
||||||
import org.apache.http.HttpResponse;
|
|
||||||
import org.apache.http.client.methods.HttpDelete;
|
|
||||||
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.entity.StringEntity;
|
|
||||||
import org.apache.http.util.EntityUtils;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -40,7 +38,6 @@ import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonSyntaxException;
|
|
||||||
|
|
||||||
public class Session {
|
public class Session {
|
||||||
|
|
||||||
|
@ -116,35 +113,34 @@ public class Session {
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public String generateToken(TokenOptions tokenOptions) throws OpenViduJavaClientException, OpenViduHttpException {
|
public String generateToken(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);
|
|
||||||
StringEntity params = new StringEntity(tokenOptions.toJsonObject(sessionId).toString(), "UTF-8");
|
|
||||||
|
|
||||||
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
|
|
||||||
request.setEntity(params);
|
|
||||||
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
try {
|
||||||
response = this.openVidu.httpClient.execute(request);
|
JsonObject json = tokenOptions.toJsonObject(sessionId);
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
HttpRequest request = this.openVidu
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
|
.addHeaders(HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(json.toString()))
|
||||||
String token = httpResponseToJson(response).get("id").getAsString();
|
.uri(new URI(this.openVidu.hostname + OpenVidu.API_TOKENS))
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.timeout(Duration.ofMillis(this.openVidu.requestTimeout)))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = this.openVidu.httpClient.send(request,
|
||||||
|
HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||||
|
String token = Utils.httpResponseToJson(response).get("id").getAsString();
|
||||||
log.info("Returning a TOKEN: {}", token);
|
log.info("Returning a TOKEN: {}", token);
|
||||||
return token;
|
return token;
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,36 +175,33 @@ public class Session {
|
||||||
*/
|
*/
|
||||||
public Connection createConnection(ConnectionProperties connectionProperties)
|
public Connection createConnection(ConnectionProperties connectionProperties)
|
||||||
throws OpenViduJavaClientException, OpenViduHttpException {
|
throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
|
|
||||||
if (!this.hasSessionId()) {
|
if (!this.hasSessionId()) {
|
||||||
this.getSessionId();
|
this.getSessionId();
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpPost request = new HttpPost(
|
|
||||||
this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection");
|
|
||||||
StringEntity params = new StringEntity(connectionProperties.toJson(sessionId).toString(), "UTF-8");
|
|
||||||
|
|
||||||
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
|
|
||||||
request.setEntity(params);
|
|
||||||
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
try {
|
||||||
response = this.openVidu.httpClient.execute(request);
|
JsonObject json = connectionProperties.toJson(sessionId);
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
HttpRequest request = this.openVidu.addHeaders(HttpRequest.newBuilder()
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
|
.POST(HttpRequest.BodyPublishers.ofString(json.toString()))
|
||||||
Connection connection = new Connection(httpResponseToJson(response));
|
.uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection"))
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.timeout(Duration.ofMillis(this.openVidu.requestTimeout))).build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = this.openVidu.httpClient.send(request,
|
||||||
|
HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||||
|
Connection connection = new Connection(Utils.httpResponseToJson(response));
|
||||||
this.connections.put(connection.getConnectionId(), connection);
|
this.connections.put(connection.getConnectionId(), connection);
|
||||||
return connection;
|
return connection;
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,27 +213,24 @@ public class Session {
|
||||||
* @throws OpenViduHttpException
|
* @throws OpenViduHttpException
|
||||||
*/
|
*/
|
||||||
public void close() throws OpenViduJavaClientException, OpenViduHttpException {
|
public void close() throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
HttpDelete request = new HttpDelete(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId);
|
|
||||||
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
|
|
||||||
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
try {
|
||||||
response = this.openVidu.httpClient.execute(request);
|
HttpRequest request = this.openVidu.addHeaders(HttpRequest.newBuilder().DELETE()
|
||||||
|
.uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId))
|
||||||
|
.timeout(Duration.ofMillis(this.openVidu.requestTimeout))).build();
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
HttpResponse<String> response = this.openVidu.httpClient.send(request,
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
|
HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT) {
|
||||||
this.openVidu.activeSessions.remove(this.sessionId);
|
this.openVidu.activeSessions.remove(this.sessionId);
|
||||||
log.info("Session {} closed", this.sessionId);
|
log.info("Session {} closed", this.sessionId);
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,32 +256,30 @@ public class Session {
|
||||||
* @throws OpenViduJavaClientException
|
* @throws OpenViduJavaClientException
|
||||||
*/
|
*/
|
||||||
public boolean fetch() throws OpenViduJavaClientException, OpenViduHttpException {
|
public boolean fetch() throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
final String beforeJSON = this.toJson();
|
|
||||||
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 = null;
|
|
||||||
try {
|
try {
|
||||||
response = this.openVidu.httpClient.execute(request);
|
final String beforeJSON = this.toJson();
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
HttpRequest request = this.openVidu.addHeaders(HttpRequest.newBuilder().GET()
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
|
.uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId
|
||||||
this.resetWithJson(httpResponseToJson(response));
|
+ "?pendingConnections=true"))
|
||||||
|
.timeout(Duration.ofMillis(this.openVidu.requestTimeout))).build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = this.openVidu.httpClient.send(request,
|
||||||
|
HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||||
|
this.resetWithJson(Utils.httpResponseToJson(response));
|
||||||
final String afterJSON = this.toJson();
|
final String afterJSON = this.toJson();
|
||||||
boolean hasChanged = !beforeJSON.equals(afterJSON);
|
boolean hasChanged = !beforeJSON.equals(afterJSON);
|
||||||
log.info("Session info fetched for session '{}'. Any change: {}", this.sessionId, hasChanged);
|
log.info("Session info fetched for session '{}'. Any change: {}", this.sessionId, hasChanged);
|
||||||
return hasChanged;
|
return hasChanged;
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,16 +328,18 @@ public class Session {
|
||||||
* @throws OpenViduHttpException
|
* @throws OpenViduHttpException
|
||||||
*/
|
*/
|
||||||
public void forceDisconnect(String connectionId) throws OpenViduJavaClientException, OpenViduHttpException {
|
public void forceDisconnect(String connectionId) throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
HttpDelete request = new HttpDelete(
|
|
||||||
this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection/" + connectionId);
|
|
||||||
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
|
|
||||||
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
try {
|
||||||
response = this.openVidu.httpClient.execute(request);
|
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
HttpRequest request = this.openVidu.addHeaders(HttpRequest
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
|
.newBuilder().DELETE().uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/"
|
||||||
|
+ this.sessionId + "/connection/" + connectionId))
|
||||||
|
.timeout(Duration.ofMillis(this.openVidu.requestTimeout))).build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = this.openVidu.httpClient.send(request,
|
||||||
|
HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT) {
|
||||||
// Remove connection from activeConnections map
|
// Remove connection from activeConnections map
|
||||||
Connection connectionClosed = this.connections.remove(connectionId);
|
Connection connectionClosed = this.connections.remove(connectionId);
|
||||||
// Remove every Publisher of the closed connection from every subscriber list of
|
// Remove every Publisher of the closed connection from every subscriber list of
|
||||||
|
@ -368,15 +358,11 @@ public class Session {
|
||||||
}
|
}
|
||||||
log.info("Connection {} closed", connectionId);
|
log.info("Connection {} closed", connectionId);
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,16 +408,20 @@ public class Session {
|
||||||
* @throws OpenViduHttpException
|
* @throws OpenViduHttpException
|
||||||
*/
|
*/
|
||||||
public void forceUnpublish(String streamId) throws OpenViduJavaClientException, OpenViduHttpException {
|
public void forceUnpublish(String streamId) throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
HttpDelete request = new HttpDelete(
|
|
||||||
this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/stream/" + streamId);
|
|
||||||
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
|
|
||||||
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
try {
|
||||||
response = this.openVidu.httpClient.execute(request);
|
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
HttpRequest request = this.openVidu
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
|
.addHeaders(HttpRequest.newBuilder().DELETE()
|
||||||
|
.uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId
|
||||||
|
+ "/stream/" + streamId))
|
||||||
|
.timeout(Duration.ofMillis(this.openVidu.requestTimeout)))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = this.openVidu.httpClient.send(request,
|
||||||
|
HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT) {
|
||||||
for (Connection connection : this.connections.values()) {
|
for (Connection connection : this.connections.values()) {
|
||||||
// Try to remove the Publisher from the Connection publishers collection
|
// Try to remove the Publisher from the Connection publishers collection
|
||||||
if (connection.publishers.remove(streamId) != null) {
|
if (connection.publishers.remove(streamId) != null) {
|
||||||
|
@ -442,15 +432,11 @@ public class Session {
|
||||||
}
|
}
|
||||||
log.info("Stream {} unpublished", streamId);
|
log.info("Stream {} unpublished", streamId);
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,26 +481,28 @@ public class Session {
|
||||||
public Connection updateConnection(String connectionId, ConnectionProperties connectionProperties)
|
public Connection updateConnection(String connectionId, ConnectionProperties connectionProperties)
|
||||||
throws OpenViduJavaClientException, OpenViduHttpException {
|
throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
|
|
||||||
HttpPatch request = new HttpPatch(
|
|
||||||
this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection/" + connectionId);
|
|
||||||
StringEntity params = new StringEntity(connectionProperties.toJson(this.sessionId).toString(), "UTF-8");
|
|
||||||
|
|
||||||
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
|
|
||||||
request.setEntity(params);
|
|
||||||
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
try {
|
||||||
response = this.openVidu.httpClient.execute(request);
|
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
JsonObject jsonPayload = connectionProperties.toJson(this.sessionId);
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
|
|
||||||
|
HttpRequest request = this.openVidu.addHeaders(HttpRequest.newBuilder()
|
||||||
|
.method("PATCH", HttpRequest.BodyPublishers.ofString(jsonPayload.toString()))
|
||||||
|
.uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection/"
|
||||||
|
+ connectionId))
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.timeout(Duration.ofMillis(this.openVidu.requestTimeout))).build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = this.openVidu.httpClient.send(request,
|
||||||
|
HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||||
log.info("Connection {} updated", connectionId);
|
log.info("Connection {} updated", connectionId);
|
||||||
} else if ((statusCode == org.apache.http.HttpStatus.SC_NO_CONTENT)) {
|
} else if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT) {
|
||||||
log.info("Properties of Connection {} remain the same", connectionId);
|
log.info("Properties of Connection {} remain the same", connectionId);
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
JsonObject json = httpResponseToJson(response);
|
JsonObject json = Utils.httpResponseToJson(response);
|
||||||
|
|
||||||
// Update the actual Connection object with the new options
|
// Update the actual Connection object with the new options
|
||||||
Connection existingConnection = this.connections.get(connectionId);
|
Connection existingConnection = this.connections.get(connectionId);
|
||||||
|
@ -530,12 +518,8 @@ public class Session {
|
||||||
return existingConnection;
|
return existingConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,23 +626,27 @@ public class Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getSessionHttp() throws OpenViduJavaClientException, OpenViduHttpException {
|
private void getSessionHttp() throws OpenViduJavaClientException, OpenViduHttpException {
|
||||||
|
|
||||||
if (this.hasSessionId()) {
|
if (this.hasSessionId()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpPost request = new HttpPost(this.openVidu.hostname + OpenVidu.API_SESSIONS);
|
|
||||||
StringEntity params = new StringEntity(properties.toJson().toString(), "UTF-8");
|
|
||||||
|
|
||||||
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
|
|
||||||
request.setEntity(params);
|
|
||||||
|
|
||||||
HttpResponse response = null;
|
|
||||||
try {
|
try {
|
||||||
response = this.openVidu.httpClient.execute(request);
|
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
JsonObject json = properties.toJson();
|
||||||
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
|
|
||||||
JsonObject responseJson = httpResponseToJson(response);
|
HttpRequest request = this.openVidu
|
||||||
|
.addHeaders(HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(json.toString()))
|
||||||
|
.uri(new URI(this.openVidu.hostname + OpenVidu.API_SESSIONS))
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.timeout(Duration.ofMillis(this.openVidu.requestTimeout)))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = this.openVidu.httpClient.send(request,
|
||||||
|
HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
if (response.statusCode() == HttpURLConnection.HTTP_OK) {
|
||||||
|
JsonObject responseJson = Utils.httpResponseToJson(response);
|
||||||
this.sessionId = responseJson.get("id").getAsString();
|
this.sessionId = responseJson.get("id").getAsString();
|
||||||
this.createdAt = responseJson.get("createdAt").getAsLong();
|
this.createdAt = responseJson.get("createdAt").getAsLong();
|
||||||
|
|
||||||
|
@ -675,31 +663,17 @@ public class Session {
|
||||||
|
|
||||||
this.properties = responseProperties;
|
this.properties = responseProperties;
|
||||||
log.info("Session '{}' created", this.sessionId);
|
log.info("Session '{}' created", this.sessionId);
|
||||||
} else if (statusCode == org.apache.http.HttpStatus.SC_CONFLICT) {
|
} else if (response.statusCode() == HttpURLConnection.HTTP_CONFLICT) {
|
||||||
// 'customSessionId' already existed
|
// 'customSessionId' already existed
|
||||||
this.sessionId = properties.customSessionId();
|
this.sessionId = properties.customSessionId();
|
||||||
this.fetch();
|
this.fetch();
|
||||||
} else {
|
} else {
|
||||||
throw new OpenViduHttpException(statusCode);
|
throw new OpenViduHttpException(response.statusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (URISyntaxException | IOException | InterruptedException e) {
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
|
||||||
} finally {
|
|
||||||
if (response != null) {
|
|
||||||
EntityUtils.consumeQuietly(response.getEntity());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonObject httpResponseToJson(HttpResponse response) throws OpenViduJavaClientException {
|
|
||||||
JsonObject json;
|
|
||||||
try {
|
|
||||||
json = new Gson().fromJson(EntityUtils.toString(response.getEntity(), "UTF-8"), JsonObject.class);
|
|
||||||
} catch (JsonSyntaxException | IOException e) {
|
|
||||||
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
}
|
}
|
||||||
return json;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setIsBeingRecorded(boolean recording) {
|
protected void setIsBeingRecorded(boolean recording) {
|
||||||
|
|
|
@ -1,9 +1,24 @@
|
||||||
package io.openvidu.java.client.utils;
|
package io.openvidu.java.client;
|
||||||
|
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hidden
|
* @hidden
|
||||||
*/
|
*/
|
||||||
public final class FormatChecker {
|
public class Utils {
|
||||||
|
|
||||||
|
public static JsonObject httpResponseToJson(HttpResponse<String> response) throws OpenViduJavaClientException {
|
||||||
|
try {
|
||||||
|
JsonObject json = new Gson().fromJson(response.body(), JsonObject.class);
|
||||||
|
return json;
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
throw new OpenViduJavaClientException(e.getMessage(), e.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isAcceptableRecordingResolution(String stringResolution) {
|
public static boolean isAcceptableRecordingResolution(String stringResolution) {
|
||||||
// Matches every string with format "AxB", being A and B any number not starting
|
// Matches every string with format "AxB", being A and B any number not starting
|
|
@ -0,0 +1,70 @@
|
||||||
|
package io.openvidu.java.client.test;
|
||||||
|
|
||||||
|
import java.net.Authenticator;
|
||||||
|
import java.net.CookieManager;
|
||||||
|
import java.net.CookiePolicy;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.PasswordAuthentication;
|
||||||
|
import java.net.ProxySelector;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpClient.Redirect;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import io.openvidu.java.client.OpenVidu;
|
||||||
|
|
||||||
|
public class OpenViduConstructorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void wrongHostname() {
|
||||||
|
RuntimeException thrown = Assertions.assertThrows(RuntimeException.class, () -> {
|
||||||
|
new OpenVidu("WRONG_URL", "MY_SECRET");
|
||||||
|
});
|
||||||
|
Assertions.assertEquals("The hostname \"WRONG_URL\" is not a valid URL: no protocol: WRONG_URL",
|
||||||
|
thrown.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void buildWithHttpClientWithoutAuthenticator() {
|
||||||
|
HttpClient.Builder builder = HttpClient.newBuilder();
|
||||||
|
builder.connectTimeout(Duration.ofMillis(10000));
|
||||||
|
ProxySelector proxy = ProxySelector.of(new InetSocketAddress("https://my.proxy.hostname/", 4444));
|
||||||
|
builder.proxy(proxy);
|
||||||
|
builder.followRedirects(Redirect.ALWAYS);
|
||||||
|
SSLContext sslContext = null;
|
||||||
|
try {
|
||||||
|
sslContext = SSLContext.getInstance("TLSv1.2");
|
||||||
|
sslContext.init(null, null, null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
builder.sslContext(sslContext);
|
||||||
|
builder.executor(Executors.newFixedThreadPool(1));
|
||||||
|
builder.cookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
|
||||||
|
OpenVidu OV = new OpenVidu("https://localhost:4443/", "MY_SECRET", builder.build());
|
||||||
|
Assertions.assertEquals(30000, OV.getRequestTimeout());
|
||||||
|
Assertions.assertTrue(OV.getRequestHeaders().isEmpty());
|
||||||
|
OV.setRequestTimeout(5000);
|
||||||
|
OV.setRequestHeaders(Map.of("header1", "value1", "header2", "value2"));
|
||||||
|
Assertions.assertEquals(5000, OV.getRequestTimeout());
|
||||||
|
Assertions.assertEquals(2, OV.getRequestHeaders().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void buildWithHttpClientWithAuthenticator() {
|
||||||
|
Authenticator authenticator = new Authenticator() {
|
||||||
|
@Override
|
||||||
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
|
return new PasswordAuthentication("OPENVIDUAPP", "secret".toCharArray());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
HttpClient.Builder builder = HttpClient.newBuilder().authenticator(authenticator);
|
||||||
|
new OpenVidu("https://localhost:4443/", "MY_SECRET", builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,9 +6,9 @@ import java.util.List;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import io.openvidu.java.client.utils.FormatChecker;
|
import io.openvidu.java.client.Utils;
|
||||||
|
|
||||||
public class FormatCheckerTest {
|
public class UtilsFormatCheckerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomSessionIdFormat() {
|
public void testCustomSessionIdFormat() {
|
||||||
|
@ -23,9 +23,9 @@ public class FormatCheckerTest {
|
||||||
"session-_", "123_session-1");
|
"session-_", "123_session-1");
|
||||||
|
|
||||||
for (String id : invalidCustomSessionIds)
|
for (String id : invalidCustomSessionIds)
|
||||||
Assertions.assertFalse(FormatChecker.isValidCustomSessionId(id));
|
Assertions.assertFalse(Utils.isValidCustomSessionId(id));
|
||||||
for (String id : validCustomSessionIds)
|
for (String id : validCustomSessionIds)
|
||||||
Assertions.assertTrue(FormatChecker.isValidCustomSessionId(id));
|
Assertions.assertTrue(Utils.isValidCustomSessionId(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -37,9 +37,9 @@ public class FormatCheckerTest {
|
||||||
List<String> validResolutions = Arrays.asList("1920x1080", "1280x720", "100x1999");
|
List<String> validResolutions = Arrays.asList("1920x1080", "1280x720", "100x1999");
|
||||||
|
|
||||||
for (String resolution : invalidResolutions)
|
for (String resolution : invalidResolutions)
|
||||||
Assertions.assertFalse(FormatChecker.isAcceptableRecordingResolution(resolution));
|
Assertions.assertFalse(Utils.isAcceptableRecordingResolution(resolution));
|
||||||
for (String resolution : validResolutions)
|
for (String resolution : validResolutions)
|
||||||
Assertions.assertTrue(FormatChecker.isAcceptableRecordingResolution(resolution));
|
Assertions.assertTrue(Utils.isAcceptableRecordingResolution(resolution));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -50,9 +50,9 @@ public class FormatCheckerTest {
|
||||||
List<Integer> validFramerates = Arrays.asList(1, 2, 30, 60, 119, 120);
|
List<Integer> validFramerates = Arrays.asList(1, 2, 30, 60, 119, 120);
|
||||||
|
|
||||||
for (int framerate : invalidFrameRates)
|
for (int framerate : invalidFrameRates)
|
||||||
Assertions.assertFalse(FormatChecker.isAcceptableRecordingFrameRate(framerate));
|
Assertions.assertFalse(Utils.isAcceptableRecordingFrameRate(framerate));
|
||||||
for (int framerate : validFramerates)
|
for (int framerate : validFramerates)
|
||||||
Assertions.assertTrue(FormatChecker.isAcceptableRecordingFrameRate(framerate));
|
Assertions.assertTrue(Utils.isAcceptableRecordingFrameRate(framerate));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -87,10 +87,10 @@ export class OpenVidu {
|
||||||
activeSessions: Session[] = [];
|
activeSessions: Session[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param hostname URL where your instance of OpenVidu Server is up an running.
|
* @param hostname URL where your OpenVidu deployment is up an running.
|
||||||
* It must be the full URL (e.g. `https://12.34.56.78:1234/`)
|
* It must be the full URL (e.g. `https://12.34.56.78:1234/`)
|
||||||
*
|
*
|
||||||
* @param secret Secret used on OpenVidu Server initialization
|
* @param secret Secret configured in your OpenVidu deployment
|
||||||
*/
|
*/
|
||||||
constructor(private hostname: string, secret: string) {
|
constructor(private hostname: string, secret: string) {
|
||||||
this.setHostnameAndPort();
|
this.setHostnameAndPort();
|
||||||
|
|
|
@ -53,7 +53,6 @@ import io.openvidu.java.client.KurentoOptions;
|
||||||
import io.openvidu.java.client.OpenViduRole;
|
import io.openvidu.java.client.OpenViduRole;
|
||||||
import io.openvidu.java.client.Recording;
|
import io.openvidu.java.client.Recording;
|
||||||
import io.openvidu.java.client.SessionProperties;
|
import io.openvidu.java.client.SessionProperties;
|
||||||
import io.openvidu.java.client.utils.FormatChecker;
|
|
||||||
import io.openvidu.server.cdr.CDREventRecordingStatusChanged;
|
import io.openvidu.server.cdr.CDREventRecordingStatusChanged;
|
||||||
import io.openvidu.server.config.OpenviduConfig;
|
import io.openvidu.server.config.OpenviduConfig;
|
||||||
import io.openvidu.server.coturn.CoturnCredentialsService;
|
import io.openvidu.server.coturn.CoturnCredentialsService;
|
||||||
|
@ -338,7 +337,7 @@ public abstract class SessionManager {
|
||||||
|
|
||||||
public Token newToken(Session session, OpenViduRole role, String serverMetadata, boolean record,
|
public Token newToken(Session session, OpenViduRole role, String serverMetadata, boolean record,
|
||||||
KurentoOptions kurentoOptions, List<IceServerProperties> customIceServers) throws Exception {
|
KurentoOptions kurentoOptions, List<IceServerProperties> customIceServers) throws Exception {
|
||||||
if (!FormatChecker.isServerMetadataFormatCorrect(serverMetadata)) {
|
if (!io.openvidu.java.client.Utils.isServerMetadataFormatCorrect(serverMetadata)) {
|
||||||
log.error("Data invalid format");
|
log.error("Data invalid format");
|
||||||
throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format");
|
throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format");
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,6 @@ import io.openvidu.client.internal.ProtocolElements;
|
||||||
import io.openvidu.java.client.ConnectionProperties;
|
import io.openvidu.java.client.ConnectionProperties;
|
||||||
import io.openvidu.java.client.ConnectionType;
|
import io.openvidu.java.client.ConnectionType;
|
||||||
import io.openvidu.java.client.OpenViduRole;
|
import io.openvidu.java.client.OpenViduRole;
|
||||||
import io.openvidu.java.client.utils.FormatChecker;
|
|
||||||
import io.openvidu.server.config.OpenviduBuildInfo;
|
import io.openvidu.server.config.OpenviduBuildInfo;
|
||||||
import io.openvidu.server.config.OpenviduConfig;
|
import io.openvidu.server.config.OpenviduConfig;
|
||||||
import io.openvidu.server.core.EndReason;
|
import io.openvidu.server.core.EndReason;
|
||||||
|
@ -304,7 +303,7 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
|
||||||
if (tokenObj != null) {
|
if (tokenObj != null) {
|
||||||
|
|
||||||
String clientMetadata = getStringParam(request, ProtocolElements.JOINROOM_METADATA_PARAM);
|
String clientMetadata = getStringParam(request, ProtocolElements.JOINROOM_METADATA_PARAM);
|
||||||
if (FormatChecker.isServerMetadataFormatCorrect(clientMetadata)) {
|
if (io.openvidu.java.client.Utils.isServerMetadataFormatCorrect(clientMetadata)) {
|
||||||
|
|
||||||
// While closing a session users can't join
|
// While closing a session users can't join
|
||||||
if (session.closingLock.readLock().tryLock()) {
|
if (session.closingLock.readLock().tryLock()) {
|
||||||
|
|
|
@ -102,6 +102,11 @@
|
||||||
<artifactId>java-client</artifactId>
|
<artifactId>java-client</artifactId>
|
||||||
<version>${version.appium}</version>
|
<version>${version.appium}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.14</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
|
|
|
@ -112,6 +112,11 @@
|
||||||
<artifactId>java-string-similarity</artifactId>
|
<artifactId>java-string-similarity</artifactId>
|
||||||
<version>${version.stringsimilarity}</version>
|
<version>${version.stringsimilarity}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.14</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -20,6 +20,13 @@ package io.openvidu.test.e2e;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.net.Authenticator;
|
||||||
|
import java.net.PasswordAuthentication;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.security.KeyManagementException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -34,6 +41,12 @@ import java.util.concurrent.TimeoutException;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLEngine;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.X509ExtendedTrustManager;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
@ -2427,6 +2440,129 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
||||||
gracefullyLeaveParticipants(user, 2);
|
gracefullyLeaveParticipants(user, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("openvidu-java-client custom HttpClient test")
|
||||||
|
void openViduJavaClientCustomHttpClientTest() throws Exception {
|
||||||
|
|
||||||
|
// Test all possible combinations: custom Authenticator present and valid,
|
||||||
|
// present and wrong and no present; in combination with custom Authorization
|
||||||
|
// header present and valid, present and wrong and no present
|
||||||
|
|
||||||
|
HttpClient.Builder builder = HttpClient.newBuilder();
|
||||||
|
SSLContext sslContext;
|
||||||
|
try {
|
||||||
|
sslContext = SSLContext.getInstance("TLS");
|
||||||
|
sslContext.init(null, new TrustManager[] { new X509ExtendedTrustManager() {
|
||||||
|
public X509Certificate[] getAcceptedIssuers() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type,
|
||||||
|
final Socket a_socket) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type,
|
||||||
|
final Socket a_socket) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkClientTrusted(final X509Certificate[] a_certificates, final String a_auth_type,
|
||||||
|
final SSLEngine a_engine) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkServerTrusted(final X509Certificate[] a_certificates, final String a_auth_type,
|
||||||
|
final SSLEngine a_engine) {
|
||||||
|
}
|
||||||
|
} }, null);
|
||||||
|
} catch (KeyManagementException | NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
builder.sslContext(sslContext);
|
||||||
|
|
||||||
|
final String BASIC_AUTH = "Basic "
|
||||||
|
+ Base64.getEncoder().encodeToString(("OPENVIDUAPP:" + OPENVIDU_SECRET).getBytes());
|
||||||
|
final String WRONG_SECRET = "WRONG_SECRET_" + RandomStringUtils.randomAlphanumeric(10);
|
||||||
|
|
||||||
|
// 1. No authenticator, no header, 200
|
||||||
|
OpenVidu customHttpClientOV1 = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET, builder.build());
|
||||||
|
customHttpClientOV1.fetch();
|
||||||
|
|
||||||
|
// 2. No authenticator, wrong header, 401
|
||||||
|
customHttpClientOV1.setRequestHeaders(Map.of("Authorization", "WRONG_AUTH_HEADER"));
|
||||||
|
OpenViduHttpException thrown = Assertions.assertThrows(OpenViduHttpException.class, () -> {
|
||||||
|
customHttpClientOV1.fetch();
|
||||||
|
});
|
||||||
|
Assertions.assertEquals(401, thrown.getStatus());
|
||||||
|
|
||||||
|
// 3. No authenticator and valid header, 200
|
||||||
|
customHttpClientOV1.setRequestHeaders(Map.of("Authorization", BASIC_AUTH));
|
||||||
|
customHttpClientOV1.fetch();
|
||||||
|
|
||||||
|
// 4. Wrong authenticator and no header, 401
|
||||||
|
builder.authenticator(new Authenticator() {
|
||||||
|
@Override
|
||||||
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
|
return new PasswordAuthentication("OPENVIDUAPP", WRONG_SECRET.toCharArray());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
OpenVidu customHttpClientOV2 = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET, builder.build());
|
||||||
|
OpenViduJavaClientException thrown2 = Assertions.assertThrows(OpenViduJavaClientException.class, () -> {
|
||||||
|
customHttpClientOV2.fetch();
|
||||||
|
});
|
||||||
|
Assertions.assertTrue(thrown2.getMessage().contains("too many authentication attempts"));
|
||||||
|
|
||||||
|
// 5. Wrong authenticator and wrong header, 401
|
||||||
|
customHttpClientOV2.setRequestHeaders(Map.of("Authorization", "WRONG_AUTH_HEADER"));
|
||||||
|
thrown2 = Assertions.assertThrows(OpenViduJavaClientException.class, () -> {
|
||||||
|
customHttpClientOV2.fetch();
|
||||||
|
});
|
||||||
|
Assertions.assertTrue(thrown2.getMessage().contains("too many authentication attempts"));
|
||||||
|
|
||||||
|
// 6. Wrong authenticator and valid header, 401
|
||||||
|
customHttpClientOV2.setRequestHeaders(Map.of("Authorization", BASIC_AUTH));
|
||||||
|
thrown2 = Assertions.assertThrows(OpenViduJavaClientException.class, () -> {
|
||||||
|
customHttpClientOV2.fetch();
|
||||||
|
});
|
||||||
|
Assertions.assertTrue(thrown2.getMessage().contains("too many authentication attempts"));
|
||||||
|
|
||||||
|
// 7. Valid authenticator and no header, 200
|
||||||
|
builder.authenticator(new Authenticator() {
|
||||||
|
@Override
|
||||||
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
|
return new PasswordAuthentication("OPENVIDUAPP", OPENVIDU_SECRET.toCharArray());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
OpenVidu customHttpClientOV3 = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET, builder.build());
|
||||||
|
customHttpClientOV3.fetch();
|
||||||
|
|
||||||
|
// 8. Valid authenticator and wrong header, 200
|
||||||
|
customHttpClientOV3.setRequestHeaders(Map.of("Authorization", "WRONG_AUTH_HEADER"));
|
||||||
|
customHttpClientOV3.fetch();
|
||||||
|
|
||||||
|
// 9. Valid authenticator and valid header, 200
|
||||||
|
customHttpClientOV3.setRequestHeaders(Map.of("Authorization", BASIC_AUTH));
|
||||||
|
customHttpClientOV3.fetch();
|
||||||
|
|
||||||
|
// 10. Wrong secret, valid authenticator, no header, 200
|
||||||
|
OpenVidu customHttpClientOV4 = new OpenVidu(OPENVIDU_URL, WRONG_SECRET, builder.build());
|
||||||
|
customHttpClientOV4.fetch();
|
||||||
|
|
||||||
|
// 11. Wrong secret, valid authenticator, wrong header, 200
|
||||||
|
customHttpClientOV4.setRequestHeaders(Map.of("Authorization", "WRONG_AUTH_HEADER"));
|
||||||
|
customHttpClientOV4.fetch();
|
||||||
|
|
||||||
|
// 12. Wrong secret, no authenticator, valid header, 200
|
||||||
|
builder = HttpClient.newBuilder().sslContext(sslContext);
|
||||||
|
customHttpClientOV4 = new OpenVidu(OPENVIDU_URL, WRONG_SECRET, builder.build());
|
||||||
|
customHttpClientOV4.setRequestHeaders(Map.of("Authorization", BASIC_AUTH));
|
||||||
|
customHttpClientOV4.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("openvidu-java-client test")
|
@DisplayName("openvidu-java-client test")
|
||||||
void openViduJavaClientTest() throws Exception {
|
void openViduJavaClientTest() throws Exception {
|
||||||
|
|
Loading…
Reference in New Issue