Open tonyiweb opened 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;
}
}
/**
Note record