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 uploadingImages = new ConcurrentHashMap<>(); /** * The UUIDs of the images that need to be checked by the crc checker. */ private static List 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 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: " + imageData.ownerLogin ); 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 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 getImagesToCheck() { List result = new LinkedList<>(); Iterator iter = imagesToCheck.iterator(); log.debug( imagesToCheck ); while ( iter.hasNext() ) { result.add( uploadingImages.get( iter.next() ) ); } return result; } public static List 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"; } }