parent
be03878e94
commit
ea314be257
@ -0,0 +1,36 @@ |
|||||||
|
<component name="InspectionProjectProfileManager"> |
||||||
|
<profile version="1.0"> |
||||||
|
<option name="myName" value="Project Default" /> |
||||||
|
<inspection_tool class="HttpUrlsUsage" enabled="true" level="WEAK WARNING" enabled_by_default="true"> |
||||||
|
<option name="ignoredUrls"> |
||||||
|
<list> |
||||||
|
<option value="http://localhost" /> |
||||||
|
<option value="http://127.0.0.1" /> |
||||||
|
<option value="http://0.0.0.0" /> |
||||||
|
<option value="http://www.w3.org/" /> |
||||||
|
<option value="http://json-schema.org/draft" /> |
||||||
|
<option value="http://java.sun.com/" /> |
||||||
|
<option value="http://xmlns.jcp.org/" /> |
||||||
|
<option value="http://javafx.com/javafx/" /> |
||||||
|
<option value="http://javafx.com/fxml" /> |
||||||
|
<option value="http://maven.apache.org/xsd/" /> |
||||||
|
<option value="http://maven.apache.org/POM/" /> |
||||||
|
<option value="http://www.springframework.org/schema/" /> |
||||||
|
<option value="http://www.springframework.org/tags" /> |
||||||
|
<option value="http://www.springframework.org/security/tags" /> |
||||||
|
<option value="http://www.thymeleaf.org" /> |
||||||
|
<option value="http://www.jboss.org/j2ee/schema/" /> |
||||||
|
<option value="http://www.jboss.com/xml/ns/" /> |
||||||
|
<option value="http://www.ibm.com/webservices/xsd" /> |
||||||
|
<option value="http://activemq.apache.org/schema/" /> |
||||||
|
<option value="http://schema.cloudfoundry.org/spring/" /> |
||||||
|
<option value="http://schemas.xmlsoap.org/" /> |
||||||
|
<option value="http://cxf.apache.org/schemas/" /> |
||||||
|
<option value="http://primefaces.org/ui" /> |
||||||
|
<option value="http://tiles.apache.org/" /> |
||||||
|
<option value="http://" /> |
||||||
|
</list> |
||||||
|
</option> |
||||||
|
</inspection_tool> |
||||||
|
</profile> |
||||||
|
</component> |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.data; |
package cn.wustlinghang.main.data; |
||||||
|
|
||||||
public class Main { |
public class Main { |
||||||
public static void main(String[] args) { |
public static void main(String[] args) { |
@ -0,0 +1,20 @@ |
|||||||
|
package cn.wustlinghang.internal.api.v1; |
||||||
|
|
||||||
|
import cn.wustlinghang.internal.api.v1.response.FrpPluginResponse; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
@RestController |
||||||
|
@RequestMapping("/internal/frp") |
||||||
|
public class FrpPluginHandler { |
||||||
|
@RequestMapping("/handler") |
||||||
|
public FrpPluginResponse handle(String request) { |
||||||
|
log.info(request); |
||||||
|
return FrpPluginResponse.builder() |
||||||
|
.reject(false) |
||||||
|
.unchange(true) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
package cn.wustlinghang.internal.api.v1.response; |
||||||
|
|
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
public class FrpPluginResponse { |
||||||
|
private boolean reject; |
||||||
|
|
||||||
|
private boolean unchange; |
||||||
|
|
||||||
|
// private String rejectReason;
|
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
package cn.wustlinghang.main.web; |
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication; |
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||||
|
import org.springframework.scheduling.annotation.EnableAsync; |
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling; |
||||||
|
|
||||||
|
@EnableAsync |
||||||
|
@EnableScheduling |
||||||
|
@SpringBootApplication |
||||||
|
public class Main { |
||||||
|
public static void main(String[] args) { |
||||||
|
SpringApplication.run(Main.class); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
package cn.wustlinghang.main.web.api.v2.undergrade; |
||||||
|
|
||||||
|
import cn.wustlinghang.wusthelper.main.response.Response; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
@RestController |
||||||
|
@RequestMapping("/jwc") |
||||||
|
public class UndergradController { |
||||||
|
public Response<String> login() { |
||||||
|
return Response.success(""); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
# 服务端配置 |
||||||
|
# 密码/密钥/内部地址『禁止』写在此处或其他git能检测到的地方 |
||||||
|
# 具体数值由运维填写在.env文件中,不能添加到git仓库中 |
||||||
|
|
||||||
|
spring: |
||||||
|
config: |
||||||
|
import: optional:file:.env[.properties] |
||||||
|
|
||||||
|
server: |
||||||
|
port: ${RUN_PORT} |
@ -0,0 +1,28 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.main.response; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 通用的响应 |
||||||
|
* |
||||||
|
* @param code 响应码 |
||||||
|
* @param msg 响应信息 |
||||||
|
* @param data 响应数据 |
||||||
|
* @param <T> data的类型 |
||||||
|
*/ |
||||||
|
public record Response<T>(int code, String msg, T data) { |
||||||
|
public static <T> Response<T> success(T data) { |
||||||
|
return new Response<>(ResponseCode.SUCCESS.getCode(), "ok", data); |
||||||
|
} |
||||||
|
|
||||||
|
public static <T> Response<T> success() { |
||||||
|
return success(null); |
||||||
|
} |
||||||
|
|
||||||
|
public static <T> Response<T> error(int code, String message) { |
||||||
|
return new Response<>(code, message, null); |
||||||
|
} |
||||||
|
|
||||||
|
public static <T> Response<T> error(ResponseCode code) { |
||||||
|
return error(code.getCode(), code.getMessage()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
/* |
||||||
|
* Class created by lensfrex. |
||||||
|
*/ |
||||||
|
|
||||||
|
package cn.wustlinghang.wusthelper.main.response; |
||||||
|
|
||||||
|
public enum ResponseCode { |
||||||
|
SUCCESS(0, "成功"), |
||||||
|
SERVER_INTERNAL_ERROR(-2, "服务器内部错误"), |
||||||
|
API_NOT_IMPLEMENT(-1, "接口未实现"); |
||||||
|
|
||||||
|
private final int code; |
||||||
|
|
||||||
|
private final String message; |
||||||
|
|
||||||
|
ResponseCode(int code, String message) { |
||||||
|
this.code = code; |
||||||
|
this.message = message; |
||||||
|
} |
||||||
|
|
||||||
|
public int getCode() { |
||||||
|
return code; |
||||||
|
} |
||||||
|
|
||||||
|
public String getMessage() { |
||||||
|
return message; |
||||||
|
} |
||||||
|
} |
@ -1 +1 @@ |
|||||||
Subproject commit 965562b69e35d445fb5c58b2e2afd9cdf27d3146 |
Subproject commit 736dc78d1b9e64124474cee98c5db6e8212fa096 |
@ -0,0 +1,38 @@ |
|||||||
|
target/ |
||||||
|
!.mvn/wrapper/maven-wrapper.jar |
||||||
|
!**/src/main/**/target/ |
||||||
|
!**/src/test/**/target/ |
||||||
|
|
||||||
|
### IntelliJ IDEA ### |
||||||
|
.idea/modules.xml |
||||||
|
.idea/jarRepositories.xml |
||||||
|
.idea/compiler.xml |
||||||
|
.idea/libraries/ |
||||||
|
*.iws |
||||||
|
*.iml |
||||||
|
*.ipr |
||||||
|
|
||||||
|
### Eclipse ### |
||||||
|
.apt_generated |
||||||
|
.classpath |
||||||
|
.factorypath |
||||||
|
.project |
||||||
|
.settings |
||||||
|
.springBeans |
||||||
|
.sts4-cache |
||||||
|
|
||||||
|
### NetBeans ### |
||||||
|
/nbproject/private/ |
||||||
|
/nbbuild/ |
||||||
|
/dist/ |
||||||
|
/nbdist/ |
||||||
|
/.nb-gradle/ |
||||||
|
build/ |
||||||
|
!**/src/main/**/build/ |
||||||
|
!**/src/test/**/build/ |
||||||
|
|
||||||
|
### VS Code ### |
||||||
|
.vscode/ |
||||||
|
|
||||||
|
### Mac OS ### |
||||||
|
.DS_Store |
@ -0,0 +1,42 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
<parent> |
||||||
|
<groupId>cn.wustlinghang.wusthelper</groupId> |
||||||
|
<artifactId>external-library</artifactId> |
||||||
|
<version>0.0.1-SNAPSHOT</version> |
||||||
|
</parent> |
||||||
|
|
||||||
|
<artifactId>rpc-frp-consul</artifactId> |
||||||
|
|
||||||
|
<properties> |
||||||
|
<maven.compiler.source>17</maven.compiler.source> |
||||||
|
<maven.compiler.target>17</maven.compiler.target> |
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||||
|
|
||||||
|
<jackson.version>2.15.2</jackson.version> |
||||||
|
<ini4j.version>0.5.4</ini4j.version> |
||||||
|
</properties> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>com.fasterxml.jackson.core</groupId> |
||||||
|
<artifactId>jackson-databind</artifactId> |
||||||
|
<version>${jackson.version}</version> |
||||||
|
<scope>compile</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>cn.wustlinghang.mywust</groupId> |
||||||
|
<artifactId>mywust-network-okhttp</artifactId> |
||||||
|
<version>${mywust.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.ini4j</groupId> |
||||||
|
<artifactId>ini4j</artifactId> |
||||||
|
<version>${ini4j.version}</version> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
</project> |
@ -0,0 +1,92 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.rpc; |
||||||
|
|
||||||
|
import cn.hutool.core.thread.ThreadUtil; |
||||||
|
import cn.hutool.core.util.RandomUtil; |
||||||
|
import cn.wustlinghang.mywust.network.Requester; |
||||||
|
import cn.wustlinghang.wusthelper.internal.rpc.client.ConsulClient; |
||||||
|
import cn.wustlinghang.wusthelper.internal.rpc.client.FrpcClient; |
||||||
|
import cn.wustlinghang.wusthelper.internal.rpc.config.FrpConfig; |
||||||
|
import cn.wustlinghang.wusthelper.internal.rpc.config.RegisterConfig; |
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
public class FrpConsulRegister { |
||||||
|
|
||||||
|
private final String serviceId; |
||||||
|
|
||||||
|
private final RegisterConfig registerConfig; |
||||||
|
|
||||||
|
private final FrpcClient frpcClientClient; |
||||||
|
|
||||||
|
private final ConsulClient consulClient; |
||||||
|
|
||||||
|
private boolean registered = false; |
||||||
|
|
||||||
|
public FrpConsulRegister(RegisterConfig registerConfig, FrpConfig frpConfig, |
||||||
|
Requester requester, ObjectMapper objectMapper) { |
||||||
|
|
||||||
|
this.serviceId = RandomUtil.randomString(8); |
||||||
|
this.registerConfig = registerConfig; |
||||||
|
|
||||||
|
this.frpcClientClient = new FrpcClient(frpConfig, requester, objectMapper); |
||||||
|
this.consulClient = new ConsulClient(this.serviceId, registerConfig, objectMapper, requester); |
||||||
|
} |
||||||
|
|
||||||
|
public void register() { |
||||||
|
ThreadUtil.execute(() -> { |
||||||
|
try { |
||||||
|
log.info("连接frp并注册consul..."); |
||||||
|
this.doRegister(); |
||||||
|
log.info("注册完毕"); |
||||||
|
} catch (Exception e) { |
||||||
|
log.warn("注册服务时发生异常:", e); |
||||||
|
log.warn("不进行转发注册,直接服务"); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(this::onShutdown, "ShutdownHookThread")); |
||||||
|
} |
||||||
|
|
||||||
|
private void onShutdown() { |
||||||
|
try { |
||||||
|
if (this.registered) { |
||||||
|
log.info("注销服务..."); |
||||||
|
this.consulClient.deregister(); |
||||||
|
this.frpcClientClient.removeProxy(); |
||||||
|
this.registered = false; |
||||||
|
log.info("服务注销完毕"); |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
log.warn("注销服务时发生异常:", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void doRegister() throws Exception { |
||||||
|
frpcClientClient.addFrpProxy( |
||||||
|
registerConfig.getServiceName(), serviceId, |
||||||
|
"127.0.0.1", registerConfig.getLocalServicePort() |
||||||
|
); |
||||||
|
|
||||||
|
String remoteAddress; |
||||||
|
String[] remote; |
||||||
|
int retry = 0; |
||||||
|
do { |
||||||
|
// 先睡个0.5秒等待连接成功再获取状态读端口
|
||||||
|
ThreadUtil.sleep(500); |
||||||
|
|
||||||
|
JsonNode proxy = frpcClientClient.getProxyStatus(registerConfig.getServiceName(), serviceId); |
||||||
|
remoteAddress = proxy.path("remote_addr") |
||||||
|
.asText("127.0.0.1:" + registerConfig.getLocalServicePort()); |
||||||
|
remote = remoteAddress.split(":"); |
||||||
|
retry++; |
||||||
|
} while (retry < 3 && remote.length < 2); |
||||||
|
if (retry == 3) { |
||||||
|
throw new Exception("获取frp隧道信息重试次数过多,请手动添加隧道和注册中心"); |
||||||
|
} |
||||||
|
|
||||||
|
this.consulClient.register(remoteAddress, Integer.parseInt(remote[1])); |
||||||
|
this.registered = true; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.rpc.client; |
||||||
|
|
||||||
|
import cn.wustlinghang.mywust.network.Requester; |
||||||
|
import cn.wustlinghang.mywust.network.entitys.HttpResponse; |
||||||
|
import cn.wustlinghang.mywust.network.request.RequestFactory; |
||||||
|
import cn.wustlinghang.wusthelper.internal.rpc.config.RegisterConfig; |
||||||
|
import cn.wustlinghang.wusthelper.internal.rpc.entity.RegisterRequestBody; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import com.google.common.collect.Lists; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
public class ConsulClient { |
||||||
|
private final String serviceId; |
||||||
|
private final String serviceName; |
||||||
|
private final String consulAddress; |
||||||
|
|
||||||
|
private final ObjectMapper objectMapper; |
||||||
|
private final Requester requester; |
||||||
|
|
||||||
|
public ConsulClient(String serviceId, RegisterConfig registerConfig, ObjectMapper objectMapper, Requester requester) { |
||||||
|
this.serviceId = serviceId; |
||||||
|
this.serviceName = registerConfig.getServiceName(); |
||||||
|
this.consulAddress = registerConfig.getConsulAddress(); |
||||||
|
|
||||||
|
this.objectMapper = objectMapper; |
||||||
|
this.requester = requester; |
||||||
|
} |
||||||
|
|
||||||
|
public void register(String remoteAddress, int remotePort, |
||||||
|
RegisterRequestBody.HealthCheckOption... healthCheckOption |
||||||
|
) throws IOException { |
||||||
|
var registerRequestBody = RegisterRequestBody.builder() |
||||||
|
.id(serviceId) |
||||||
|
.name(serviceName) |
||||||
|
.address(remoteAddress) |
||||||
|
.port(remotePort) |
||||||
|
.checks(Lists.newArrayList(healthCheckOption)) |
||||||
|
.build(); |
||||||
|
|
||||||
|
byte[] registerRequestData = objectMapper.writeValueAsBytes(registerRequestBody); |
||||||
|
var url = consulAddress + "/v1/agent/service/register"; |
||||||
|
|
||||||
|
var registerRequest = RequestFactory.makeHttpRequest(url, registerRequestData); |
||||||
|
var registerResponse = requester.put(registerRequest); |
||||||
|
|
||||||
|
if (registerResponse.getStatusCode() != HttpResponse.HTTP_OK) { |
||||||
|
log.warn("注册中心注册不成功,请手动注册"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void deregister() throws IOException { |
||||||
|
var url = String.format("%s/v1/agent/service/deregister/%s", consulAddress, serviceId); |
||||||
|
var deregisterRequest = RequestFactory.makeHttpRequest(url); |
||||||
|
var deregisterResponse = requester.put(deregisterRequest); |
||||||
|
|
||||||
|
if (deregisterResponse.getStatusCode() != HttpResponse.HTTP_OK) { |
||||||
|
log.warn("服务注销不成功,请手动注册"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,96 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.rpc.client; |
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64; |
||||||
|
import cn.wustlinghang.mywust.network.request.RequestFactory; |
||||||
|
import cn.wustlinghang.mywust.network.Requester; |
||||||
|
import cn.wustlinghang.wusthelper.internal.rpc.config.FrpConfig; |
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import com.fasterxml.jackson.databind.node.MissingNode; |
||||||
|
import org.ini4j.Ini; |
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream; |
||||||
|
import java.io.ByteArrayOutputStream; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
public class FrpcClient { |
||||||
|
private final String frpcAdminAddress; |
||||||
|
|
||||||
|
private final String frpAuthHeaderValue; |
||||||
|
|
||||||
|
private final Requester requester; |
||||||
|
|
||||||
|
private final ObjectMapper objectMapper; |
||||||
|
|
||||||
|
public FrpcClient(FrpConfig config, Requester requester, ObjectMapper objectMapper) { |
||||||
|
|
||||||
|
this.frpcAdminAddress = config.getFrpcAdminAddress(); |
||||||
|
|
||||||
|
this.requester = requester; |
||||||
|
this.objectMapper = objectMapper; |
||||||
|
|
||||||
|
String username = config.getFrpcAdminUsername(); |
||||||
|
String password = config.getFrpcAdminPassword(); |
||||||
|
this.frpAuthHeaderValue = "Basic " + Base64.encode(username + ":" + password); |
||||||
|
} |
||||||
|
|
||||||
|
private String frpProxyName; |
||||||
|
|
||||||
|
public void addFrpProxy(String serviceName, String serviceId, String localAddress, String localPort) |
||||||
|
throws IOException { |
||||||
|
this.frpProxyName = String.format("%s-%s", serviceName, serviceId); |
||||||
|
|
||||||
|
Ini ini = this.getFrpConfig(); |
||||||
|
ini.put(frpProxyName, "type", "tcp"); |
||||||
|
ini.put(frpProxyName, "local_address", localAddress); |
||||||
|
ini.put(frpProxyName, "local_port", localPort); |
||||||
|
ini.put(frpProxyName, "use_compression", "true"); |
||||||
|
|
||||||
|
var output = new ByteArrayOutputStream(); |
||||||
|
ini.store(output); |
||||||
|
|
||||||
|
this.reloadFrpConfig(ini); |
||||||
|
} |
||||||
|
|
||||||
|
public void removeProxy() throws IOException { |
||||||
|
Ini ini = this.getFrpConfig(); |
||||||
|
ini.remove(this.frpProxyName); |
||||||
|
|
||||||
|
this.reloadFrpConfig(ini); |
||||||
|
} |
||||||
|
|
||||||
|
public Ini getFrpConfig() throws IOException { |
||||||
|
var frpConfigRequest = RequestFactory.makeHttpRequest(frpcAdminAddress + "/api/config"); |
||||||
|
frpConfigRequest.addHeaders("Authorization", frpAuthHeaderValue); |
||||||
|
var response = requester.get(frpConfigRequest); |
||||||
|
|
||||||
|
return new Ini(new ByteArrayInputStream(response.getBody())); |
||||||
|
} |
||||||
|
|
||||||
|
public void reloadFrpConfig(Ini ini) throws IOException { |
||||||
|
var output = new ByteArrayOutputStream(); |
||||||
|
ini.store(output); |
||||||
|
|
||||||
|
var uploadRequest = RequestFactory.makeHttpRequest(frpcAdminAddress + "/api/config", output.toByteArray()); |
||||||
|
uploadRequest.addHeaders("Authorization", frpAuthHeaderValue); |
||||||
|
requester.put(uploadRequest); |
||||||
|
var reloadRequest = RequestFactory.makeHttpRequest(frpcAdminAddress + "/api/reload"); |
||||||
|
reloadRequest.addHeaders("Authorization", frpAuthHeaderValue); |
||||||
|
requester.get(reloadRequest); |
||||||
|
} |
||||||
|
|
||||||
|
public JsonNode getProxyStatus(String serviceName, String serviceId) throws IOException { |
||||||
|
var statusRequest = RequestFactory.makeHttpRequest(frpcAdminAddress + "/api/status"); |
||||||
|
statusRequest.addHeaders("Authorization", frpAuthHeaderValue); |
||||||
|
var statusResponse = requester.get(statusRequest); |
||||||
|
|
||||||
|
JsonNode proxies = objectMapper.readTree(statusResponse.getBody()).path("tcp"); |
||||||
|
for (JsonNode proxy : proxies) { |
||||||
|
if (proxy.path("name").asText().equals(serviceName + "-" + serviceId)) { |
||||||
|
return proxy; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return MissingNode.getInstance(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.rpc.config; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
@Data |
||||||
|
public class FrpConfig { |
||||||
|
private String frpcAdminAddress; |
||||||
|
|
||||||
|
private String frpcAdminUsername; |
||||||
|
|
||||||
|
private String frpcAdminPassword; |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.rpc.config; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
@Data |
||||||
|
public class RegisterConfig { |
||||||
|
private String localServicePort; |
||||||
|
|
||||||
|
private String serviceName; |
||||||
|
|
||||||
|
private String consulAddress; |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.rpc.entity; |
||||||
|
|
||||||
|
import lombok.Builder; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
@Builder |
||||||
|
public record RegisterRequestBody(String address, int port, List<HealthCheckOption> checks, String name, String id) { |
||||||
|
@Builder |
||||||
|
public record HealthCheckOption(String http, String interval, String timeout) { |
||||||
|
} |
||||||
|
} |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.graduate.api.http; |
package cn.wustlinghang.wusthelper.internal.graduate.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.graduate.services.LoginService; |
import cn.wustlinghang.wusthelper.internal.graduate.services.LoginService; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.graduate.api.http; |
package cn.wustlinghang.wusthelper.internal.graduate.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.global.Course; |
import cn.wustlinghang.mywust.data.global.Course; |
||||||
import cn.wustlinghang.wusthelper.internal.graduate.services.CourseTableService; |
import cn.wustlinghang.wusthelper.internal.graduate.services.CourseTableService; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.graduate.api.http; |
package cn.wustlinghang.wusthelper.internal.graduate.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.global.Score; |
import cn.wustlinghang.mywust.data.global.Score; |
||||||
import cn.wustlinghang.wusthelper.internal.graduate.services.ScoreService; |
import cn.wustlinghang.wusthelper.internal.graduate.services.ScoreService; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.graduate.api.http; |
package cn.wustlinghang.wusthelper.internal.graduate.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.global.StudentInfo; |
import cn.wustlinghang.mywust.data.global.StudentInfo; |
||||||
import cn.wustlinghang.wusthelper.internal.graduate.services.StudentInfoService; |
import cn.wustlinghang.wusthelper.internal.graduate.services.StudentInfoService; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.graduate.api.http; |
package cn.wustlinghang.wusthelper.internal.graduate.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.graduate.services.TrainingPlanService; |
import cn.wustlinghang.wusthelper.internal.graduate.services.TrainingPlanService; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.graduate.api.http.handler; |
package cn.wustlinghang.wusthelper.internal.graduate.api.http.v1.handler; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
||||||
import jakarta.ws.rs.core.Response; |
import jakarta.ws.rs.core.Response; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.graduate.api.http.handler; |
package cn.wustlinghang.wusthelper.internal.graduate.api.http.v1.handler; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.GraduateRpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.GraduateRpcException; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,6 +1,6 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.interceptor; |
package cn.wustlinghang.wusthelper.internal.graduate.api.http.v1.interceptor; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.undergrad.api.http.handler.BaseExceptionHandler; |
import cn.wustlinghang.wusthelper.internal.graduate.api.http.v1.handler.BaseExceptionHandler; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.response.RpcResponse; |
import cn.wustlinghang.wusthelper.internal.rpc.response.RpcResponse; |
||||||
import com.fasterxml.jackson.databind.ObjectMapper; |
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
import jakarta.ws.rs.WebApplicationException; |
import jakarta.ws.rs.WebApplicationException; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.library.api.http; |
package cn.wustlinghang.wusthelper.internal.library.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.library.services.BookCoverImageUrlService; |
import cn.wustlinghang.wusthelper.internal.library.services.BookCoverImageUrlService; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.library.api.http; |
package cn.wustlinghang.wusthelper.internal.library.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.library.parsed.BookDetail; |
import cn.wustlinghang.mywust.data.library.parsed.BookDetail; |
||||||
import cn.wustlinghang.wusthelper.internal.library.services.BookDetailService; |
import cn.wustlinghang.wusthelper.internal.library.services.BookDetailService; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.library.api.http; |
package cn.wustlinghang.wusthelper.internal.library.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.library.parsed.BookHolding; |
import cn.wustlinghang.mywust.data.library.parsed.BookHolding; |
||||||
import cn.wustlinghang.wusthelper.internal.library.services.BookHoldingService; |
import cn.wustlinghang.wusthelper.internal.library.services.BookHoldingService; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.library.api.http; |
package cn.wustlinghang.wusthelper.internal.library.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.library.services.LoginService; |
import cn.wustlinghang.wusthelper.internal.library.services.LoginService; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.library.api.http; |
package cn.wustlinghang.wusthelper.internal.library.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.library.PagingResult; |
import cn.wustlinghang.mywust.data.library.PagingResult; |
||||||
import cn.wustlinghang.mywust.data.library.origin.CurrentLoanBook; |
import cn.wustlinghang.mywust.data.library.origin.CurrentLoanBook; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.library.api.http; |
package cn.wustlinghang.wusthelper.internal.library.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.library.PagingResult; |
import cn.wustlinghang.mywust.data.library.PagingResult; |
||||||
import cn.wustlinghang.mywust.data.library.origin.HistoryLoanBook; |
import cn.wustlinghang.mywust.data.library.origin.HistoryLoanBook; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.library.api.http; |
package cn.wustlinghang.wusthelper.internal.library.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.library.PagingResult; |
import cn.wustlinghang.mywust.data.library.PagingResult; |
||||||
import cn.wustlinghang.mywust.data.library.origin.BaseLoanBook; |
import cn.wustlinghang.mywust.data.library.origin.BaseLoanBook; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.library.api.http; |
package cn.wustlinghang.wusthelper.internal.library.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.library.PagingResult; |
import cn.wustlinghang.mywust.data.library.PagingResult; |
||||||
import cn.wustlinghang.mywust.data.library.origin.BookSearchResult; |
import cn.wustlinghang.mywust.data.library.origin.BookSearchResult; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.physics.api.http.handler; |
package cn.wustlinghang.wusthelper.internal.library.api.http.v1.handler; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
||||||
import jakarta.ws.rs.core.Response; |
import jakarta.ws.rs.core.Response; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.library.api.http.handler; |
package cn.wustlinghang.wusthelper.internal.library.api.http.v1.handler; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.LibraryRpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.LibraryRpcException; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,6 +1,6 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.physics.api.http.interceptor; |
package cn.wustlinghang.wusthelper.internal.library.api.http.v1.interceptor; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.physics.api.http.handler.BaseExceptionHandler; |
import cn.wustlinghang.wusthelper.internal.library.api.http.v1.handler.BaseExceptionHandler; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.response.RpcResponse; |
import cn.wustlinghang.wusthelper.internal.rpc.response.RpcResponse; |
||||||
import com.fasterxml.jackson.databind.ObjectMapper; |
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
import jakarta.ws.rs.WebApplicationException; |
import jakarta.ws.rs.WebApplicationException; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.physics.api.http; |
package cn.wustlinghang.wusthelper.internal.physics.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.physics.services.LoginService; |
import cn.wustlinghang.wusthelper.internal.physics.services.LoginService; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.physics.api.http; |
package cn.wustlinghang.wusthelper.internal.physics.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.physics.PhysicsCourse; |
import cn.wustlinghang.mywust.data.physics.PhysicsCourse; |
||||||
import cn.wustlinghang.wusthelper.internal.physics.services.CourseTableService; |
import cn.wustlinghang.wusthelper.internal.physics.services.CourseTableService; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.physics.api.http; |
package cn.wustlinghang.wusthelper.internal.physics.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.global.Score; |
import cn.wustlinghang.mywust.data.global.Score; |
||||||
import cn.wustlinghang.wusthelper.internal.physics.services.ScoreService; |
import cn.wustlinghang.wusthelper.internal.physics.services.ScoreService; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.library.api.http.handler; |
package cn.wustlinghang.wusthelper.internal.physics.api.http.v1.handler; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
||||||
import jakarta.ws.rs.core.Response; |
import jakarta.ws.rs.core.Response; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.physics.api.http.handler; |
package cn.wustlinghang.wusthelper.internal.physics.api.http.v1.handler; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.PhysicsRpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.PhysicsRpcException; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,6 +1,6 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.graduate.api.http.interceptor; |
package cn.wustlinghang.wusthelper.internal.physics.api.http.v1.interceptor; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.graduate.api.http.handler.BaseExceptionHandler; |
import cn.wustlinghang.wusthelper.internal.physics.api.http.v1.handler.BaseExceptionHandler; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.response.RpcResponse; |
import cn.wustlinghang.wusthelper.internal.rpc.response.RpcResponse; |
||||||
import com.fasterxml.jackson.databind.ObjectMapper; |
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
import jakarta.ws.rs.WebApplicationException; |
import jakarta.ws.rs.WebApplicationException; |
@ -1,16 +0,0 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad; |
|
||||||
|
|
||||||
import io.quarkus.runtime.Startup; |
|
||||||
import jakarta.annotation.PostConstruct; |
|
||||||
import jakarta.inject.Singleton; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
|
|
||||||
@Slf4j |
|
||||||
@Startup |
|
||||||
@Singleton |
|
||||||
public class Main { |
|
||||||
@PostConstruct |
|
||||||
public void run() { |
|
||||||
log.info("Undergrad service started."); |
|
||||||
} |
|
||||||
} |
|
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad.api.http; |
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.undergrad.services.LoginService; |
import cn.wustlinghang.wusthelper.internal.undergrad.services.LoginService; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad.api.http; |
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.global.Course; |
import cn.wustlinghang.mywust.data.global.Course; |
||||||
import cn.wustlinghang.wusthelper.internal.undergrad.services.CourseTableService; |
import cn.wustlinghang.wusthelper.internal.undergrad.services.CourseTableService; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad.api.http; |
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.undergrad.services.CreditStatusService; |
import cn.wustlinghang.wusthelper.internal.undergrad.services.CreditStatusService; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad.api.http; |
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradExamDelayApiService; |
import cn.wustlinghang.mywust.core.request.service.undergraduate.UndergradExamDelayApiService; |
||||||
import cn.wustlinghang.mywust.data.global.Score; |
import cn.wustlinghang.mywust.data.global.Score; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad.api.http; |
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.undergrad.ExamDelayApplication; |
import cn.wustlinghang.mywust.data.undergrad.ExamDelayApplication; |
||||||
import cn.wustlinghang.wusthelper.internal.undergrad.services.ExamDelayApplicationService; |
import cn.wustlinghang.wusthelper.internal.undergrad.services.ExamDelayApplicationService; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad.api.http; |
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.global.Score; |
import cn.wustlinghang.mywust.data.global.Score; |
||||||
import cn.wustlinghang.wusthelper.internal.undergrad.services.ScoreService; |
import cn.wustlinghang.wusthelper.internal.undergrad.services.ScoreService; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad.api.http; |
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.mywust.data.global.StudentInfo; |
import cn.wustlinghang.mywust.data.global.StudentInfo; |
||||||
import cn.wustlinghang.wusthelper.internal.undergrad.services.StudentInfoService; |
import cn.wustlinghang.wusthelper.internal.undergrad.services.StudentInfoService; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad.api.http; |
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.undergrad.services.TrainingPlanService; |
import cn.wustlinghang.wusthelper.internal.undergrad.services.TrainingPlanService; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.handler; |
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1.handler; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
||||||
import jakarta.ws.rs.core.Response; |
import jakarta.ws.rs.core.Response; |
@ -1,4 +1,4 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.handler; |
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1.handler; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.UndergradRpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.UndergradRpcException; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
import cn.wustlinghang.wusthelper.internal.rpc.exception.RpcException; |
@ -1,6 +1,6 @@ |
|||||||
package cn.wustlinghang.wusthelper.internal.library.api.http.interceptor; |
package cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1.interceptor; |
||||||
|
|
||||||
import cn.wustlinghang.wusthelper.internal.library.api.http.handler.BaseExceptionHandler; |
import cn.wustlinghang.wusthelper.internal.undergrad.api.http.v1.handler.BaseExceptionHandler; |
||||||
import cn.wustlinghang.wusthelper.internal.rpc.response.RpcResponse; |
import cn.wustlinghang.wusthelper.internal.rpc.response.RpcResponse; |
||||||
import com.fasterxml.jackson.databind.ObjectMapper; |
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
import jakarta.ws.rs.WebApplicationException; |
import jakarta.ws.rs.WebApplicationException; |
@ -0,0 +1,107 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.undergrad.rpc; |
||||||
|
|
||||||
|
import cn.hutool.core.thread.ThreadUtil; |
||||||
|
import cn.hutool.core.util.RandomUtil; |
||||||
|
import cn.wustlinghang.mywust.network.Requester; |
||||||
|
import cn.wustlinghang.wusthelper.internal.undergrad.rpc.client.ConsulClient; |
||||||
|
import cn.wustlinghang.wusthelper.internal.undergrad.rpc.client.FrpcClient; |
||||||
|
import cn.wustlinghang.wusthelper.internal.undergrad.rpc.config.RpcConfig; |
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import io.quarkus.runtime.Startup; |
||||||
|
import jakarta.annotation.PostConstruct; |
||||||
|
import jakarta.annotation.PreDestroy; |
||||||
|
import jakarta.enterprise.context.ApplicationScoped; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
@Startup |
||||||
|
@ApplicationScoped |
||||||
|
public class FrpConsulRegister { |
||||||
|
|
||||||
|
@ConfigProperty(name = "quarkus.http.port") |
||||||
|
String localServicePort; |
||||||
|
|
||||||
|
private final String serviceId; |
||||||
|
|
||||||
|
private final RpcConfig rpcConfig; |
||||||
|
|
||||||
|
private final FrpcClient frpcClientClient; |
||||||
|
|
||||||
|
private final ConsulClient consulClient; |
||||||
|
|
||||||
|
private boolean registered = false; |
||||||
|
|
||||||
|
public FrpConsulRegister(RpcConfig rpcConfig, FrpcClient frpcClientClient, Requester requester, |
||||||
|
ObjectMapper objectMapper) { |
||||||
|
this.rpcConfig = rpcConfig; |
||||||
|
|
||||||
|
this.frpcClientClient = frpcClientClient; |
||||||
|
|
||||||
|
this.serviceId = RandomUtil.randomString(8); |
||||||
|
|
||||||
|
this.consulClient = new ConsulClient( |
||||||
|
rpcConfig.getServiceName(), this.serviceId, |
||||||
|
rpcConfig.getConsulAddress(), |
||||||
|
objectMapper, requester); |
||||||
|
} |
||||||
|
|
||||||
|
@PostConstruct |
||||||
|
public void onStartup() { |
||||||
|
ThreadUtil.execute(() -> { |
||||||
|
try { |
||||||
|
log.info("连接frp并注册consul..."); |
||||||
|
this.doRegister(); |
||||||
|
log.info("注册完毕"); |
||||||
|
} catch (Exception e) { |
||||||
|
log.warn("注册服务时发生异常:", e); |
||||||
|
log.warn("不进行转发注册,直接服务"); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(this::onShutdown, "ShutdownHookThread")); |
||||||
|
} |
||||||
|
|
||||||
|
@PreDestroy |
||||||
|
public void onShutdown() { |
||||||
|
try { |
||||||
|
if (this.registered) { |
||||||
|
log.info("注销服务..."); |
||||||
|
this.consulClient.deregister(); |
||||||
|
this.frpcClientClient.removeProxy(); |
||||||
|
log.info("服务注销完毕"); |
||||||
|
this.registered = false; |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
log.warn("注销服务时发生异常:", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void doRegister() throws Exception { |
||||||
|
frpcClientClient.addFrpProxy( |
||||||
|
rpcConfig.getServiceName(), serviceId, |
||||||
|
"127.0.0.1", localServicePort |
||||||
|
); |
||||||
|
|
||||||
|
String remoteAddress; |
||||||
|
String[] remote; |
||||||
|
int retry = 0; |
||||||
|
do { |
||||||
|
// 先睡个0.5秒等待连接成功再获取状态读端口
|
||||||
|
ThreadUtil.sleep(500); |
||||||
|
|
||||||
|
JsonNode proxy = frpcClientClient.getProxyStatus(rpcConfig.getServiceName(), serviceId); |
||||||
|
remoteAddress = proxy.path("remote_addr") |
||||||
|
.asText("127.0.0.1:" + localServicePort); |
||||||
|
remote = remoteAddress.split(":"); |
||||||
|
retry++; |
||||||
|
} while (retry < 3 && remote.length < 2); |
||||||
|
if (retry == 3) { |
||||||
|
throw new Exception("获取frp隧道信息重试次数过多,请手动添加隧道和注册中心"); |
||||||
|
} |
||||||
|
|
||||||
|
this.consulClient.register(remoteAddress, Integer.parseInt(remote[1])); |
||||||
|
this.registered = true; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.undergrad.rpc.client; |
||||||
|
|
||||||
|
import cn.wustlinghang.mywust.network.request.RequestFactory; |
||||||
|
import cn.wustlinghang.mywust.network.Requester; |
||||||
|
import cn.wustlinghang.mywust.network.entitys.HttpResponse; |
||||||
|
import cn.wustlinghang.wusthelper.internal.undergrad.rpc.entity.RegisterRequestBody; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import com.google.common.collect.Lists; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
public class ConsulClient { |
||||||
|
private final String serviceId; |
||||||
|
private final String serviceName; |
||||||
|
private final String consulAddress; |
||||||
|
private final ObjectMapper objectMapper; |
||||||
|
private final Requester requester; |
||||||
|
|
||||||
|
public ConsulClient(String serviceName, String serviceId, String consulAddress, |
||||||
|
ObjectMapper objectMapper, Requester requester) { |
||||||
|
this.serviceId = serviceId; |
||||||
|
this.serviceName = serviceName; |
||||||
|
this.consulAddress = consulAddress; |
||||||
|
|
||||||
|
this.objectMapper = objectMapper; |
||||||
|
this.requester = requester; |
||||||
|
} |
||||||
|
|
||||||
|
public void register(String remoteAddress, int remotePort) throws IOException { |
||||||
|
var checksItem = RegisterRequestBody.ChecksItem.builder() |
||||||
|
.http("http://" + remoteAddress + "/health") |
||||||
|
.interval("3s") |
||||||
|
.build(); |
||||||
|
|
||||||
|
var registerRequestBody = RegisterRequestBody.builder() |
||||||
|
.id(serviceId) |
||||||
|
.name(serviceName) |
||||||
|
.address("127.0.0.1") |
||||||
|
.port(remotePort) |
||||||
|
.checks(Lists.newArrayList(checksItem)) |
||||||
|
.build(); |
||||||
|
|
||||||
|
byte[] registerRequestData = objectMapper.writeValueAsBytes(registerRequestBody); |
||||||
|
var registerRequest = RequestFactory.makeHttpRequest(consulAddress + "/v1/agent/service/register", registerRequestData); |
||||||
|
var registerResponse = requester.put(registerRequest); |
||||||
|
if (registerResponse.getStatusCode() != HttpResponse.HTTP_OK) { |
||||||
|
log.warn("注册中心注册不成功,请手动注册"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void deregister() throws IOException { |
||||||
|
var deregisterRequest = RequestFactory.makeHttpRequest(consulAddress + "/v1/agent/service/deregister/" + serviceId); |
||||||
|
var deregisterResponse = requester.put(deregisterRequest); |
||||||
|
if (deregisterResponse.getStatusCode() != HttpResponse.HTTP_OK) { |
||||||
|
log.warn("服务注销不成功,请手动注册"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,100 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.undergrad.rpc.client; |
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64; |
||||||
|
import cn.wustlinghang.mywust.network.request.RequestFactory; |
||||||
|
import cn.wustlinghang.mywust.network.Requester; |
||||||
|
import cn.wustlinghang.wusthelper.internal.undergrad.rpc.config.FrpConfig; |
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import com.fasterxml.jackson.databind.node.MissingNode; |
||||||
|
import jakarta.inject.Singleton; |
||||||
|
import org.ini4j.Ini; |
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream; |
||||||
|
import java.io.ByteArrayOutputStream; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
@Singleton |
||||||
|
public class FrpcClient { |
||||||
|
|
||||||
|
private final String frpcAdminAddress; |
||||||
|
|
||||||
|
private final String frpAuthHeaderValue; |
||||||
|
|
||||||
|
private final Requester requester; |
||||||
|
|
||||||
|
private final ObjectMapper objectMapper; |
||||||
|
|
||||||
|
private String frpProxyName; |
||||||
|
|
||||||
|
public FrpcClient(FrpConfig frpConfig, |
||||||
|
Requester requester, ObjectMapper objectMapper) { |
||||||
|
|
||||||
|
this.frpcAdminAddress = frpConfig.getFrpcAdminAddress(); |
||||||
|
|
||||||
|
this.requester = requester; |
||||||
|
this.objectMapper = objectMapper; |
||||||
|
|
||||||
|
String username = frpConfig.getFrpcAdminUsername(); |
||||||
|
String password = frpConfig.getFrpcAdminPassword(); |
||||||
|
this.frpAuthHeaderValue = "Basic " + Base64.encode(username + ":" + password); |
||||||
|
} |
||||||
|
|
||||||
|
public void addFrpProxy(String serviceName, String serviceId, String localAddress, String localPort) |
||||||
|
throws IOException { |
||||||
|
this.frpProxyName = String.format("%s-%s", serviceName, serviceId); |
||||||
|
|
||||||
|
Ini ini = this.getFrpConfig(); |
||||||
|
ini.put(frpProxyName, "type", "tcp"); |
||||||
|
ini.put(frpProxyName, "local_address", localAddress); |
||||||
|
ini.put(frpProxyName, "local_port", localPort); |
||||||
|
ini.put(frpProxyName, "use_compression", "true"); |
||||||
|
|
||||||
|
var output = new ByteArrayOutputStream(); |
||||||
|
ini.store(output); |
||||||
|
|
||||||
|
this.reloadFrpConfig(ini); |
||||||
|
} |
||||||
|
|
||||||
|
public void removeProxy() throws IOException { |
||||||
|
Ini ini = this.getFrpConfig(); |
||||||
|
ini.remove(this.frpProxyName); |
||||||
|
|
||||||
|
this.reloadFrpConfig(ini); |
||||||
|
} |
||||||
|
|
||||||
|
public Ini getFrpConfig() throws IOException { |
||||||
|
var frpConfigRequest = RequestFactory.makeHttpRequest(frpcAdminAddress + "/api/config"); |
||||||
|
frpConfigRequest.addHeaders("Authorization", frpAuthHeaderValue); |
||||||
|
var response = requester.get(frpConfigRequest); |
||||||
|
|
||||||
|
return new Ini(new ByteArrayInputStream(response.getBody())); |
||||||
|
} |
||||||
|
|
||||||
|
public void reloadFrpConfig(Ini ini) throws IOException { |
||||||
|
var output = new ByteArrayOutputStream(); |
||||||
|
ini.store(output); |
||||||
|
|
||||||
|
var uploadRequest = RequestFactory.makeHttpRequest(frpcAdminAddress + "/api/config", output.toByteArray()); |
||||||
|
uploadRequest.addHeaders("Authorization", frpAuthHeaderValue); |
||||||
|
requester.put(uploadRequest); |
||||||
|
var reloadRequest = RequestFactory.makeHttpRequest(frpcAdminAddress + "/api/reload"); |
||||||
|
reloadRequest.addHeaders("Authorization", frpAuthHeaderValue); |
||||||
|
requester.get(reloadRequest); |
||||||
|
} |
||||||
|
|
||||||
|
public JsonNode getProxyStatus(String serviceName, String serviceId) throws IOException { |
||||||
|
var statusRequest = RequestFactory.makeHttpRequest(frpcAdminAddress + "/api/status"); |
||||||
|
statusRequest.addHeaders("Authorization", frpAuthHeaderValue); |
||||||
|
var statusResponse = requester.get(statusRequest); |
||||||
|
|
||||||
|
JsonNode proxies = objectMapper.readTree(statusResponse.getBody()).path("tcp"); |
||||||
|
for (JsonNode proxy : proxies) { |
||||||
|
if (proxy.path("name").asText().equals(serviceName + "-" + serviceId)) { |
||||||
|
return proxy; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return MissingNode.getInstance(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.undergrad.rpc.config; |
||||||
|
|
||||||
|
import jakarta.inject.Singleton; |
||||||
|
import jakarta.ws.rs.DefaultValue; |
||||||
|
import lombok.Data; |
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty; |
||||||
|
|
||||||
|
@Data |
||||||
|
@Singleton |
||||||
|
public class FrpConfig { |
||||||
|
@DefaultValue("http://127.0.0.1:7400") |
||||||
|
@ConfigProperty(name = "frpc.admin-api.address") |
||||||
|
String frpcAdminAddress; |
||||||
|
|
||||||
|
@DefaultValue("") |
||||||
|
@ConfigProperty(name = "frpc.admin.username") |
||||||
|
String frpcAdminUsername; |
||||||
|
|
||||||
|
@DefaultValue("") |
||||||
|
@ConfigProperty(name = "frpc.admin.password") |
||||||
|
String frpcAdminPassword; |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.undergrad.rpc.config; |
||||||
|
|
||||||
|
import jakarta.inject.Singleton; |
||||||
|
import jakarta.ws.rs.DefaultValue; |
||||||
|
import lombok.Data; |
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty; |
||||||
|
|
||||||
|
@Data |
||||||
|
@Singleton |
||||||
|
public class RpcConfig { |
||||||
|
@DefaultValue("default.service") |
||||||
|
@ConfigProperty(name = "rpc.service.name") |
||||||
|
String serviceName; |
||||||
|
|
||||||
|
@DefaultValue("http://127.0.0.1:8500") |
||||||
|
@ConfigProperty(name = "rpc.register.consul-api.address") |
||||||
|
String consulAddress; |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.undergrad.rpc.entity; |
||||||
|
|
||||||
|
import lombok.Builder; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
@Builder |
||||||
|
public record RegisterRequestBody(String address, int port, List<ChecksItem> checks, String name, String id) { |
||||||
|
|
||||||
|
@Builder |
||||||
|
public record ChecksItem(String http, String interval) { |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
package cn.wustlinghang.wusthelper.internal.undergrad.rpc.health; |
||||||
|
|
||||||
|
import jakarta.ws.rs.GET; |
||||||
|
import jakarta.ws.rs.Path; |
||||||
|
import jakarta.ws.rs.core.Response; |
||||||
|
|
||||||
|
@Path("/health") |
||||||
|
public class HealthCheck { |
||||||
|
private static final Response successResponse = Response.accepted().status(200).build(); |
||||||
|
|
||||||
|
@GET |
||||||
|
@Path("/") |
||||||
|
public Response response() {return successResponse;} |
||||||
|
} |
Loading…
Reference in new issue