blob: b66984300937b72eff2d3af4dbeb9951ba294478 [file] [log] [blame]
2230107166504b72025-06-08 13:54:29 +08001package com.example.g8backend.util;
2
3import com.example.g8backend.dto.AnnounceResponseDTO;
4
5import java.io.ByteArrayOutputStream;
6import java.nio.charset.StandardCharsets;
7import java.util.*;
8
2230107123955142025-06-09 16:37:03 +08009//package com.bjtu.pt_station.common;
10
11import com.example.g8backend.entity.Peer;
12import com.dampcake.bencode.Bencode;
13import com.dampcake.bencode.Type;
14import org.slf4j.Logger;
15import org.slf4j.LoggerFactory;
16import org.springframework.beans.factory.annotation.Autowired;
17import org.springframework.web.multipart.MultipartFile;
18
19import java.net.InetAddress;
20import java.net.UnknownHostException;
21import java.nio.ByteBuffer;
22import java.security.MessageDigest;
23import java.security.NoSuchAlgorithmException;
24import java.io.ByteArrayInputStream;
25import java.io.File;
26import java.io.FileInputStream;
27import java.io.IOException;
28import java.net.InetSocketAddress;
29import java.nio.charset.StandardCharsets;
30import java.security.MessageDigest;
31import java.util.*;
32
33import java.util.List;
34import java.util.Map;
35
2230107166504b72025-06-08 13:54:29 +080036public class BencodeUtil {
2230107123955142025-06-09 16:37:03 +080037 private static final Logger logger = LoggerFactory.getLogger(BencodeUtil.class);
38 private static final Bencode bencodeUTF8 = new Bencode(StandardCharsets.UTF_8);
39 private static final Bencode bencodeInfoHash = new Bencode(StandardCharsets.ISO_8859_1);
40
41 public static String encodeUTF8(Map<String, Object> map) {
42 byte[] encodedBytes = bencodeUTF8.encode(map);
43 return new String(encodedBytes, StandardCharsets.UTF_8);
44 }
45
46 public static String encodeISO(Map<String, Object> map) {
47 byte[] encodedBytes = bencodeInfoHash.encode(map);
48 return new String(encodedBytes, StandardCharsets.ISO_8859_1);
49 }
50
51 public static Map<String, Object> decodeHash(byte[] torrentBytes) throws IOException {
52 return bencodeInfoHash.decode(torrentBytes, Type.DICTIONARY);
53 }
54
55 public static Map<String, Object> decodeUTF8(byte[] torrentBytes) throws IOException {
56 return bencodeUTF8.decode(torrentBytes, Type.DICTIONARY);
57 }
58
59 public static Map<String, Object> decodeISO(byte[] torrentBytes) throws IOException {
60 return bencodeInfoHash.decode(torrentBytes, Type.DICTIONARY);
61 }
62
63 public static String calInfoHash(MultipartFile torrentFile) throws IOException {
64 byte[] torrentBytes = torrentFile.getBytes();
2230107166504b72025-06-08 13:54:29 +080065 try {
2230107123955142025-06-09 16:37:03 +080066 Map<String, Object> dict = decodeUTF8(torrentBytes);
67 Map<String, Object> dictInfoHash = decodeISO(torrentBytes);
2230107166504b72025-06-08 13:54:29 +080068
2230107123955142025-06-09 16:37:03 +080069 Object infoObj = dictInfoHash.get("info");
70 if (infoObj == null) {
71 logger.error("Torrent file does not contain 'info' field.");
72 return null;
2230107166504b72025-06-08 13:54:29 +080073 }
2230107166504b72025-06-08 13:54:29 +080074
2230107123955142025-06-09 16:37:03 +080075 byte[] infoData = bencodeInfoHash.encode((Map<?, ?>) infoObj);
76 return calculateInfoHash(infoData);
77 } catch (IOException e) {
78 logger.error("Failed to calculate info hash: {}", e.getMessage());
79 throw e;
2230107166504b72025-06-08 13:54:29 +080080 }
2230107166504b72025-06-08 13:54:29 +080081 }
82
2230107123955142025-06-09 16:37:03 +080083 private static String calculateInfoHash(byte[] bencodedInfo) {
84 try {
85 MessageDigest digest = MessageDigest.getInstance("SHA-1");
86 byte[] hashBytes = digest.digest(bencodedInfo);
87
88 StringBuilder hexString = new StringBuilder();
89 for (byte b : hashBytes) {
90 String hex = Integer.toHexString(0xff & b);
91 if (hex.length() == 1) {
92 hexString.append('0');
93 }
94 hexString.append(hex);
95 }
96 return hexString.toString();
97 } catch (NoSuchAlgorithmException e) {
98 throw new RuntimeException("SHA-1 algorithm not available", e);
99 }
2230107166504b72025-06-08 13:54:29 +0800100 }
101
2230107123955142025-06-09 16:37:03 +0800102 public static String convertToString(byte[] bytes) {
103 return new String(bytes, bencodeInfoHash.getCharset());
104 }
105
106 public static Bencode bittorrent() {
107 return bencodeInfoHash;
108 }
109
110 public static Bencode utf8() {
111 return bencodeUTF8;
112 }
113
114 public static String compactPeers(List<Peer> peers) throws UnknownHostException {
115 ByteBuffer buffer = ByteBuffer.allocate(6 * peers.size());
116 for (Peer peer : peers) {
117 for (byte addr : InetAddress.getByName(peer.getIpAddress()).getAddress()) {
118 buffer.put(addr);
119 }
120 int in = peer.getPort();
121 buffer.put((byte) ((in >>> 8) & 0xFF));
122 buffer.put((byte) (in & 0xFF));
123 }
124 return convertToString(buffer.array());
2230107166504b72025-06-08 13:54:29 +0800125 }
126}
2230107123955142025-06-09 16:37:03 +0800127
128//public class BencodeUtil {
129// public static byte[] encodeAnnounceResponse(AnnounceResponseDTO dto) {
130// ByteArrayOutputStream out = new ByteArrayOutputStream();
131// try {
132// out.write('d'); // dictionary start
133//
134// writeString(out, "interval");
135// writeInt(out, dto.getInterval());
136//
137// writeString(out, "peers");
138// out.write('l'); // list start
139// for (Map<String, Object> peer : dto.getPeers()) {
140// out.write('d');
141// writeString(out, "ip");
142// writeString(out, (String) peer.get("ip"));
143// writeString(out, "port");
144// writeInt(out, ((Number) peer.get("port")).intValue());
145// out.write('e');
146// }
147// out.write('e'); // list end
148//
149// out.write('e'); // dictionary end
150// } catch (Exception e) {
151// throw new RuntimeException("Bencoding failed", e);
152// }
153// return out.toByteArray();
154// }
155//
156// private static void writeString(ByteArrayOutputStream out, String str) throws Exception {
157// byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
158// out.write(String.valueOf(bytes.length).getBytes(StandardCharsets.UTF_8));
159// out.write(':');
160// out.write(bytes);
161// }
162//
163// private static void writeInt(ByteArrayOutputStream out, int i) throws Exception {
164// out.write('i');
165// out.write(String.valueOf(i).getBytes(StandardCharsets.UTF_8));
166// out.write('e');
167// }
168//}