This commit is contained in:
藏柏 2024-04-12 15:39:20 +08:00
parent 7b68f10cd7
commit 2ea9fcba13
22 changed files with 133 additions and 46 deletions

13
Dockerfile Normal file
View File

@ -0,0 +1,13 @@
FROM java:21
ADD target/Jetbrains-Help.jar /Jetbrains-Help.jar
RUN bash -c 'touch /Jetbrains-Help.jar'
ENV TZ=Asia/Shanghai
RUN ln -sf /usr/share/zoneinfo/{TZ} /etc/localtime && echo "{TZ}" > /etc/timezone
EXPOSE 10768
ENTRYPOINT ["java", "-jar","/Jetbrains-Help.jar"]

View File

@ -55,6 +55,7 @@
</dependencies> </dependencies>
<build> <build>
<finalName>${artifactId}</finalName>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@ -1,8 +1,13 @@
package com.jetbrains.help; package com.jetbrains.help;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.net.Ipv4Util;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil; import cn.hutool.extra.spring.SpringUtil;
import com.jetbrains.help.context.*; import com.jetbrains.help.context.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
@ -11,9 +16,11 @@ import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import java.net.InetAddress;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@Slf4j
@EnableScheduling @EnableScheduling
@Import(SpringUtil.class) @Import(SpringUtil.class)
@SpringBootApplication @SpringBootApplication
@ -23,12 +30,21 @@ public class JetbrainsHelpApplication {
SpringApplication.run(JetbrainsHelpApplication.class, args); SpringApplication.run(JetbrainsHelpApplication.class, args);
} }
@SneakyThrows
@EventListener(ApplicationReadyEvent.class) @EventListener(ApplicationReadyEvent.class)
public void ready() { public void ready() {
ProductsContextHolder.init(); ProductsContextHolder.init();
PluginsContextHolder.init(); PluginsContextHolder.init();
CertificateContextHolder.init(); CertificateContextHolder.init();
AgentContextHolder.init(); AgentContextHolder.init();
InetAddress localHost = InetAddress.getLocalHost();
String address = CharSequenceUtil.format("http://{}:{}", localHost.getHostAddress(), SpringUtil.getProperty("server.port"));
String runSuccessWarn = "\n====================================================================================\n" +
"= Jetbrains-Help Run Success~ =\n" +
"= address:" + address + " =\n" +
"====================================================================================\n";
log.info(runSuccessWarn);
} }
@Scheduled(cron = "0 0 12 * * ?") @Scheduled(cron = "0 0 12 * * ?")

View File

@ -24,25 +24,33 @@ import java.util.concurrent.CompletableFuture;
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public class AgentContextHolder { public class AgentContextHolder {
private static final String JA_NETFILTER_FILE_PATH = "static/agent/ja-netfilter"; private static final String JA_NETFILTER_FILE_PATH = "external/agent/ja-netfilter";
// private static final String JA_NETFILTER_FILE_PATH = "static/agent/ja";
private static final String POWER_CONF_FILE_NAME = JA_NETFILTER_FILE_PATH + "/config/power.conf"; private static final String POWER_CONF_FILE_NAME = JA_NETFILTER_FILE_PATH + "/config/power.conf";
private static File jaNetfilterFile; private static File jaNetfilterFile;
private static File jaNetfilterZipFile;
public static void init() { public static void init() {
log.info("Agent context init loading..."); log.info("Agent context init loading...");
jaNetfilterFile = FileTools.getFileOrCreat(JA_NETFILTER_FILE_PATH); jaNetfilterZipFile = FileTools.getFileOrCreat(JA_NETFILTER_FILE_PATH + ".zip");
if (!powerConfHasInit()) { if (!FileTools.fileExists(JA_NETFILTER_FILE_PATH)) {
log.info("Agent config init loading..."); unzipJaNetfilter();
loadPowerConf(); if (!powerConfHasInit()) {
zipJaNetfilter(); log.info("Agent config init loading...");
log.info("Agent config init success !"); loadPowerConf();
zipJaNetfilter();
log.info("Agent config init success !");
}
} }
log.info("Agent context init success !"); log.info("Agent context init success !");
} }
public static File jaNetfilterZipFile() {
return AgentContextHolder.jaNetfilterZipFile;
}
private static boolean powerConfHasInit() { private static boolean powerConfHasInit() {
File powerConfFile = FileTools.getFileOrCreat(POWER_CONF_FILE_NAME); File powerConfFile = FileTools.getFileOrCreat(POWER_CONF_FILE_NAME);
String powerConfStr; String powerConfStr;
@ -90,7 +98,11 @@ public class AgentContextHolder {
} }
} }
private static void unzipJaNetfilter() {
jaNetfilterFile = ZipUtil.unzip(jaNetfilterZipFile);
}
private static void zipJaNetfilter() { private static void zipJaNetfilter() {
ZipUtil.zip(jaNetfilterFile); jaNetfilterZipFile = ZipUtil.zip(jaNetfilterFile);
} }
} }

View File

@ -31,10 +31,10 @@ import java.security.cert.CertificateException;
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CertificateContextHolder { public class CertificateContextHolder {
private static final String ROOT_KEY_FILE_NAME = "certificate/root.key"; private static final String ROOT_KEY_FILE_NAME = "external/certificate/root.key";
private static final String PRIVATE_KEY_FILE_NAME = "certificate/private.key"; private static final String PRIVATE_KEY_FILE_NAME = "external/certificate/private.key";
private static final String PUBLIC_KEY_FILE_NAME = "certificate/public.key"; private static final String PUBLIC_KEY_FILE_NAME = "external/certificate/public.key";
private static final String CET_FILE_NAME = "certificate/ca.crt"; private static final String CET_FILE_NAME = "external/certificate/ca.crt";
private static File rootKeyFile; private static File rootKeyFile;
@ -52,6 +52,7 @@ public class CertificateContextHolder {
|| !FileTools.fileExists(CET_FILE_NAME)) { || !FileTools.fileExists(CET_FILE_NAME)) {
log.info("certificate context generate loading..."); log.info("certificate context generate loading...");
generateCertificate(); generateCertificate();
log.info("certificate context generate success!");
} else { } else {
privateKeyFile = FileTools.getFileOrCreat(PRIVATE_KEY_FILE_NAME); privateKeyFile = FileTools.getFileOrCreat(PRIVATE_KEY_FILE_NAME);
publicKeyFile = FileTools.getFileOrCreat(PUBLIC_KEY_FILE_NAME); publicKeyFile = FileTools.getFileOrCreat(PUBLIC_KEY_FILE_NAME);

View File

@ -13,6 +13,7 @@ import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
@ -28,7 +29,7 @@ public class PluginsContextHolder {
private static final String PLUGIN_INFO_URL = PLUGIN_BASIC_URL + "/api/plugins/"; private static final String PLUGIN_INFO_URL = PLUGIN_BASIC_URL + "/api/plugins/";
private static final String PLUGIN_JSON_FILE_NAME = "plugin.json"; private static final String PLUGIN_JSON_FILE_NAME = "external/data/plugin.json";
private static List<PluginCache> pluginCacheList; private static List<PluginCache> pluginCacheList;
@ -84,11 +85,14 @@ public class PluginsContextHolder {
public static PluginList pluginList() { public static PluginList pluginList() {
return HttpUtil.createGet(PLUGIN_LIST_URL) return HttpUtil.createGet(PLUGIN_LIST_URL)
.thenFunction(response -> { .thenFunction(response -> {
InputStream is = response.bodyStream(); try (InputStream is = response.bodyStream()) {
if (!response.isOk()) { if (!response.isOk()) {
throw new IllegalArgumentException(CharSequenceUtil.format("{} The request failed = {}", PLUGIN_LIST_URL, response)); throw new IllegalArgumentException(CharSequenceUtil.format("{} The request failed = {}", PLUGIN_LIST_URL, response));
}
return IoUtil.readObj(is, PluginList.class);
} catch (IOException e) {
throw new IllegalArgumentException(CharSequenceUtil.format("{} The request io read failed", PLUGIN_LIST_URL), e);
} }
return IoUtil.readObj(is, PluginList.class);
}); });
} }
@ -119,11 +123,14 @@ public class PluginsContextHolder {
public static PluginInfo pluginInfo(Long pluginId) { public static PluginInfo pluginInfo(Long pluginId) {
return HttpUtil.createGet(PLUGIN_INFO_URL + pluginId) return HttpUtil.createGet(PLUGIN_INFO_URL + pluginId)
.thenFunction(response -> { .thenFunction(response -> {
InputStream is = response.bodyStream(); try (InputStream is = response.bodyStream()) {
if (!response.isOk()) { if (!response.isOk()) {
throw new IllegalArgumentException(CharSequenceUtil.format("{} The request failed = {}", PLUGIN_INFO_URL, response)); throw new IllegalArgumentException(CharSequenceUtil.format("{} The request failed = {}", PLUGIN_INFO_URL, response));
}
return IoUtil.readObj(is, PluginInfo.class);
} catch (IOException e) {
throw new IllegalArgumentException(CharSequenceUtil.format("{} The request io read failed", PLUGIN_LIST_URL), e);
} }
return IoUtil.readObj(is, PluginInfo.class);
}); });
} }

View File

@ -18,7 +18,7 @@ import java.util.List;
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ProductsContextHolder { public class ProductsContextHolder {
private static final String PRODUCT_JSON_FILE_NAME = "product.json"; private static final String PRODUCT_JSON_FILE_NAME = "external/data/product.json";
private static List<ProductCache> productCacheList; private static List<ProductCache> productCacheList;

View File

@ -1,20 +1,32 @@
package com.jetbrains.help.route; package com.jetbrains.help.route;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.jetbrains.help.JetbrainsHelpApplication; import com.jetbrains.help.JetbrainsHelpApplication;
import com.jetbrains.help.context.AgentContextHolder;
import com.jetbrains.help.context.PluginsContextHolder; import com.jetbrains.help.context.PluginsContextHolder;
import com.jetbrains.help.context.ProductsContextHolder; import com.jetbrains.help.context.ProductsContextHolder;
import com.jetbrains.help.properties.JetbrainsHelpProperties; import com.jetbrains.help.properties.JetbrainsHelpProperties;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.File;
import java.util.List; import java.util.List;
import static org.springframework.http.HttpHeaders.CONTENT_DISPOSITION;
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM;
@Controller @Controller
@RequiredArgsConstructor @RequiredArgsConstructor
public class IndexController { public class IndexController {
@ -48,4 +60,14 @@ public class IndexController {
model.addAttribute("defaults", jetbrainsHelpProperties); model.addAttribute("defaults", jetbrainsHelpProperties);
return "index::product-list"; return "index::product-list";
} }
@GetMapping("ja-netfilter")
@ResponseBody
public ResponseEntity<Resource> downloadJaNetfilter() {
File jaNetfilterZipFile = AgentContextHolder.jaNetfilterZipFile();
return ResponseEntity.ok()
.header(CONTENT_DISPOSITION, "attachment;filename=" + jaNetfilterZipFile.getName())
.contentType(APPLICATION_OCTET_STREAM)
.body(new InputStreamResource(FileUtil.getInputStream(jaNetfilterZipFile)));
}
} }

View File

@ -2,6 +2,9 @@ package com.jetbrains.help.util;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import java.io.File; import java.io.File;
@ -9,25 +12,35 @@ import java.io.IOException;
public interface FileTools { public interface FileTools {
static boolean fileExists(String pathOrFile) { ApplicationHome application = new ApplicationHome();
return FileUtil.file(new ClassPathResource(pathOrFile).getPath()).exists();
static boolean fileExists(String path) {
return getFile(path).exists();
} }
static File getFileOrCreat(String pathOrFile) { static File getFile(String path) {
File file = FileUtil.file(new ClassPathResource(pathOrFile).getPath()); File homeDir = application.getDir();
if (!file.exists()) { File source = application.getSource();
try { ClassPathResource classPathResource = new ClassPathResource(path);
File parentFile = file.getParentFile(); return ObjectUtil.isNull(source) ? FileUtil.file(classPathResource.getPath()) : FileUtil.file(homeDir, path);
if (!parentFile.exists() && !parentFile.mkdir()) { }
throw new IllegalArgumentException(CharSequenceUtil.format("{} File directory create Failed", pathOrFile));
static File getFileOrCreat(String path) {
File file = getFile(path);
if (ObjectUtil.isNotNull(application.getSource())) {
ClassPathResource classPathResource = new ClassPathResource(path);
File classPathFile = FileUtil.file(classPathResource.getPath());
if (classPathResource.exists() && !file.exists()) {
try {
FileUtil.writeFromStream(classPathResource.getInputStream(), classPathFile);
} catch (Exception e) {
throw new IllegalArgumentException(CharSequenceUtil.format("{} File read failed", classPathFile.getPath()), e);
} }
if (!file.createNewFile()) { FileUtil.copy(classPathFile, file, true);
throw new IllegalArgumentException(CharSequenceUtil.format("{} File create failed", pathOrFile));
}
} catch (IOException e) {
throw new IllegalArgumentException(CharSequenceUtil.format("{} File create failed", pathOrFile), e);
} }
} }
return file; return file;
} }
} }

View File

@ -0,0 +1,10 @@
██╗███████╗████████╗██████╗ ██████╗ █████╗ ██╗███╗ ██╗███████╗ ██╗ ██╗███████╗██╗ ██████╗
██║██╔════╝╚══██╔══╝██╔══██╗██╔══██╗██╔══██╗██║████╗ ██║██╔════╝ ██║ ██║██╔════╝██║ ██╔══██╗
██║█████╗ ██║ ██████╔╝██████╔╝███████║██║██╔██╗ ██║███████╗█████╗███████║█████╗ ██║ ██████╔╝
██ ██║██╔══╝ ██║ ██╔══██╗██╔══██╗██╔══██║██║██║╚██╗██║╚════██║╚════╝██╔══██║██╔══╝ ██║ ██╔═══╝
╚█████╔╝███████╗ ██║ ██████╔╝██║ ██║██║ ██║██║██║ ╚████║███████║ ██║ ██║███████╗███████╗██║
╚════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝
${AnsiColor.BRIGHT_YELLOW} Spring Boot Version: ${spring-boot.version}

View File

@ -1,3 +0,0 @@
[DNS]
; put dns filter rules here

View File

@ -1,4 +0,0 @@
[URL]
; put url filter rules here
PREFIX,https://account.jetbrains.com/lservice/rpc/validateKey.action

View File

@ -11,7 +11,7 @@
<body> <body>
<header class="tip sticky flex items-center py-6"> <header class="tip sticky flex items-center py-6">
<p> <p>
🇨🇳 Download <a href="/agent/ja-netfilter.zip" title="Download jetbra first">ja-netfilter.zip</a> , and configure 🇨🇳 Download <a href="ja-netfilter" title="Download jetbra first">ja-netfilter.zip</a> , and configure
your JetBrains's <strong onclick="showVmoptins()">vmoptions!</strong> <br> your JetBrains's <strong onclick="showVmoptins()">vmoptions!</strong> <br>
🇨🇳 Also you can <a onclick="showLicenseForm()">Refill license information</a> to customizer your license!</br> 🇨🇳 Also you can <a onclick="showLicenseForm()">Refill license information</a> to customizer your license!</br>
<strong>🇨🇳 Please note that this page is only developed and used by <span <strong>🇨🇳 Please note that this page is only developed and used by <span