直链API添加文件信息

修复蓝奏目录文件大小处理报错问题 #120
This commit is contained in:
q
2025-08-19 18:56:42 +08:00
parent 2092230a61
commit a66bf84381
13 changed files with 382 additions and 32 deletions

View File

@@ -8,7 +8,11 @@ public interface ConfigConstant {
String SERVER = "server"; String SERVER = "server";
String CACHE = "cache"; String CACHE = "cache";
String PROXY_SERVER = "proxy-server";
String PROXY = "proxy"; String PROXY = "proxy";
String AUTHS = "auths";
String GLOBAL_CONFIG = "globalConfig"; String GLOBAL_CONFIG = "globalConfig";
String CUSTOM_CONFIG = "customConfig"; String CUSTOM_CONFIG = "customConfig";
String ASYNC_SERVICE_INSTANCES = "asyncServiceInstances"; String ASYNC_SERVICE_INSTANCES = "asyncServiceInstances";

View File

@@ -72,6 +72,9 @@ public class FileInfo {
//预览地址 //预览地址
private String previewUrl; private String previewUrl;
// 文件hash默认类型为md5
private String hash;
/** /**
* 扩展参数 * 扩展参数
*/ */
@@ -210,6 +213,15 @@ public class FileInfo {
return this; return this;
} }
public String getHash() {
return hash;
}
public FileInfo setHash(String hash) {
this.hash = hash;
return this;
}
public Map<String, Object> getExtParameters() { public Map<String, Object> getExtParameters() {
return extParameters; return extParameters;
} }

View File

@@ -225,7 +225,6 @@ public class LzTool extends PanBase {
.setParserUrl(getDomainName() + "/d/" + panType + "/" + id) .setParserUrl(getDomainName() + "/d/" + panType + "/" + id)
.setPreviewUrl(String.format("%s/v2/view/%s/%s", getDomainName(), .setPreviewUrl(String.format("%s/v2/view/%s/%s", getDomainName(),
shareLinkInfo.getType(), id)); shareLinkInfo.getType(), id));
;
log.debug("文件信息: {}", fileInfo); log.debug("文件信息: {}", fileInfo);
list.add(fileInfo); list.add(fileInfo);
}); });

View File

@@ -4,10 +4,13 @@ import cn.qaiu.WebClientVertxInit;
import cn.qaiu.entity.FileInfo; import cn.qaiu.entity.FileInfo;
import cn.qaiu.entity.ShareLinkInfo; import cn.qaiu.entity.ShareLinkInfo;
import cn.qaiu.parser.PanBase; import cn.qaiu.parser.PanBase;
import cn.qaiu.util.FileSizeConverter;
import cn.qaiu.util.HeaderUtils; import cn.qaiu.util.HeaderUtils;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.MultiMap; import io.vertx.core.MultiMap;
import io.vertx.core.Promise; import io.vertx.core.Promise;
import io.vertx.core.json.JsonObject;
import io.vertx.core.json.pointer.JsonPointer;
import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.client.WebClient;
import io.vertx.uritemplate.UriTemplate; import io.vertx.uritemplate.UriTemplate;
@@ -75,7 +78,18 @@ public class PvyyTool extends PanBase {
.putHeaders(header) .putHeaders(header)
.send().onSuccess(res -> { .send().onSuccess(res -> {
try { try {
String id = asJson(res).getJsonObject("data").getJsonObject("data").getString("id"); JsonObject resJson = asJson(res);
if (!resJson.containsKey("code") || resJson.getInteger("code") != 0) {
fail("获取文件信息失败: " + resJson.getString("message"));
return;
}
JsonObject fileData = resJson.getJsonObject("data").getJsonObject("data");
if (fileData == null) {
fail("文件数据为空");
return;
}
setFileInfo(fileData);
String id = fileData.getString("id");
client.getAbs(UriTemplate.of(apiUrl)) client.getAbs(UriTemplate.of(apiUrl))
.setTemplateParam("key", shareLinkInfo.getShareKey()) .setTemplateParam("key", shareLinkInfo.getShareKey())
@@ -97,6 +111,23 @@ public class PvyyTool extends PanBase {
}); });
} }
private void setFileInfo(JsonObject fileData) {
JsonObject attributes = fileData.getJsonObject("attributes");
JsonObject user = (JsonObject)(JsonPointer.from("/relationships/user/data").queryJson(fileData));
int downCount = (Integer)(JsonPointer.from("/relationships/shared/data/attributes/down").queryJson(fileData));
String filesize = attributes.getString("filesize");
FileInfo fileInfo = new FileInfo()
.setFileId(fileData.getString("id"))
.setFileName(attributes.getString("basename"))
.setFileType(attributes.getString("mimetype"))
.setPanType(shareLinkInfo.getType())
.setCreateBy(user.getString("email"))
.setDownloadCount(downCount)
.setSize(FileSizeConverter.convertToBytes(filesize))
.setSizeStr(filesize);
shareLinkInfo.getOtherParam().put("fileInfo", fileInfo);
}
private static final String DIR_API = "https://www.vyuyun.com/apiv1/share/folders/809Pt6/bMjnUg?sort=created_at&direction=DESC&password={pwd}"; private static final String DIR_API = "https://www.vyuyun.com/apiv1/share/folders/809Pt6/bMjnUg?sort=created_at&direction=DESC&password={pwd}";
private static final String SHARE_TYPE_API = "https://www.vyuyun.com/apiv1/share/info/{key}?password={pwd}"; private static final String SHARE_TYPE_API = "https://www.vyuyun.com/apiv1/share/info/{key}?password={pwd}";
// //

View File

@@ -7,8 +7,17 @@ public class FileSizeConverter {
throw new IllegalArgumentException("Invalid file size string"); throw new IllegalArgumentException("Invalid file size string");
} }
sizeStr = sizeStr.trim().toUpperCase(); sizeStr = sizeStr.replace(",","").trim().toUpperCase();
char unit = sizeStr.charAt(sizeStr.length() - 1); // 判断是2位单位还是1位单位
// 判断单位是否为2位
int unitIndex = sizeStr.length() - 1;
char unit = sizeStr.charAt(unitIndex);
if (Character.isLetter(sizeStr.charAt(unitIndex - 1))) {
unit = sizeStr.charAt(unitIndex - 1);
sizeStr = sizeStr.substring(0, unitIndex - 1);
} else {
sizeStr = sizeStr.substring(0, unitIndex);
}
double size = Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 1)); double size = Double.parseDouble(sizeStr.substring(0, sizeStr.length() - 1));
return switch (unit) { return switch (unit) {

View File

@@ -11,7 +11,7 @@
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.3.1", "@element-plus/icons-vue": "^2.3.1",
"@vueuse/core": "^11.2.0", "@vueuse/core": "^11.2.0",
"axios": "^1.7.4", "axios": "1.11.0",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"element-plus": "^2.8.7", "element-plus": "^2.8.7",

View File

@@ -153,6 +153,13 @@
} }
} }
</style> </style>
<script>
const saved = localStorage.getItem('isDarkMode') === 'true'
const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches
if (saved || (!saved && systemDark)) {
document.body.classList.add('dark-theme')
}
</script>
</head> </head>
<body> <body>
<div id="app"> <div id="app">

View File

@@ -1,5 +1,5 @@
<template> <template>
<div id="app" :class="{ 'dark-theme': isDarkMode }"> <div id="app" v-cloak :class="{ 'dark-theme': isDarkMode }">
<!-- <el-dialog <!-- <el-dialog
v-model="showRiskDialog" v-model="showRiskDialog"
title="使用本网站您应改同意" title="使用本网站您应改同意"
@@ -293,6 +293,9 @@ export default {
// 主题切换 // 主题切换
handleThemeChange(isDark) { handleThemeChange(isDark) {
this.isDarkMode = isDark this.isDarkMode = isDark
document.body.classList.toggle('dark-theme', isDark)
window.localStorage.setItem('isDarkMode', isDark)
}, },
// 验证输入 // 验证输入
@@ -600,6 +603,8 @@ export default {
</script> </script>
<style> <style>
[v-cloak] { display: none; }
body { body {
background-color: #f5f7fa; background-color: #f5f7fa;
color: #2c3e50; color: #2c3e50;

View File

@@ -3,29 +3,38 @@ package cn.qaiu.lz.common.cache;
import cn.qaiu.db.pool.JDBCPoolInit; import cn.qaiu.db.pool.JDBCPoolInit;
import cn.qaiu.db.pool.JDBCType; import cn.qaiu.db.pool.JDBCType;
import cn.qaiu.lz.web.model.CacheLinkInfo; import cn.qaiu.lz.web.model.CacheLinkInfo;
import cn.qaiu.lz.web.model.PanFileInfo;
import cn.qaiu.lz.web.model.PanFileInfoRowMapper;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.Promise; import io.vertx.core.Promise;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.jdbcclient.JDBCPool; import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import io.vertx.sqlclient.templates.SqlTemplate; import io.vertx.sqlclient.templates.SqlTemplate;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class CacheManager { public class CacheManager {
private final JDBCPool jdbcPool = JDBCPoolInit.instance().getPool(); private final Pool jdbcPool = JDBCPoolInit.instance().getPool();
private final JDBCType jdbcType = JDBCPoolInit.instance().getType(); private final JDBCType jdbcType = JDBCPoolInit.instance().getType();
private static final Logger LOGGER = LoggerFactory.getLogger(CacheManager.class); private static final Logger LOGGER = LoggerFactory.getLogger(CacheManager.class);
public Future<CacheLinkInfo> get(String cacheKey) { public Future<CacheLinkInfo> get(String cacheKey) {
String sql = "SELECT share_key as shareKey, direct_link as directLink, expiration FROM cache_link_info WHERE share_key = #{share_key}"; String sql = "SELECT share_key as shareKey, direct_link as directLink, expiration FROM cache_link_info WHERE share_key = #{share_key}";
String sql2 = "SELECT * FROM pan_file_info WHERE share_key = #{share_key}";
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("share_key", cacheKey); params.put("share_key", cacheKey);
Promise<CacheLinkInfo> promise = Promise.promise(); Promise<CacheLinkInfo> promise = Promise.promise();
Future<RowSet<PanFileInfo>> execute = SqlTemplate.forQuery(jdbcPool, sql2)
.mapTo(PanFileInfoRowMapper.INSTANCE)
.execute(params);
SqlTemplate.forQuery(jdbcPool, sql) SqlTemplate.forQuery(jdbcPool, sql)
.mapTo(CacheLinkInfo.class) .mapTo(CacheLinkInfo.class)
.execute(params) .execute(params)
@@ -34,10 +43,18 @@ public class CacheManager {
if (rows.size() > 0) { if (rows.size() > 0) {
cacheHit = rows.iterator().next(); cacheHit = rows.iterator().next();
cacheHit.setCacheHit(true); cacheHit.setCacheHit(true);
execute.onSuccess(r2 -> {
if (r2.size() > 0) {
cacheHit.setFileInfo(r2.iterator().next().toFileInfo());
}
promise.complete(cacheHit);
}).onFailure(e -> {
promise.complete(cacheHit);
});
} else { } else {
cacheHit = new CacheLinkInfo(JsonObject.of("cacheHit", false, "shareKey", cacheKey)); cacheHit = new CacheLinkInfo(JsonObject.of("cacheHit", false, "shareKey", cacheKey));
promise.complete(cacheHit);
} }
promise.complete(cacheHit);
}).onFailure(e->{ }).onFailure(e->{
promise.fail(e); promise.fail(e);
LOGGER.error("cache get:", e); LOGGER.error("cache get:", e);
@@ -47,7 +64,7 @@ public class CacheManager {
// 插入或更新缓存数据 // 插入或更新缓存数据
public Future<Void> cacheShareLink(CacheLinkInfo cacheLinkInfo) { public void cacheShareLink(CacheLinkInfo cacheLinkInfo) {
String sql; String sql;
if (jdbcType == JDBCType.MySQL) { if (jdbcType == JDBCType.MySQL) {
sql = """ sql = """
@@ -63,12 +80,53 @@ public class CacheManager {
"VALUES (#{shareKey}, #{directLink}, #{expiration})"; "VALUES (#{shareKey}, #{directLink}, #{expiration})";
} }
// 直接传递 CacheLinkInfo 实体类 // 直接传递 CacheLinkInfo 实体类
return SqlTemplate.forUpdate(jdbcPool, sql) SqlTemplate.forUpdate(jdbcPool, sql)
.mapFrom(CacheLinkInfo.class) // 将实体类映射为 Tuple 参数 .mapFrom(CacheLinkInfo.class) // 将实体类映射为 Tuple 参数
.execute(cacheLinkInfo) .execute(cacheLinkInfo).onSuccess(result -> {
.mapEmpty(); if (result.rowCount() > 0) {
LOGGER.debug("Cache link info updated for shareKey: {}", cacheLinkInfo.getShareKey());
} else {
LOGGER.warn("No rows affected when updating cache link info for shareKey: {}", cacheLinkInfo.getShareKey());
}
}).onFailure(Throwable::printStackTrace);
if (cacheLinkInfo.getFileInfo() != null) {
String sql2 = """
INSERT IGNORE INTO pan_file_info (
share_key, file_name, file_id, file_icon, size, size_str, file_type,
file_path, create_time, update_time, create_by, description, download_count,
pan_type, parser_url, preview_url, hash
) VALUES (
#{shareKey}, #{fileName}, #{fileId}, #{fileIcon}, #{size}, #{sizeStr}, #{fileType},
#{filePath}, #{createTime}, #{updateTime}, #{createBy}, #{description}, #{downloadCount},
#{panType}, #{parserUrl}, #{previewUrl}, #{hash}
);
""";
// 判断文件信息是否缓存
SqlTemplate
.forQuery(jdbcPool, "SELECT count(1) AS count FROM pan_file_info WHERE share_key = #{share_key};")
.mapTo(Row::toJson)
.execute(Collections.singletonMap("share_key", cacheLinkInfo.getShareKey()))
.onSuccess(rows -> {
JsonObject row = rows.iterator().next();
int count = row.getInteger("count");
if (count == 0) {
// 没有缓存,执行插入
PanFileInfo fileInfo = PanFileInfo.fromFileInfo(cacheLinkInfo.getFileInfo());
fileInfo.setShareKey(cacheLinkInfo.getShareKey());
SqlTemplate.forUpdate(jdbcPool, sql2)
.mapFrom(PanFileInfo.class) // 将实体类映射为 Tuple 参数
.execute(fileInfo).onSuccess(result -> {
if (result.rowCount() > 0) {
LOGGER.debug("Pan file info inserted for shareKey: {}", cacheLinkInfo.getShareKey());
} else {
LOGGER.warn("No rows affected when inserting pan file info for shareKey: {}", cacheLinkInfo.getShareKey());
}
}).onFailure(Throwable::printStackTrace);
}
});
}
} }
// 写入网盘厂商API解析次数 // 写入网盘厂商API解析次数

View File

@@ -1,7 +1,13 @@
package cn.qaiu.lz.common.util; package cn.qaiu.lz.common.util;
import cn.qaiu.parser.ParserCreate;
import cn.qaiu.vx.core.util.ConfigConstant;
import cn.qaiu.vx.core.util.SharedDataUtil;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.MultiMap; import io.vertx.core.MultiMap;
import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.json.JsonObject;
import io.vertx.core.shareddata.LocalMap;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@@ -72,4 +78,42 @@ public class URLParamUtil {
return urlBuilder.toString(); return urlBuilder.toString();
} }
/**
* 添加共享链接的其他参数到ParserCreate对象中
* @param parserCreate ParserCreate对象包含共享链接信息
*/
public static void addParam(ParserCreate parserCreate) {
LocalMap<Object, Object> localMap = VertxHolder.getVertxInstance().sharedData()
.getLocalMap(ConfigConstant.LOCAL);
String type = parserCreate.getShareLinkInfo().getType();
if (localMap.containsKey(ConfigConstant.PROXY)) {
JsonObject proxy = (JsonObject) localMap.get(ConfigConstant.PROXY);
if (proxy.containsKey(type)) {
parserCreate.getShareLinkInfo().getOtherParam().put(ConfigConstant.PROXY, proxy.getJsonObject(type));
}
}
if (localMap.containsKey(ConfigConstant.AUTHS)) {
JsonObject auths = (JsonObject) localMap.get(ConfigConstant.AUTHS);
if (auths.containsKey(type)) {
// 需要处理引号
MultiMap entries = MultiMap.caseInsensitiveMultiMap();
JsonObject jsonObject = auths.getJsonObject(type);
if (jsonObject != null) {
jsonObject.forEach(entity -> {
if (entity == null || entity.getValue() == null) {
return;
}
entries.set(entity.getKey(), entity.getValue().toString());
});
}
parserCreate.getShareLinkInfo().getOtherParam().put(ConfigConstant.AUTHS, entries);
}
}
String linkPrefix = SharedDataUtil.getJsonConfig("server").getString("domainName");
parserCreate.getShareLinkInfo().getOtherParam().put("domainName", linkPrefix);
}
} }

View File

@@ -5,8 +5,10 @@ import cn.qaiu.db.ddl.Table;
import cn.qaiu.db.ddl.TableGenIgnore; import cn.qaiu.db.ddl.TableGenIgnore;
import cn.qaiu.entity.FileInfo; import cn.qaiu.entity.FileInfo;
import cn.qaiu.lz.common.ToJson; import cn.qaiu.lz.common.ToJson;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.vertx.codegen.annotations.DataObject; import io.vertx.codegen.annotations.DataObject;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.core.json.jackson.DatabindCodec;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@@ -66,6 +68,11 @@ public class CacheLinkInfo implements ToJson {
if (json.containsKey("expiration")) { if (json.containsKey("expiration")) {
this.setExpiration(json.getLong("expiration")); this.setExpiration(json.getLong("expiration"));
} }
if (json.containsKey("fileInfo")) {
ObjectMapper mapper = DatabindCodec.mapper(); // Vert.x 自带的 mapper
this.setFileInfo(mapper.convertValue(json.getJsonObject("fileInfo"), FileInfo.class));
}
this.setCacheHit(json.getBoolean("cacheHit", false)); this.setCacheHit(json.getBoolean("cacheHit", false));
} }

View File

@@ -0,0 +1,163 @@
package cn.qaiu.lz.web.model;
import cn.qaiu.db.ddl.Table;
import cn.qaiu.entity.FileInfo;
import io.vertx.codegen.annotations.DataObject;
import io.vertx.codegen.format.SnakeCase;
import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.templates.annotations.RowMapped;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author <a href="https://qaiu.top">QAIU</a>
* @date 2025/8/4 12:38
*/
@Table(keyFields = "share_key")
@DataObject
@RowMapped(formatter = SnakeCase.class)
@NoArgsConstructor
@Data
public class PanFileInfo {
String shareKey;
/**
* 文件名
*/
private String fileName;
/**
* 文件ID
*/
private String fileId;
private String fileIcon;
/**
* 文件大小(byte)
*/
private Long size;
private String sizeStr;
/**
* 类型
*/
private String fileType;
/**
* 文件路径
*/
private String filePath;
/**
* 创建(上传)时间 yyyy-MM-dd HH:mm:ss格式
*/
private String createTime;
/**
* 上次修改时间
*/
private String updateTime;
/**
* 创建者
*/
private String createBy;
/**
* 文件描述
*/
private String description;
/**
* 下载次数
*/
private Integer downloadCount;
/**
* 网盘标识
*/
private String panType;
/**
* nfd下载链接(可能获取不到)
* note: 不是下载直链
*/
private String parserUrl;
//预览地址
private String previewUrl;
// 文件hash默认类型为md5
private String hash;
public PanFileInfo(JsonObject jsonObject) {
this.shareKey = jsonObject.getString("shareKey");
this.fileName = jsonObject.getString("fileName");
this.fileId = jsonObject.getString("fileId");
this.fileIcon = jsonObject.getString("fileIcon");
this.size = jsonObject.getLong("size");
this.sizeStr = jsonObject.getString("sizeStr");
this.fileType = jsonObject.getString("fileType");
this.filePath = jsonObject.getString("filePath");
this.createTime = jsonObject.getString("createTime");
this.updateTime = jsonObject.getString("updateTime");
this.createBy = jsonObject.getString("createBy");
this.description = jsonObject.getString("description");
this.downloadCount = jsonObject.getInteger("downloadCount");
this.panType = jsonObject.getString("panType");
this.parserUrl = jsonObject.getString("parserUrl");
this.previewUrl = jsonObject.getString("previewUrl");
this.hash = jsonObject.getString("hash");
}
public static PanFileInfo fromFileInfo(FileInfo info) {
PanFileInfo panFileInfo = new PanFileInfo();
if (info == null) {
return panFileInfo;
}
// 拷贝 FileInfo 的字段
panFileInfo.setFileName(info.getFileName());
panFileInfo.setFileId(info.getFileId());
panFileInfo.setFileIcon(info.getFileIcon());
panFileInfo.setSize(info.getSize());
panFileInfo.setSizeStr(info.getSizeStr());
panFileInfo.setFileType(info.getFileType());
panFileInfo.setFilePath(info.getFilePath());
panFileInfo.setCreateTime(info.getCreateTime());
panFileInfo.setUpdateTime(info.getUpdateTime());
panFileInfo.setCreateBy(info.getCreateBy());
panFileInfo.setDescription(info.getDescription());
panFileInfo.setDownloadCount(info.getDownloadCount());
panFileInfo.setPanType(info.getPanType());
panFileInfo.setParserUrl(info.getParserUrl());
panFileInfo.setPreviewUrl(info.getPreviewUrl());
panFileInfo.setHash(info.getHash());
return panFileInfo;
}
public FileInfo toFileInfo() {
FileInfo fileInfo = new FileInfo();
fileInfo.setFileName(this.getFileName());
fileInfo.setFileId(this.getFileId());
fileInfo.setFileIcon(this.getFileIcon());
fileInfo.setSize(this.getSize());
fileInfo.setSizeStr(this.getSizeStr());
fileInfo.setFileType(this.getFileType());
fileInfo.setFilePath(this.getFilePath());
fileInfo.setCreateTime(this.getCreateTime());
fileInfo.setUpdateTime(this.getUpdateTime());
fileInfo.setCreateBy(this.getCreateBy());
fileInfo.setDescription(this.getDescription());
fileInfo.setDownloadCount(this.getDownloadCount());
fileInfo.setPanType(this.getPanType());
fileInfo.setParserUrl(this.getParserUrl());
fileInfo.setPreviewUrl(this.getPreviewUrl());
fileInfo.setHash(this.getHash());
return fileInfo;
}
}

View File

@@ -1,38 +1,33 @@
package cn.qaiu.lz.web.service.impl; package cn.qaiu.lz.web.service.impl;
import cn.qaiu.entity.FileInfo;
import cn.qaiu.entity.ShareLinkInfo; import cn.qaiu.entity.ShareLinkInfo;
import cn.qaiu.lz.common.cache.CacheConfigLoader; import cn.qaiu.lz.common.cache.CacheConfigLoader;
import cn.qaiu.lz.common.cache.CacheManager; import cn.qaiu.lz.common.cache.CacheManager;
import cn.qaiu.lz.common.cache.CacheTotalField; import cn.qaiu.lz.common.cache.CacheTotalField;
import cn.qaiu.lz.common.util.URLParamUtil;
import cn.qaiu.lz.web.model.CacheLinkInfo; import cn.qaiu.lz.web.model.CacheLinkInfo;
import cn.qaiu.lz.web.service.CacheService; import cn.qaiu.lz.web.service.CacheService;
import cn.qaiu.parser.IPanTool;
import cn.qaiu.parser.ParserCreate; import cn.qaiu.parser.ParserCreate;
import cn.qaiu.vx.core.annotaions.Service; import cn.qaiu.vx.core.annotaions.Service;
import cn.qaiu.vx.core.util.ConfigConstant;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.Promise; import io.vertx.core.Promise;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.core.shareddata.LocalMap; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils; import org.apache.commons.lang3.time.DateFormatUtils;
import java.util.Date; import java.util.Date;
@Service @Service
@Slf4j
public class CacheServiceImpl implements CacheService { public class CacheServiceImpl implements CacheService {
private final CacheManager cacheManager = new CacheManager(); private final CacheManager cacheManager = new CacheManager();
private Future<CacheLinkInfo> getAndSaveCachedShareLink(ParserCreate parserCreate) { private Future<CacheLinkInfo> getAndSaveCachedShareLink(ParserCreate parserCreate) {
LocalMap<Object, Object> localMap = VertxHolder.getVertxInstance().sharedData()
.getLocalMap(ConfigConstant.LOCAL); URLParamUtil.addParam(parserCreate);
if (localMap.containsKey(ConfigConstant.PROXY)) {
JsonObject proxy = (JsonObject) localMap.get(ConfigConstant.PROXY);
String type = parserCreate.getShareLinkInfo().getType();
if (proxy.containsKey(type)) {
parserCreate.getShareLinkInfo().getOtherParam().put(ConfigConstant.PROXY, proxy.getJsonObject(type));
}
}
Promise<CacheLinkInfo> promise = Promise.promise(); Promise<CacheLinkInfo> promise = Promise.promise();
// 构建组合的缓存key // 构建组合的缓存key
@@ -46,20 +41,36 @@ public class CacheServiceImpl implements CacheService {
// parse // parse
result.setCacheHit(false); result.setCacheHit(false);
result.setExpiration(0L); result.setExpiration(0L);
parserCreate.createTool().parse().onSuccess(redirectUrl -> { IPanTool tool;
try {
tool = parserCreate.createTool();
} catch (Exception e) {
promise.fail(e.getCause().getCause());
return;
}
tool.parse().onSuccess(redirectUrl -> {
long expires = System.currentTimeMillis() + long expires = System.currentTimeMillis() +
CacheConfigLoader.getDuration(shareLinkInfo.getType()) * 60 * 1000L; CacheConfigLoader.getDuration(shareLinkInfo.getType()) * 60 * 1000L;
result.setDirectLink(redirectUrl); result.setDirectLink(redirectUrl);
// result.setExpires(generateDate(expires));
promise.complete(result);
// 更新缓存
// 将直链存储到缓存
CacheLinkInfo cacheLinkInfo = new CacheLinkInfo(JsonObject.of( CacheLinkInfo cacheLinkInfo = new CacheLinkInfo(JsonObject.of(
"directLink", redirectUrl, "directLink", redirectUrl,
"expiration", expires, "expiration", expires,
"shareKey", cacheKey "shareKey", cacheKey
)); ));
cacheManager.cacheShareLink(cacheLinkInfo).onFailure(Throwable::printStackTrace); if (shareLinkInfo.getOtherParam().containsKey("fileInfo")) {
try {
FileInfo fileInfo = (FileInfo) shareLinkInfo.getOtherParam().get("fileInfo");
result.setFileInfo(fileInfo);
cacheLinkInfo.setFileInfo(fileInfo);
} catch (Exception ignored) {
log.error("文件对象转换异常");
}
}
promise.complete(result);
// 更新缓存
// 将直链存储到缓存
cacheManager.cacheShareLink(cacheLinkInfo);
cacheManager.updateTotalByField(cacheKey, CacheTotalField.API_PARSER_TOTAL).onFailure(Throwable::printStackTrace); cacheManager.updateTotalByField(cacheKey, CacheTotalField.API_PARSER_TOTAL).onFailure(Throwable::printStackTrace);
}).onFailure(promise::fail); }).onFailure(promise::fail);
} else { } else {