private void handleGetFileRequest(GetFileRequest fileRequest) { try { FileHistoryId fileHistoryId = FileHistoryId.parseFileId(fileRequest.getFileHistoryId()); long version = fileRequest.getVersion(); FileVersion fileVersion = localDatabase.getFileVersion(fileHistoryId, version); FileContent fileContent = localDatabase.getFileContent(fileVersion.getChecksum(), true); Map<ChunkChecksum, MultiChunkId> multiChunks = localDatabase.getMultiChunkIdsByChecksums(fileContent.getChunks()); TransferManager transferManager = config.getTransferPlugin().createTransferManager(config.getConnection()); Downloader downloader = new Downloader(config, transferManager); Assembler assembler = new Assembler(config, localDatabase); downloader.downloadAndDecryptMultiChunks(new HashSet<MultiChunkId>(multiChunks.values())); File tempFile = assembler.assembleToCache(fileVersion); String tempFileToken = StringUtil.toHex(ObjectId.secureRandomBytes(40)); GetFileResponse fileResponse = new GetFileResponse(fileRequest.getId(), fileRequest.getRoot(), tempFileToken); GetFileResponseInternal fileResponseInternal = new GetFileResponseInternal(fileResponse, tempFile); eventBus.post(fileResponseInternal); } catch (Exception e) { logger.log(Level.WARNING, "Cannot reassemble file.", e); eventBus.post(new BadRequestResponse(fileRequest.getId(), "Cannot reassemble file.")); } }
/** * Finds the multichunks that need to be downloaded for the given file version -- using the local * database and given winners database. Returns a set of multichunk identifiers. */ private Collection<MultiChunkId> determineMultiChunksToDownload( FileVersion fileVersion, MemoryDatabase winnersDatabase) { Set<MultiChunkId> multiChunksToDownload = new HashSet<MultiChunkId>(); // First: Check if we know this file locally! List<MultiChunkId> multiChunkIds = localDatabase.getMultiChunkIds(fileVersion.getChecksum()); if (multiChunkIds.size() > 0) { multiChunksToDownload.addAll(multiChunkIds); } else { // Second: We don't know it locally; must be from the winners database FileContent winningFileContent = winnersDatabase.getContent(fileVersion.getChecksum()); boolean winningFileHasContent = winningFileContent != null; if (winningFileHasContent) { // File can be empty! List<ChunkChecksum> fileChunks = winningFileContent.getChunks(); // TODO [medium] Instead of just looking for multichunks to download here, we should look // for chunks in local files as well // and return the chunk positions in the local files ChunkPosition (chunk123 at file12, // offset 200, size 250) Map<ChunkChecksum, MultiChunkId> checksumsWithMultiChunkIds = localDatabase.getMultiChunkIdsByChecksums(fileChunks); for (ChunkChecksum chunkChecksum : fileChunks) { MultiChunkId multiChunkIdForChunk = checksumsWithMultiChunkIds.get(chunkChecksum); if (multiChunkIdForChunk == null) { multiChunkIdForChunk = winnersDatabase.getMultiChunkIdForChunk(chunkChecksum); if (multiChunkIdForChunk == null) { throw new RuntimeException("Cannot find multichunk for chunk " + chunkChecksum); } } if (!multiChunksToDownload.contains(multiChunkIdForChunk)) { logger.log( Level.INFO, " + Adding multichunk " + multiChunkIdForChunk + " to download list ..."); multiChunksToDownload.add(multiChunkIdForChunk); } } } } return multiChunksToDownload; }
private void handleGetFileHistoryRequest(GetFileHistoryRequest fileHistoryRequest) { FileHistoryId fileHistoryId = FileHistoryId.parseFileId(fileHistoryRequest.getFileHistoryId()); List<FileVersion> fileHistory = localDatabase.getFileHistory(fileHistoryId); GetFileHistoryResponse fileHistoryRespose = new GetFileHistoryResponse( fileHistoryRequest.getId(), fileHistoryRequest.getRoot(), fileHistory); eventBus.post(fileHistoryRespose); }
private void handleGetDatabaseVersionHeadersRequest( GetDatabaseVersionHeadersRequest headersRequest) { List<DatabaseVersionHeader> databaseVersionHeaders = localDatabase.getNonEmptyDatabaseVersionHeaders(); GetDatabaseVersionHeadersResponse headersResponse = new GetDatabaseVersionHeadersResponse( headersRequest.getId(), headersRequest.getRoot(), databaseVersionHeaders); eventBus.post(headersResponse); }
/** * This method implements the index/deduplication functionality of Syncany. It uses a {@link * Deduper} to break files down, compares them to the local database and creates a new {@link * DatabaseVersion} as a result. * * <p>Depending on what has changed, the new database version will contain new instances of {@link * PartialFileHistory}, {@link FileVersion}, {@link FileContent}, {@link ChunkEntry} and {@link * MultiChunkEntry}. * * @param files List of files to be deduplicated * @return New database version containing new/changed/deleted entities * @throws IOException If the chunking/deduplication cannot read/process any of the files */ public DatabaseVersion index(List<File> files) throws IOException { DatabaseVersion newDatabaseVersion = new DatabaseVersion(); // Load file history cache List<PartialFileHistory> fileHistoriesWithLastVersion = localDatabase.getFileHistoriesWithLastVersion(); // TODO [medium] This should be in FileHistoryDao Map<FileChecksum, List<PartialFileHistory>> fileChecksumCache = fillFileChecksumCache(fileHistoriesWithLastVersion); Map<String, PartialFileHistory> filePathCache = fillFilePathCache(fileHistoriesWithLastVersion); // Find and index new files deduper.deduplicate( files, new IndexerDeduperListener(newDatabaseVersion, fileChecksumCache, filePathCache, listener)); // Find and remove deleted files removeDeletedFiles(newDatabaseVersion, fileHistoriesWithLastVersion); return newDatabaseVersion; }
private void handleGetFileTreeRequest(GetFileTreeRequest fileTreeRequest) { try { String prefixLikeQuery = fileTreeRequest.getPrefix() + "%"; Date date = (fileTreeRequest.getDate() != null) ? new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ").parse(fileTreeRequest.getDate()) : null; Map<String, FileVersion> fileTree = localDatabase.getFileTree(prefixLikeQuery, date, false, (FileType[]) null); GetFileTreeResponse fileTreeResponse = new GetFileTreeResponse( fileTreeRequest.getId(), fileTreeRequest.getRoot(), fileTreeRequest.getPrefix(), new ArrayList<FileVersion>(fileTree.values())); eventBus.post(fileTreeResponse); } catch (Exception e) { eventBus.post( new BadRequestResponse(fileTreeRequest.getId(), "Invalid request: " + e.getMessage())); } }