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>
<build>
<finalName>${artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>

View File

@ -1,8 +1,13 @@
package com.jetbrains.help;
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 com.jetbrains.help.context.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
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.Scheduled;
import java.net.InetAddress;
import java.util.Collection;
import java.util.List;
@Slf4j
@EnableScheduling
@Import(SpringUtil.class)
@SpringBootApplication
@ -23,12 +30,21 @@ public class JetbrainsHelpApplication {
SpringApplication.run(JetbrainsHelpApplication.class, args);
}
@SneakyThrows
@EventListener(ApplicationReadyEvent.class)
public void ready() {
ProductsContextHolder.init();
PluginsContextHolder.init();
CertificateContextHolder.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 * * ?")

View File

@ -24,25 +24,33 @@ import java.util.concurrent.CompletableFuture;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class AgentContextHolder {
private static final String JA_NETFILTER_FILE_PATH = "static/agent/ja-netfilter";
// private static final String JA_NETFILTER_FILE_PATH = "static/agent/ja";
private static final String JA_NETFILTER_FILE_PATH = "external/agent/ja-netfilter";
private static final String POWER_CONF_FILE_NAME = JA_NETFILTER_FILE_PATH + "/config/power.conf";
private static File jaNetfilterFile;
private static File jaNetfilterZipFile;
public static void init() {
log.info("Agent context init loading...");
jaNetfilterFile = FileTools.getFileOrCreat(JA_NETFILTER_FILE_PATH);
if (!powerConfHasInit()) {
log.info("Agent config init loading...");
loadPowerConf();
zipJaNetfilter();
log.info("Agent config init success !");
jaNetfilterZipFile = FileTools.getFileOrCreat(JA_NETFILTER_FILE_PATH + ".zip");
if (!FileTools.fileExists(JA_NETFILTER_FILE_PATH)) {
unzipJaNetfilter();
if (!powerConfHasInit()) {
log.info("Agent config init loading...");
loadPowerConf();
zipJaNetfilter();
log.info("Agent config init success !");
}
}
log.info("Agent context init success !");
}
public static File jaNetfilterZipFile() {
return AgentContextHolder.jaNetfilterZipFile;
}
private static boolean powerConfHasInit() {
File powerConfFile = FileTools.getFileOrCreat(POWER_CONF_FILE_NAME);
String powerConfStr;
@ -90,7 +98,11 @@ public class AgentContextHolder {
}
}
private static void unzipJaNetfilter() {
jaNetfilterFile = ZipUtil.unzip(jaNetfilterZipFile);
}
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)
public class CertificateContextHolder {
private static final String ROOT_KEY_FILE_NAME = "certificate/root.key";
private static final String PRIVATE_KEY_FILE_NAME = "certificate/private.key";
private static final String PUBLIC_KEY_FILE_NAME = "certificate/public.key";
private static final String CET_FILE_NAME = "certificate/ca.crt";
private static final String ROOT_KEY_FILE_NAME = "external/certificate/root.key";
private static final String PRIVATE_KEY_FILE_NAME = "external/certificate/private.key";
private static final String PUBLIC_KEY_FILE_NAME = "external/certificate/public.key";
private static final String CET_FILE_NAME = "external/certificate/ca.crt";
private static File rootKeyFile;
@ -52,6 +52,7 @@ public class CertificateContextHolder {
|| !FileTools.fileExists(CET_FILE_NAME)) {
log.info("certificate context generate loading...");
generateCertificate();
log.info("certificate context generate success!");
} else {
privateKeyFile = FileTools.getFileOrCreat(PRIVATE_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 java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
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_JSON_FILE_NAME = "plugin.json";
private static final String PLUGIN_JSON_FILE_NAME = "external/data/plugin.json";
private static List<PluginCache> pluginCacheList;
@ -84,11 +85,14 @@ public class PluginsContextHolder {
public static PluginList pluginList() {
return HttpUtil.createGet(PLUGIN_LIST_URL)
.thenFunction(response -> {
InputStream is = response.bodyStream();
if (!response.isOk()) {
throw new IllegalArgumentException(CharSequenceUtil.format("{} The request failed = {}", PLUGIN_LIST_URL, response));
try (InputStream is = response.bodyStream()) {
if (!response.isOk()) {
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) {
return HttpUtil.createGet(PLUGIN_INFO_URL + pluginId)
.thenFunction(response -> {
InputStream is = response.bodyStream();
if (!response.isOk()) {
throw new IllegalArgumentException(CharSequenceUtil.format("{} The request failed = {}", PLUGIN_INFO_URL, response));
try (InputStream is = response.bodyStream()) {
if (!response.isOk()) {
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)
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;

View File

@ -1,20 +1,32 @@
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.util.StrUtil;
import com.jetbrains.help.JetbrainsHelpApplication;
import com.jetbrains.help.context.AgentContextHolder;
import com.jetbrains.help.context.PluginsContextHolder;
import com.jetbrains.help.context.ProductsContextHolder;
import com.jetbrains.help.properties.JetbrainsHelpProperties;
import lombok.AllArgsConstructor;
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.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.File;
import java.util.List;
import static org.springframework.http.HttpHeaders.CONTENT_DISPOSITION;
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM;
@Controller
@RequiredArgsConstructor
public class IndexController {
@ -48,4 +60,14 @@ public class IndexController {
model.addAttribute("defaults", jetbrainsHelpProperties);
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.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 java.io.File;
@ -9,25 +12,35 @@ import java.io.IOException;
public interface FileTools {
static boolean fileExists(String pathOrFile) {
return FileUtil.file(new ClassPathResource(pathOrFile).getPath()).exists();
ApplicationHome application = new ApplicationHome();
static boolean fileExists(String path) {
return getFile(path).exists();
}
static File getFileOrCreat(String pathOrFile) {
File file = FileUtil.file(new ClassPathResource(pathOrFile).getPath());
if (!file.exists()) {
try {
File parentFile = file.getParentFile();
if (!parentFile.exists() && !parentFile.mkdir()) {
throw new IllegalArgumentException(CharSequenceUtil.format("{} File directory create Failed", pathOrFile));
static File getFile(String path) {
File homeDir = application.getDir();
File source = application.getSource();
ClassPathResource classPathResource = new ClassPathResource(path);
return ObjectUtil.isNull(source) ? FileUtil.file(classPathResource.getPath()) : FileUtil.file(homeDir, path);
}
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()) {
throw new IllegalArgumentException(CharSequenceUtil.format("{} File create failed", pathOrFile));
}
} catch (IOException e) {
throw new IllegalArgumentException(CharSequenceUtil.format("{} File create failed", pathOrFile), e);
FileUtil.copy(classPathFile, file, true);
}
}
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>
<header class="tip sticky flex items-center py-6">
<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>
🇨🇳 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