package org.openslx.imagemaster.serverconnection;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.log4j.Logger;
import org.openslx.imagemaster.Globals;
import org.openslx.imagemaster.crcchecker.CrcFile;
import org.openslx.imagemaster.db.DbImage;
import org.openslx.imagemaster.db.DbUser;
import org.openslx.imagemaster.thrift.iface.DownloadData;
import org.openslx.imagemaster.thrift.iface.ImageData;
import org.openslx.imagemaster.thrift.iface.ImageDataError;
import org.openslx.imagemaster.thrift.iface.ImageDataException;
import org.openslx.imagemaster.thrift.iface.UploadData;
import org.openslx.imagemaster.thrift.iface.UploadError;
import org.openslx.imagemaster.thrift.iface.UploadException;
import org.openslx.imagemaster.util.RandomString;
import org.openslx.imagemaster.util.Util;
/**
* Processing the up- and download of images.
* Handles who is authorized and knows which blocks are missing / need to be sent
*/
public class ImageProcessor
{
private static final Logger log = Logger.getLogger( ImageProcessor.class );
/**
* The uploading images.
* Key: imageUUID,
* Value: uploadingImageInfos
*/
private static Map<String, UploadingImage> uploadingImages = new ConcurrentHashMap<>();
/**
* The UUIDs of the images that need to be checked by the crc checker.
*/
private static List<String> imagesToCheck = new ArrayList<>();
/**
* Checks if this image is already uploading and returns a new list with missing blocks if so.
* Puts the new image into processing list else.
*
* @param serverSessionId The uploading server
* @param imageData The data of the image
* @return
* @throws UploadException If some error occurred during the process
*/
public static UploadData getUploadInfos( ImageData imageData, List<Integer> crcSums )
throws UploadException, ImageDataException
{
// check image data
if ( imageData.title == null || imageData.title.isEmpty() )
throw new ImageDataException( ImageDataError.INVALID_DATA, "Image name not set." );
if ( imageData.ownerLogin == null || !DbUser.exists( imageData.ownerLogin ) )
throw new ImageDataException( ImageDataError.INVALID_DATA, "Invalid image owner." );
if ( !imageData.isSetOperatingSystem() )
throw new ImageDataException( ImageDataError.INVALID_DATA, "Content operating system not set." );
if ( imageData.fileSize <= 0 )
throw new ImageDataException( ImageDataError.INVALID_DATA, "File size is too small." );
log.debug( "Satellite is submitting " + imageData.uuid );
final String uuid = imageData.uuid;
final String filepathRelative;
final CrcFile crcFile;
if ( crcSums == null ) {
crcFile = null;
} else {
crcFile = new CrcFile( crcSums );
}
UploadingImage image;
synchronized ( uploadingImages ) {
// check if image is already uploading
if ( ( image = uploadingImages.get( uuid ) ) == null ) {
// insert new image
if ( crcSums != null && !crcFile.isValid() )
throw new UploadException( UploadError.INVALID_CRC, "CRC sums were invalid." );
filepathRelative = generateFilepathOfImage( imageData );
DbImage.insert( imageData, filepathRelative ); // Make sure it exists in DB
try {
image = new UploadingImage( uuid );
} catch ( Exception e ) {
throw new UploadException( UploadError.GENERIC_ERROR, "Internal error" );
}
uploadingImages.put( uuid, image );
}
}
final String token = RandomString.generate( 50, false );
ConnectionHandler.addUpload( token, image );
// Set crc file on image - if there is already a crc file assigned, this does nothing
image.setCrcFile( crcFile );
if ( image.allBlocksValid() )
removeFinishedUploads();
return new UploadData( token, Globals.getSslSocketPort() );
}
public static DownloadData getDownloadInfos( String uuid ) throws ImageDataException
{
DbImage image = DbImage.getImageByUuid( uuid );
if ( image == null )
throw new ImageDataException( ImageDataError.UNKNOWN_IMAGE, "UUID '" + uuid + "' does not map to a known image." );
// server was downloading another image and now gets a new connection for this new download
String token = RandomString.generate( 50, false );
ConnectionHandler.addDownload( token, image );
return new DownloadData( token, Globals.getSslSocketPort(), null ); // TODO: Return crc list
}
/**
* Go though list of active uploading images and remove
* those that are finished.
*/
public static void removeFinishedUploads()
{
for ( Iterator<UploadingImage> it = uploadingImages.values().iterator(); it.hasNext(); ) {
UploadingImage image = it.next();
if ( image.allBlocksValid() ) {
synchronized ( imagesToCheck ) {
imagesToCheck.remove( image.getUuid() );
image.updateMissingBlocks( null );
}
it.remove();
}
}
}
public static List<UploadingImage> getImagesToCheck()
{
List<UploadingImage> result = new LinkedList<>();
Iterator<String> iter = imagesToCheck.iterator();
log.debug( imagesToCheck );
while ( iter.hasNext() ) {
result.add( uploadingImages.get( iter.next() ) );
}
return result;
}
public static List<Integer> getRequestedBlocks( String token )
{
// for the downloader
// TODO
return null;
}
/**
* Generates the filePath of an image.
* And creates the folder if wanted.
* The crc file is found under filePath + ".crc"
*
* @param imageData The data of the image
* @return The filePath of the given image
*/
public static String generateFilepathOfImage( ImageData imageData )
{
return generateFilePathOfImage( imageData.uuid, imageData.title, imageData.revision );
}
public static String generateFilePathOfImage( String uuid, String imageName, int imageVersion )
{
String result = Util.sanitizeFileName( uuid ) + "/";
File dir = new File( Globals.getImageDir() + "/" + result );
if ( !dir.exists() ) {
dir.mkdirs();
}
result += imageName + "-rev" + String.valueOf( imageVersion );
return result;
}
public static String generateFilepathOfCrcFile( ImageData imageData )
{
return generateFilepathOfImage( imageData ) + ".crc";
}
public static String generateFilepathOfCrcFile( String uuid, String imageName, int imageVersion )
{
return generateFilePathOfImage( uuid, imageName, imageVersion ) + ".crc";
}
}