tonyiweb / Pottery

0 stars 0 forks source link

Note #2

Open tonyiweb opened 7 years ago

tonyiweb commented 7 years ago

Note record

tonyiweb commented 7 years ago

package com.turn.ttorrent.common.downloader;

import java.io.File; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.OutputStream; import java.net.Inet4Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URI; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Observable; import java.util.Observer; import java.util.Set;

import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.log4j.Logger;

import com.turn.ttorrent.client.Client; import com.turn.ttorrent.client.Client.ClientState; import com.turn.ttorrent.client.SharedTorrent; import com.turn.ttorrent.common.Torrent; import com.turn.ttorrent.tracker.TrackedTorrent; import com.turn.ttorrent.tracker.Tracker;

public class BTDownloader { private static final Logger logger = Logger.getLogger(BTDownloader.class);

private static String TORRENT_DIR = "D:/torrents";

private static Map<String, Client> clients = new HashMap<String, Client>();

private static List<String> torrents = new ArrayList<String>();

/**
 * 根据种子文件下载文件,下载完成之后关闭下载通道。
 * @param torrentFileName 种子文件
 * @param distDirectory 下载文件的放置的目录
 */
public static void downloadFromTorrent(String torrentFileName, String distDirectory)
{
    logger.info("Begin download from torrent===>" + torrentFileName);
    int maxDownloadRate = 1024 * 1024 * 1024;
    int maxUploadRate = 1024 * 1024 * 1024;
    Client client = null;
    try
    {
        client =
            new Client(getIPAddress(null), SharedTorrent.fromFile(new File(torrentFileName.trim()), new File(
                distDirectory.trim())));
        client.setMaxDownloadRate(maxDownloadRate);
        client.setMaxUploadRate(maxUploadRate);
        logger.info("Beginning to download from " + torrentFileName);
        //下载文件,相当于share(0)
        client.download();
        client.addObserver(new Observer()
        {
            public void update(Observable observable, Object data)
            {
                Client client = (Client)observable;
                float progress = client.getTorrent().getCompletion();
                logger.info("progress=====>" + progress + "%");
            }
        });
        client.waitForCompletion();
        logger.info("Download Over");
    }
    catch (Exception e)
    {
        logger.error("Download Exception:" + e.toString());
        e.printStackTrace();
    }
}

/**
 * 根据种子文件下载文件,继续Share,提供继续下载。
 * @param torrentFilePath 种子文件
 * @param distDirectory 下载文件的放置的目录
 */
public static void downloadAndShareFromTorrent(String torrentFilePath, String distDirectory)
{
    logger.info("Begin download and share from torrent===>" + torrentFilePath);
    int maxDownloadRate = 1024 * 1024 * 1024;
    int maxUploadRate = 1024 * 1024 * 1024;
    Client client = null;
    File seedFile = new File(torrentFilePath);
    try
    {
        //增加文件拷贝前是否存在
        File newDirectory = new File(TORRENT_DIR);
        if (!seedFile.getParentFile().equals(newDirectory))
        {
            FileUtils.copyFileToDirectory(seedFile, newDirectory);
        }
        File linkFile = new File(TORRENT_DIR + "/" + seedFile.getName().split("\\.")[0] + ".link");
        if(!linkFile.exists())
        {
            //生成种子文件时,保存种子文件对应的源文件的路径,文件为种子文件名.link
            FileUtils.writeStringToFile(linkFile, distDirectory);
        }
    }
    catch (IOException e1)
    {
        e1.printStackTrace();
    }
    try
    {
        //获取distDirectory的父目录与bindSeedAndSource方法中fromFile统一
        client =
            new Client(getIPAddress(null), SharedTorrent.fromFile(new File(torrentFilePath.trim()), new File(
                distDirectory.trim()).getParentFile()));
        client.setMaxDownloadRate(maxDownloadRate);
        client.setMaxUploadRate(maxUploadRate);
        //保存种子对应的client对象
        clients.put(seedFile.getName().split("\\.")[0], client);
        logger.info("Beginning to download from===>"
            + torrentFilePath.substring(torrentFilePath.lastIndexOf("/") + 1));
        //下载文件,下载完成之后SEEDING,作为seeder提供别人下载
        client.share(-1);
    }
    catch (Exception e)
    {
        logger.error("Download Exception:" + e.toString());
        e.printStackTrace();
    }
}

/**
 * 生成BT下载的种子
 * @param fileName  种子文件名
 * @param sourceFile 源文件(夹)
 * @param annouceUrls 监听服务器的URL
 */
public static boolean createTorrentFile(String fileName, String sourceFile, String[] annouceUrls)
{
    logger.info("Begin create torrent file===>" + fileName + "===>" + sourceFile);
    OutputStream fos = null;
    sourceFile = sourceFile.trim();
    try
    {
        if (fileName != null)
        {
            fileName = fileName.trim();
            fos = new FileOutputStream(fileName);
        }

        //设置给哪些tracker可以监测到
        List<URI> announceURIs = new ArrayList<URI>();
        if (annouceUrls != null && annouceUrls.length > 0)
        {
            for (String url : annouceUrls)
            {
                announceURIs.add(new URI("http://" + url + ":6969/announce"));
            }
        }
        List<List<URI>> announceList = new ArrayList<List<URI>>();
        announceList.add(announceURIs);

        //源文件:要下载的文件或是文件夹
        File source = new File(sourceFile);
        logger.info("source===>" + source + "==exists===>" + source.exists() + "==read===>" + source.canRead());
        if (!source.exists() || !source.canRead())
        {
            throw new IllegalArgumentException("Cannot access source file or directory===>" + source.getName());
        }
        //获取种子制作者的信息
        String creator = String.format("%s (ttorrent)", System.getProperty("user.name"));
        //分块下载时每块的大小
        Integer pieceLengthVal = 10 * 1024 * 1024;
        Torrent torrent = null;
        if (source.isDirectory())
        {
            List<File> files =
                new ArrayList<File>(FileUtils.listFiles(source, TrueFileFilter.TRUE, TrueFileFilter.TRUE));
            Collections.sort(files);
            torrent = Torrent.create(source, files, pieceLengthVal, announceList, creator);
        }
        else
        {
            torrent = Torrent.create(source, pieceLengthVal, announceList, creator);
        }
        torrent.save(fos);
        Torrent.load(new File(fileName), true);
        logger.info("Create Torrent Over");
    }
    catch (Exception ex)
    {
        ex.printStackTrace();
        return false;
    }
    finally
    {
        IOUtils.closeQuietly(fos);
    }
    return true;
}

/**
 * 建立tracker
 *@param host Tracker服务器的IP
 * @param seedDirectory 保存种子文件的目录
 */
public static Tracker createTrack(String host, String seedDirectory)
{
    logger.info("Begin create track===>" + host + "===>" + seedDirectory);
    try
    {
        //默认监听端口
        int port = 6969;
        Tracker tracker = new Tracker(new InetSocketAddress(host, port));
        tracker.start();
        logger.info("Start tracker..." + tracker.toString());

        //起一个线程,不断扫描文件夹下面的种子文件
        final Tracker pTracker = tracker;
        final String pDir = seedDirectory;
        Runnable run = new Runnable()
        {
            @Override
            public void run()
            {
                FilenameFilter filter = new FilenameFilter()
                {
                    public boolean accept(File dir, String name)
                    {
                        return name.toLowerCase().endsWith(".torrent");
                    }
                };
                Set<String> fileNames = new HashSet<String>();
                String fileName = null;
                int count = 0;
                while (!pTracker.isStop())
                {
                    try
                    {
                        File parent = new File(pDir);
                        for (File file : parent.listFiles(filter))
                        {
                            if (!fileNames.contains(file.getName()))
                            {
                                fileName = file.getName();
                                logger.info("Loading torrent from " + fileName);
                                pTracker.announce(TrackedTorrent.load(file));
                                fileNames.add(fileName);
                            }
                        }
                    }catch (Exception e)
                    {
                        logger.error(fileName +"\n Load a tracked torrent Exception: " + e.getMessage()+ "\n" +e.getStackTrace()[0]);
                        count++;
                        if(count == 10)
                        {
                            //超过10次失败不再继续announce;
                            fileNames.add(fileName);
                            count = 0;
                        }
                    }
                    try 
                    {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) 
                    {
                        e.printStackTrace();
                    }
                }
            }
        };
        new Thread(run).start();
        logger.info("Starting tracker with {} announced torrents..." + tracker.getTrackedTorrents().size());
        return tracker;
    }
    catch (Exception e)
    {
        logger.info("Creating Tracker Exception:" + e.toString(), e);
    }
    return null;
}

/**
 * 初始化seeder
 * @param torrentDir 种子文件存放的目录(本地配置的固定位置)
 */
public static void init(String torrentDir)
{
    logger.info("Begin to init seeder===>" + torrentDir);
    TORRENT_DIR = torrentDir;
    //在所有种子文件中找到有.link的文件,开始seeder
    File seedDir = new File(torrentDir);
    if (!seedDir.exists())
    {
        seedDir.mkdir();
    }
    File[] files = seedDir.listFiles();
    Map<String, String> linkFilesMap = new HashMap<String, String>();
    for (File file : files)
    {
        String linkFileName = file.getName();
        if (linkFileName.endsWith(".link"))
        {
            String dir = "";
            try
            {
                dir = FileUtils.readFileToString(file);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            linkFilesMap.put(file.getParent() + "\\" + (linkFileName.split("\\.")[0]) + ".torrent", dir.trim());
        }
    }
    Set<String> keys = linkFilesMap.keySet();
    Iterator<String> iter = keys.iterator();
    while (iter.hasNext())
    {
        String key = iter.next();
        boolean falg = bindSeedAndSource(key, linkFilesMap.get(key));
        logger.info("seedFilePath===>"+ key +"bind result===>" + falg);
    }
}

/**
 * 种子和源文件夹的关系建立(Seeder)
 * @param seedFilePath 种子文件
 * @param sourceFilePath 源文件夹
 * @return boolean 是否绑定seeder成功
 */
public static boolean bindSeedAndSource(String seedFilePath, String sourceFilePath)
{
    logger.info("Begin to bind seed and source===>" + seedFilePath + "===>" + sourceFilePath + "===TORRENT_DIR===>"
        + TORRENT_DIR);
    File oldPath = new File(seedFilePath);
    try
    {
        File newFile = new File(TORRENT_DIR + File.separator + oldPath.getName());
        if (!oldPath.equals(newFile))
        {
            FileUtils.copyFile(oldPath, newFile);
        }
        File linkFile = new File(TORRENT_DIR + "/" + newFile.getName().split("\\.")[0] + ".link");
        if(!linkFile.exists())
        {
            //生成种子文件时,保存种子文件对应的源文件的路径,文件为种子文件名.link
            FileUtils.writeStringToFile(linkFile, sourceFilePath);
        }
    }
    catch (IOException e1)
    {
        logger.error(e1.getMessage(), e1);
    }
    int maxDownloadRate = 1024 * 1024 * 1024;
    int maxUploadRate = 1024 * 1024 * 1024;
    boolean flag = false;
    File sourceFile = new File(sourceFilePath);
    if (sourceFile.getParentFile() == null)
    {
        logger.info("No Parent Directory Exists");
        return false;
    }
    try
    {
        File parentFile = sourceFile.getParentFile();
        if (parentFile.listFiles().length > 0)
        {
            Client client = new Client(getIPAddress(null),
            //建立种子文件和源文件的联系。很关键。源文件的父目录
                SharedTorrent.fromFile(new File(seedFilePath), sourceFile.getParentFile()));
            client.setMaxDownloadRate(maxDownloadRate);
            client.setMaxUploadRate(maxUploadRate);
            //建立种子文件和源文件的联系
            client.share();
            clients.put(oldPath.getName().split("\\.")[0], client);
            logger.info("Client begin to share...");
            int count = 0;
            while (ClientState.SEEDING != client.getState())
            {
                Thread.sleep(1000);
                logger.info("Bind Torrent And SourceFile...State=====>" + client.getState().toString());
                if (ClientState.SEEDING == client.getState())
                {
                    logger.info("Bind Torrent And SourceFile Over...State=====>" + client.getState().toString());
                    flag = true;
                    break;
                }
                if (ClientState.ERROR == client.getState())
                {
                    flag = false;
                    break;
                }
                if (ClientState.SHARING == client.getState())
                {
                    count++;
                    if (count == 10)
                    {
                        flag = false;
                        break;
                    }
                }
            }

            if(client.getAnnounce().getAnnouceState() == 1)
            {
                if(!torrents.contains(oldPath.getName().split("\\.")[0]))
                {
                    torrents.add(oldPath.getName().split("\\.")[0]);
                }
            }
            return flag;
        }
        else
        {
            logger.error("Source File Not Exists!");
            return false;
        }
    }
    catch (Exception e)
    {
        e.printStackTrace();
        return flag;
    }
}

/**
 * 通过IP获取Inet4Address对象
 * @param ip 文件下载服务器的IP
 * @return 返回Inet4Address对象
 */
public static Inet4Address getIPAddress(String ip)
{
    InetAddress address = null;
    try
    {
        if (ip != null)
        {
            address = InetAddress.getByName(ip);
        }
        else
        {
            address = InetAddress.getLocalHost();
        }
    }
    catch (UnknownHostException e)
    {
        logger.error("IP Exception: " + e.toString());
    }
    return (Inet4Address)address;
}

/**
 * stop掉种子对应的client,停止share
 */
public static boolean stopSharing(String torrentName)
{
    if (clients.get(torrentName) != null)
    {
        clients.get(torrentName).stop();
    }
    return true;
}

/**
 * 返回无效的种子集合
 * @return List<String>
 */
public static List<String> getTorrents()
{
    return torrents;
}

}

tonyiweb commented 7 years ago

/**