/* * Created on Jul 16, 2008 * Created by Paul Gardner * * Copyright 2008 Vuze, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License only. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ package com.aelitis.azureus.core.lws; import java.io.File; import java.util.List; import org.gudy.azureus2.core3.disk.DiskManager; import org.gudy.azureus2.core3.disk.DiskManagerCheckRequest; import org.gudy.azureus2.core3.disk.DiskManagerCheckRequestListener; import org.gudy.azureus2.core3.disk.DiskManagerFileInfo; import org.gudy.azureus2.core3.disk.DiskManagerFileInfoSet; import org.gudy.azureus2.core3.disk.DiskManagerListener; import org.gudy.azureus2.core3.disk.DiskManagerPiece; import org.gudy.azureus2.core3.disk.DiskManagerReadRequest; import org.gudy.azureus2.core3.disk.DiskManagerReadRequestListener; import org.gudy.azureus2.core3.disk.DiskManagerWriteRequest; import org.gudy.azureus2.core3.disk.DiskManagerWriteRequestListener; import org.gudy.azureus2.core3.disk.impl.DiskManagerFileInfoImpl; import org.gudy.azureus2.core3.disk.impl.DiskManagerHelper; import org.gudy.azureus2.core3.disk.impl.DiskManagerImpl; import org.gudy.azureus2.core3.disk.impl.DiskManagerPieceImpl; import org.gudy.azureus2.core3.disk.impl.DiskManagerRecheckScheduler; import org.gudy.azureus2.core3.disk.impl.DiskManagerUtil; import org.gudy.azureus2.core3.disk.impl.access.DMAccessFactory; import org.gudy.azureus2.core3.disk.impl.access.DMChecker; import org.gudy.azureus2.core3.disk.impl.access.DMReader; import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceList; import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceMap; import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceMapper; import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceMapperFactory; import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceMapperFile; import org.gudy.azureus2.core3.download.DownloadManagerState; import org.gudy.azureus2.core3.internat.LocaleTorrentUtil; import org.gudy.azureus2.core3.internat.LocaleUtilDecoder; import org.gudy.azureus2.core3.peer.PEPeer; import org.gudy.azureus2.core3.torrent.TOTorrent; import org.gudy.azureus2.core3.torrent.TOTorrentException; import org.gudy.azureus2.core3.util.ByteFormatter; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.core3.util.DirectByteBuffer; import org.gudy.azureus2.core3.util.IndentWriter; import org.gudy.azureus2.core3.util.SystemTime; import com.aelitis.azureus.core.diskmanager.access.DiskAccessController; import com.aelitis.azureus.core.diskmanager.cache.CacheFile; import com.aelitis.azureus.core.diskmanager.cache.CacheFileOwner; public class LWSDiskManager implements DiskManagerHelper { private static sePiece piece = new sePiece(); private LightWeightSeed lws; private DiskAccessController disk_access_controller; private File save_file; private DMReader reader; private DMChecker checker_use_accessor; private DMPieceMapper piece_mapper; private DMPieceMap piece_map_use_accessor; private sePiece[] pieces; private DiskManagerFileInfoImpl[] files; private String internal_name; private DownloadManagerState download_state; private boolean started; private int state = DiskManager.INITIALIZING; private String error_message = ""; protected LWSDiskManager( LightWeightSeed _lws, File _save_file ) { lws = _lws; save_file = _save_file; disk_access_controller = DiskManagerImpl.getDefaultDiskAccessController(); download_state = new LWSDiskManagerState(); TOTorrent torrent = lws.getTOTorrent( false ); pieces = new sePiece[ torrent.getNumberOfPieces() ]; for (int i=0;i<pieces.length;i++){ pieces[i] = piece; } } public String getName() { return( lws.getName()); } public int getCacheMode() { return( CacheFileOwner.CACHE_MODE_NORMAL ); } public long[] getReadStats() { if ( reader == null ){ return( new long[]{ 0, 0 }); } return( reader.getStats()); } public void start() { try{ TOTorrent torrent = lws.getTOTorrent( false ); internal_name = ByteFormatter.nicePrint(torrent.getHash(),true); LocaleUtilDecoder locale_decoder = LocaleTorrentUtil.getTorrentEncoding( torrent ); piece_mapper = DMPieceMapperFactory.create( torrent ); piece_mapper.construct( locale_decoder, save_file.getName()); files = getFileInfo( piece_mapper.getFiles(), save_file ); reader = DMAccessFactory.createReader( this ); reader.start(); if ( state != DiskManager.FAULTY ){ started = true; state = DiskManager.READY; } }catch( Throwable e ){ setFailed( "start failed - " + Debug.getNestedExceptionMessage(e)); } } protected DiskManagerFileInfoImpl[] getFileInfo( DMPieceMapperFile[] pm_files, File save_location ) { boolean ok = false; DiskManagerFileInfoImpl[] local_files = new DiskManagerFileInfoImpl[pm_files.length]; try{ TOTorrent torrent = lws.getTOTorrent( false ); if ( torrent.isSimpleTorrent()){ save_location = save_location.getParentFile(); } for (int i = 0; i < pm_files.length; i++) { DMPieceMapperFile pm_info = pm_files[i]; File relative_file = pm_info.getDataFile(); long target_length = pm_info.getLength(); DiskManagerFileInfoImpl file_info = new DiskManagerFileInfoImpl( this, save_location.toString(), relative_file, i, pm_info.getTorrentFile(), DiskManagerFileInfo.ST_LINEAR ); local_files[i] = file_info; CacheFile cache_file = file_info.getCacheFile(); File data_file = file_info.getFile(true); if ( !cache_file.exists()){ throw( new Exception( "File '" + data_file + "' doesn't exist" )); } if ( cache_file.getLength() != target_length ){ throw( new Exception( "File '" + data_file + "' doesn't exist" )); } pm_info.setFileInfo( file_info ); } ok = true; return( local_files ); }catch( Throwable e ){ setFailed( "getFiles failed - " + Debug.getNestedExceptionMessage( e )); return( null ); }finally{ if ( !ok ){ for (int i=0;i<local_files.length;i++){ if ( local_files[i] != null ){ local_files[i].close(); } } } } } public void setPieceDone( DiskManagerPieceImpl dmPiece, boolean done ) { } public boolean stop( boolean closing ) { started = false; if ( reader != null ){ reader.stop(); reader = null; } if ( files != null ){ for (int i=0;i<files.length;i++){ try{ files[i].getCacheFile().close(); }catch( Throwable e ){ e.printStackTrace(); } } } return( false ); } public boolean isStopped() { return( !started ); } public boolean filesExist() { throw( new RuntimeException( "filesExist not implemented" )); } public DiskManagerWriteRequest createWriteRequest( int pieceNumber, int offset, DirectByteBuffer data, Object user_data ) { throw( new RuntimeException( "createWriteRequest not implemented" )); } public void enqueueWriteRequest( DiskManagerWriteRequest request, DiskManagerWriteRequestListener listener ) { throw( new RuntimeException( "enqueueWriteRequest not implemented" )); } public boolean hasOutstandingWriteRequestForPiece( int piece_number ) { throw( new RuntimeException( "hasOutstandingWriteRequestForPiece not implemented" )); } public boolean hasOutstandingReadRequestForPiece( int piece_number ) { throw( new RuntimeException( "hasOutstandingReadRequestForPiece not implemented" )); } public boolean hasOutstandingCheckRequestForPiece( int piece_number ) { throw( new RuntimeException( "hasOutstandingCheckRequestForPiece not implemented" )); } public DirectByteBuffer readBlock( int pieceNumber, int offset, int length ) { return( reader.readBlock( pieceNumber, offset, length )); } public DiskManagerReadRequest createReadRequest( int pieceNumber, int offset, int length ) { return( reader.createReadRequest( pieceNumber, offset, length )); } public void enqueueReadRequest( DiskManagerReadRequest request, DiskManagerReadRequestListener listener ) { reader.readBlock( request, listener ); } public DiskManagerCheckRequest createCheckRequest( int pieceNumber, Object user_data ) { DMChecker checker = getChecker(); return( checker.createCheckRequest( pieceNumber, user_data)); } public void enqueueCheckRequest( DiskManagerCheckRequest request, DiskManagerCheckRequestListener listener ) { DMChecker checker = getChecker(); checker.enqueueCheckRequest( request, listener ); } public void enqueueCompleteRecheckRequest( DiskManagerCheckRequest request, DiskManagerCheckRequestListener listener ) { throw( new RuntimeException( "enqueueCompleteRecheckRequest not implemented" )); } public void setPieceCheckingEnabled( boolean enabled ) { } public void saveResumeData( boolean interim_save ) { } public DiskManagerPiece[] getPieces() { return( pieces ); } public DiskManagerPiece getPiece( int index ) { return( pieces[index] ); } public boolean isInteresting( int piece_num ) { return( false ); } public boolean isDone( int piece_num ) { return( false ); } public int getNbPieces() { return( pieces.length ); } public DiskManagerFileInfo[] getFiles() { return( files ); } public DiskManagerFileInfoSet getFileSet() { throw( new RuntimeException( "getFileSet not implemented" )); } public int getState() { return( state ); } public long getTotalLength() { return( piece_mapper.getTotalLength()); } public int getPieceLength() { return( piece_mapper.getPieceLength()); } public int getPieceLength( int piece_number) { if ( piece_number == pieces.length-1 ){ return( piece_mapper.getLastPieceLength()); }else{ return( piece_mapper.getPieceLength()); } } public int getLastPieceLength() { return( piece_mapper.getLastPieceLength()); } public long getRemaining() { return( 0 ); } public long getRemainingExcludingDND() { return( 0 ); } public int getPercentDone() { return( 100 ); } public int getPercentDoneExcludingDND() { // Either this one or getPercentDone is wrong, mebbe return 1000; } public long getSizeExcludingDND() { return getTotalLength(); } public String getErrorMessage() { return( error_message ); } public void downloadEnded( OperationStatus op_status ) { } public void moveDataFiles( File new_parent_dir, String new_name, OperationStatus op_status ) { throw( new RuntimeException( "moveDataFiles not implemented" )); } public int getCompleteRecheckStatus() { return( -1 ); } public int getMoveProgress() { return( -1 ); } public boolean checkBlockConsistencyForWrite( String originator, int pieceNumber, int offset, DirectByteBuffer data ) { long pos = pieceNumber * (long)piece_mapper.getPieceLength() + offset + data.remaining( DirectByteBuffer.AL_EXTERNAL ); return( pos <= piece_mapper.getTotalLength()); } public boolean checkBlockConsistencyForRead( String originator, boolean peer_request, int pieceNumber, int offset, int length ) { return( DiskManagerUtil.checkBlockConsistencyForRead( this, originator, peer_request, pieceNumber, offset, length)); } public boolean checkBlockConsistencyForHint( String originator, int pieceNumber, int offset, int length ) { return( DiskManagerUtil.checkBlockConsistencyForHint( this, originator, pieceNumber, offset, length)); } public void addListener( DiskManagerListener l ) { } public void removeListener( DiskManagerListener l ) { } public boolean hasListener( DiskManagerListener l ) { return( false ); } public void saveState() { } public DiskAccessController getDiskAccessController() { return( disk_access_controller ); } public DMPieceMap getPieceMap() { DMPieceMap map = piece_map_use_accessor; if ( map == null ){ piece_map_use_accessor = map = piece_mapper.getPieceMap(); } return( map ); } public DMPieceList getPieceList( int piece_number ) { DMPieceMap map = getPieceMap(); return( map.getPieceList( piece_number )); } protected DMChecker getChecker() { DMChecker checker = checker_use_accessor; if ( checker == null ){ checker = checker_use_accessor = DMAccessFactory.createChecker( this ); } return( checker ); } public byte[] getPieceHash( int piece_number ) throws TOTorrentException { return( lws.getTorrent().getPieces()[piece_number] ); } public DiskManagerRecheckScheduler getRecheckScheduler() { throw( new RuntimeException( "getPieceHash not implemented" )); } public void downloadRemoved() { } public void setFailed( String reason ) { started = false; state = FAULTY; error_message = reason; } public void setFailed( DiskManagerFileInfo file, String reason ) { started = false; state = FAULTY; error_message = reason; } public long getAllocated() { return( 0 ); } public void setAllocated( long num ) { } public void setPercentDone( int num ) { } public TOTorrent getTorrent() { return( lws.getTOTorrent( false )); } public String[] getStorageTypes() { throw( new RuntimeException( "getStorageTypes not implemented" )); } public String getStorageType( int fileIndex) { throw( new RuntimeException( "getStorageType not implemented" )); } public void accessModeChanged( DiskManagerFileInfoImpl file, int old_mode, int new_mode ) { } public void skippedFileSetChanged( DiskManagerFileInfo file ) { } public void priorityChanged( DiskManagerFileInfo file ) { } public File getSaveLocation() { return( save_file ); } public String getInternalName() { return( internal_name ); } public DownloadManagerState getDownloadState() { return( download_state ); } public void generateEvidence( IndentWriter writer ) { } protected static class sePiece implements DiskManagerPiece { public void clearChecking(){throw( new RuntimeException( "clearChecking not implemented" ));} public boolean isNeedsCheck(){throw( new RuntimeException( "isNeedsCheck not implemented" ));} public int getLength(){throw( new RuntimeException( "getLength not implemented" ));} public int getNbBlocks(){throw( new RuntimeException( "getNbBlocks not implemented" ));} public int getPieceNumber(){throw( new RuntimeException( "getPieceNumber not implemented" ));} public int getBlockSize(int b ){throw( new RuntimeException( "getBlockSize not implemented" ));} public boolean isWritten(){throw( new RuntimeException( "isWritten not implemented" ));} public int getNbWritten(){throw( new RuntimeException( "getNbWritten not implemented" ));} public boolean[] getWritten(){throw( new RuntimeException( "getWritten not implemented" ));} public void reDownloadBlock(int blockNumber){throw( new RuntimeException( "reDownloadBlock not implemented" ));} public void reset(){throw( new RuntimeException( "reset not implemented" ));} public boolean isDownloadable(){ return( false );} public void setDownloadable(){throw( new RuntimeException( "setRequestable not implemented" ));} public DiskManager getManager(){throw( new RuntimeException( "getManager not implemented" ));} public boolean calcNeeded(){throw( new RuntimeException( "calcNeeded not implemented" ));} public void clearNeeded(){throw( new RuntimeException( "clearNeeded not implemented" ));} public boolean isNeeded(){throw( new RuntimeException( "isNeeded not implemented" ));} public void setNeeded(){throw( new RuntimeException( "setNeeded not implemented" ));} public void setNeeded(boolean b){throw( new RuntimeException( "setNeeded not implemented" ));} public void setWritten(int b){throw( new RuntimeException( "setWritten not implemented" ));} public boolean isWritten(int blockNumber){throw( new RuntimeException( "isWritten not implemented" ));} public boolean calcChecking(){throw( new RuntimeException( "calcChecking not implemented" ));} public boolean isChecking(){return( false );} public void setChecking(){throw( new RuntimeException( "setChecking not implemented" ));} public void setChecking(boolean b){throw( new RuntimeException( "setChecking not implemented" ));} public boolean calcDone(){throw( new RuntimeException( "calcDone not implemented" ));} public boolean isDone(){ return( true );} public boolean isInteresting(){ return( false );} public boolean isSkipped(){ return false; } public String getString(){ return( "" );} public short getReadCount(){ return 0 ;} public void setReadCount(short c){} public void setDone( boolean b) { // get here when doing delayed rechecks if ( !b ){ Debug.out( "Piece failed recheck" ); } //throw( new RuntimeException( "setDone not implemented" )); } } }