mirror of https://github.com/OpenVidu/openvidu.git
Enable google cloud storage uploading for recordings
parent
bd3b0f5b66
commit
e3992b4383
|
@ -327,6 +327,18 @@
|
||||||
<artifactId>openvidu-java-client</artifactId>
|
<artifactId>openvidu-java-client</artifactId>
|
||||||
<version>${version.openvidu.java.client}</version>
|
<version>${version.openvidu.java.client}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.cloud</groupId>
|
||||||
|
<artifactId>libraries-bom</artifactId>
|
||||||
|
<version>16.1.0</version>
|
||||||
|
<type>pom</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.cloud</groupId>
|
||||||
|
<artifactId>google-cloud-storage</artifactId>
|
||||||
|
<version>1.113.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- Test dependencies -->
|
<!-- Test dependencies -->
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
import io.openvidu.server.recording.*;
|
||||||
import org.bouncycastle.util.Arrays;
|
import org.bouncycastle.util.Arrays;
|
||||||
import org.kurento.jsonrpc.internal.server.config.JsonRpcConfiguration;
|
import org.kurento.jsonrpc.internal.server.config.JsonRpcConfiguration;
|
||||||
import org.kurento.jsonrpc.server.JsonRpcConfigurer;
|
import org.kurento.jsonrpc.server.JsonRpcConfigurer;
|
||||||
|
@ -61,10 +62,6 @@ import io.openvidu.server.kurento.kms.DummyLoadManager;
|
||||||
import io.openvidu.server.kurento.kms.FixedOneKmsManager;
|
import io.openvidu.server.kurento.kms.FixedOneKmsManager;
|
||||||
import io.openvidu.server.kurento.kms.KmsManager;
|
import io.openvidu.server.kurento.kms.KmsManager;
|
||||||
import io.openvidu.server.kurento.kms.LoadManager;
|
import io.openvidu.server.kurento.kms.LoadManager;
|
||||||
import io.openvidu.server.recording.DummyRecordingDownloader;
|
|
||||||
import io.openvidu.server.recording.DummyRecordingUploader;
|
|
||||||
import io.openvidu.server.recording.RecordingDownloader;
|
|
||||||
import io.openvidu.server.recording.RecordingUploader;
|
|
||||||
import io.openvidu.server.recording.service.RecordingManager;
|
import io.openvidu.server.recording.service.RecordingManager;
|
||||||
import io.openvidu.server.recording.service.RecordingManagerUtils;
|
import io.openvidu.server.recording.service.RecordingManagerUtils;
|
||||||
import io.openvidu.server.recording.service.RecordingManagerUtilsLocalStorage;
|
import io.openvidu.server.recording.service.RecordingManagerUtilsLocalStorage;
|
||||||
|
@ -203,7 +200,11 @@ public class OpenViduServer implements JsonRpcConfigurer {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public RecordingUploader recordingUpload() {
|
@DependsOn("openviduConfig")
|
||||||
|
public RecordingUploader recordingUpload(OpenviduConfig openviduConfig) {
|
||||||
|
if (openviduConfig.isGcpRecordingStorageEnabled()) {
|
||||||
|
return new GoogleCloudStorageRecordingUploader();
|
||||||
|
}
|
||||||
return new DummyRecordingUploader();
|
return new DummyRecordingUploader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -190,6 +190,10 @@ public class OpenviduConfig {
|
||||||
|
|
||||||
private String dotenvPath;
|
private String dotenvPath;
|
||||||
|
|
||||||
|
private boolean gcpRecordingStorageEnabled;
|
||||||
|
|
||||||
|
private String gcpStorageBucketName;
|
||||||
|
|
||||||
// Derived properties
|
// Derived properties
|
||||||
|
|
||||||
public static String finalUrl;
|
public static String finalUrl;
|
||||||
|
@ -338,6 +342,14 @@ public class OpenviduConfig {
|
||||||
return dotenvPath;
|
return dotenvPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isGcpRecordingStorageEnabled() {
|
||||||
|
return gcpRecordingStorageEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGcpStorageBucketName() {
|
||||||
|
return gcpStorageBucketName;
|
||||||
|
}
|
||||||
|
|
||||||
// Derived properties methods
|
// Derived properties methods
|
||||||
|
|
||||||
public String getSpringProfile() {
|
public String getSpringProfile() {
|
||||||
|
@ -533,6 +545,10 @@ public class OpenviduConfig {
|
||||||
openviduForcedCodec = asEnumValue("OPENVIDU_STREAMS_FORCED_VIDEO_CODEC", VideoCodec.class);
|
openviduForcedCodec = asEnumValue("OPENVIDU_STREAMS_FORCED_VIDEO_CODEC", VideoCodec.class);
|
||||||
openviduAllowTranscoding = asBoolean("OPENVIDU_STREAMS_ALLOW_TRANSCODING");
|
openviduAllowTranscoding = asBoolean("OPENVIDU_STREAMS_ALLOW_TRANSCODING");
|
||||||
|
|
||||||
|
gcpRecordingStorageEnabled = asBoolean("OPENVIDU_GCP_RECORDING_STORAGE_ENABLED");
|
||||||
|
gcpStorageBucketName = gcpRecordingStorageEnabled ? asNonEmptyString("OPENVIDU_GCP_STORAGE_BUCKET_NAME")
|
||||||
|
: null;
|
||||||
|
|
||||||
kmsUrisList = checkKmsUris();
|
kmsUrisList = checkKmsUris();
|
||||||
|
|
||||||
checkCoturnIp();
|
checkCoturnIp();
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package io.openvidu.server.recording;
|
||||||
|
|
||||||
|
import com.google.cloud.storage.BlobId;
|
||||||
|
import com.google.cloud.storage.BlobInfo;
|
||||||
|
import com.google.cloud.storage.Storage;
|
||||||
|
import com.google.cloud.storage.StorageException;
|
||||||
|
import io.openvidu.server.config.OpenviduConfig;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
||||||
|
public class GoogleCloudStorageRecordingUploader implements RecordingUploader {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(GoogleCloudStorageRecordingUploader.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OpenviduConfig config;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Storage gcpStorage;
|
||||||
|
|
||||||
|
private final Set<String> recordingsBeingCurrentlyUploaded = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uploadRecording(Recording recording, Runnable successCallback, Runnable errorCallback) {
|
||||||
|
recordingsBeingCurrentlyUploaded.add(recording.getId());
|
||||||
|
|
||||||
|
String bucketName = config.getGcpStorageBucketName();
|
||||||
|
BlobInfo blobInfo = BlobInfo.newBuilder(BlobId.of(bucketName, recording.getName())).build();
|
||||||
|
String filePath = getComposedRecordingLocalFilePath(recording);
|
||||||
|
|
||||||
|
try {
|
||||||
|
gcpStorage.create(blobInfo, Files.readAllBytes(Paths.get(filePath)));
|
||||||
|
} catch (StorageException | IOException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
errorCallback.run();
|
||||||
|
} finally {
|
||||||
|
recordingsBeingCurrentlyUploaded.remove(recording.getId());
|
||||||
|
}
|
||||||
|
successCallback.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getComposedRecordingLocalFilePath(Recording recording) {
|
||||||
|
// Audio-only recordings are in WEBM file format
|
||||||
|
String fileExt = recording.hasVideo() ? ".mp4" : ".webm";
|
||||||
|
return config.getOpenViduRecordingPath() + "/" + recording.getId() + "/" + recording.getName() + fileExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent uploading recordings from being retrieved from REST API with "ready"
|
||||||
|
// status. This will force their status back to "stopped" on GET until upload
|
||||||
|
// process has finished
|
||||||
|
@Override
|
||||||
|
public void storeAsUploadingRecording(String recordingId) {
|
||||||
|
recordingsBeingCurrentlyUploaded.add(recordingId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBeingUploaded(String recordingId) {
|
||||||
|
return recordingsBeingCurrentlyUploaded.contains(recordingId);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue