package com.aimmac23.hub.videostorage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.exec.StreamPumper;
import org.openqa.grid.internal.ExternalSessionKey;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
/**
* A plugin to temporarily store videos in temporary local files. Videos are deleted when
* we store over a certain number of them (currently 200) to save on disk space. Use this plugin if:
*
* <ul>
* <li>You are just getting your grid setup, and you don't want the added complexity</li>
* <li>You don't mind the grid forgetting about videos over restarts</li>
* <li>You don't need the grid to store videos to be stored for very long</li>
* </ul>
* @author Alasdair Macmillan
*
*/
public class LocalTempFileStore implements IVideoStore {
private static final Logger log = Logger.getLogger(LocalTempFileStore.class.getName());
private static Cache<ExternalSessionKey, File> availableVideos;
static {
availableVideos = CacheBuilder.newBuilder().maximumSize(200).removalListener(new RemovalListener<ExternalSessionKey, File>() {
@Override
public void onRemoval(RemovalNotification<ExternalSessionKey, File> arg0) {
if(arg0.getValue().delete()) {
log.info("Deleted recording due to excess videos: " + arg0.getKey());
}
}
}).build();
}
@Override
public void storeVideo(InputStream videoStream, long contentLength, String mimeType,
String sessionId, SessionInfoBean infoBean) throws Exception {
File outputFile = File.createTempFile("screencast", ".webm");
FileOutputStream outputStream = new FileOutputStream(outputFile);
try {
new StreamPumper(videoStream, outputStream).run();
}
finally {
outputStream.close();
}
availableVideos.put(new ExternalSessionKey(sessionId), outputFile);
log.info("Successfully retrieved video for session: " + sessionId + " and temporarily stashed it at: " + outputFile);
}
@Override
public LocalTempFileDownloadContext retrieveVideo(String sessionId) throws Exception {
File file = availableVideos.getIfPresent(new ExternalSessionKey(sessionId));
if(file != null && file.exists() && file.isFile()) {
return new LocalTempFileDownloadContext(file);
}
return new LocalTempFileDownloadContext(null);
}
@Override
public StoredVideoInfoContext getVideoInformation(String sessionId)
throws Exception {
// XXX: Abuse the class heirarchy for this one
return retrieveVideo(sessionId);
}
@Override
public String getVideoStoreTypeIdentifier() {
return "TEMP_FILE";
}
private static class LocalTempFileDownloadContext implements StoredVideoDownloadContext, StoredVideoInfoContext {
private File file;
private FileInputStream stream;
public LocalTempFileDownloadContext(File file) throws FileNotFoundException {
this.file = file;
if(file != null) {
stream = new FileInputStream(file);
}
else {
stream = null;
}
}
@Override
public boolean isVideoFound() {
return file != null;
}
@Override
public InputStream getStream() throws IOException {
return stream;
}
@Override
public Long getContentLengthIfKnown() {
return new Long(file.length());
}
@Override
public void close() {
if(stream == null) {
// nothing to do
return;
}
try {
stream.close();
} catch (IOException e) {
log.log(Level.WARNING, "Could not close file: " + file, e);
}
}
@Override
public Map<String, Object> additionalInformation() {
return Collections.emptyMap();
}
}
}