org.klomp.snark.web

## Class FetchAndAdd

- java.lang.Object
- - org.klomp.snark.Snark
  - - org.klomp.snark.web.FetchAndAdd

- All Implemented Interfaces:
    Runnable, EepGet.StatusListener, CoordinatorListener, ShutdownListener, StorageListener

      public class FetchAndAdd
      extends Snark
      implements EepGet.StatusListener, Runnable

  A cancellable torrent file downloader. We extend Snark so its status may be easily listed in the web table without adding a lot of code there.

  Upon successful download, this Snark will be deleted and a "real" Snark created.

  The methods return values similar to a Snark in magnet mode. A fake info hash, which is the SHA1 of the URL, is returned to prevent duplicates.

  This Snark may be stopped and restarted, although a partially downloaded file is discarded.

- - ### Field Summary

    - ### Fields inherited from class org.klomp.snark.Snark

      `_util, PROP_MAX_CONNECTIONS, storageCompleted`

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `FetchAndAdd(I2PAppContext ctx, SnarkManager mgr, String url, File dataDir)` Caller should call _mgr.addDownloader(this), which will start things off.

  - ### Method Summary

    All Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `void` | `attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause)`
    `void` | `attempting(String url)`
    `void` | `bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url)` Total length should be == alreadyTransferred + currentWrite + bytesRemaining for all calls
    `String` | `getBaseName()`
    `long` | `getDownloaded()` Get the total number of bytes downloaded.
    `long` | `getDownloadRate()` Get the current download rate in bytes per second.
    `byte[]` | `getInfoHash()`
    `String` | `getName()`
    `long` | `getNeededLength()` Bytes still wanted.
    `int` | `getPeerCount()`
    `long` | `getRemainingLength()` Bytes not yet in storage.
    `long` | `getTotalLength()`
    `int` | `getTrackerSeenPeers()`
    `void` | `headerReceived(String url, int attemptNum, String key, String val)` Note: Headers are not processed, and this is not called, for most error response codes, unless setWriteErrorToOutput() is called before fetch().
    `boolean` | `isStopped()`
    `void` | `run()` Set off by startTorrent()
    `void` | `startTorrent()` Start up contacting peers and querying the tracker.
    `void` | `stopTorrent()` Stop contacting the tracker and talking with peers
    `void` | `transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified)`
    `void` | `transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt)`

    - ### Methods inherited from class org.klomp.snark.Snark

      `addComments, addMessage, getCheckingProgress, getComments, getID, getMetaInfo, getNeeded, getPeerList, getPieceLength, getPieces, getRPCID, getSkippedLength, getStartedTime, getStorage, getTrackerProblems, getTrackerURL, getUploaded, getUploadRate, gotMetaInfo, isAllocating, isAutoStoppable, isChecking, isNotificationSent, isStarting, isStorageCompleted, overUploadLimit, peerChange, replaceMetaInfo, restartAcceptor, setAutoStoppable, setNotificationSent, setStarting, setTrackerProblems, setTrackerSeenPeers, setWantedPieces, shutdown, stopTorrent, storageAllChecked, storageAllocated, storageChecked, storageCompleted, storageCreateFile, updatePiecePriorities`

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Constructor Detail

    - #### FetchAndAdd

          public FetchAndAdd(I2PAppContext ctx,
                             SnarkManager mgr,
                             String url,
                             File dataDir)

      Caller should call _mgr.addDownloader(this), which will start things off.
      Parameters:
        `dataDir` - null to default to snark data directory

  - ### Method Detail

    - #### attemptFailed

          public void attemptFailed(String url,
                                    long bytesTransferred,
                                    long bytesRemaining,
                                    int currentAttempt,
                                    int numRetries,
                                    Exception cause)

      Specified by:
        `attemptFailed` in interface `EepGet.StatusListener`
      See Also:
        `EepGet.StatusListener.bytesTransferred(long, int, long, long, java.lang.String)`

    - #### attempting

          public void attempting(String url)

      Specified by:
        `attempting` in interface `EepGet.StatusListener`

    - #### bytesTransferred

          public void bytesTransferred(long alreadyTransferred,
                                       int currentWrite,
                                       long bytesTransferred,
                                       long bytesRemaining,
                                       String url)

      Description copied from interface: `EepGet.StatusListener`
      Total length should be == alreadyTransferred + currentWrite + bytesRemaining for all calls
      Specified by:
        `bytesTransferred` in interface `EepGet.StatusListener`
      Parameters:
        `alreadyTransferred` - total of all attempts, not including currentWrite If nonzero on the first call, a partial file of that length was found, _and_ the server supports resume. If zero on a subsequent call after some bytes are transferred (and presumably after an attemptFailed), the server does _not_ support resume and we had to start over. To track _actual_ transfer if the output file could already exist, the listener should keep its own counter, or subtract the initial alreadyTransferred value. And watch out for alreadyTransferred resetting if a resume failed...
        `currentWrite` - since last call to the listener
        `bytesTransferred` - includes headers, retries, redirects, discarded partial downloads, ...
        `bytesRemaining` - on this attempt only, currentWrite already subtracted - or -1 if chunked encoding or server does not return a length

    - #### getBaseName

          public String getBaseName()

      Overrides:
        `getBaseName` in class `Snark`
      Returns:
        base name of torrent [filtered version of getMetaInfo.getName()], or a fake name if in magnet mode

    - #### getDownloaded

          public long getDownloaded()

      Description copied from class: `Snark`
      Get the total number of bytes downloaded.
      Overrides:
        `getDownloaded` in class `Snark`
      Returns:
        total bytes downloaded, or 0 if not available

    - #### getDownloadRate

          public long getDownloadRate()

      Description copied from class: `Snark`
      Get the current download rate in bytes per second.
      Overrides:
        `getDownloadRate` in class `Snark`
      Returns:
        download rate in bytes per second, or 0 if not available

    - #### getInfoHash

          public byte[] getInfoHash()

      Overrides:
        `getInfoHash` in class `Snark`
      Returns:
        always will be valid even in magnet mode

    - #### getName

          public String getName()

      Overrides:
        `getName` in class `Snark`
      Returns:
        file name of .torrent file (should be full absolute path), or a fake name if in magnet mode.

    - #### getNeededLength

          public long getNeededLength()

      Description copied from class: `Snark`
      Bytes still wanted. DOES account for (i.e. does not include) skipped files. FIXME -1 when not running.
      Overrides:
        `getNeededLength` in class `Snark`
      Returns:
        torrent file bytes remaining or -1

    - #### getPeerCount

          public int getPeerCount()

      Overrides:
        `getPeerCount` in class `Snark`

    - #### getRemainingLength

          public long getRemainingLength()

      Description copied from class: `Snark`
      Bytes not yet in storage. Does NOT account for skipped files.
      Overrides:
        `getRemainingLength` in class `Snark`
      Returns:
        -1 when done so the web will list us as "complete" instead of "seeding"

    - #### getTotalLength

          public long getTotalLength()

      Overrides:
        `getTotalLength` in class `Snark`
      Returns:
        torrent file size or -1

    - #### getTrackerSeenPeers

          public int getTrackerSeenPeers()

      Overrides:
        `getTrackerSeenPeers` in class `Snark`
      Returns:
        count returned from tracker

    - #### headerReceived

          public void headerReceived(String url,
                                     int attemptNum,
                                     String key,
                                     String val)

      Description copied from interface: `EepGet.StatusListener`
      Note: Headers are not processed, and this is not called, for most error response codes, unless setWriteErrorToOutput() is called before fetch(). To be changed?
      Specified by:
        `headerReceived` in interface `EepGet.StatusListener`

    - #### isStopped

          public boolean isStopped()

      Overrides:
        `isStopped` in class `Snark`

    - #### run

          public void run()

      Set off by startTorrent()
      Specified by:
        `run` in interface `Runnable`

    - #### startTorrent

          public void startTorrent()

      Description copied from class: `Snark`
      Start up contacting peers and querying the tracker. Blocks if tunnel is not yet open.
      Overrides:
        `startTorrent` in class `Snark`

    - #### stopTorrent

          public void stopTorrent()

      Description copied from class: `Snark`
      Stop contacting the tracker and talking with peers
      Overrides:
        `stopTorrent` in class `Snark`

    - #### transferComplete

          public void transferComplete(long alreadyTransferred,
                                       long bytesTransferred,
                                       long bytesRemaining,
                                       String url,
                                       String outputFile,
                                       boolean notModified)

      Specified by:
        `transferComplete` in interface `EepGet.StatusListener`
        `outputFile` - null if unknown (output stream constructor)
      See Also:
        `EepGet.StatusListener.bytesTransferred(long, int, long, long, java.lang.String)`

    - #### transferFailed

          public void transferFailed(String url,
                                     long bytesTransferred,
                                     long bytesRemaining,
                                     int currentAttempt)

      Specified by:
        `transferFailed` in interface `EepGet.StatusListener`
      See Also:
        `EepGet.StatusListener.bytesTransferred(long, int, long, long, java.lang.String)`