From c3b96414e94392658fcebb45ad58507636a48a1b Mon Sep 17 00:00:00 2001 From: chuzhongzai Date: Sat, 22 Mar 2025 23:50:25 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=B0=86=E9=98=9F=E5=88=97=E4=BB=8Elist?= =?UTF-8?q?=E6=8D=A2=E6=88=90map=EF=BC=8C=E8=83=BD=E5=A4=9F=E5=AF=B9?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=8E=BB=E9=87=8D;=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=97=B6=E4=BC=9A=E5=88=A4=E6=96=AD=E8=AF=A5?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=98=AF=E5=90=A6=E4=B8=8B=E8=BD=BD=E5=AE=8C?= =?UTF-8?q?=E6=88=90;=E4=BF=AE=E6=94=B9=E4=B8=8B=E8=BD=BD=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E5=A4=B4;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/encodings.xml | 7 ++++ src/main/java/lion/CustomUtil.java | 13 ++++++ .../java/lion/MultiThreadedHTTPServer.java | 1 + .../lion/Service/DownloadCheckService.java | 42 ++++++++++++++++--- src/main/java/lion/storageNode.java | 34 +++++++++------ 5 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 .idea/encodings.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/java/lion/CustomUtil.java b/src/main/java/lion/CustomUtil.java index 6621e72..a10b556 100644 --- a/src/main/java/lion/CustomUtil.java +++ b/src/main/java/lion/CustomUtil.java @@ -1,5 +1,7 @@ package lion; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; @@ -12,4 +14,15 @@ public class CustomUtil { public static AtomicInteger counter = new AtomicInteger(); public static ObjectMapper objectMapper = new ObjectMapper(); + + public static void notifyMe(String message) { + String url = "https://personal.lionwebsite.xyz/message2me?AuthCode=alone&message=" + message; + HttpRequest request = HttpRequest.post(url); + request.header("User-Agent", "Mozilla/5.0"); + try(HttpResponse response = request.execute()) { + if(response.getStatus() != 200) { + System.out.println("通知失败, status code:" + response.getStatus() + ", message:" + message); + } + } + } } diff --git a/src/main/java/lion/MultiThreadedHTTPServer.java b/src/main/java/lion/MultiThreadedHTTPServer.java index c8ca647..a7d33eb 100644 --- a/src/main/java/lion/MultiThreadedHTTPServer.java +++ b/src/main/java/lion/MultiThreadedHTTPServer.java @@ -127,6 +127,7 @@ public class MultiThreadedHTTPServer { responseWriter.println("Accept-Ranges: bytes"); responseWriter.println("Content-Length: " + (endByte - startByte + 1)); responseWriter.println("Content-Range: bytes " + startByte + "-" + endByte + "/" + fileLength); + responseWriter.println("Content-Disposition: attachment; filename=\"" + fileName + "\""); responseWriter.println(); // Send the file content diff --git a/src/main/java/lion/Service/DownloadCheckService.java b/src/main/java/lion/Service/DownloadCheckService.java index 14a4920..03e9c75 100644 --- a/src/main/java/lion/Service/DownloadCheckService.java +++ b/src/main/java/lion/Service/DownloadCheckService.java @@ -4,6 +4,7 @@ import io.netty.channel.Channel; import io.netty.channel.DefaultEventLoop; import io.netty.channel.EventLoop; import io.netty.util.concurrent.Promise; +import lion.CustomUtil; import lion.Domain.GalleryTask; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.ZipUtil; @@ -21,7 +22,7 @@ import java.util.concurrent.locks.ReentrantLock; @Slf4j @Data public class DownloadCheckService { - ArrayList queue; + Map queue; String downloadPath = "/root/gallery/hentai/download/"; @@ -37,7 +38,7 @@ public class DownloadCheckService { EventLoop eventLoop; - public DownloadCheckService(ArrayList queue, HashMap> promises){ + public DownloadCheckService(Map queue, HashMap> promises){ this.queue = queue; this.promises = promises; eventLoop = new DefaultEventLoop(); @@ -49,7 +50,7 @@ public class DownloadCheckService { public boolean downloadCheck(){ if(queue.isEmpty()) return false; - log.info("下载检查:" + Arrays.toString(queue.toArray())); + log.info("下载检查:{}", Arrays.toString(queue.values().toArray())); File downloadDirectory = new File(downloadPath); File[] fileArray = downloadDirectory.listFiles(); @@ -62,7 +63,7 @@ public class DownloadCheckService { boolean result = false; //扫描进度 Iterator fileIterator = files.iterator(); - for(GalleryTask galleryTask: queue){ + for(GalleryTask galleryTask: queue.values()){ //跳过已经下载完成或者压缩完成的任务 if(galleryTask.is_compress_complete() || galleryTask.is_compressing()) { result = true; @@ -96,7 +97,7 @@ public class DownloadCheckService { } //压缩队列 - for(GalleryTask galleryTask: queue) + for(GalleryTask galleryTask: queue.values()) if (galleryTask.is_download_complete()) { galleryTask.setStatus(GalleryTask.COMPRESSING); compress_queue.add(galleryTask); @@ -139,4 +140,35 @@ public class DownloadCheckService { } } } + + /** + * 检查改任务是否为已完成任务,如已完成则返回true,若未完成则加入队列 + * @return true if compress complete, false otherwise + */ + public boolean addToQueue(GalleryTask galleryTask){ + //是否含有名字,进行中任务一般有名字,没有名字则肯定为初始任务,存在名字至少在下载路径出现过 + if(galleryTask.getName() == null || !galleryTask.getName().isEmpty()){ + queue.putIfAbsent(galleryTask.getGid(), galleryTask); + return false; + } + + //查询hah下载路径中,是否存在该任务下载路径,存在则为下载中或下载完成任务,加入队列 + if(new File(downloadPath + galleryTask.getGid()).isDirectory()){ + queue.putIfAbsent(galleryTask.getGid(), galleryTask); + return false; + } + + + //查询存放路径中是否含有该任务的压缩包,存在则为下载完成任务 + if(new File(storagePath + galleryTask.getName() + "/" + galleryTask.getName() + ".zip").exists()){ + galleryTask.setStatus(GalleryTask.COMPRESS_COMPLETE); + CustomUtil.notifyMe(String.format("任务:%s在添加时已下载完成,更新任务状态", galleryTask.getName())); + return true; + } + + + //异常情况,发送通知 + CustomUtil.notifyMe(String.format("任务:%s存在名字,但是下载路径为空且不存在压缩包", galleryTask.getName() )); + return false; + } } diff --git a/src/main/java/lion/storageNode.java b/src/main/java/lion/storageNode.java index 77f0efd..f79c99c 100644 --- a/src/main/java/lion/storageNode.java +++ b/src/main/java/lion/storageNode.java @@ -17,8 +17,8 @@ import lombok.extern.slf4j.Slf4j; import java.net.InetSocketAddress; import java.net.Socket; -import java.util.ArrayList; import java.util.HashMap; +import java.util.Map; import java.util.concurrent.*; import java.util.concurrent.locks.ReentrantLock; @@ -33,9 +33,9 @@ public class storageNode { DownloadCheckService downloadCheckService; - ArrayList queue; + Map queue; - ArrayList tempQueue; + Map tempQueue; ScheduledExecutorService checkThreadPool; @@ -48,8 +48,8 @@ public class storageNode { public static String storagePath = "/root/gallery/gallery/"; public storageNode(){ - queue = new ArrayList<>(0); - tempQueue = new ArrayList<>(0); + queue = new HashMap<>(); + tempQueue = new HashMap<>(); lock = new ReentrantLock(); counter = 0; promises = new HashMap<>(); @@ -79,7 +79,7 @@ public class storageNode { try { lock.lock(); if(!tempQueue.isEmpty()){ - queue.addAll(tempQueue); + queue.putAll(tempQueue); tempQueue.clear(); } lock.unlock(); @@ -88,7 +88,7 @@ public class storageNode { boolean isSkip = true; //返回false之后,还要额外检查是否有压缩完成的任务 if(!queue.isEmpty()) - for (GalleryTask galleryTask : queue) + for (GalleryTask galleryTask : queue.values()) if (galleryTask.is_compress_complete()) { isSkip = false; break; @@ -106,11 +106,16 @@ public class storageNode { //上锁后再发送,避免出现发送完之后再下载完成 lock.lock(); DownloadStatusMessage downloadStatusMessage = new DownloadStatusMessage(); - downloadStatusMessage.setGalleryTasks(queue.toArray(GalleryTask[]::new)); + downloadStatusMessage.setGalleryTasks(queue.values().toArray(GalleryTask[]::new)); server.writeAndFlush(downloadStatusMessage); + + queue.forEach((gid, galleryTask) -> { + if (galleryTask.is_compress_complete()) + queue.remove(gid); + }); log.info("任务状态发送完成"); - queue.removeIf(GalleryTask::is_compress_complete); + lock.unlock(); }catch (Exception e){ log.error("发送任务状态时发生异常:{}", e.getMessage()); @@ -118,9 +123,9 @@ public class storageNode { } class MyChannelInboundHandlerAdapter extends ChannelInboundHandlerAdapter{ - ArrayList queue; + Map queue; - public MyChannelInboundHandlerAdapter(ArrayList queue) { + public MyChannelInboundHandlerAdapter(Map queue) { this.queue = queue; } @@ -144,7 +149,12 @@ public class storageNode { case AbstractMessage.DOWNLOAD_POST_MESSAGE -> { DownloadPostMessage dpm = (DownloadPostMessage) abstractMessage; lock.lock(); - queue.add(dpm.getGalleryTask()); + //添加到队列方法返回真说明该任务已下载完成,直接发送下载进度 + if(downloadCheckService.addToQueue(dpm.getGalleryTask())){ + DownloadStatusMessage downloadStatusMessage = new DownloadStatusMessage(); + downloadStatusMessage.setGalleryTasks(new GalleryTask[]{dpm.getGalleryTask()}); + server.writeAndFlush(downloadStatusMessage); + } log.info(String.valueOf(queue)); lock.unlock(); ctx.writeAndFlush(new ResponseMessage(dpm.messageId, (byte) 0)); From a8e61cba8f5ea37919a249cc8aca6249e6459e09 Mon Sep 17 00:00:00 2001 From: chuzhongzai Date: Mon, 24 Mar 2025 22:08:10 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E7=8A=B6=E6=80=81=E4=B9=8B=E5=90=8E=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E9=94=99=E8=AF=AF=E7=9A=84=E7=A7=BB=E9=99=A4=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=AF=BC=E8=87=B4=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lion/storageNode.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/lion/storageNode.java b/src/main/java/lion/storageNode.java index f79c99c..f9fe35c 100644 --- a/src/main/java/lion/storageNode.java +++ b/src/main/java/lion/storageNode.java @@ -109,10 +109,7 @@ public class storageNode { downloadStatusMessage.setGalleryTasks(queue.values().toArray(GalleryTask[]::new)); server.writeAndFlush(downloadStatusMessage); - queue.forEach((gid, galleryTask) -> { - if (galleryTask.is_compress_complete()) - queue.remove(gid); - }); + queue.entrySet().removeIf(entry -> entry.getValue().is_compress_complete()); log.info("任务状态发送完成"); From ceef2dae12fc6bcb05f35e2d035d6fa67913641c Mon Sep 17 00:00:00 2001 From: chuzhongzai Date: Sat, 26 Apr 2025 23:59:28 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=E4=BB=A3=E7=90=86;=E6=96=B0=E5=A2=9E=E5=A4=87=E7=94=A8?= =?UTF-8?q?=E8=AE=A2=E9=98=85=E6=9B=B4=E6=96=B0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/encodings.xml | 7 + pom.xml | 6 + src/main/java/lion/Config/Config.java | 23 ++ .../java/lion/Externel/BackupSubServer.java | 295 ++++++++++++++++++ src/main/java/lion/Extranel/AESUtils.java | 26 -- src/main/java/lion/Extranel/Server.java | 65 ---- src/main/java/lion/Main.java | 6 +- src/main/resources/config.properties | 2 + 8 files changed, 337 insertions(+), 93 deletions(-) create mode 100644 .idea/encodings.xml create mode 100644 src/main/java/lion/Config/Config.java create mode 100644 src/main/java/lion/Externel/BackupSubServer.java delete mode 100644 src/main/java/lion/Extranel/AESUtils.java delete mode 100644 src/main/java/lion/Extranel/Server.java create mode 100644 src/main/resources/config.properties diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 840afc1..8bc0482 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,12 @@ commons-compress 1.25.0 + + + org.apache.httpcomponents + httpclient + 4.5.14 + diff --git a/src/main/java/lion/Config/Config.java b/src/main/java/lion/Config/Config.java new file mode 100644 index 0000000..8462194 --- /dev/null +++ b/src/main/java/lion/Config/Config.java @@ -0,0 +1,23 @@ +package lion.Config; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class Config { + public static String DouNaiV2ray; + public static String DouNaiClash; + + public static void loadConfig(){ + Properties prop = new Properties(); + + try (InputStream input = new FileInputStream("/root/gallery/storageNode/config.properties")) { + prop.load(input); + DouNaiV2ray = prop.getProperty("DouNaiV2ray"); + DouNaiClash = prop.getProperty("DouNaiClash"); + } catch (IOException ex) { + ex.printStackTrace(); + } + } +} diff --git a/src/main/java/lion/Externel/BackupSubServer.java b/src/main/java/lion/Externel/BackupSubServer.java new file mode 100644 index 0000000..71b5fb9 --- /dev/null +++ b/src/main/java/lion/Externel/BackupSubServer.java @@ -0,0 +1,295 @@ +package lion.Externel; + +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; + +import java.io.*; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static lion.Config.Config.DouNaiClash; +import static lion.Config.Config.DouNaiV2ray; + +@Slf4j +public class BackupSubServer { + + public static void main(String[] args) { + updateSub(); + ExecutorService threadPool = Executors.newFixedThreadPool(3600); + threadPool.submit(() -> { + if(LocalDateTime.now().getHour() == 0){ + updateSub(); + } + }); + + String ip = ""; + try(ServerSocket serverSocket = new ServerSocket(8889)) { + log.info("Sub Server listening on port {}", 8889); + while (true) { + Socket clientSocket = serverSocket.accept(); + ip = clientSocket.getInetAddress().getHostAddress(); + log.info("Client connected:{}", ip); + // 线程池处理下载请求 + handleClientRequest(clientSocket); + } + } catch (IOException e) { + log.error("处理http请求时出错,IP:{},ERROR:{}", ip, e.getMessage()); + } + } + + public static void updateSub(){ + File DouNaiClashFile = new File("sub/DouNaiClash.txt"); + File DouNaiV2rayFile = new File("sub/DouNaiV2ray.txt"); + File directory = new File("sub"); + + if(!directory.isDirectory()) + try { + Files.createDirectory(Paths.get("sub")); + } catch (IOException e) { + log.error("create directory error:{}", e.getMessage()); + } + + List DouNaiClash_profile; + + //下载豆奶v2ray订阅 + try(FileWriter writer = new FileWriter(DouNaiV2rayFile)) { + String DouNaiV2rayRaw = Get(DouNaiV2ray).getFirst(); + String[] v2rayPlain = new String(Base64.getDecoder().decode(DouNaiV2rayRaw)).split("\n"); + StringBuilder stringBuilder = new StringBuilder(); + Pattern pattern = Pattern.compile("-?\\d+(\\.\\d+)?"); + + //过滤高倍率节点 + for(String node: v2rayPlain){ + String name = URLDecoder.decode(node.split("#")[1], StandardCharsets.UTF_8); + if(name.contains("流量")){ + Matcher matcher = pattern.matcher(name.substring(name.indexOf("(") + 1, name.indexOf(")"))); + + if (matcher.find()) { + // 将匹配到的数字添加到列表中 + float ratio = Float.parseFloat(matcher.group()); + if(ratio <= 2) { + stringBuilder.append(node).append("\n"); + continue; + } + } + stringBuilder.append(node).append("\n"); + } + else{ + stringBuilder.append(node).append("\n"); + } + } + writer.write(new String(Base64.getEncoder().encode(stringBuilder.toString().getBytes(StandardCharsets.UTF_8)))); + + log.info("load DouNai v2ray complete"); + }catch (IOException e){ + log.error("load DouNai v2ray failure: {}", e.getMessage()); + } + + //下载豆奶clash订阅 + try(FileWriter writer = new FileWriter(DouNaiClashFile)) { + DouNaiClash_profile = Get(DouNaiClash); + //过滤高倍率节点 + ArrayList clashProcessed = new ArrayList<>(); + boolean isProxies = false; + boolean skip = false; + for(String line: DouNaiClash_profile){ + if(line.equals("proxies:")) + isProxies = true; + else if(line.equals("proxy-groups:") && isProxies) + isProxies = false; + + if(isProxies) { + if (line.contains("name")) + skip = line.contains("流量"); + if (!skip) + clashProcessed.add(line); + } + else + if (!line.contains("流量")) + clashProcessed.add(line); + } + + for(String line: clashProcessed) + writer.write(line + "\n"); + + log.info("load DouNai clash complete"); + }catch (IOException e){ + log.error("load DouNai clash failure: {}", e.getMessage()); + } + } + + + public static ArrayList Get(String url) throws IOException { + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse httpResponse; + HttpGet httpGet = new HttpGet(url); + + httpResponse = httpClient.execute(httpGet); + + HttpEntity responseEntity = httpResponse.getEntity(); + int statusCode = httpResponse.getStatusLine().getStatusCode(); + ArrayList temp = new ArrayList<>(); + + if (statusCode == 200) { + BufferedReader reader = new BufferedReader(new InputStreamReader(responseEntity.getContent())); + String str; + while ((str = reader.readLine()) != null) + temp.add(str); + } + + httpClient.close(); + httpResponse.close(); + return temp; + } + + private static void handleClientRequest(Socket clientSocket) { + String fileName = ""; + try { + BufferedReader requestReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + String requestLine = requestReader.readLine(); + + // Parse the request line to get the method and path + String[] requestParts = requestLine.split(" "); + String method = requestParts[0]; + Map paramMap = parseRequestLine(requestParts[1]);//path + if(paramMap == null){ + sendErrorResponse(clientSocket, "404"); + return; + } + log.info(Arrays.toString(requestParts)); + + // Only handle GET requests + if (method.equals("GET")) { + // Set the file path for download + File file = new File(fileName); + switch (paramMap.get("Client")) { + case "v2" -> file = new File("sub/DouNaiV2ray.txt"); + case "cat" -> file = new File("sub/DouNaiClash.txt"); + } + fileName = file.getName(); + log.info(file.getAbsolutePath()); + // Check if the file exists and is readable + if (file.exists() && file.isFile() && file.canRead()) { + // Get the file length + long fileLength = file.length(); + + // Get the range information for resuming download + long startByte = 0; + long endByte = fileLength - 1; + String rangeHeader = getRequestHeader(requestReader); + if (rangeHeader != null && rangeHeader.startsWith("bytes=")) { + String[] rangeValues = rangeHeader.substring(6).split("-"); + startByte = Long.parseLong(rangeValues[0]); + if (rangeValues.length > 1 && !rangeValues[1].isEmpty()) { + endByte = Long.parseLong(rangeValues[1]); + } + } + + // Send the HTTP response headers + OutputStream responseStream = clientSocket.getOutputStream(); + PrintWriter responseWriter = new PrintWriter(responseStream, true); + responseWriter.println("HTTP/1.1 206 Partial Content"); + responseWriter.println("Content-Type: application/octet-stream"); + responseWriter.println("Accept-Ranges: bytes"); + responseWriter.println("Content-Length: " + (endByte - startByte + 1)); + responseWriter.println("Content-Range: bytes " + startByte + "-" + endByte + "/" + fileLength); + responseWriter.println(); + + // Send the file content + try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")) { + randomAccessFile.seek(startByte); + byte[] buffer = new byte[1024]; + int bytesRead; + long bytesRemaining = endByte - startByte + 1; + while (bytesRemaining > 0 && (bytesRead = randomAccessFile.read(buffer, 0, (int) Math.min(buffer.length, bytesRemaining))) != -1) { + responseStream.write(buffer, 0, bytesRead); + bytesRemaining -= bytesRead; + } + }catch (SocketException ignore){ + + } + + // Close the response output stream + responseStream.close(); + } else { + // File not found or not readable, send 404 response + sendErrorResponse(clientSocket, "404 Not Found"); + } + } else { + // Non-GET requests, send 501 response + sendErrorResponse(clientSocket, "501 Not Implemented"); + } + + // Close the request reader and client socket + requestReader.close(); + clientSocket.close(); + } catch (IOException e) { + log.error("处理文件下载时出错,IP:{}, 文件:{}, ERROR:{}", clientSocket.getInetAddress().getHostAddress(), fileName, e.getMessage()); + } + } + + private static String getRequestHeader(BufferedReader requestReader) throws IOException { + String line; + while ((line = requestReader.readLine()) != null) { + if (line.trim().isEmpty()) { + break; + } + + if (line.startsWith("Range" + ":")) { + return line.substring("Range".length() + 1).trim(); + } + } + return null; + } + + public static Map parseRequestLine(String requestLine) { + Map pathParams = new HashMap<>(); + + if(requestLine == null) + return null; + + String path; + if(requestLine.contains("?")) + path = requestLine.split("\\?")[0]; + else + path = requestLine; + + String[] vars = path.split("/"); + + if(vars.length < 4) + return null; + + pathParams.put("Key", vars[3]); + pathParams.put("Client", vars[2]); + + if(!pathParams.get("Client").equals("cat") && !pathParams.get("Client").equals("v2")) + return null; + + if(pathParams.get("Key").length()<6) + return null; + + return pathParams; + } + + private static void sendErrorResponse(Socket clientSocket, String statusCode) throws IOException { + OutputStream responseStream = clientSocket.getOutputStream(); + PrintWriter responseWriter = new PrintWriter(responseStream, true); + responseWriter.println("HTTP/1.1 " + statusCode); + responseWriter.println("Content-Type: text/html"); + responseWriter.println(); + responseWriter.println("

" + statusCode + "

"); + responseStream.close(); + } +} diff --git a/src/main/java/lion/Extranel/AESUtils.java b/src/main/java/lion/Extranel/AESUtils.java deleted file mode 100644 index 8797821..0000000 --- a/src/main/java/lion/Extranel/AESUtils.java +++ /dev/null @@ -1,26 +0,0 @@ -package lion.Extranel; - -import javax.crypto.Cipher; -import javax.crypto.spec.SecretKeySpec; -import java.security.Key; - -public class AESUtils { - private static final String ALGORITHM = "AES"; - private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding"; - - private static final byte[] keyBytes = "ThisIsA128BitKey".getBytes(); - - public static byte[] encrypt(byte[] data) throws Exception { - Key key = new SecretKeySpec(keyBytes, ALGORITHM); - Cipher cipher = Cipher.getInstance(TRANSFORMATION); - cipher.init(Cipher.ENCRYPT_MODE, key); - return cipher.doFinal(data); - } - - public static byte[] decrypt(byte[] encryptedData) throws Exception { - Key key = new SecretKeySpec(keyBytes, ALGORITHM); - Cipher cipher = Cipher.getInstance(TRANSFORMATION); - cipher.init(Cipher.DECRYPT_MODE, key); - return cipher.doFinal(encryptedData); - } -} diff --git a/src/main/java/lion/Extranel/Server.java b/src/main/java/lion/Extranel/Server.java deleted file mode 100644 index 770b0c4..0000000 --- a/src/main/java/lion/Extranel/Server.java +++ /dev/null @@ -1,65 +0,0 @@ -package lion.Extranel; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lion.CustomUtil; -import lombok.extern.slf4j.Slf4j; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.URI; -import java.net.URL; -import java.util.HashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -@Slf4j -public class Server { - - ExecutorService thread_pool; - - ObjectMapper objectMapper; - - public static void main(String[] args) { - new Server(); - } - - public Server(){ - log.info("开始监听:55555"); - objectMapper = CustomUtil.objectMapper; - thread_pool = Executors.newFixedThreadPool(2); - thread_pool.submit(() -> { - try(ServerSocket server = new ServerSocket(55555)){ - server.setSoTimeout(1000000); - while (true){ - Socket socket = server.accept(); - thread_pool.submit(() -> handleSocket(socket)); - } - }catch (IOException e){ - log.error(e.getMessage()); - } - }); - } - - - public void handleSocket(Socket socket){ - try{ - BufferedInputStream inputStream = new BufferedInputStream(socket.getInputStream()); - Thread.sleep(500); - byte[] buf = new byte[inputStream.available()]; - inputStream.read(buf); - byte[] bytes = AESUtils.decrypt(buf); - - HashMap map = (HashMap) objectMapper.readValue(bytes, HashMap.class); - URL url = new URI(map.get("path")).toURL(); - log.info("处理反代 ip: {},路径: {}", socket.getInetAddress().getHostAddress(), map.get("path")); - bytes = url.openConnection().getInputStream().readAllBytes(); - socket.getOutputStream().write(AESUtils.encrypt(bytes)); - socket.getOutputStream().flush(); - socket.getOutputStream().close(); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/src/main/java/lion/Main.java b/src/main/java/lion/Main.java index af58463..235ab32 100644 --- a/src/main/java/lion/Main.java +++ b/src/main/java/lion/Main.java @@ -1,7 +1,8 @@ package lion; import io.netty.bootstrap.Bootstrap; -import lion.Extranel.Server; +import lion.Config.Config; +import lion.Externel.BackupSubServer; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -9,8 +10,9 @@ public class Main { public static void main(String[] args) { boot(); + Config.loadConfig(); + new Thread(() -> BackupSubServer.main(null)).start(); new Thread(() -> MultiThreadedHTTPServer.main(null)).start(); - new Thread(() -> Server.main(null)).start(); new storageNode(); } diff --git a/src/main/resources/config.properties b/src/main/resources/config.properties new file mode 100644 index 0000000..427b6b4 --- /dev/null +++ b/src/main/resources/config.properties @@ -0,0 +1,2 @@ +DouNaiV2ray=https://aaaa.gay/link/X7zEqkIx5gtIGugO?client=v2 +DouNaiClash=https://aaaa.gay/link/X7zEqkIx5gtIGugO?client=clashmeta \ No newline at end of file From df6c39ba56c2ee39de5e270f6e025d9ee8a42a37 Mon Sep 17 00:00:00 2001 From: chuzhongzai Date: Thu, 28 Aug 2025 10:30:38 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E5=B0=86=E7=BA=BF=E7=A8=8B=E6=B1=A0?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=AE=9A=E6=97=B6=E7=BA=BF=E7=A8=8B=E6=B1=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lion/Externel/BackupSubServer.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/lion/Externel/BackupSubServer.java b/src/main/java/lion/Externel/BackupSubServer.java index 71b5fb9..ba4611c 100644 --- a/src/main/java/lion/Externel/BackupSubServer.java +++ b/src/main/java/lion/Externel/BackupSubServer.java @@ -14,8 +14,7 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.time.LocalDateTime; import java.util.*; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -27,12 +26,8 @@ public class BackupSubServer { public static void main(String[] args) { updateSub(); - ExecutorService threadPool = Executors.newFixedThreadPool(3600); - threadPool.submit(() -> { - if(LocalDateTime.now().getHour() == 0){ - updateSub(); - } - }); + ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(1); + threadPool.scheduleAtFixedRate(BackupSubServer::updateSub, 0, 12, TimeUnit.HOURS); String ip = ""; try(ServerSocket serverSocket = new ServerSocket(8889)) { From c84f11cd8f436580cfac4ec2e1e4425b91d054cf Mon Sep 17 00:00:00 2001 From: chuzhongzai Date: Fri, 29 Aug 2025 16:16:59 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E4=B8=8B=E8=BD=BD=E5=AE=8C=E6=88=90=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lion/Service/DownloadCheckService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/lion/Service/DownloadCheckService.java b/src/main/java/lion/Service/DownloadCheckService.java index 03e9c75..8d0c844 100644 --- a/src/main/java/lion/Service/DownloadCheckService.java +++ b/src/main/java/lion/Service/DownloadCheckService.java @@ -147,7 +147,7 @@ public class DownloadCheckService { */ public boolean addToQueue(GalleryTask galleryTask){ //是否含有名字,进行中任务一般有名字,没有名字则肯定为初始任务,存在名字至少在下载路径出现过 - if(galleryTask.getName() == null || !galleryTask.getName().isEmpty()){ + if(galleryTask.getName() == null || galleryTask.getName().isEmpty()){ queue.putIfAbsent(galleryTask.getGid(), galleryTask); return false; } @@ -168,7 +168,7 @@ public class DownloadCheckService { //异常情况,发送通知 - CustomUtil.notifyMe(String.format("任务:%s存在名字,但是下载路径为空且不存在压缩包", galleryTask.getName() )); + CustomUtil.notifyMe(String.format("任务:%s存在名字,但是下载路径为空且不存在压缩包", galleryTask.getName())); return false; } }