content: package com.acgist.snail.protocol.magnet;
  
  import com.acgist.snail.context.ITaskSession;
  import com.acgist.snail.context.ITaskSession.FileType;
  import com.acgist.snail.downloader.IDownloader;
  import com.acgist.snail.downloader.magnet.MagnetDownloader;
  import com.acgist.snail.net.DownloadException;
  import com.acgist.snail.net.torrent.Magnet;
  import com.acgist.snail.net.torrent.TorrentContext;
  import com.acgist.snail.net.torrent.peer.extension.MetadataMessageHandler;
  import com.acgist.snail.protocol.Protocol;
  import com.acgist.snail.utils.FileUtils;
  import com.acgist.snail.utils.StringUtils;
  
  /**
   * 磁力链接协议
   * 原理：磁力链接通过Tracker服务器和DHT网络获取Peer，然后使用{@linkplain MetadataMessageHandler 扩展协议}交换种子。
   * 
   * @author acgist
   */
  public final class MagnetProtocol extends Protocol {
      
      private static final MagnetProtocol INSTANCE = new MagnetProtocol();
      
      public static final MagnetProtocol getInstance() {
          return INSTANCE;
      }
  
      /**
       * 磁力链接
       */
      private Magnet magnet;
      
      private MagnetProtocol() {
          super(Type.MAGNET, "磁力链接");
      }
      
      @Override
      public boolean available() {
          return true;
      }
      
      @Override
      public IDownloader buildDownloader(ITaskSession taskSession) {
          return MagnetDownloader.newInstance(taskSession);
      }
      
      @Override
      protected void prep() throws DownloadException {
          final Magnet magnetCheck = MagnetBuilder.newInstance(this.url).build();
          this.checkExist(magnetCheck);
          this.magnet = magnetCheck;
      }
      
      @Override
      protected String buildFileName() {
          final String dn = this.magnet.getDn();
          if(StringUtils.isNotEmpty(dn)) {
              return dn;
          }
          return this.magnet.getHash();
      }
      
      @Override
      protected void buildName(String fileName) {
          this.taskEntity.setName(fileName);
      }
      
      @Override
      protected void buildFileType(String fileName) {
          this.taskEntity.setFileType(FileType.TORRENT);
      }
      
      @Override
      protected void buildSize() throws DownloadException {
          // 磁力链接下载完成修改大小
          this.taskEntity.setSize(0L);
      }
      
      @Override
      protected void done() {
          this.buildFolder();
      }
      
      @Override
      protected void release(boolean success) {
          if(!success && this.magnet != null) {
              // 清除种子信息
              TorrentContext.getInstance().remove(this.magnet.getHash());
          }
          this.magnet = null;
          super.release(success);
      }
      
      /**
       * 检查任务是否已经存在
       * 一定要先检查BT任务是否已经存在（如果已经存在不能赋值：防止清除下载任务）
       * 
       * @param magnet 磁力链接
       * 
       * @throws DownloadException 下载异常
       */
      private void checkExist(Magnet magnet) throws DownloadException {
          if(TorrentContext.getInstance().exist(magnet.getHash())) {
              throw new DownloadException("任务已经存在");
          }
      }
      
      /**
       * 新建下载目录
       */
      private void buildFolder() {
          FileUtils.buildFolder(this.taskEntity.getFile());
      }
      
  }
  