openvidu-server: POST Connection

pull/553/head
pabloFuente 2020-10-19 12:52:29 +02:00
parent 43f2f26dbd
commit 759acb1f7c
9 changed files with 302 additions and 216 deletions

View File

@ -0,0 +1,5 @@
package io.openvidu.server.core;
public enum ConnectionType {
WEBRTC, IPCAM
}

View File

@ -43,6 +43,7 @@ public class Participant {
active active
} }
protected ConnectionType type; // WEBRTC, IPCAM
protected String finalUserId; // ID to match this connection with a final user (HttpSession id) protected String finalUserId; // ID to match this connection with a final user (HttpSession id)
protected String participantPrivatetId; // ID to identify the user on server (org.kurento.jsonrpc.Session.id) protected String participantPrivatetId; // ID to identify the user on server (org.kurento.jsonrpc.Session.id)
protected String participantPublicId; // ID to identify the user on clients protected String participantPublicId; // ID to identify the user on clients
@ -76,9 +77,10 @@ public class Participant {
*/ */
public Lock singleRecordingLock = new ReentrantLock(); public Lock singleRecordingLock = new ReentrantLock();
public Participant(String finalUserId, String participantPrivatetId, String participantPublicId, String sessionId, public Participant(ConnectionType type, String finalUserId, String participantPrivatetId,
Token token, String clientMetadata, GeoLocation location, String platform, EndpointType endpointType, String participantPublicId, String sessionId, Token token, String clientMetadata, GeoLocation location,
Long activeAt) { String platform, EndpointType endpointType, Long activeAt) {
this.type = type;
this.finalUserId = finalUserId; this.finalUserId = finalUserId;
this.participantPrivatetId = participantPrivatetId; this.participantPrivatetId = participantPrivatetId;
this.participantPublicId = participantPublicId; this.participantPublicId = participantPublicId;
@ -101,6 +103,10 @@ public class Participant {
this.endpointType = endpointType; this.endpointType = endpointType;
} }
public ConnectionType getType() {
return type;
}
public String getFinalUserId() { public String getFinalUserId() {
return finalUserId; return finalUserId;
} }
@ -300,6 +306,7 @@ public class Participant {
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
json.addProperty("id", this.participantPublicId); json.addProperty("id", this.participantPublicId);
json.addProperty("object", "connection"); json.addProperty("object", "connection");
json.addProperty("type", this.type.name());
json.addProperty("status", this.status.name()); json.addProperty("status", this.status.name());
json.addProperty("connectionId", this.participantPublicId); // TODO: deprecated. Better use only "id" json.addProperty("connectionId", this.participantPublicId); // TODO: deprecated. Better use only "id"
json.addProperty("sessionId", this.sessionId); json.addProperty("sessionId", this.sessionId);

View File

@ -363,8 +363,9 @@ public abstract class SessionManager {
if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) { if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) {
Participant p = new Participant(finalUserId, participantPrivatetId, token.getConnectionId(), sessionId, Participant p = new Participant(ConnectionType.WEBRTC, finalUserId, participantPrivatetId,
token, clientMetadata, location, platform, EndpointType.WEBRTC_ENDPOINT, null); token.getConnectionId(), sessionId, token, clientMetadata, location, platform,
EndpointType.WEBRTC_ENDPOINT, null);
this.sessionidParticipantpublicidParticipant.get(sessionId).put(p.getParticipantPublicId(), p); this.sessionidParticipantpublicidParticipant.get(sessionId).put(p.getParticipantPublicId(), p);
@ -384,8 +385,9 @@ public abstract class SessionManager {
public Participant newRecorderParticipant(String sessionId, String participantPrivatetId, Token token, public Participant newRecorderParticipant(String sessionId, String participantPrivatetId, Token token,
String clientMetadata) { String clientMetadata) {
if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) { if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) {
Participant p = new Participant(null, participantPrivatetId, ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, Participant p = new Participant(ConnectionType.WEBRTC, null, participantPrivatetId,
sessionId, token, clientMetadata, null, null, EndpointType.WEBRTC_ENDPOINT, null); ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, sessionId, token, clientMetadata, null, null,
EndpointType.WEBRTC_ENDPOINT, null);
this.sessionidParticipantpublicidParticipant.get(sessionId) this.sessionidParticipantpublicidParticipant.get(sessionId)
.put(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, p); .put(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, p);
return p; return p;
@ -397,8 +399,8 @@ public abstract class SessionManager {
public Participant newIpcamParticipant(String sessionId, String ipcamId, Token token, GeoLocation location, public Participant newIpcamParticipant(String sessionId, String ipcamId, Token token, GeoLocation location,
String platform) { String platform) {
if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) { if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) {
Participant p = new Participant(ipcamId, ipcamId, ipcamId, sessionId, token, null, location, platform, Participant p = new Participant(ConnectionType.IPCAM, ipcamId, ipcamId, ipcamId, sessionId, token, null,
EndpointType.PLAYER_ENDPOINT, null); location, platform, EndpointType.PLAYER_ENDPOINT, null);
this.sessionidParticipantpublicidParticipant.get(sessionId).put(ipcamId, p); this.sessionidParticipantpublicidParticipant.get(sessionId).put(ipcamId, p);
return p; return p;
} else { } else {

View File

@ -117,6 +117,7 @@ public class Token {
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
json.addProperty("id", this.getConnectionId()); json.addProperty("id", this.getConnectionId());
json.addProperty("object", "connection"); json.addProperty("object", "connection");
json.addProperty("type", ConnectionType.WEBRTC.name());
json.addProperty("status", ParticipantStatus.pending.name()); json.addProperty("status", ParticipantStatus.pending.name());
json.addProperty("connectionId", this.getConnectionId()); // DEPRECATED: better use id json.addProperty("connectionId", this.getConnectionId()); // DEPRECATED: better use id
json.addProperty("sessionId", this.sessionId); json.addProperty("sessionId", this.sessionId);

View File

@ -77,7 +77,7 @@ public class KurentoParticipant extends Participant {
public KurentoParticipant(Participant participant, KurentoSession kurentoSession, public KurentoParticipant(Participant participant, KurentoSession kurentoSession,
KurentoParticipantEndpointConfig endpointConfig, OpenviduConfig openviduConfig, KurentoParticipantEndpointConfig endpointConfig, OpenviduConfig openviduConfig,
RecordingManager recordingManager) { RecordingManager recordingManager) {
super(participant.getFinalUserId(), participant.getParticipantPrivateId(), participant.getParticipantPublicId(), super(participant.getType(), participant.getFinalUserId(), participant.getParticipantPrivateId(), participant.getParticipantPublicId(),
kurentoSession.getSessionId(), participant.getToken(), participant.getClientMetadata(), kurentoSession.getSessionId(), participant.getToken(), participant.getClientMetadata(),
participant.getLocation(), participant.getPlatform(), participant.getEndpointType(), participant.getLocation(), participant.getPlatform(), participant.getEndpointType(),
participant.getActiveAt()); participant.getActiveAt());

View File

@ -20,6 +20,7 @@ package io.openvidu.server.rest;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -57,6 +58,7 @@ import io.openvidu.java.client.RecordingMode;
import io.openvidu.java.client.RecordingProperties; import io.openvidu.java.client.RecordingProperties;
import io.openvidu.java.client.SessionProperties; import io.openvidu.java.client.SessionProperties;
import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.config.OpenviduConfig;
import io.openvidu.server.core.ConnectionType;
import io.openvidu.server.core.EndReason; import io.openvidu.server.core.EndReason;
import io.openvidu.server.core.IdentifierPrefixes; import io.openvidu.server.core.IdentifierPrefixes;
import io.openvidu.server.core.Participant; import io.openvidu.server.core.Participant;
@ -92,7 +94,7 @@ public class SessionRestController {
protected OpenviduConfig openviduConfig; protected OpenviduConfig openviduConfig;
@RequestMapping(value = "/sessions", method = RequestMethod.POST) @RequestMapping(value = "/sessions", method = RequestMethod.POST)
public ResponseEntity<?> getSessionId(@RequestBody(required = false) Map<?, ?> params) { public ResponseEntity<?> initializeSession(@RequestBody(required = false) Map<?, ?> params) {
log.info("REST API: POST {}/sessions {}", RequestMappings.API, params != null ? params.toString() : "{}"); log.info("REST API: POST {}/sessions {}", RequestMappings.API, params != null ? params.toString() : "{}");
@ -267,8 +269,99 @@ public class SessionRestController {
} }
} }
@RequestMapping(value = "/sessions/{sessionId}/connection", method = RequestMethod.POST)
public ResponseEntity<?> initializeConnection(@PathVariable("sessionId") String sessionId,
@RequestBody Map<?, ?> params) {
log.info("REST API: POST {}/sessions/{}/connection {}", RequestMappings.API, sessionId, params.toString());
Session session = this.sessionManager.getSessionWithNotActive(sessionId);
if (session == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
String typeString;
String data;
Boolean record;
try {
typeString = (String) params.get("type");
data = (String) params.get("data");
record = (Boolean) params.get("record");
} catch (ClassCastException e) {
return this.generateErrorResponse("Type error in parameter \"type\"",
"/sessions/" + sessionId + "/connection", HttpStatus.BAD_REQUEST);
}
ConnectionType type;
try {
if (typeString != null) {
type = ConnectionType.valueOf(typeString);
} else {
type = ConnectionType.WEBRTC;
}
} catch (IllegalArgumentException e) {
return this.generateErrorResponse("Parameter type " + params.get("typeString") + " is not defined",
RequestMappings.API + "/sessions/" + sessionId + "/connection", HttpStatus.BAD_REQUEST);
}
switch (type) {
case WEBRTC:
return this.newWebrtcConnection(session, data, record, params);
case IPCAM:
return this.newIpcamConnection(session, data, record, params);
default:
return this.generateErrorResponse("Wrong type " + typeString,
RequestMappings.API + "/sessions/" + sessionId + "/connection", HttpStatus.BAD_REQUEST);
}
}
@RequestMapping(value = "/sessions/{sessionId}/connection/{connectionId}", method = RequestMethod.GET)
public ResponseEntity<?> getConnection(@PathVariable("sessionId") String sessionId,
@PathVariable("connectionId") String connectionId) {
log.info("REST API: GET {}/sessions/{}/connection/{}", RequestMappings.API, sessionId, connectionId);
Session session = this.sessionManager.getSessionWithNotActive(sessionId);
if (session != null) {
Participant p = session.getParticipantByPublicId(connectionId);
if (p != null) {
return new ResponseEntity<>(p.toJson().toString(), RestUtils.getResponseHeaders(), HttpStatus.OK);
} else {
Token t = getTokenFromConnectionId(connectionId, session.getTokenIterator());
if (t != null) {
return new ResponseEntity<>(t.toJsonAsParticipant().toString(), RestUtils.getResponseHeaders(),
HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
} else {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
@RequestMapping(value = "/sessions/{sessionId}/connection", method = RequestMethod.GET)
public ResponseEntity<?> listConnections(@PathVariable("sessionId") String sessionId,
@RequestParam(value = "pendingConnections", defaultValue = "true", required = false) boolean pendingConnections,
@RequestParam(value = "webRtcStats", defaultValue = "false", required = false) boolean webRtcStats) {
log.info("REST API: GET {}/sessions/{}/connection", RequestMappings.API, sessionId);
Session session = this.sessionManager.getSessionWithNotActive(sessionId);
if (session != null) {
JsonObject json = new JsonObject();
JsonArray jsonArray = session.getSnapshotOfConnectionsAsJsonArray(pendingConnections, webRtcStats);
json.addProperty("numberOfElements", jsonArray.size());
json.add("content", jsonArray);
return new ResponseEntity<>(json.toString(), RestUtils.getResponseHeaders(), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@RequestMapping(value = "/sessions/{sessionId}/connection/{connectionId}", method = RequestMethod.DELETE) @RequestMapping(value = "/sessions/{sessionId}/connection/{connectionId}", method = RequestMethod.DELETE)
public ResponseEntity<?> disconnectParticipant(@PathVariable("sessionId") String sessionId, public ResponseEntity<?> closeConnection(@PathVariable("sessionId") String sessionId,
@PathVariable("connectionId") String participantPublicId) { @PathVariable("connectionId") String participantPublicId) {
log.info("REST API: DELETE {}/sessions/{}/connection/{}", RequestMappings.API, sessionId, participantPublicId); log.info("REST API: DELETE {}/sessions/{}/connection/{}", RequestMappings.API, sessionId, participantPublicId);
@ -292,127 +385,8 @@ public class SessionRestController {
} }
} }
@RequestMapping(value = "/sessions/{sessionId}/stream/{streamId}", method = RequestMethod.DELETE)
public ResponseEntity<?> unpublishStream(@PathVariable("sessionId") String sessionId,
@PathVariable("streamId") String streamId) {
log.info("REST API: DELETE {}/sessions/{}/stream/{}", RequestMappings.API, sessionId, streamId);
Session session = this.sessionManager.getSessionWithNotActive(sessionId);
if (session == null) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
session = this.sessionManager.getSession(sessionId);
if (session != null) {
final String participantPrivateId = this.sessionManager.getParticipantPrivateIdFromStreamId(sessionId,
streamId);
if (participantPrivateId == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Participant participant = this.sessionManager.getParticipant(participantPrivateId);
if (participant.isIpcam()) {
return new ResponseEntity<>(HttpStatus.METHOD_NOT_ALLOWED);
}
this.sessionManager.unpublishStream(session, streamId, null, null, EndReason.forceUnpublishByServer);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@RequestMapping(value = "/tokens", method = RequestMethod.POST)
public ResponseEntity<String> newToken(@RequestBody Map<?, ?> params) {
if (params == null) {
return this.generateErrorResponse("Error in body parameters. Cannot be empty", "/tokens",
HttpStatus.BAD_REQUEST);
}
log.info("REST API: POST {}/tokens {}", RequestMappings.API, params.toString());
String sessionId;
String roleString;
String metadata;
Boolean record;
try {
sessionId = (String) params.get("session");
roleString = (String) params.get("role");
metadata = (String) params.get("data");
record = (Boolean) params.get("record");
} catch (ClassCastException e) {
return this.generateErrorResponse("Type error in some parameter", "/tokens", HttpStatus.BAD_REQUEST);
}
if (sessionId == null) {
return this.generateErrorResponse("\"session\" parameter is mandatory", "/tokens", HttpStatus.BAD_REQUEST);
}
final Session session = this.sessionManager.getSessionWithNotActive(sessionId);
if (session == null) {
return this.generateErrorResponse("Session " + sessionId + " not found", "/tokens", HttpStatus.NOT_FOUND);
}
JsonObject kurentoOptions = null;
if (params.get("kurentoOptions") != null) {
try {
kurentoOptions = JsonParser.parseString(params.get("kurentoOptions").toString()).getAsJsonObject();
} catch (Exception e) {
return this.generateErrorResponse("Error in parameter 'kurentoOptions'. It is not a valid JSON object",
"/tokens", HttpStatus.BAD_REQUEST);
}
}
OpenViduRole role;
try {
if (roleString != null) {
role = OpenViduRole.valueOf(roleString);
} else {
role = OpenViduRole.PUBLISHER;
}
} catch (IllegalArgumentException e) {
return this.generateErrorResponse("Parameter role " + params.get("role") + " is not defined", "/tokens",
HttpStatus.BAD_REQUEST);
}
KurentoTokenOptions kurentoTokenOptions = null;
if (kurentoOptions != null) {
try {
kurentoTokenOptions = new KurentoTokenOptions(kurentoOptions);
} catch (Exception e) {
return this.generateErrorResponse("Type error in some parameter of 'kurentoOptions'", "/tokens",
HttpStatus.BAD_REQUEST);
}
}
metadata = (metadata != null) ? metadata : "";
record = (record != null) ? record : true;
// While closing a session tokens can't be generated
if (session.closingLock.readLock().tryLock()) {
try {
Token token = sessionManager.newToken(session, role, metadata, record, kurentoTokenOptions);
return new ResponseEntity<>(token.toJson().toString(), RestUtils.getResponseHeaders(), HttpStatus.OK);
} catch (Exception e) {
return this.generateErrorResponse(
"Error generating token for session " + sessionId + ": " + e.getMessage(), "/tokens",
HttpStatus.INTERNAL_SERVER_ERROR);
} finally {
session.closingLock.readLock().unlock();
}
} else {
log.error("Session {} is in the process of closing. Token couldn't be generated", sessionId);
return this.generateErrorResponse("Session " + sessionId + " not found", "/tokens", HttpStatus.NOT_FOUND);
}
}
@RequestMapping(value = "/recordings/start", method = RequestMethod.POST) @RequestMapping(value = "/recordings/start", method = RequestMethod.POST)
public ResponseEntity<?> startRecordingSession(@RequestBody Map<?, ?> params) { public ResponseEntity<?> startRecording(@RequestBody Map<?, ?> params) {
if (params == null) { if (params == null) {
return this.generateErrorResponse("Error in body parameters. Cannot be empty", "/recordings/start", return this.generateErrorResponse("Error in body parameters. Cannot be empty", "/recordings/start",
@ -568,7 +542,7 @@ public class SessionRestController {
} }
@RequestMapping(value = "/recordings/stop/{recordingId}", method = RequestMethod.POST) @RequestMapping(value = "/recordings/stop/{recordingId}", method = RequestMethod.POST)
public ResponseEntity<?> stopRecordingSession(@PathVariable("recordingId") String recordingId) { public ResponseEntity<?> stopRecording(@PathVariable("recordingId") String recordingId) {
log.info("REST API: POST {}/recordings/stop/{}", RequestMappings.API, recordingId); log.info("REST API: POST {}/recordings/stop/{}", RequestMappings.API, recordingId);
@ -632,7 +606,7 @@ public class SessionRestController {
} }
@RequestMapping(value = "/recordings", method = RequestMethod.GET) @RequestMapping(value = "/recordings", method = RequestMethod.GET)
public ResponseEntity<?> getAllRecordings() { public ResponseEntity<?> listRecordings() {
log.info("REST API: GET {}/recordings", RequestMappings.API); log.info("REST API: GET {}/recordings", RequestMappings.API);
@ -669,6 +643,87 @@ public class SessionRestController {
return new ResponseEntity<>(this.recordingManager.deleteRecordingFromHost(recordingId, false)); return new ResponseEntity<>(this.recordingManager.deleteRecordingFromHost(recordingId, false));
} }
@RequestMapping(value = "/tokens", method = RequestMethod.POST)
public ResponseEntity<String> newToken(@RequestBody Map<?, ?> params) {
if (params == null) {
return this.generateErrorResponse("Error in body parameters. Cannot be empty", "/tokens",
HttpStatus.BAD_REQUEST);
}
log.info("REST API: POST {}/tokens {}", RequestMappings.API, params.toString());
String sessionId;
String metadata;
Boolean record;
try {
sessionId = (String) params.get("session");
metadata = (String) params.get("data");
record = (Boolean) params.get("record");
} catch (ClassCastException e) {
return this.generateErrorResponse("Type error in some parameter", "/tokens", HttpStatus.BAD_REQUEST);
}
if (sessionId == null) {
return this.generateErrorResponse("\"session\" parameter is mandatory", "/tokens", HttpStatus.BAD_REQUEST);
}
log.warn("Token API is deprecated. Use Connection API instead (POST {}/sessions/{}/connection)",
RequestMappings.API, sessionId);
final Session session = this.sessionManager.getSessionWithNotActive(sessionId);
if (session == null) {
return this.generateErrorResponse("Session " + sessionId + " not found", "/tokens", HttpStatus.NOT_FOUND);
}
Map<String, Object> map = new HashMap<>();
params.entrySet().forEach(entry -> map.put((String) entry.getKey(), entry.getValue()));
map.put("type", "WEBRTC");
ResponseEntity<?> entity = this.newWebrtcConnection(session, metadata, record, params);
JsonObject jsonResponse = JsonParser.parseString(entity.getBody().toString()).getAsJsonObject();
if (jsonResponse.has("error")) {
return this.generateErrorResponse(jsonResponse.get("message").getAsString(), "/tokens",
HttpStatus.valueOf(jsonResponse.get("status").getAsInt()));
} else {
String connectionId = jsonResponse.get("id").getAsString();
Token token = getTokenFromConnectionId(connectionId, session.getTokenIterator());
return new ResponseEntity<>(token.toJson().toString(), RestUtils.getResponseHeaders(), HttpStatus.OK);
}
}
@RequestMapping(value = "/sessions/{sessionId}/stream/{streamId}", method = RequestMethod.DELETE)
public ResponseEntity<?> unpublishStream(@PathVariable("sessionId") String sessionId,
@PathVariable("streamId") String streamId) {
log.info("REST API: DELETE {}/sessions/{}/stream/{}", RequestMappings.API, sessionId, streamId);
Session session = this.sessionManager.getSessionWithNotActive(sessionId);
if (session == null) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
session = this.sessionManager.getSession(sessionId);
if (session != null) {
final String participantPrivateId = this.sessionManager.getParticipantPrivateIdFromStreamId(sessionId,
streamId);
if (participantPrivateId == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Participant participant = this.sessionManager.getParticipant(participantPrivateId);
if (participant.isIpcam()) {
return new ResponseEntity<>(HttpStatus.METHOD_NOT_ALLOWED);
}
this.sessionManager.unpublishStream(session, streamId, null, null, EndReason.forceUnpublishByServer);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@RequestMapping(value = "/signal", method = RequestMethod.POST) @RequestMapping(value = "/signal", method = RequestMethod.POST)
public ResponseEntity<?> signal(@RequestBody Map<?, ?> params) { public ResponseEntity<?> signal(@RequestBody Map<?, ?> params) {
@ -738,99 +793,108 @@ public class SessionRestController {
return new ResponseEntity<>(HttpStatus.OK); return new ResponseEntity<>(HttpStatus.OK);
} }
@RequestMapping(value = "/sessions/{sessionId}/connection/{connectionId}", method = RequestMethod.GET) protected ResponseEntity<?> newWebrtcConnection(Session session, String serverData, Boolean record,
public ResponseEntity<?> getConnection(@PathVariable("sessionId") String sessionId, Map<?, ?> params) {
@PathVariable("connectionId") String connectionId) {
log.info("REST API: GET {}/sessions/{}/connection/{}", RequestMappings.API, sessionId, connectionId); final String REQUEST_PATH = RequestMappings.API + "/sessions/" + session.getSessionId() + "/connection";
Session session = this.sessionManager.getSessionWithNotActive(sessionId); String roleString = null;
if (session != null) { try {
Participant p = session.getParticipantByPublicId(connectionId); roleString = (String) params.get("role");
if (p != null) { } catch (ClassCastException e) {
return new ResponseEntity<>(p.toJson().toString(), RestUtils.getResponseHeaders(), HttpStatus.OK); return this.generateErrorResponse("Type error in some parameter", REQUEST_PATH, HttpStatus.BAD_REQUEST);
}
OpenViduRole role = null;
try {
if (roleString != null) {
role = OpenViduRole.valueOf(roleString);
} else { } else {
Token t = getTokenFromConnectionId(connectionId, session.getTokenIterator()); role = OpenViduRole.PUBLISHER;
if (t != null) { }
return new ResponseEntity<>(t.toJsonAsParticipant().toString(), RestUtils.getResponseHeaders(), } catch (IllegalArgumentException e) {
return this.generateErrorResponse("Parameter role " + params.get("role") + " is not defined", REQUEST_PATH,
HttpStatus.BAD_REQUEST);
}
JsonObject kurentoOptions = null;
if (params.get("kurentoOptions") != null) {
try {
kurentoOptions = JsonParser.parseString(params.get("kurentoOptions").toString()).getAsJsonObject();
} catch (Exception e) {
return this.generateErrorResponse("Error in parameter 'kurentoOptions'. It is not a valid JSON object",
REQUEST_PATH, HttpStatus.BAD_REQUEST);
}
}
KurentoTokenOptions kurentoTokenOptions = null;
if (kurentoOptions != null) {
try {
kurentoTokenOptions = new KurentoTokenOptions(kurentoOptions);
} catch (Exception e) {
return this.generateErrorResponse("Type error in some parameter of 'kurentoOptions'", REQUEST_PATH,
HttpStatus.BAD_REQUEST);
}
}
serverData = (serverData != null) ? serverData : "";
record = (record != null) ? record : true;
// While closing a session tokens can't be generated
if (session.closingLock.readLock().tryLock()) {
try {
Token token = sessionManager.newToken(session, role, serverData, record, kurentoTokenOptions);
return new ResponseEntity<>(token.toJsonAsParticipant().toString(), RestUtils.getResponseHeaders(),
HttpStatus.OK); HttpStatus.OK);
} else { } catch (Exception e) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND); return this.generateErrorResponse(
} "Error creating Connection for session " + session.getSessionId() + ": " + e.getMessage(),
REQUEST_PATH, HttpStatus.INTERNAL_SERVER_ERROR);
} finally {
session.closingLock.readLock().unlock();
} }
} else { } else {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST); log.error("Session {} is in the process of closing. Connection couldn't be created",
session.getSessionId());
return this.generateErrorResponse("Session " + session.getSessionId() + " not found", REQUEST_PATH,
HttpStatus.NOT_FOUND);
} }
} }
@RequestMapping(value = "/sessions/{sessionId}/connection", method = RequestMethod.GET) protected ResponseEntity<?> newIpcamConnection(Session session, String serverData, Boolean record,
public ResponseEntity<?> listConnections(@PathVariable("sessionId") String sessionId, Map<?, ?> params) {
@RequestParam(value = "pendingConnections", defaultValue = "true", required = false) boolean pendingConnections,
@RequestParam(value = "webRtcStats", defaultValue = "false", required = false) boolean webRtcStats) {
log.info("REST API: GET {}/sessions/{}/connection", RequestMappings.API, sessionId); final String REQUEST_PATH = RequestMappings.API + "/sessions/" + session.getSessionId() + "/connection";
Session session = this.sessionManager.getSessionWithNotActive(sessionId);
if (session != null) {
JsonObject json = new JsonObject();
JsonArray jsonArray = session.getSnapshotOfConnectionsAsJsonArray(pendingConnections, webRtcStats);
json.addProperty("numberOfElements", jsonArray.size());
json.add("content", jsonArray);
return new ResponseEntity<>(json.toString(), RestUtils.getResponseHeaders(), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@RequestMapping(value = "/sessions/{sessionId}/connection", method = RequestMethod.POST)
public ResponseEntity<?> publishIpcam(@PathVariable("sessionId") String sessionId, @RequestBody Map<?, ?> params) {
if (params == null) {
return this.generateErrorResponse("Error in body parameters. Cannot be empty",
"/sessions/" + sessionId + "/connection", HttpStatus.BAD_REQUEST);
}
log.info("REST API: POST {}/sessions/{}/connection {}", RequestMappings.API, sessionId, params.toString());
Session session = this.sessionManager.getSessionWithNotActive(sessionId);
if (session == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
String type;
String rtspUri; String rtspUri;
Boolean adaptativeBitrate; Boolean adaptativeBitrate;
Boolean onlyPlayWithSubscribers; Boolean onlyPlayWithSubscribers;
Integer networkCache; Integer networkCache;
String data;
try { try {
type = (String) params.get("type");
rtspUri = (String) params.get("rtspUri"); rtspUri = (String) params.get("rtspUri");
adaptativeBitrate = (Boolean) params.get("adaptativeBitrate"); adaptativeBitrate = (Boolean) params.get("adaptativeBitrate");
onlyPlayWithSubscribers = (Boolean) params.get("onlyPlayWithSubscribers"); onlyPlayWithSubscribers = (Boolean) params.get("onlyPlayWithSubscribers");
networkCache = (Integer) params.get("networkCache"); networkCache = (Integer) params.get("networkCache");
data = (String) params.get("data");
} catch (ClassCastException e) { } catch (ClassCastException e) {
return this.generateErrorResponse("Type error in some parameter", "/sessions/" + sessionId + "/connection", return this.generateErrorResponse("Type error in some parameter", REQUEST_PATH, HttpStatus.BAD_REQUEST);
HttpStatus.BAD_REQUEST); }
}
if (rtspUri == null) { if (rtspUri == null) {
return this.generateErrorResponse("\"rtspUri\" parameter is mandatory", return this.generateErrorResponse("\"rtspUri\" parameter is mandatory", REQUEST_PATH,
"/sessions/" + sessionId + "/connection", HttpStatus.BAD_REQUEST); HttpStatus.BAD_REQUEST);
} }
type = "IPCAM"; // Other possible values in the future
adaptativeBitrate = adaptativeBitrate != null ? adaptativeBitrate : true; adaptativeBitrate = adaptativeBitrate != null ? adaptativeBitrate : true;
onlyPlayWithSubscribers = onlyPlayWithSubscribers != null ? onlyPlayWithSubscribers : true; onlyPlayWithSubscribers = onlyPlayWithSubscribers != null ? onlyPlayWithSubscribers : true;
networkCache = networkCache != null ? networkCache : 2000; networkCache = networkCache != null ? networkCache : 2000;
data = data != null ? data : ""; serverData = serverData != null ? serverData : "";
record = (record != null) ? record : true;
boolean hasAudio = true; boolean hasAudio = true;
boolean hasVideo = true; boolean hasVideo = true;
boolean audioActive = true; boolean audioActive = true;
boolean videoActive = true; boolean videoActive = true;
String typeOfVideo = type; String typeOfVideo = ConnectionType.IPCAM.name();
Integer frameRate = null; Integer frameRate = null;
String videoDimensions = null; String videoDimensions = null;
KurentoMediaOptions mediaOptions = new KurentoMediaOptions(true, null, hasAudio, hasVideo, audioActive, KurentoMediaOptions mediaOptions = new KurentoMediaOptions(true, null, hasAudio, hasVideo, audioActive,
@ -843,15 +907,14 @@ public class SessionRestController {
if (session.isClosed()) { if (session.isClosed()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND); return new ResponseEntity<>(HttpStatus.NOT_FOUND);
} }
Participant ipcamParticipant = this.sessionManager.publishIpcam(session, mediaOptions, data); Participant ipcamParticipant = this.sessionManager.publishIpcam(session, mediaOptions, serverData);
return new ResponseEntity<>(ipcamParticipant.toJson().toString(), RestUtils.getResponseHeaders(), return new ResponseEntity<>(ipcamParticipant.toJson().toString(), RestUtils.getResponseHeaders(),
HttpStatus.OK); HttpStatus.OK);
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
return this.generateErrorResponse("\"rtspUri\" parameter is not a valid rtsp uri", return this.generateErrorResponse("\"rtspUri\" parameter is not a valid rtsp uri", REQUEST_PATH,
"/sessions/" + sessionId + "/connection", HttpStatus.BAD_REQUEST); HttpStatus.BAD_REQUEST);
} catch (Exception e) { } catch (Exception e) {
return this.generateErrorResponse(e.getMessage(), "/sessions/" + sessionId + "/connection", return this.generateErrorResponse(e.getMessage(), REQUEST_PATH, HttpStatus.INTERNAL_SERVER_ERROR);
HttpStatus.INTERNAL_SERVER_ERROR);
} finally { } finally {
session.closingLock.readLock().unlock(); session.closingLock.readLock().unlock();
} }

View File

@ -98,7 +98,7 @@ public class SessionGarbageCollectorIntegrationTest {
} }
private String getSessionId() { private String getSessionId() {
String stringResponse = (String) sessionRestController.getSessionId(new HashMap<>()).getBody(); String stringResponse = (String) sessionRestController.initializeSession(new HashMap<>()).getBody();
return new Gson().fromJson(stringResponse, JsonObject.class).get("id").getAsString(); return new Gson().fromJson(stringResponse, JsonObject.class).get("id").getAsString();
} }

View File

@ -212,14 +212,16 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
// Updating only role should let record value untouched // Updating only role should let record value untouched
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'role':'MODERATOR'}", HttpStatus.SC_OK, true, true, true, "{'role':'MODERATOR'}", HttpStatus.SC_OK, true, true, true,
"{'id':'" + tokenConnectionId + "','object':'connection','status':'pending','connectionId':'" "{'id':'" + tokenConnectionId
+ "','object':'connection','type':'WEBRTC','status':'pending','connectionId':'"
+ tokenConnectionId + "','role':'MODERATOR','record':false,'token':'" + token + tokenConnectionId + "','role':'MODERATOR','record':false,'token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':null,'subscribers':null,'createdAt':" + "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':null,'subscribers':null,'createdAt':"
+ createdAt + ",'activeAt':null,'platform':null,'location':null,'clientData':null}"); + createdAt + ",'activeAt':null,'platform':null,'location':null,'clientData':null}");
// Updating only record should let role value untouched // Updating only record should let role value untouched
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'record':true}", HttpStatus.SC_OK, true, true, true, "{'record':true}", HttpStatus.SC_OK, true, true, true,
"{'id':'" + tokenConnectionId + "','object':'connection','status':'pending','connectionId':'" "{'id':'" + tokenConnectionId
+ "','object':'connection','type':'WEBRTC','status':'pending','connectionId':'"
+ tokenConnectionId + "','role':'MODERATOR','record':true,'token':'" + token + tokenConnectionId + "','role':'MODERATOR','record':true,'token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':null,'subscribers':null,'createdAt':" + "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':null,'subscribers':null,'createdAt':"
+ createdAt + ",'activeAt':null,'platform':null,'location':null,'clientData':null}"); + createdAt + ",'activeAt':null,'platform':null,'location':null,'clientData':null}");
@ -282,23 +284,28 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
// Updating only role should let record value untouched // Updating only role should let record value untouched
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'role':'MODERATOR'}", HttpStatus.SC_OK, false, true, true, "{'role':'MODERATOR'}", HttpStatus.SC_OK, false, true, true,
"{'id':'" + tokenConnectionId + "','object':'connection','status':'active','connectionId':'" "{'id':'" + tokenConnectionId
+ "','object':'connection','type':'WEBRTC','status':'active','connectionId':'"
+ tokenConnectionId + "','role':'MODERATOR','record':false,'token':'" + token + tokenConnectionId + "','role':'MODERATOR','record':false,'token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}"); + "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}");
// Updating only record should let role value untouched // Updating only record should let role value untouched
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'record':true}", HttpStatus.SC_OK, false, true, true, "{'record':true}", HttpStatus.SC_OK, false, true, true,
"{'id':'" + tokenConnectionId + "','object':'connection','status':'active','connectionId':'" "{'id':'" + tokenConnectionId
+ "','object':'connection','type':'WEBRTC','status':'active','connectionId':'"
+ tokenConnectionId + "','role':'MODERATOR','record':true,'token':'" + token + tokenConnectionId + "','role':'MODERATOR','record':true,'token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}"); + "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}");
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'role':'SUBSCRIBER','record':true,'data':'OTHER DATA'}", HttpStatus.SC_OK, false, true, true, "{'role':'SUBSCRIBER','record':true,'data':'OTHER DATA'}", HttpStatus.SC_OK, false, true, true,
"{'id':'" + tokenConnectionId + "','object':'connection','status':'active','connectionId':'" "{'id':'" + tokenConnectionId
+ "','object':'connection','type':'WEBRTC','status':'active','connectionId':'"
+ tokenConnectionId + "','role':'SUBSCRIBER','record':true,'token':'" + token + tokenConnectionId + "','role':'SUBSCRIBER','record':true,'token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}"); + "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}");
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'role':'PUBLISHER'}", HttpStatus.SC_OK, false, true, true, "{'role':'PUBLISHER'}", HttpStatus.SC_OK,
"{'id':'" + tokenConnectionId + "','object':'connection','status':'active','connectionId':'" false, true, true,
"{'id':'" + tokenConnectionId
+ "','object':'connection','type':'WEBRTC','status':'active','connectionId':'"
+ tokenConnectionId + "','role':'PUBLISHER','record':true,'token':'" + token + tokenConnectionId + "','role':'PUBLISHER','record':true,'token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}"); + "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}");

View File

@ -86,7 +86,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
final String DEFAULT_JSON_SESSION = "{'id':'STR','object':'STR','sessionId':'STR','createdAt':0,'mediaMode':'STR','recordingMode':'STR','defaultOutputMode':'STR','defaultRecordingLayout':'STR','customSessionId':'STR','connections':{'numberOfElements':0,'content':[]},'recording':false}"; final String DEFAULT_JSON_SESSION = "{'id':'STR','object':'STR','sessionId':'STR','createdAt':0,'mediaMode':'STR','recordingMode':'STR','defaultOutputMode':'STR','defaultRecordingLayout':'STR','customSessionId':'STR','connections':{'numberOfElements':0,'content':[]},'recording':false}";
final String DEFAULT_JSON_TOKEN = "{'id':'STR','object':'STR','token':'STR','connectionId':0,'session':'STR','createdAt':0,'role':'STR','data':'STR','record':true}"; final String DEFAULT_JSON_TOKEN = "{'id':'STR','object':'STR','token':'STR','connectionId':0,'session':'STR','createdAt':0,'role':'STR','data':'STR','record':true}";
final String DEFAULT_JSON_CONNECTION = "{'id':'STR','object':'STR','status':'STR','connectionId':'STR','sessionId':'STR','createdAt':0,'activeAt':0,'location':'STR','platform':'STR','role':'STR','record':true,'serverData':'STR','clientData':'STR','publishers':[],'subscribers':[]}"; final String DEFAULT_JSON_CONNECTION = "{'id':'STR','object':'STR','type':'STR','status':'STR','connectionId':'STR','sessionId':'STR','createdAt':0,'activeAt':0,'location':'STR','platform':'STR','role':'STR','record':true,'serverData':'STR','clientData':'STR','publishers':[],'subscribers':[]}";
@BeforeAll() @BeforeAll()
protected static void setupAll() { protected static void setupAll() {
@ -2647,7 +2647,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + connectionId1, null, restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + connectionId1, null,
HttpStatus.SC_OK, true, true, true, HttpStatus.SC_OK, true, true, true,
"{'id':'" + connectionId1 + "','connectionId':'" + connectionId1 "{'id':'" + connectionId1 + "','connectionId':'" + connectionId1
+ "','object':'connection','status':'pending','sessionId':'CUSTOM_SESSION_ID','token':'" + "','object':'connection','type':'WEBRTC','status':'pending','sessionId':'CUSTOM_SESSION_ID','token':'"
+ token1 + "','role':'MODERATOR','serverData':'SERVER_DATA','record':true,'createdAt':" + token1 + "','role':'MODERATOR','serverData':'SERVER_DATA','record':true,'createdAt':"
+ createdAt1 + createdAt1
+ ",'activeAt':null,'platform':null,'location':null,'clientData':null,'publishers':null,'subscribers':null}"); + ",'activeAt':null,'platform':null,'location':null,'clientData':null,'publishers':null,'subscribers':null}");
@ -2744,13 +2744,13 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + connectionId1, null, restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + connectionId1, null,
HttpStatus.SC_OK, false, true, false, HttpStatus.SC_OK, false, true, false,
"{'id':'" + connectionId1 + "','connectionId':'" + connectionId1 "{'id':'" + connectionId1 + "','connectionId':'" + connectionId1
+ "','object':'connection','status':'active','sessionId':'CUSTOM_SESSION_ID','token':'" + token1 + "','object':'connection','type':'WEBRTC','status':'active','sessionId':'CUSTOM_SESSION_ID','token':'"
+ "','role':'MODERATOR','serverData':'SERVER_DATA','record':true}"); + token1 + "','role':'MODERATOR','serverData':'SERVER_DATA','record':true}");
restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + connectionId2, null, restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + connectionId2, null,
HttpStatus.SC_OK, false, true, false, HttpStatus.SC_OK, false, true, false,
"{'id':'" + connectionId2 + "','connectionId':'" + connectionId2 "{'id':'" + connectionId2 + "','connectionId':'" + connectionId2
+ "','object':'connection','status':'active','sessionId':'CUSTOM_SESSION_ID','token':'" + token2 + "','object':'connection','type':'WEBRTC','status':'active','sessionId':'CUSTOM_SESSION_ID','token':'"
+ "','role':'PUBLISHER','serverData':'','record':true}"); + token2 + "','role':'PUBLISHER','serverData':'','record':true}");
/** GET /openvidu/api/recordings (before recording started) **/ /** GET /openvidu/api/recordings (before recording started) **/
restClient.rest(HttpMethod.GET, "/openvidu/api/recordings/NOT_EXISTS", HttpStatus.SC_NOT_FOUND); restClient.rest(HttpMethod.GET, "/openvidu/api/recordings/NOT_EXISTS", HttpStatus.SC_NOT_FOUND);
@ -3291,6 +3291,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
Assert.assertEquals("Wrong serverData property", "MY_IP_CAMERA", response.get("serverData").getAsString()); Assert.assertEquals("Wrong serverData property", "MY_IP_CAMERA", response.get("serverData").getAsString());
Assert.assertEquals("Wrong platform property", "IPCAM", response.get("platform").getAsString()); Assert.assertEquals("Wrong platform property", "IPCAM", response.get("platform").getAsString());
Assert.assertEquals("Wrong role property", "PUBLISHER", response.get("role").getAsString()); Assert.assertEquals("Wrong role property", "PUBLISHER", response.get("role").getAsString());
Assert.assertEquals("Wrong type property", "IPCAM", response.get("type").getAsString());
Assert.assertEquals("Wrong number of publishers in IPCAM participant", 1, Assert.assertEquals("Wrong number of publishers in IPCAM participant", 1,
response.get("publishers").getAsJsonArray().size()); response.get("publishers").getAsJsonArray().size());