1. 添加缓存

2. 优化解析架构
3. 优化核心模块
This commit is contained in:
qaiu
2024-09-15 06:53:11 +08:00
parent af5cba5ed6
commit 30a53dd47c
40 changed files with 1056 additions and 409 deletions

View File

@@ -1,13 +1,13 @@
package cn.qaiu.lz.web.http;
import cn.qaiu.parser.IPanTool;
import cn.qaiu.parser.impl.EcTool;
import cn.qaiu.parser.impl.QQTool;
import cn.qaiu.lz.common.util.URLParamUtil;
import cn.qaiu.lz.web.service.CacheService;
import cn.qaiu.parser.PanDomainTemplate;
import cn.qaiu.vx.core.annotaions.RouteHandler;
import cn.qaiu.vx.core.annotaions.RouteMapping;
import cn.qaiu.vx.core.enums.RouteMethod;
import cn.qaiu.vx.core.util.AsyncServiceUtil;
import cn.qaiu.vx.core.util.ResponseUtil;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpServerRequest;
@@ -24,33 +24,27 @@ import lombok.extern.slf4j.Slf4j;
@RouteHandler("/")
public class ServerApi {
@RouteMapping(value = "/parser", method = RouteMethod.GET, order = 4)
public Future<Void> parse(HttpServerResponse response, HttpServerRequest request, String url, String pwd) {
private final CacheService cacheService = AsyncServiceUtil.getAsyncServiceInstance(CacheService.class);
@RouteMapping(value = "/parser", method = RouteMethod.GET, order = 4)
public Future<Void> parse(HttpServerResponse response, HttpServerRequest request, String pwd) {
Promise<Void> promise = Promise.promise();
if (url.contains(EcTool.SHARE_URL_PREFIX)) {
// 默认读取Url参数会被截断手动获取一下其他参数
url = EcTool.SHARE_URL_PREFIX + request.getParam("data");
}
if (url.contains(QQTool.SHARE_URL_PREFIX)) {
// 默认读取Url参数会被截断手动获取一下其他参数
url = url + "&key=" + request.getParam("key") +
"&code=" + request.getParam("code") + "&k=" + request.getParam("k") +
"&fweb=" + request.getParam("fweb") + "&cl=" + request.getParam("cl");
}
IPanTool.shareURLPrefixMatching(url, pwd).parse()
.onSuccess(resUrl -> ResponseUtil.redirect(response, resUrl, promise))
String url = URLParamUtil.parserParams(request);
PanDomainTemplate panDomainTemplate = PanDomainTemplate.fromShareUrl(url).setShareLinkInfoPwd(pwd);
cacheService.getAndSaveCachedShareLink(panDomainTemplate)
.onSuccess(res -> ResponseUtil.redirect(
response.putHeader("nfd-cache-hit", res.getCacheHit().toString())
.putHeader("nfd-cache-expires", res.getExpires()),
res.getDirectLink(), promise))
.onFailure(t -> promise.fail(t.fillInStackTrace()));
return promise.future();
}
@RouteMapping(value = "/json/parser", method = RouteMethod.GET, order = 3)
public Future<String> parseJson(HttpServerRequest request, String url, String pwd) {
if (url.contains(EcTool.SHARE_URL_PREFIX)) {
// 默认读取Url参数会被截断手动获取一下其他参数
url = EcTool.SHARE_URL_PREFIX + request.getParam("data");
}
return IPanTool.shareURLPrefixMatching(url, pwd).parse();
public Future<String> parseJson(HttpServerRequest request, String pwd) {
String url = URLParamUtil.parserParams(request);
return PanDomainTemplate.fromShareUrl(url).setShareLinkInfoPwd(pwd).createTool().parse();
}
@RouteMapping(value = "/json/:type/:key", method = RouteMethod.GET, order = 2)
@@ -61,7 +55,8 @@ public class ServerApi {
key = keys[0];
code = keys[1];
}
return IPanTool.typeMatching(type, key, code).parse();
return PanDomainTemplate.fromShortName(type)
.generateShareLink(key).setShareLinkInfoPwd(code).createTool().parse();
}
@RouteMapping(value = "/:type/:key", method = RouteMethod.GET, order = 1)
@@ -74,8 +69,16 @@ public class ServerApi {
code = keys[1];
}
IPanTool.typeMatching(type, key, code).parse()
.onSuccess(resUrl -> ResponseUtil.redirect(response, resUrl, promise))
PanDomainTemplate panDomainTemplate = PanDomainTemplate
.fromShortName(type)
.generateShareLink(key)
.setShareLinkInfoPwd(code);
cacheService.getAndSaveCachedShareLink(panDomainTemplate)
.onSuccess(res -> ResponseUtil.redirect(
response.putHeader("nfd-cache-hit", res.getCacheHit().toString())
.putHeader("nfd-cache-expires", res.getExpires()),
res.getDirectLink(), promise))
.onFailure(t -> promise.fail(t.fillInStackTrace()));
return promise.future();
}

View File

@@ -0,0 +1,56 @@
package cn.qaiu.lz.web.model;
import cn.qaiu.db.ddl.Length;
import cn.qaiu.db.ddl.Table;
import cn.qaiu.db.ddl.TableGenIgnore;
import cn.qaiu.lz.common.ToJson;
import io.vertx.codegen.annotations.DataObject;
import io.vertx.core.json.JsonObject;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author <a href="https://qaiu.top">QAIU</a>
* @date 2024/9/11 16:06
*/
@Table(value = "cache_link_info", keyFields = "share_key")
@Data
@DataObject
@NoArgsConstructor
public class CacheLinkInfo implements ToJson {
/**
* 缓存key: type@ShareKey; e.g. lz@xxxx
*/
@Length(varcharSize = 4096)
private String shareKey;
/**
* 解析后的直链
*/
@Length(varcharSize = 4096)
private String directLink;
/**
* 是否命中缓存
*/
@TableGenIgnore
private Boolean cacheHit;
/**
* 到期时间 yyyy-MM-dd hh:mm:ss
*/
@TableGenIgnore
private String expires;
/**
* 有效期
*/
private Long expiration;
// 使用 JsonObject 构造
public CacheLinkInfo(JsonObject json) {
CacheLinkInfoConverter.fromJson(json, this);
}
}

View File

@@ -0,0 +1,23 @@
package cn.qaiu.lz.web.model;
import io.vertx.core.json.JsonObject;
// CacheLinkInfoConverter.java
public class CacheLinkInfoConverter {
public static void fromJson(JsonObject json, CacheLinkInfo obj) {
if (json.containsKey("shareKey")) {
obj.setShareKey(json.getString("shareKey"));
}
if (json.containsKey("directLink")) {
obj.setDirectLink(json.getString("directLink"));
}
if (json.containsKey("expires")) {
obj.setExpires(json.getString("expires"));
}
if (json.containsKey("expiration")) {
obj.setExpiration(json.getLong("expiration"));
}
obj.setCacheHit(json.getBoolean("cacheHit", false));
}
}

View File

@@ -0,0 +1,17 @@
package cn.qaiu.lz.web.service;
import cn.qaiu.lz.web.model.CacheLinkInfo;
import cn.qaiu.parser.PanDomainTemplate;
import cn.qaiu.vx.core.base.BaseAsyncService;
import io.vertx.codegen.annotations.ProxyGen;
import io.vertx.core.Future;
/**
* @author <a href="https://qaiu.top">QAIU</a>
* @date 2024/9/12 8:26
*/
@ProxyGen
public interface CacheService extends BaseAsyncService {
Future<CacheLinkInfo> getAndSaveCachedShareLink(PanDomainTemplate shareLinkInfo);
}

View File

@@ -19,4 +19,5 @@ public interface DbService extends BaseAsyncService {
Future<JsonObject> sayOk2(String data, UserInfo holder);
Future<StatisticsInfo> getStatisticsInfo();
}

View File

@@ -1,18 +0,0 @@
package cn.qaiu.lz.web.service;
import cn.qaiu.vx.core.util.CastUtil;
import java.lang.reflect.Proxy;
/**
* JDK代理类工厂
*/
public class JdkProxyFactory {
public static <T> T getProxy(T target) {
return CastUtil.cast(Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new ServiceJdkProxy<>(target))
);
}
}

View File

@@ -0,0 +1,65 @@
package cn.qaiu.lz.web.service.impl;
import cn.qaiu.entity.ShareLinkInfo;
import cn.qaiu.lz.common.cache.CacheConfigLoader;
import cn.qaiu.lz.common.cache.CacheManager;
import cn.qaiu.lz.web.model.CacheLinkInfo;
import cn.qaiu.lz.web.service.CacheService;
import cn.qaiu.parser.PanDomainTemplate;
import cn.qaiu.vx.core.annotaions.Service;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.json.JsonObject;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.util.Date;
@Service
public class CacheServiceImpl implements CacheService {
private final CacheManager cacheManager = new CacheManager();
@Override
public Future<CacheLinkInfo> getAndSaveCachedShareLink(PanDomainTemplate template) {
Promise<CacheLinkInfo> promise = Promise.promise();
// 构建组合的缓存key
ShareLinkInfo shareLinkInfo = template.getShareLinkInfo();
String cacheKey = generateCacheKey(shareLinkInfo.getType(), shareLinkInfo.getShareKey());
// 尝试从缓存中获取
cacheManager.get(cacheKey).onSuccess(result -> {
// 判断是否已过期
// 未命中或者过期
if (!result.getCacheHit() || result.getExpiration() < System.currentTimeMillis()) {
template.createTool().parse().onSuccess(redirectUrl -> {
long expires = System.currentTimeMillis() +
CacheConfigLoader.getDuration(shareLinkInfo.getType()) * 60 * 1000;
result.setDirectLink(redirectUrl);
// result.setExpires(generateDate(expires));
promise.complete(result);
// 更新缓存
// 将直链存储到缓存
CacheLinkInfo cacheLinkInfo = new CacheLinkInfo(JsonObject.of(
"directLink", redirectUrl,
"expiration", expires,
"shareKey", cacheKey
));
cacheManager.cacheShareLink(cacheLinkInfo).onFailure(Throwable::printStackTrace);
}).onFailure(promise::fail);
} else {
result.setExpires(generateDate(result.getExpiration()));
promise.complete(result);
}
}).onFailure(t -> promise.fail(t.fillInStackTrace()));
return promise.future();
}
private String generateCacheKey(String type, String shareKey) {
// 将type和shareKey组合成一个字符串作为缓存key
return type + ":" + shareKey;
}
private String generateDate(Long ts) {
return DateFormatUtils.format(new Date(ts), "yyyy-MM-dd hh:mm:ss");
}
}