public void removeTorrent(TorrentHash torrentHash) { this.announce.removeTorrent(torrentHash); SharedTorrent torrent = this.torrents.remove(torrentHash.getHexInfoHash()); if (torrent != null) { torrent.setClientState(ClientState.DONE); torrent.close(); } }
/** Main client entry point for stand-alone operation. */ public static void main(String[] args) { BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d [%-25t] %-5p: %m%n"))); CmdLineParser parser = new CmdLineParser(); CmdLineParser.Option help = parser.addBooleanOption('h', "help"); CmdLineParser.Option output = parser.addStringOption('o', "output"); CmdLineParser.Option iface = parser.addStringOption('i', "iface"); try { parser.parse(args); } catch (CmdLineParser.OptionException oe) { System.err.println(oe.getMessage()); usage(System.err); System.exit(1); } // Display help and exit if requested if (Boolean.TRUE.equals(parser.getOptionValue(help))) { usage(System.out); System.exit(0); } String outputValue = (String) parser.getOptionValue(output, DEFAULT_OUTPUT_DIRECTORY); String ifaceValue = (String) parser.getOptionValue(iface); String[] otherArgs = parser.getRemainingArgs(); if (otherArgs.length != 1) { usage(System.err); System.exit(1); } try { Client c = new Client(getIPv4Address(ifaceValue)); SharedTorrent torrent = SharedTorrent.fromFile(new File(otherArgs[0]), new File(outputValue), false); c.addTorrent(torrent); // Set a shutdown hook that will stop the sharing/seeding and send // a STOPPED announce request. Runtime.getRuntime().addShutdownHook(new Thread(new ClientShutdown(c, null))); c.share(); if (ClientState.ERROR.equals(torrent.getClientState())) { System.exit(1); } } catch (Exception e) { logger.error("Fatal error: {}", e.getMessage(), e); System.exit(2); } }
/** Close torrent and set final client state before signing off. */ private void finish() { this.announce.stop(); for (SharedTorrent torrent : this.torrents.values()) { torrent.close(); if (torrent.isFinished()) { torrent.setClientState(ClientState.DONE); } else { torrent.setClientState(ClientState.ERROR); } } logger.info("BitTorrent client signing off."); }
/** * Display information about the BitTorrent client state. * * <p>This emits an information line in the log about this client's state. It includes the number * of choked peers, number of connected peers, number of known peers, information about the * torrent availability and completion and current transmission rates. */ public synchronized void info() { float dl = 0; float ul = 0; int numConnected = 0; for (SharingPeer peer : getConnectedPeers()) { dl += peer.getDLRate().get(); ul += peer.getULRate().get(); numConnected++; } for (SharedTorrent torrent : this.torrents.values()) { logger.debug( "{} {}/{} pieces ({}%) [{}/{}] with {}/{} peers at {}/{} kB/s.", new Object[] { torrent.getClientState().name(), torrent.getCompletedPieces().cardinality(), torrent.getPieceCount(), String.format("%.2f", torrent.getCompletion()), torrent.getAvailablePieces().cardinality(), torrent.getRequestedPieces().cardinality(), numConnected, this.peers.size(), String.format("%.2f", dl / 1024.0), String.format("%.2f", ul / 1024.0), }); } }
/** * Piece download completion handler. * * <p>When a piece is completed, and valid, we announce to all connected peers that we now have * this piece. * * <p>We use this handler to identify when all of the pieces have been downloaded. When that's the * case, we can start the seeding period, if any. * * @param peer The peer we got the piece from. * @param piece The piece in question. */ @Override public void handlePieceCompleted(SharingPeer peer, Piece piece) throws IOException { final SharedTorrent torrent = peer.getTorrent(); synchronized (torrent) { if (piece.isValid()) { // Make sure the piece is marked as completed in the torrent // Note: this is required because the order the // PeerActivityListeners are called is not defined, and we // might be called before the torrent's piece completion // handler is. torrent.markCompleted(piece); logger.debug( "Completed download of {}, now has {}/{} pieces.", new Object[] { piece, torrent.getCompletedPieces().cardinality(), torrent.getPieceCount() }); // Send a HAVE message to all connected peers PeerMessage have = PeerMessage.HaveMessage.craft(piece.getIndex()); for (SharingPeer remote : getConnectedPeers()) { remote.send(have); } } if (torrent.isComplete()) { logger.info("Last piece validated and completed, " + "download is complete."); torrent.finish(); try { this.announce .getCurrentTrackerClient(torrent) .announce( TrackerMessage.AnnounceRequestMessage.RequestEvent.COMPLETED, true, torrent); } catch (AnnounceException ae) { logger.warn("Error announcing completion event to " + "tracker: {}", ae.getMessage()); } torrent.setClientState(ClientState.SEEDING); if (seed == 0) { peer.unbind(false); this.announce.removeTorrent(torrent); } } } }
public void addTorrent(SharedTorrent torrent) throws IOException, InterruptedException { torrent.init(); if (!torrent.isInitialized()) { torrent.close(); return; } this.torrents.put(torrent.getHexInfoHash(), torrent); // Initial completion test if (torrent.isComplete()) { torrent.setClientState(ClientState.SEEDING); } else { torrent.setClientState(ClientState.SHARING); } this.announce.addTorrent(torrent, this); }
/** Tells whether we are a seed for the torrent we're sharing. */ public boolean isSeed(String hexInfoHash) { SharedTorrent t = this.torrents.get(hexInfoHash); return t != null && t.isComplete(); }