mirror of https://github.com/OpenVidu/openvidu.git
Check openvidu-browser and openvidu-server compatibility
parent
1a244f68cd
commit
8e418bfd16
|
@ -5,6 +5,7 @@
|
|||
"hark": "1.2.3",
|
||||
"jsnlog": "2.30.0",
|
||||
"platform": "1.3.6",
|
||||
"semver": "7.3.5",
|
||||
"uuid": "8.3.2",
|
||||
"wolfy87-eventemitter": "5.2.9"
|
||||
},
|
||||
|
|
|
@ -44,6 +44,8 @@ import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/Open
|
|||
import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode';
|
||||
import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger';
|
||||
import { PlatformUtils } from '../OpenViduInternal/Utils/Platform';
|
||||
import semverMajor = require('semver/functions/major');
|
||||
import semverMinor = require('semver/functions/minor');
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
|
@ -1250,6 +1252,7 @@ export class Session extends EventDispatcher {
|
|||
token: (!!token) ? token : '',
|
||||
session: this.sessionId,
|
||||
platform: !!platform.getDescription() ? platform.getDescription() : 'unknown',
|
||||
sdkVersion: this.openvidu.libraryVersion,
|
||||
metadata: !!this.options.metadata ? this.options.metadata : '',
|
||||
secret: this.openvidu.getSecret(),
|
||||
recorder: this.openvidu.getRecorder()
|
||||
|
@ -1547,10 +1550,14 @@ export class Session extends EventDispatcher {
|
|||
if (opts.life != null) {
|
||||
this.openvidu.life = opts.life;
|
||||
}
|
||||
if (opts.version !== this.openvidu.libraryVersion) {
|
||||
logger.warn('OpenVidu Server (' + opts.version +
|
||||
') and OpenVidu Browser (' + this.openvidu.libraryVersion +
|
||||
') versions do NOT match. There may be incompatibilities')
|
||||
const minorDifference: number = semverMinor(opts.version) - semverMinor(this.openvidu.libraryVersion);
|
||||
if ((semverMajor(opts.version) !== semverMajor(this.openvidu.libraryVersion)) || !(minorDifference == 0 || minorDifference == 1)) {
|
||||
logger.error(`openvidu-browser (${this.openvidu.libraryVersion}) and openvidu-server (${opts.version}) versions are incompatible. `
|
||||
+ 'Errors are likely to occur. openvidu-browser SDK is only compatible with the same version or the immediately following minor version of an OpenVidu deployment');
|
||||
} else if (minorDifference == 1) {
|
||||
logger.warn(`openvidu-browser version ${this.openvidu.libraryVersion} does not match openvidu-server version ${opts.version}. `
|
||||
+ `These versions are still compatible with each other, but openvidu-browser version must be updated as soon as possible to ${semverMajor(opts.version)}.${semverMinor(opts.version)}.x. `
|
||||
+ `This client using openvidu-browser ${this.openvidu.libraryVersion} will become incompatible with the next release of openvidu-server`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ public class ProtocolElements {
|
|||
public static final String JOINROOM_METADATA_PARAM = "metadata";
|
||||
public static final String JOINROOM_SECRET_PARAM = "secret";
|
||||
public static final String JOINROOM_PLATFORM_PARAM = "platform";
|
||||
public static final String JOINROOM_SDKVERSION_PARAM = "sdkVersion";
|
||||
public static final String JOINROOM_RECORDER_PARAM = "recorder";
|
||||
|
||||
public static final String JOINROOM_PEERID_PARAM = "id";
|
||||
|
|
|
@ -332,6 +332,11 @@
|
|||
<artifactId>openvidu-java-client</artifactId>
|
||||
<version>${version.openvidu.java.client}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-artifact</artifactId>
|
||||
<version>${version.maven.artifact}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.concurrent.ConcurrentMap;
|
|||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.kurento.jsonrpc.DefaultJsonRpcHandler;
|
||||
import org.kurento.jsonrpc.Session;
|
||||
import org.kurento.jsonrpc.Transaction;
|
||||
|
@ -46,6 +47,7 @@ import io.openvidu.client.OpenViduException;
|
|||
import io.openvidu.client.OpenViduException.Code;
|
||||
import io.openvidu.client.internal.ProtocolElements;
|
||||
import io.openvidu.java.client.ConnectionProperties;
|
||||
import io.openvidu.server.config.OpenviduBuildInfo;
|
||||
import io.openvidu.server.config.OpenviduConfig;
|
||||
import io.openvidu.server.core.EndReason;
|
||||
import io.openvidu.server.core.IdentifierPrefixes;
|
||||
|
@ -55,6 +57,8 @@ import io.openvidu.server.core.SessionManager;
|
|||
import io.openvidu.server.core.Token;
|
||||
import io.openvidu.server.utils.GeoLocation;
|
||||
import io.openvidu.server.utils.GeoLocationByIp;
|
||||
import io.openvidu.server.utils.VersionComparator;
|
||||
import io.openvidu.server.utils.VersionComparator.VersionMismatchException;
|
||||
|
||||
public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
|
||||
|
||||
|
@ -63,6 +67,9 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
|
|||
@Autowired
|
||||
OpenviduConfig openviduConfig;
|
||||
|
||||
@Autowired
|
||||
OpenviduBuildInfo openviduBuildConfig;
|
||||
|
||||
@Autowired
|
||||
GeoLocationByIp geoLocationByIp;
|
||||
|
||||
|
@ -292,6 +299,8 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
|
|||
participant.getPlatform());
|
||||
}
|
||||
|
||||
checkSdkVersionCompliancy(request, participant);
|
||||
|
||||
rpcConnection.setSessionId(sessionId);
|
||||
sessionManager.joinRoom(participant, sessionId, request.getId());
|
||||
|
||||
|
@ -795,36 +804,36 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
|
|||
return Arrays.asList("*");
|
||||
}
|
||||
|
||||
public static String getStringParam(Request<JsonObject> request, String key) {
|
||||
public static String getStringParam(Request<JsonObject> request, String key) throws RuntimeException {
|
||||
if (request.getParams() == null || request.getParams().get(key) == null) {
|
||||
throw new RuntimeException("Request element '" + key + "' is missing in method '" + request != null
|
||||
? request.getMethod()
|
||||
: "[NO REQUEST OBJECT]"
|
||||
+ "'. CHECK THAT 'openvidu-server' AND 'openvidu-browser' SHARE THE SAME VERSION NUMBER");
|
||||
+ "'. Check that 'openvidu-server' AND 'openvidu-browser' versions are compatible with each other");
|
||||
}
|
||||
return request.getParams().get(key).getAsString();
|
||||
}
|
||||
|
||||
public static int getIntParam(Request<JsonObject> request, String key) {
|
||||
public static int getIntParam(Request<JsonObject> request, String key) throws RuntimeException {
|
||||
if (request.getParams() == null || request.getParams().get(key) == null) {
|
||||
throw new RuntimeException("Request element '" + key + "' is missing in method '" + request.getMethod()
|
||||
+ "'. CHECK THAT 'openvidu-server' AND 'openvidu-browser' SHARE THE SAME VERSION NUMBER");
|
||||
+ "'. Check that 'openvidu-server' AND 'openvidu-browser' versions are compatible with each other");
|
||||
}
|
||||
return request.getParams().get(key).getAsInt();
|
||||
}
|
||||
|
||||
public static boolean getBooleanParam(Request<JsonObject> request, String key) {
|
||||
public static boolean getBooleanParam(Request<JsonObject> request, String key) throws RuntimeException {
|
||||
if (request.getParams() == null || request.getParams().get(key) == null) {
|
||||
throw new RuntimeException("Request element '" + key + "' is missing in method '" + request.getMethod()
|
||||
+ "'. CHECK THAT 'openvidu-server' AND 'openvidu-browser' SHARE THE SAME VERSION NUMBER");
|
||||
+ "'. Check that 'openvidu-server' AND 'openvidu-browser' versions are compatible with each other");
|
||||
}
|
||||
return request.getParams().get(key).getAsBoolean();
|
||||
}
|
||||
|
||||
public static JsonElement getParam(Request<JsonObject> request, String key) {
|
||||
public static JsonElement getParam(Request<JsonObject> request, String key) throws RuntimeException {
|
||||
if (request.getParams() == null || request.getParams().get(key) == null) {
|
||||
throw new RuntimeException("Request element '" + key + "' is missing in method '" + request.getMethod()
|
||||
+ "'. CHECK THAT 'openvidu-server' AND 'openvidu-browser' SHARE THE SAME VERSION NUMBER");
|
||||
+ "'. Check that 'openvidu-server' AND 'openvidu-browser' versions are compatible with each other");
|
||||
}
|
||||
return request.getParams().get(key);
|
||||
}
|
||||
|
@ -879,4 +888,39 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
|
|||
return senderPublicId;
|
||||
}
|
||||
|
||||
private void checkSdkVersionCompliancy(Request<JsonObject> request, Participant participant) {
|
||||
// TODO: remove try-catch after release 2.21.0
|
||||
String clientVersion = null;
|
||||
try {
|
||||
clientVersion = getStringParam(request, ProtocolElements.JOINROOM_SDKVERSION_PARAM);
|
||||
} catch (RuntimeException e) {
|
||||
// This empty catch is here to support client SDK 2.20.0 with server 2.21.0
|
||||
// TODO: remove try-catch after release 2.21.0
|
||||
return;
|
||||
}
|
||||
final String serverVersion = openviduBuildConfig.getOpenViduServerVersion();
|
||||
try {
|
||||
new VersionComparator().checkVersionCompatibility(clientVersion, serverVersion);
|
||||
} catch (VersionMismatchException e) {
|
||||
if (e.isIncompatible()) {
|
||||
log.error(
|
||||
"Participant {} with IP {} and platform {} has an incompatible version of openvidu-browser SDK ({}) for this OpenVidu deployment ({}). This may cause the system to malfunction",
|
||||
participant.getParticipantPublicId(), participant.getLocation().getIp(),
|
||||
participant.getPlatform(), clientVersion, serverVersion);
|
||||
log.error(e.getMessage());
|
||||
log.error(
|
||||
"openvidu-browser SDK is only compatible with the same version or the immediately following minor version of an OpenVidu deployment");
|
||||
} else {
|
||||
DefaultArtifactVersion v = new DefaultArtifactVersion(serverVersion);
|
||||
log.warn(
|
||||
"Participant {} with IP {} and platform {} has an older version of openvidu-browser SDK ({}) for this OpenVidu deployment ({}). "
|
||||
+ "These versions are still compatible with each other, but client SDK must be updated as soon as possible to {}.x. This client using "
|
||||
+ "openvidu-browser {} will become incompatible with the next release of openvidu-server",
|
||||
participant.getParticipantPublicId(), participant.getLocation().getIp(),
|
||||
participant.getPlatform(), clientVersion, serverVersion,
|
||||
(v.getMajorVersion() + "." + v.getMinorVersion()), clientVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package io.openvidu.server.utils;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
|
||||
public class VersionComparator {
|
||||
|
||||
// https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
||||
private final String OFFICIAL_SEMVER_REGEX = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$";
|
||||
|
||||
/**
|
||||
* Checks if client version and server version are compatible with each other
|
||||
*
|
||||
* @param clientVersion
|
||||
* @param serverVersion
|
||||
* @throws VersionMismatchException if versions do not comply with semver
|
||||
* format, or if client version and server
|
||||
* version do not match
|
||||
*/
|
||||
public void checkVersionCompatibility(String clientVersion, String serverVersion) throws VersionMismatchException {
|
||||
checkSemver(clientVersion, "openvidu-browser");
|
||||
checkSemver(serverVersion, "openvidu-server");
|
||||
DefaultArtifactVersion comparableClientVersion = new DefaultArtifactVersion(clientVersion);
|
||||
DefaultArtifactVersion comparableServerVersion = new DefaultArtifactVersion(serverVersion);
|
||||
if (comparableClientVersion.getMajorVersion() != comparableServerVersion.getMajorVersion()) {
|
||||
throw new VersionMismatchException(true, "Incompatible major versions of openvidu-browser (\""
|
||||
+ clientVersion + "\") and openvidu-server (\"" + serverVersion + "\")");
|
||||
}
|
||||
checkMinorVersions(comparableClientVersion, comparableServerVersion);
|
||||
}
|
||||
|
||||
private void checkSemver(String version, String artifactName) {
|
||||
if (!Pattern.compile(OFFICIAL_SEMVER_REGEX).matcher(version).matches()) {
|
||||
throw new RuntimeException(
|
||||
"Version \"" + version + "\" of " + artifactName + " does not comply with semver format");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMinorVersions(DefaultArtifactVersion clientVersion, DefaultArtifactVersion serverVersion)
|
||||
throws VersionMismatchException {
|
||||
int difference = serverVersion.getMinorVersion() - clientVersion.getMinorVersion();
|
||||
if (difference == 1) {
|
||||
throw new VersionMismatchException(false, "openvidu-browser \"" + clientVersion + "\" requires update to \""
|
||||
+ serverVersion.getMajorVersion() + "." + serverVersion.getMinorVersion() + ".x\"");
|
||||
}
|
||||
if (difference != 0) {
|
||||
throw new VersionMismatchException(true, "Incompatible minor versions of openvidu-browser (\""
|
||||
+ clientVersion + "\") and openvidu-server (\"" + serverVersion + "\")");
|
||||
}
|
||||
}
|
||||
|
||||
public class VersionMismatchException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private boolean incompatible;
|
||||
|
||||
public VersionMismatchException(boolean incompatible, String errorMessage) {
|
||||
super(errorMessage);
|
||||
this.incompatible = incompatible;
|
||||
}
|
||||
|
||||
public boolean isIncompatible() {
|
||||
return this.incompatible;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package io.openvidu.server.test.unit;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import io.openvidu.server.utils.VersionComparator;
|
||||
import io.openvidu.server.utils.VersionComparator.VersionMismatchException;
|
||||
|
||||
public class VersionComparatorTest {
|
||||
|
||||
@Test
|
||||
void versionSyntaxWrongTest() throws VersionMismatchException {
|
||||
VersionComparator comparator = new VersionComparator();
|
||||
assertThrows(RuntimeException.class, () -> {
|
||||
comparator.checkVersionCompatibility("not_a_valid_semver", "2.21.0");
|
||||
});
|
||||
assertThrows(RuntimeException.class, () -> {
|
||||
comparator.checkVersionCompatibility("2.21.0", "not.valid.semver");
|
||||
});
|
||||
assertThrows(RuntimeException.class, () -> {
|
||||
comparator.checkVersionCompatibility("2.21", "2.21");
|
||||
});
|
||||
assertThrows(RuntimeException.class, () -> {
|
||||
comparator.checkVersionCompatibility("2.21.0", "2.21");
|
||||
});
|
||||
assertThrows(RuntimeException.class, () -> {
|
||||
comparator.checkVersionCompatibility("2", "2.21.0");
|
||||
});
|
||||
assertThrows(RuntimeException.class, () -> {
|
||||
comparator.checkVersionCompatibility("", "");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void versionsDoMatchTest() throws VersionMismatchException {
|
||||
VersionComparator comparator = new VersionComparator();
|
||||
comparator.checkVersionCompatibility("2.21.0", "2.21.0");
|
||||
comparator.checkVersionCompatibility("2.21.1", "2.21.0");
|
||||
comparator.checkVersionCompatibility("2.19.20", "2.19.0");
|
||||
comparator.checkVersionCompatibility("2.21.1-beta", "2.21.0");
|
||||
comparator.checkVersionCompatibility("3.0.0", "3.0.0-beta4");
|
||||
}
|
||||
|
||||
@Test
|
||||
void versionsDoNotMatchButAreCompatibleTest() throws VersionMismatchException {
|
||||
VersionComparator comparator = new VersionComparator();
|
||||
try {
|
||||
comparator.checkVersionCompatibility("2.20.0", "2.21.0");
|
||||
} catch (VersionMismatchException e) {
|
||||
assertFalse(e.isIncompatible());
|
||||
}
|
||||
try {
|
||||
comparator.checkVersionCompatibility("2.20.5", "2.21.0");
|
||||
} catch (VersionMismatchException e) {
|
||||
assertFalse(e.isIncompatible());
|
||||
}
|
||||
try {
|
||||
comparator.checkVersionCompatibility("2.20.5-dev", "2.21.0");
|
||||
} catch (VersionMismatchException e) {
|
||||
assertFalse(e.isIncompatible());
|
||||
}
|
||||
try {
|
||||
comparator.checkVersionCompatibility("2.0.0", "2.0.0-dev1");
|
||||
} catch (VersionMismatchException e) {
|
||||
assertFalse(e.isIncompatible());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void versionsIncompatibleTest() {
|
||||
VersionComparator comparator = new VersionComparator();
|
||||
assertThrows(VersionMismatchException.class, () -> {
|
||||
comparator.checkVersionCompatibility("2.0.0", "3.0.0");
|
||||
});
|
||||
assertThrows(VersionMismatchException.class, () -> {
|
||||
comparator.checkVersionCompatibility("3.0.0", "2.0.0");
|
||||
});
|
||||
assertThrows(VersionMismatchException.class, () -> {
|
||||
comparator.checkVersionCompatibility("2.21.0", "2.23.0");
|
||||
});
|
||||
assertThrows(VersionMismatchException.class, () -> {
|
||||
comparator.checkVersionCompatibility("2.21.0", "2.30.0");
|
||||
});
|
||||
assertThrows(VersionMismatchException.class, () -> {
|
||||
comparator.checkVersionCompatibility("2.22.0-dev1", "2.21.0");
|
||||
});
|
||||
assertThrows(VersionMismatchException.class, () -> {
|
||||
comparator.checkVersionCompatibility("2.22.0", "2.21.0-dev1");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
1
pom.xml
1
pom.xml
|
@ -75,6 +75,7 @@
|
|||
<version.nexus.staging.plugin>1.6.8</version.nexus.staging.plugin>
|
||||
<version.exec.plugin>3.0.0</version.exec.plugin>
|
||||
<version.javadoc.plugin>3.2.0</version.javadoc.plugin>
|
||||
<version.maven.artifact>3.8.3</version.maven.artifact>
|
||||
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
|
|
Loading…
Reference in New Issue