tracker完成
Change-Id: Ib69b662cfd24a8a5c7f3a29e6e5b6baa25611e57
diff --git a/src/main/java/com/example/g8backend/util/BencodeUtil.java b/src/main/java/com/example/g8backend/util/BencodeUtil.java
index 4ec9ce1..b669843 100644
--- a/src/main/java/com/example/g8backend/util/BencodeUtil.java
+++ b/src/main/java/com/example/g8backend/util/BencodeUtil.java
@@ -6,44 +6,163 @@
import java.nio.charset.StandardCharsets;
import java.util.*;
+//package com.bjtu.pt_station.common;
+
+import com.example.g8backend.entity.Peer;
+import com.dampcake.bencode.Bencode;
+import com.dampcake.bencode.Type;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.util.*;
+
+import java.util.List;
+import java.util.Map;
+
public class BencodeUtil {
- public static byte[] encodeAnnounceResponse(AnnounceResponseDTO dto) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
+ private static final Logger logger = LoggerFactory.getLogger(BencodeUtil.class);
+ private static final Bencode bencodeUTF8 = new Bencode(StandardCharsets.UTF_8);
+ private static final Bencode bencodeInfoHash = new Bencode(StandardCharsets.ISO_8859_1);
+
+ public static String encodeUTF8(Map<String, Object> map) {
+ byte[] encodedBytes = bencodeUTF8.encode(map);
+ return new String(encodedBytes, StandardCharsets.UTF_8);
+ }
+
+ public static String encodeISO(Map<String, Object> map) {
+ byte[] encodedBytes = bencodeInfoHash.encode(map);
+ return new String(encodedBytes, StandardCharsets.ISO_8859_1);
+ }
+
+ public static Map<String, Object> decodeHash(byte[] torrentBytes) throws IOException {
+ return bencodeInfoHash.decode(torrentBytes, Type.DICTIONARY);
+ }
+
+ public static Map<String, Object> decodeUTF8(byte[] torrentBytes) throws IOException {
+ return bencodeUTF8.decode(torrentBytes, Type.DICTIONARY);
+ }
+
+ public static Map<String, Object> decodeISO(byte[] torrentBytes) throws IOException {
+ return bencodeInfoHash.decode(torrentBytes, Type.DICTIONARY);
+ }
+
+ public static String calInfoHash(MultipartFile torrentFile) throws IOException {
+ byte[] torrentBytes = torrentFile.getBytes();
try {
- out.write('d'); // dictionary start
+ Map<String, Object> dict = decodeUTF8(torrentBytes);
+ Map<String, Object> dictInfoHash = decodeISO(torrentBytes);
- writeString(out, "interval");
- writeInt(out, dto.getInterval());
-
- writeString(out, "peers");
- out.write('l'); // list start
- for (Map<String, Object> peer : dto.getPeers()) {
- out.write('d');
- writeString(out, "ip");
- writeString(out, (String) peer.get("ip"));
- writeString(out, "port");
- writeInt(out, ((Number) peer.get("port")).intValue());
- out.write('e');
+ Object infoObj = dictInfoHash.get("info");
+ if (infoObj == null) {
+ logger.error("Torrent file does not contain 'info' field.");
+ return null;
}
- out.write('e'); // list end
- out.write('e'); // dictionary end
- } catch (Exception e) {
- throw new RuntimeException("Bencoding failed", e);
+ byte[] infoData = bencodeInfoHash.encode((Map<?, ?>) infoObj);
+ return calculateInfoHash(infoData);
+ } catch (IOException e) {
+ logger.error("Failed to calculate info hash: {}", e.getMessage());
+ throw e;
}
- return out.toByteArray();
}
- private static void writeString(ByteArrayOutputStream out, String str) throws Exception {
- byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
- out.write(String.valueOf(bytes.length).getBytes(StandardCharsets.UTF_8));
- out.write(':');
- out.write(bytes);
+ private static String calculateInfoHash(byte[] bencodedInfo) {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-1");
+ byte[] hashBytes = digest.digest(bencodedInfo);
+
+ StringBuilder hexString = new StringBuilder();
+ for (byte b : hashBytes) {
+ String hex = Integer.toHexString(0xff & b);
+ if (hex.length() == 1) {
+ hexString.append('0');
+ }
+ hexString.append(hex);
+ }
+ return hexString.toString();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("SHA-1 algorithm not available", e);
+ }
}
- private static void writeInt(ByteArrayOutputStream out, int i) throws Exception {
- out.write('i');
- out.write(String.valueOf(i).getBytes(StandardCharsets.UTF_8));
- out.write('e');
+ public static String convertToString(byte[] bytes) {
+ return new String(bytes, bencodeInfoHash.getCharset());
+ }
+
+ public static Bencode bittorrent() {
+ return bencodeInfoHash;
+ }
+
+ public static Bencode utf8() {
+ return bencodeUTF8;
+ }
+
+ public static String compactPeers(List<Peer> peers) throws UnknownHostException {
+ ByteBuffer buffer = ByteBuffer.allocate(6 * peers.size());
+ for (Peer peer : peers) {
+ for (byte addr : InetAddress.getByName(peer.getIpAddress()).getAddress()) {
+ buffer.put(addr);
+ }
+ int in = peer.getPort();
+ buffer.put((byte) ((in >>> 8) & 0xFF));
+ buffer.put((byte) (in & 0xFF));
+ }
+ return convertToString(buffer.array());
}
}
+
+//public class BencodeUtil {
+// public static byte[] encodeAnnounceResponse(AnnounceResponseDTO dto) {
+// ByteArrayOutputStream out = new ByteArrayOutputStream();
+// try {
+// out.write('d'); // dictionary start
+//
+// writeString(out, "interval");
+// writeInt(out, dto.getInterval());
+//
+// writeString(out, "peers");
+// out.write('l'); // list start
+// for (Map<String, Object> peer : dto.getPeers()) {
+// out.write('d');
+// writeString(out, "ip");
+// writeString(out, (String) peer.get("ip"));
+// writeString(out, "port");
+// writeInt(out, ((Number) peer.get("port")).intValue());
+// out.write('e');
+// }
+// out.write('e'); // list end
+//
+// out.write('e'); // dictionary end
+// } catch (Exception e) {
+// throw new RuntimeException("Bencoding failed", e);
+// }
+// return out.toByteArray();
+// }
+//
+// private static void writeString(ByteArrayOutputStream out, String str) throws Exception {
+// byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
+// out.write(String.valueOf(bytes.length).getBytes(StandardCharsets.UTF_8));
+// out.write(':');
+// out.write(bytes);
+// }
+//
+// private static void writeInt(ByteArrayOutputStream out, int i) throws Exception {
+// out.write('i');
+// out.write(String.valueOf(i).getBytes(StandardCharsets.UTF_8));
+// out.write('e');
+// }
+//}