MySQL支持, 其他优化

This commit is contained in:
QAIU
2025-02-06 16:52:06 +08:00
parent e85215fca1
commit 5052fea9ef
14 changed files with 465 additions and 62 deletions

View File

@@ -59,6 +59,12 @@
<artifactId>vertx-jdbc-client</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.2.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -32,7 +32,7 @@ public @interface Constraint {
*/
String defaultValue() default "";
/**
* 默认值是否是函数
* 默认值是否是函数 like value=NOW()
* @return false 不是函数
*/
boolean defaultValueIsFunction() default false;

View File

@@ -0,0 +1,67 @@
package cn.qaiu.db.ddl;
import cn.qaiu.db.pool.JDBCPoolInit;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CreateDatabase {
private static final Logger LOGGER = LoggerFactory.getLogger(JDBCPoolInit.class);
/**
* 解析数据库URL获取数据库名
* @param url 数据库URL
* @return 数据库名
*/
public static String getDatabaseName(String url) {
// 正则表达式匹配数据库名
String regex = "jdbc:mysql://[^/]+/(\\w+)(\\?.*)?";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(url);
if (matcher.find()) {
return matcher.group(1);
} else {
throw new IllegalArgumentException("Invalid database URL: " + url);
}
}
/**
* 使用JDBC原生方法创建数据库
* @param url 数据库连接URL
* @param user 数据库用户名
* @param password 数据库密码
*/
public static void createDatabase(String url, String user, String password) {
String dbName = getDatabaseName(url);
LOGGER.info(">>>>>>>>>>> 创建数据库:'{}' <<<<<<<<<<<< ", dbName);
// 去掉数据库名构建不带数据库名的URL
String baseUrl = url.substring(0, url.lastIndexOf("/") + 1) + "?characterEncoding=UTF-8&useUnicode=true";
try (Connection conn = DriverManager.getConnection(baseUrl, user, password);
Statement stmt = conn.createStatement()) {
// 创建数据库
stmt.executeUpdate("CREATE DATABASE IF NOT EXISTS " + dbName + " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
LOGGER.info(">>>>>>>>>>> 数据库'{}'创建成功 <<<<<<<<<<<<", dbName);
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void createDatabase(JsonObject dbConfig) {
createDatabase(
dbConfig.getString("jdbcUrl"),
dbConfig.getString("username"),
dbConfig.getString("password")
);
}
}

View File

@@ -1,13 +1,18 @@
package cn.qaiu.db.pool;
import cn.qaiu.db.ddl.CreateTable;
import cn.qaiu.db.ddl.CreateDatabase;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.jdbcclient.JDBCPool;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 初始化JDBC
* <br>Create date 2021/8/10 12:04
@@ -17,18 +22,32 @@ import org.slf4j.LoggerFactory;
public class JDBCPoolInit {
private static final Logger LOGGER = LoggerFactory.getLogger(JDBCPoolInit.class);
private static final String providerClass = io.vertx.ext.jdbc.spi.impl.HikariCPDataSourceProvider.class.getName();
private JDBCPool pool = null;
JsonObject dbConfig;
Vertx vertx = VertxHolder.getVertxInstance();
String url;
private final JDBCType type;
private static JDBCPoolInit instance;
public JDBCType getType() {
return type;
}
public JDBCPoolInit(Builder builder) {
this.dbConfig = builder.dbConfig;
this.url = builder.url;
this.type = builder.type;
this.type = JDBCType.getJDBCTypeByURL(builder.url);
if (StringUtils.isBlank(builder.dbConfig.getString("provider_class"))) {
builder.dbConfig.put("provider_class", providerClass);
}
if (StringUtils.isBlank(builder.dbConfig.getString("driverClassName"))) {
builder.dbConfig.put("driverClassName", this.type.getDriverClassName());
}
}
public static Builder builder() {
@@ -42,12 +61,10 @@ public class JDBCPoolInit {
public static class Builder {
private JsonObject dbConfig;
private String url;
private JDBCType type;
public Builder config(JsonObject dbConfig) {
this.dbConfig = dbConfig;
this.url = dbConfig.getString("jdbcUrl");
this.type = JDBCUtil.getJDBCType(dbConfig.getString("driverClassName"));
return this;
}
@@ -59,7 +76,6 @@ public class JDBCPoolInit {
}
}
/**
* init h2db<br>
* 这个方法只允许调用一次
@@ -72,6 +88,9 @@ public class JDBCPoolInit {
// 初始化数据库连接
// 初始化连接池
if (type == JDBCType.MySQL) {
CreateDatabase.createDatabase(dbConfig);
}
pool = JDBCPool.pool(vertx, dbConfig);
CreateTable.createTable(pool, type);
LOGGER.info("数据库连接初始化: URL=" + url);

View File

@@ -1,9 +1,52 @@
package cn.qaiu.db.pool;
import org.apache.commons.lang3.StringUtils;
/**
* @author <a href="https://qaiu.top">QAIU</a>
* @date 2023/10/10 14:06
* @since 2023/10/10 14:06
*/
public enum JDBCType {
MySQL, H2DB
// 添加驱动类型字段
MySQL("com.mysql.cj.jdbc.Driver", "jdbc:mysql:"),
H2DB("org.h2.Driver", "jdbc:h2:");
private final String driverClassName; // 驱动类名
private final String urlPrefix; // JDBC URL 前缀
// 构造函数
JDBCType(String driverClassName, String urlPrefix) {
this.driverClassName = driverClassName;
this.urlPrefix = urlPrefix;
}
// 获取驱动类名
public String getDriverClassName() {
return driverClassName;
}
// 获取 JDBC URL 前缀
public String getUrlPrefix() {
return urlPrefix;
}
// 根据驱动类名获取 JDBC 类型
public static JDBCType getJDBCType(String driverClassName) {
for (JDBCType jdbcType : values()) {
if (jdbcType.getDriverClassName().equalsIgnoreCase(driverClassName)) {
return jdbcType;
}
}
throw new RuntimeException("不支持的SQL驱动类型: " + driverClassName);
}
// 根据 JDBC URL 获取 JDBC 类型
public static JDBCType getJDBCTypeByURL(String jdbcURL) {
for (JDBCType jdbcType : values()) {
if (StringUtils.startsWithIgnoreCase(jdbcURL, jdbcType.getUrlPrefix())) {
return jdbcType;
}
}
throw new RuntimeException("不支持的SQL驱动类型: " + jdbcURL);
}
}

View File

@@ -1,18 +0,0 @@
package cn.qaiu.db.pool;
/**
* @author <a href="https://qaiu.top">QAIU</a>
* @date 2023/10/10 14:05
*/
public class JDBCUtil {
public static JDBCType getJDBCType(String deviceName) {
switch (deviceName) {
case "com.mysql.cj.jdbc.Driver":
case "com.mysql.jdbc.Driver":
return JDBCType.MySQL;
case "org.h2.Driver":
return JDBCType.H2DB;
}
throw new RuntimeException("不支持的SQL驱动类型: " + deviceName);
}
}

View File

@@ -60,7 +60,15 @@ jwt鉴权用户
文件信息: 文件/文件夹, 文件数量, 文件大小, 文件类型; 链接信息: 解析次数, 缓存次数等)
微服务设计:
TODO
后台管理:
菜单:
网盘管理: token配置, 启用/禁用
短链管理: 短链列表, 新增, 删除
解析统计: 下载次数统计, 下载流量统计, 详细解析列表
状态监视: 服务请求并发数; 来源IP列表: 拉黑, 限制次数; Nginx
系统配置: 管理员账户, 系统参数: 域名配置, 预览URL,

View File

@@ -0,0 +1,122 @@
package cn.qaiu.parser.impl;
import cn.qaiu.entity.ShareLinkInfo;
import cn.qaiu.parser.PanBase;
import io.vertx.core.Future;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.uritemplate.UriTemplate;
/**
* UC网盘解析
*/
public class UcTool extends PanBase {
private static final String API_URL_PREFIX = "https://pc-api.uc.cn/1/clouddrive/";
public static final String SHARE_URL_PREFIX = "https://fast.uc.cn/s/";
private static final String FIRST_REQUEST_URL = API_URL_PREFIX + "share/sharepage/token?entry=ft&fr=pc&pr" +
"=UCBrowser";
private static final String SECOND_REQUEST_URL = API_URL_PREFIX + "transfer_share/detail?pwd_id={pwd_id}&passcode" +
"={passcode}&stoken={stoken}";
private static final String THIRD_REQUEST_URL = API_URL_PREFIX + "file/download?entry=ft&fr=pc&pr=UCBrowser";
public UcTool(ShareLinkInfo shareLinkInfo) {
super(shareLinkInfo);
}
public Future<String> parse() {
var dataKey = shareLinkInfo.getShareKey();
var passcode = shareLinkInfo.getSharePassword();
var jsonObject = JsonObject.of("share_for_transfer", true);
jsonObject.put("pwd_id", dataKey);
jsonObject.put("passcode", passcode);
// 第一次请求 获取文件信息
client.postAbs(FIRST_REQUEST_URL).sendJsonObject(jsonObject).onSuccess(res -> {
log.debug("第一阶段 {}", res.body());
var resJson = res.bodyAsJsonObject();
if (resJson.getInteger("code") != 0) {
fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
return;
}
var stoken = resJson.getJsonObject("data").getString("stoken");
// 第二次请求
client.getAbs(UriTemplate.of(SECOND_REQUEST_URL))
.setTemplateParam("pwd_id", dataKey)
.setTemplateParam("passcode", passcode)
.setTemplateParam("stoken", stoken)
.send().onSuccess(res2 -> {
log.debug("第二阶段 {}", res2.body());
JsonObject resJson2 = res2.bodyAsJsonObject();
if (resJson2.getInteger("code") != 0) {
fail(FIRST_REQUEST_URL + " 返回异常: " + resJson2);
return;
}
// 文件信息
var info = resJson2.getJsonObject("data").getJsonArray("list").getJsonObject(0);
// 第二次请求
var bodyJson = JsonObject.of()
.put("fids", JsonArray.of(info.getString("fid")))
.put("pwd_id", dataKey)
.put("stoken", stoken)
.put("fids_token", JsonArray.of(info.getString("share_fid_token")));
client.postAbs(THIRD_REQUEST_URL).sendJsonObject(bodyJson)
.onSuccess(res3 -> {
log.debug("第三阶段 {}", res3.body());
var resJson3 = res3.bodyAsJsonObject();
if (resJson3.getInteger("code") != 0) {
fail(FIRST_REQUEST_URL + " 返回异常: " + resJson2);
return;
}
promise.complete(resJson3.getJsonArray("data").getJsonObject(0).getString("download_url"));
}).onFailure(handleFail(THIRD_REQUEST_URL));
}).onFailure(handleFail(SECOND_REQUEST_URL));
}
).onFailure(handleFail(FIRST_REQUEST_URL));
return promise.future();
}
public static void main(String[] args) {
// https://dl-uf-zb.pds.uc.cn/l3PNAKfz/64623447/
// 646b0de6e9f13000c9b14ba182b805312795a82a/
// 646b0de6717e1bfa5bb44dd2a456f103c5177850?
// Expires=1737784900&OSSAccessKeyId=LTAI5tJJpWQEfrcKHnd1LqsZ&
// Signature=oBVV3anhv3tBKanHUcEIsktkB%2BM%3D&x-oss-traffic-limit=503316480
// &response-content-disposition=attachment%3B%20filename%3DC%2523%2520Shell%2520%2528C%2523%2520Offline%2520Compiler%2529_2.5.16.apks
// %3Bfilename%2A%3Dutf-8%27%27C%2523%2520Shell%2520%2528C%2523%2520Offline%2520Compiler%2529_2.5.16.apks
//eyJ4OmF1IjoiLSIsIng6dWQiOiI0LU4tNS0wLTYtTi0zLWZ0LTAtMi1OLU4iLCJ4OnNwIjoiMTAwIiwieDp0b2tlbiI6IjQtZjY0ZmMxMDFjZmQxZGVkNTRkMGM0NmMzYzliMzkyOWYtNS03LTE1MzYxMS1kYWNiMzY2NWJiYWE0ZjVlOWQzNzgwMGVjNjQwMzE2MC0wLTAtMC0wLTQ5YzUzNTE3OGIxOTY0YzhjYzUwYzRlMDk5MTZmYWRhIiwieDp0dGwiOiIxMDgwMCJ9
//eyJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24vanNvbiIsImNhbGxiYWNrU3RhZ2UiOiJiZWZvcmUtZXhlY3V0ZSIsImNhbGxiYWNrRmFpbHVyZUFjdGlvbiI6Imlnbm9yZSIsImNhbGxiYWNrVXJsIjoiaHR0cHM6Ly9hdXRoLWNkbi51Yy5jbi9vdXRlci9vc3MvY2hlY2twbGF5IiwiY2FsbGJhY2tCb2R5Ijoie1wiaG9zdFwiOiR7aHR0cEhlYWRlci5ob3N0fSxcInNpemVcIjoke3NpemV9LFwicmFuZ2VcIjoke2h0dHBIZWFkZXIucmFuZ2V9LFwicmVmZXJlclwiOiR7aHR0cEhlYWRlci5yZWZlcmVyfSxcImNvb2tpZVwiOiR7aHR0cEhlYWRlci5jb29raWV9LFwibWV0aG9kXCI6JHtodHRwSGVhZGVyLm1ldGhvZH0sXCJpcFwiOiR7Y2xpZW50SXB9LFwicG9ydFwiOiR7Y2xpZW50UG9ydH0sXCJvYmplY3RcIjoke29iamVjdH0sXCJzcFwiOiR7eDpzcH0sXCJ1ZFwiOiR7eDp1ZH0sXCJ0b2tlblwiOiR7eDp0b2tlbn0sXCJhdVwiOiR7eDphdX0sXCJ0dGxcIjoke3g6dHRsfSxcImR0X3NwXCI6JHt4OmR0X3NwfSxcImhzcFwiOiR7eDpoc3B9LFwiY2xpZW50X3Rva2VuXCI6JHtxdWVyeVN0cmluZy5jbGllbnRfdG9rZW59fSJ9
//callback-var {"x:au":"-","x:ud":"4-N-5-0-6-N-3-ft-0-2-N-N","x:sp":"100","x:token":"4-f64fc101cfd1ded54d0c46c3c9b3929f-5-7-153611-dacb3665bbaa4f5e9d37800ec6403160-0-0-0-0-49c535178b1964c8cc50c4e09916fada","x:ttl":"10800"}
//callback {"callbackBodyType":"application/json","callbackStage":"before-execute","callbackFailureAction":"ignore","callbackUrl":"https://auth-cdn.uc.cn/outer/oss/checkplay","callbackBody":"{\"host\":${httpHeader.host},\"size\":${size},\"range\":${httpHeader.range},\"referer\":${httpHeader.referer},\"cookie\":${httpHeader.cookie},\"method\":${httpHeader.method},\"ip\":${clientIp},\"port\":${clientPort},\"object\":${object},\"sp\":${x:sp},\"ud\":${x:ud},\"token\":${x:token},\"au\":${x:au},\"ttl\":${x:ttl},\"dt_sp\":${x:dt_sp},\"hsp\":${x:hsp},\"client_token\":${queryString.client_token}}"}
/*
// callback-var
{
"x:au": "-",
"x:ud": "4-N-5-0-6-N-3-ft-0-2-N-N",
"x:sp": "100",
"x:token": "4-f64fc101cfd1ded54d0c46c3c9b3929f-5-7-153611-dacb3665bbaa4f5e9d37800ec6403160-0-0-0-0-49c535178b1964c8cc50c4e09916fada",
"x:ttl": "10800"
}
// callback
{
"callbackBodyType": "application/json",
"callbackStage": "before-execute",
"callbackFailureAction": "ignore",
"callbackUrl": "https://auth-cdn.uc.cn/outer/oss/checkplay",
"callbackBody": "{\"host\":${httpHeader.host},\"size\":${size},\"range\":${httpHeader.range},\"referer\":${httpHeader.referer},\"cookie\":${httpHeader.cookie},\"method\":${httpHeader.method},\"ip\":${clientIp},\"port\":${clientPort},\"object\":${object},\"sp\":${x:sp},\"ud\":${x:ud},\"token\":${x:token},\"au\":${x:au},\"ttl\":${x:ttl},\"dt_sp\":${x:dt_sp},\"hsp\":${x:hsp},\"client_token\":${queryString.client_token}}"
}
*/
new UcTool(ShareLinkInfo.newBuilder().shareUrl("https://fast.uc.cn/s/33197dd53ace4").shareKey("33197dd53ace4").build()).parse().onSuccess(
System.out::println
);
}
}

View File

@@ -1,6 +1,7 @@
package cn.qaiu.lz.common.cache;
import cn.qaiu.db.pool.JDBCPoolInit;
import cn.qaiu.db.pool.JDBCType;
import cn.qaiu.lz.web.model.CacheLinkInfo;
import io.vertx.core.Future;
import io.vertx.core.Promise;
@@ -8,13 +9,17 @@ import io.vertx.core.json.JsonObject;
import io.vertx.jdbcclient.JDBCPool;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.templates.SqlTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
public class CacheManager {
private final JDBCPool jdbcPool = JDBCPoolInit.instance().getPool();
private final JDBCType jdbcType = JDBCPoolInit.instance().getType();
private static final Logger LOGGER = LoggerFactory.getLogger(CacheManager.class);
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}";
@@ -33,16 +38,31 @@ public class CacheManager {
cacheHit = new CacheLinkInfo(JsonObject.of("cacheHit", false, "shareKey", cacheKey));
}
promise.complete(cacheHit);
}).onFailure(Throwable::printStackTrace);
}).onFailure(e->{
promise.fail(e);
LOGGER.error("cache get:", e);
});
return promise.future();
}
// 插入或更新缓存数据
public Future<Void> cacheShareLink(CacheLinkInfo cacheLinkInfo) {
String sql = "MERGE INTO cache_link_info (share_key, direct_link, expiration) " +
"KEY (share_key) " +
"VALUES (#{shareKey}, #{directLink}, #{expiration})";
String sql;
if (jdbcType == JDBCType.MySQL) {
sql = """
INSERT INTO cache_link_info (share_key, direct_link, expiration)
VALUES (#{shareKey}, #{directLink}, #{expiration})
ON DUPLICATE KEY UPDATE
direct_link = VALUES(direct_link),
expiration = VALUES(expiration);
""";
} else { // 运行H2
sql = "MERGE INTO cache_link_info (share_key, direct_link, expiration) " +
"KEY (share_key) " +
"VALUES (#{shareKey}, #{directLink}, #{expiration})";
}
// 直接传递 CacheLinkInfo 实体类
return SqlTemplate.forUpdate(jdbcPool, sql)
@@ -55,11 +75,23 @@ public class CacheManager {
public Future<Integer> updateTotalByField(String shareKey, CacheTotalField field) {
Promise<Integer> promise = Promise.promise();
String fieldLower = field.name().toLowerCase();
String sql = """
String sql;
if (jdbcType == JDBCType.MySQL) { // 假设你有一个标识当前数据库类型的布尔变量
sql = """
INSERT INTO `api_statistics_info` (`pan_type`, `share_key`, `{field}`, `update_ts`)
VALUES (#{panType}, #{shareKey}, #{total}, #{ts})
ON DUPLICATE KEY UPDATE
`pan_type` = VALUES(`pan_type`),
`{field}` = VALUES(`{field}`),
`update_ts` = VALUES(`update_ts`);
""".replace("{field}", fieldLower);
} else { // 运行H2
sql = """
MERGE INTO `api_statistics_info` (`pan_type`, `share_key`, `{field}`, `update_ts`)
KEY (`share_key`)
VALUES (#{panType}, #{shareKey}, #{total}, #{ts})
""".replace("{field}", fieldLower);
}
getShareKeyTotal(shareKey, fieldLower).onSuccess(total -> {
Integer newTotal = (total == null ? 0 : total) + 1;
@@ -71,7 +103,10 @@ public class CacheManager {
put("ts", System.currentTimeMillis());
}})
.onSuccess(res -> promise.complete(res.rowCount()))
.onFailure(Throwable::printStackTrace);
.onFailure(e->{
promise.fail(e);
LOGGER.error("updateTotalByField: ", e);
});
});
return promise.future();
}
@@ -84,10 +119,12 @@ public class CacheManager {
public Future<Integer> getShareKeyTotal(String shareKey, String name) {
String sql = """
select `share_key`, sum({total_name}) sum_num
from `api_statistics_info`
group by `share_key` having `share_key` = #{shareKey};
SELECT `share_key`, SUM({total_name}) AS sum_num
FROM `api_statistics_info`
WHERE `share_key` = #{shareKey}
GROUP BY `share_key`;
""".replace("{total_name}", name);
Promise<Integer> promise = Promise.promise();
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("shareKey", shareKey);
@@ -98,16 +135,21 @@ public class CacheManager {
Integer total = res.iterator().hasNext() ?
res.iterator().next().getInteger("sum_num") : null;
promise.complete(total);
}).onFailure(e->{
promise.fail(e);
LOGGER.error("getShareKeyTotal: ", e);
});
return promise.future();
}
public Future<Map<String, Integer>> getShareKeyTotal(String shareKey) {
String sql = """
select `share_key`, sum(cache_hit_total) hit_total, sum(api_parser_total) parser_total,
from `api_statistics_info`
group by `share_key` having `share_key` = #{shareKey}
SELECT `share_key`, SUM(cache_hit_total) AS hit_total, SUM(api_parser_total) AS parser_total
FROM `api_statistics_info`
WHERE `share_key` = #{shareKey}
GROUP BY `share_key`;
""";
Promise<Map<String, Integer>> promise = Promise.promise();
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("shareKey", shareKey);
@@ -115,16 +157,19 @@ public class CacheManager {
.mapTo(Row::toJson)
.execute(paramMap)
.onSuccess(res -> {
if(res.iterator().hasNext()) {
JsonObject next = res.iterator().next();
Map<String, Integer> resp = new HashMap<>(){{
put("hit_total" ,next.getInteger("hit_total"));
put("parser_total" ,next.getInteger("parser_total"));
}};
promise.complete(resp);
if(res.iterator().hasNext()) {
JsonObject next = res.iterator().next();
Map<String, Integer> resp = new HashMap<>(){{
put("hit_total" ,next.getInteger("hit_total"));
put("parser_total" ,next.getInteger("parser_total"));
}};
promise.complete(resp);
} else {
promise.complete();
}
promise.complete();
}
}).onFailure(e->{
promise.fail(e);
LOGGER.error("getShareKeyTotal0: ", e);
});
return promise.future();
}

View File

@@ -21,13 +21,13 @@ public class ApiStatisticsInfo implements ToJson {
/**
* pan type 单独拿出来便于统计.
*/
@Length(varcharSize = 4)
@Length(varcharSize = 16)
private String panType;
/**
* 分享key type:key
*/
@Length(varcharSize = 4096)
@Length(varcharSize = 1024)
private String shareKey;
/**

View File

@@ -23,7 +23,7 @@ public class CacheLinkInfo implements ToJson {
/**
* 缓存key: type:ShareKey; e.g. lz:xxxx
*/
@Length(varcharSize = 4096)
@Length(varcharSize = 1024)
private String shareKey;
/**

View File

@@ -48,10 +48,11 @@ public class DbServiceImpl implements DbService {
JDBCPool client = JDBCPoolInit.instance().getPool();
Promise<StatisticsInfo> promise = Promise.promise();
String sql = """
select sum(api_parser_total) parserTotal,sum("cache_hit_total") cacheTotal,
sum(api_parser_total) + sum("cache_hit_total") total
from "api_statistics_info";
select sum(api_parser_total) as parserTotal, sum(cache_hit_total) as cacheTotal,
sum(api_parser_total) + sum(cache_hit_total) as total
from api_statistics_info;
""";
SqlTemplate.forQuery(client, sql).mapTo(StatisticsInfo.class).execute(new HashMap<>()).onSuccess(row -> {
StatisticsInfo info;
if ((info = row.iterator().next()) != null) {
@@ -59,7 +60,10 @@ public class DbServiceImpl implements DbService {
} else {
promise.fail("t_parser_log_info查询为空");
}
}).onFailure(promise::fail);
}).onFailure(e->{
log.error("getStatisticsInfo: ", e);
promise.fail(e);
});
return promise.future();
}
}

View File

@@ -35,9 +35,8 @@ custom:
# 数据源配置
dataSource:
provider_class: io.vertx.ext.jdbc.spi.impl.HikariCPDataSourceProvider
jdbcUrl: jdbc:h2:file:./db/nfdData;MODE=MySQL;DATABASE_TO_UPPER=FALSE
driverClassName: org.h2.Driver
#jdbcUrl: jdbc:mysql://127.0.0.1:3306/nfddata?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false
jdbcUrl: jdbc:h2:file:./db/nfdData111;MODE=MySQL;DATABASE_TO_UPPER=FALSE
username: root
password: '123456'
@@ -49,17 +48,17 @@ cache:
defaultDuration: 59
# 具体网盘的缓存配置如果不加配置则不缓存每次请求都会请求网盘API格式网盘标识: 时长
duration:
ce:
ce: 5
cow:
ec:
ec: 5
fc:
fj:
fj: 20
iz: 20
le: 2879
lz: 20
qq: 9999999
ws:
ye:
ws: 10
ye: -1
mne: 30
mqq: 30
mkg: 30

View File

@@ -51,3 +51,111 @@ Cookie: __pugs=efc5f3f9c041af5dc62eea4481901cbbAAT912628i+uT/WMwOFWBjJ1TjbKGC1j6
https://dl-uf-zb.pds.uc.cn/l3PNAKfz/64623447/646b0de6e9f13000c9b14ba182b805312795a82a/646b0de6717e1bfa5bb44dd2a456f103c5177850?Expires=1691489999&OSSAccessKeyId=LTAIyYfxTqY7YZsg&Signature=NbQLAEUCkvJxmSsRoIynZ%2BuPMvY%3D&x-oss-traffic-limit=503316480&response-content-disposition=attachment%3B%20filename%3DC%23%20Shell%20%28C%23%20Offline%20Compiler%29_2.5.16.apks&callback-var=eyJ4OmF1IjoiLSIsIng6c3AiOiIxOTkiLCJ4OnRva2VuIjoiMi0wNDBjYjFjMDNjNzU1YWY1NDc0NjkxNjNmOTYzYWY2NC0yLTctNjE0NDAtZGFjYjM2NjViYmFhNGY1ZTlkMzc4MDBlYzY0MDMxNjAtYTU2MGJiMmU1MzhlNzY0OTFkMDY1MjA2OGRiNmEzMzEiLCJ4OnR0bCI6IjEwODAwIn0%3D&callback=eyJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24vanNvbiIsImNhbGxiYWNrU3RhZ2UiOiJiZWZvcmUtZXhlY3V0ZSIsImNhbGxiYWNrRmFpbHVyZUFjdGlvbiI6Imlnbm9yZSIsImNhbGxiYWNrVXJsIjoiaHR0cHM6Ly9hdXRoLWNkbi51Yy5jbi9vdXRlci9vc3MvY2hlY2twbGF5IiwiY2FsbGJhY2tCb2R5Ijoie1wiaG9zdFwiOiR7aHR0cEhlYWRlci5ob3N0fSxcInNpemVcIjoke3NpemV9LFwicmFuZ2VcIjoke2h0dHBIZWFkZXIucmFuZ2V9LFwicmVmZXJlclwiOiR7aHR0cEhlYWRlci5yZWZlcmVyfSxcImNvb2tpZVwiOiR7aHR0cEhlYWRlci5jb29raWV9LFwibWV0aG9kXCI6JHtodHRwSGVhZGVyLm1ldGhvZH0sXCJpcFwiOiR7Y2xpZW50SXB9LFwicG9ydFwiOiR7Y2xpZW50UG9ydH0sXCJvYmplY3RcIjoke29iamVjdH0sXCJzcFwiOiR7eDpzcH0sXCJ0b2tlblwiOiR7eDp0b2tlbn0sXCJhdVwiOiR7eDphdX0sXCJ0dGxcIjoke3g6dHRsfSxcImNsaWVudF90b2tlblwiOiR7cXVlcnlTdHJpbmcuY2xpZW50X3Rva2VufX0ifQ%3D%3D&ud=4-0-5-0-6-N-3-ft-0-2
Cookie: __puus=dc48cb12577eb3df6fe84fdea250ad6fAAOF0LBv/M4HTtkYfuUNdcVLXHZl1x2mw8NQSdxo5abymS+irugphlPNv5kwQZkDI+pXaeOD22v/whNQT5AwUULF0q1nSNXmHqxr20AJjXlEhvbIZNgUfwmw8aOCyarrLi7o7w6w0Rod4DLCSeYGwlTF3P9jMcqCM+WqWHnxKY6i8gaXZkHLObatSHkwivB7Xpc=
Referer: https://fast.uc.cn/
###
# curl 'https://dl-uf-zb.pds.uc.cn/l3PNAKfz/64623447/646b0de6e9f13000c9b14ba182b805312795a82a/646b0de6717e1bfa5bb44dd2a456f103c5177850?Expires=1737791001&OSSAccessKeyId=LTAI5tJJpWQEfrcKHnd1LqsZ&Signature=n7Q7BNK5Z1rFS0nDgQZxbBBpqqE%3D&x-oss-traffic-limit=503316480&response-content-disposition=attachment%3B%20filename%3DC%2523%2520Shell%2520%2528C%2523%2520Offline%2520Compiler%2529_2.5.16.apks%3Bfilename%2A%3Dutf-8%27%27C%2523%2520Shell%2520%2528C%2523%2520Offline%2520Compiler%2529_2.5.16.apks&callback-var=eyJ4OmF1IjoiLSIsIng6dWQiOiI0LTAtNS0wLTYtTi0zLWZ0LTAtMi0wLU4iLCJ4OnNwIjoiMTAwIiwieDp0b2tlbiI6IjQtYjZlMGU5ZWUyMWFkOWZlZGIzNjMwMGY4ZWYyMWU5MjUtMi03LTE1MzYxMS1kYWNiMzY2NWJiYWE0ZjVlOWQzNzgwMGVjNjQwMzE2MC0wLTAtMC0wLTYzYmFhOGEzZGFlZGNlYzA5MmNlNzhkMDgyMmFlMjQ4IiwieDp0dGwiOiIxMDgwMCJ9&callback=eyJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24vanNvbiIsImNhbGxiYWNrU3RhZ2UiOiJiZWZvcmUtZXhlY3V0ZSIsImNhbGxiYWNrRmFpbHVyZUFjdGlvbiI6Imlnbm9yZSIsImNhbGxiYWNrVXJsIjoiaHR0cHM6Ly9hdXRoLWNkbi51Yy5jbi9vdXRlci9vc3MvY2hlY2twbGF5IiwiY2FsbGJhY2tCb2R5Ijoie1wiaG9zdFwiOiR7aHR0cEhlYWRlci5ob3N0fSxcInNpemVcIjoke3NpemV9LFwicmFuZ2VcIjoke2h0dHBIZWFkZXIucmFuZ2V9LFwicmVmZXJlclwiOiR7aHR0cEhlYWRlci5yZWZlcmVyfSxcImNvb2tpZVwiOiR7aHR0cEhlYWRlci5jb29raWV9LFwibWV0aG9kXCI6JHtodHRwSGVhZGVyLm1ldGhvZH0sXCJpcFwiOiR7Y2xpZW50SXB9LFwicG9ydFwiOiR7Y2xpZW50UG9ydH0sXCJvYmplY3RcIjoke29iamVjdH0sXCJzcFwiOiR7eDpzcH0sXCJ1ZFwiOiR7eDp1ZH0sXCJ0b2tlblwiOiR7eDp0b2tlbn0sXCJhdVwiOiR7eDphdX0sXCJ0dGxcIjoke3g6dHRsfSxcImR0X3NwXCI6JHt4OmR0X3NwfSxcImhzcFwiOiR7eDpoc3B9LFwiY2xpZW50X3Rva2VuXCI6JHtxdWVyeVN0cmluZy5jbGllbnRfdG9rZW59fSJ9&ud=4-0-5-0-6-N-3-ft-0-2-0-N'
# -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'
# -H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8'
# -H 'Cache-Control: no-cache'
# -H 'Connection: keep-alive'
# -H 'Cookie: _UP_28A_52_=519; _UP_A4A_11_=wb9c5167d67c42ba9444ac9f42b20a05; _UP_D_=pc; __sdid=AARkEnYbifr7X5obz/wd2gzbXPw1zviyFe4xBC3uVp7xQG20ziCSbbxMib8Fov3RPRk=; __pus=9db24ba75335a2deb2e99fc400ac59ffAAQ9T+W6s02ilSvzMeh5ionWLTKFfaa2QFvJNU1PoiCYQe0aunWWq5GyJCVzXrVuICNHxooijrybFKlkUoI7xCfP; __kp=aaaeba0e-8c8e-4837-869f-882283adb802; __kps=AASxYmDMULu4nzmEK/wFzK3I; __ktd=dvy3qySVr8aXEqUuxMJydA==; __uid=AASxYmDMULu4nzmEK/wFzK3I; tfstk=gJ-IibMk8WVC79FMKXHNG51AEQSSgQi2v86JnLEUeMIdVLdF_65rKL8_2QCwYaSKtg1R6Q4UY_SeVCOMsBJeU3TgVKvkYvjrKMvhqghqgmSWKpjooOET3fJteTj5pUMeYcJhqghZgmo2KpAxkBSuFgH1XT65pgUpwGpOsTX89TEKCdCG6_IR2QptCTfOpfAThTgCtpMB-WEBJUCvp1Z8V-XCJsnc1uEJf9NVMp302uK1dwtlqg1VZw8JnZxeQ0ZGYKTOX9O-DXQMJdt5o30zYpINOKb6SXZOQa1BWHQ_euphbFOyPBGQ-6Le1ZXOW8icQI59KHLsE5ppg6sdBNoxhdQJ7HbDYfECDEvFYUdtfkOA4YqVG7kLPR_02O1qCAaurBoEyuDPFR31JOXC7AM_9UbdIO1qCAaurwBGdtksCWLl.; __puus=7a473fc40c62988cd82a0e443bb2a1baAAR498zI4bjrVRD3mNor9LX8Upgw8asjZxzEjBkb4gLBZ0tfOM5jNElFhDUmiKxA9d/xwzIgTARhY8ySH0Yl8Ipm2njsKPbk3gkplByVAZ62t0TQCe0hEdprNbdImIFDM8RbnpQ5PLvMeiJMZFJyXsK9EhAWvCpp0mO7sHVVk1oxjYkuBM3jff1l6YLQaZfd3h8='
# -H 'DNT: 1'
# -H 'Pragma: no-cache'
# -H 'Referer: https://fast.uc.cn/'
# -H 'Sec-Fetch-Dest: iframe'
# -H 'Sec-Fetch-Mode: navigate'
# -H 'Sec-Fetch-Site: same-site'
# -H 'Sec-Fetch-User: ?1'
# -H 'Upgrade-Insecure-Requests: 1'
# -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36'
# -H 'sec-ch-ua: "Not A(Brand";v="8", "Chromium";v="132", "Google Chrome";v="132"'
# -H 'sec-ch-ua-mobile: ?0'
# -H 'sec-ch-ua-platform: "Windows"'
GET https://dl-uf-zb.pds.uc.cn/l3PNAKfz/64623447/646b0de6e9f13000c9b14ba182b805312795a82a/646b0de6717e1bfa5bb44dd2a456f103c5177850?Expires=1737791001&OSSAccessKeyId=LTAI5tJJpWQEfrcKHnd1LqsZ&Signature=n7Q7BNK5Z1rFS0nDgQZxbBBpqqE%3D&x-oss-traffic-limit=503316480&response-content-disposition=attachment%3B%20filename%3DC%2523%2520Shell%2520%2528C%2523%2520Offline%2520Compiler%2529_2.5.16.apks%3Bfilename%2A%3Dutf-8%27%27C%2523%2520Shell%2520%2528C%2523%2520Offline%2520Compiler%2529_2.5.16.apks&callback-var=eyJ4OmF1IjoiLSIsIng6dWQiOiI0LTAtNS0wLTYtTi0zLWZ0LTAtMi0wLU4iLCJ4OnNwIjoiMTAwIiwieDp0b2tlbiI6IjQtYjZlMGU5ZWUyMWFkOWZlZGIzNjMwMGY4ZWYyMWU5MjUtMi03LTE1MzYxMS1kYWNiMzY2NWJiYWE0ZjVlOWQzNzgwMGVjNjQwMzE2MC0wLTAtMC0wLTYzYmFhOGEzZGFlZGNlYzA5MmNlNzhkMDgyMmFlMjQ4IiwieDp0dGwiOiIxMDgwMCJ9&callback=eyJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24vanNvbiIsImNhbGxiYWNrU3RhZ2UiOiJiZWZvcmUtZXhlY3V0ZSIsImNhbGxiYWNrRmFpbHVyZUFjdGlvbiI6Imlnbm9yZSIsImNhbGxiYWNrVXJsIjoiaHR0cHM6Ly9hdXRoLWNkbi51Yy5jbi9vdXRlci9vc3MvY2hlY2twbGF5IiwiY2FsbGJhY2tCb2R5Ijoie1wiaG9zdFwiOiR7aHR0cEhlYWRlci5ob3N0fSxcInNpemVcIjoke3NpemV9LFwicmFuZ2VcIjoke2h0dHBIZWFkZXIucmFuZ2V9LFwicmVmZXJlclwiOiR7aHR0cEhlYWRlci5yZWZlcmVyfSxcImNvb2tpZVwiOiR7aHR0cEhlYWRlci5jb29raWV9LFwibWV0aG9kXCI6JHtodHRwSGVhZGVyLm1ldGhvZH0sXCJpcFwiOiR7Y2xpZW50SXB9LFwicG9ydFwiOiR7Y2xpZW50UG9ydH0sXCJvYmplY3RcIjoke29iamVjdH0sXCJzcFwiOiR7eDpzcH0sXCJ1ZFwiOiR7eDp1ZH0sXCJ0b2tlblwiOiR7eDp0b2tlbn0sXCJhdVwiOiR7eDphdX0sXCJ0dGxcIjoke3g6dHRsfSxcImR0X3NwXCI6JHt4OmR0X3NwfSxcImhzcFwiOiR7eDpoc3B9LFwiY2xpZW50X3Rva2VuXCI6JHtxdWVyeVN0cmluZy5jbGllbnRfdG9rZW59fSJ9&ud=4-0-5-0-6-N-3-ft-0-2-0-N
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Cookie: _UP_28A_52_=519; _UP_A4A_11_=wb9c5167d67c42ba9444ac9f42b20a05; _UP_D_=pc; __sdid=AARkEnYbifr7X5obz/wd2gzbXPw1zviyFe4xBC3uVp7xQG20ziCSbbxMib8Fov3RPRk=; __pus=9db24ba75335a2deb2e99fc400ac59ffAAQ9T+W6s02ilSvzMeh5ionWLTKFfaa2QFvJNU1PoiCYQe0aunWWq5GyJCVzXrVuICNHxooijrybFKlkUoI7xCfP; __kp=aaaeba0e-8c8e-4837-869f-882283adb802; __kps=AASxYmDMULu4nzmEK/wFzK3I; __ktd=dvy3qySVr8aXEqUuxMJydA==; __uid=AASxYmDMULu4nzmEK/wFzK3I; tfstk=gJ-IibMk8WVC79FMKXHNG51AEQSSgQi2v86JnLEUeMIdVLdF_65rKL8_2QCwYaSKtg1R6Q4UY_SeVCOMsBJeU3TgVKvkYvjrKMvhqghqgmSWKpjooOET3fJteTj5pUMeYcJhqghZgmo2KpAxkBSuFgH1XT65pgUpwGpOsTX89TEKCdCG6_IR2QptCTfOpfAThTgCtpMB-WEBJUCvp1Z8V-XCJsnc1uEJf9NVMp302uK1dwtlqg1VZw8JnZxeQ0ZGYKTOX9O-DXQMJdt5o30zYpINOKb6SXZOQa1BWHQ_euphbFOyPBGQ-6Le1ZXOW8icQI59KHLsE5ppg6sdBNoxhdQJ7HbDYfECDEvFYUdtfkOA4YqVG7kLPR_02O1qCAaurBoEyuDPFR31JOXC7AM_9UbdIO1qCAaurwBGdtksCWLl.;
Pragma: no-cache
Referer: https://fast.uc.cn/
###
# curl 'https://fast-api.uc.cn/1/transfer/member?fr=pc&pr=UCBrowser&fetch_rights=ALL'
# -H 'accept: application/json, text/plain, */*'
# -H 'accept-language: zh-CN,zh;q=0.9'
# -H 'cache-control: no-cache'
# -H 'cookie: __pus=52e1ead14f116cf7c9e1f661e94cd253AAT2jmfclZedBkubcvIXwKTFo7XJmjaf4bHgaMR/vSLdC1iXn192H+d3SgVIFkiWWjUAlSInoboPn7Zg5KU1Cbis; __kp=ac118c62-20c1-4e12-aac1-d901f6a0e8d4; __kps=AASxYmDMULu4nzmEK/wFzK3I; __ktd=dvy3qySVr8aXEqUuxMJydA==; __uid=AASxYmDMULu4nzmEK/wFzK3I; XSRF-TOKEN=67412de4-5552-4f80-aca5-a4e23ac2621a; XSRF-TOKEN=67412de4-5552-4f80-aca5-a4e23ac2621a; __puus=b2c6f59b3607030fb60c1d486ca09126AAR498zI4bjrVRD3mNor9LX86VT5PSEpFI0gt/S1i/S8HStTB8LEW+gpFt7z2zsuZDcCgcxzWFAPKQXYedkkQ03+iTFqCGSScL0iSNCfE1+aqsf7fkE2ToXKz+zHxg3iVTYNaSnUCkbXk6QlMPaatHGJeHuh0RpS7lG75zREt1MArKS0wWYF5hCgYogvvp92tkQ='
# -H 'dnt: 1'
# -H 'origin: https://fast.uc.cn'
# -H 'pragma: no-cache'
# -H 'priority: u=1, i'
# -H 'referer: https://fast.uc.cn/'
# -H 'sec-ch-ua: "Not A(Brand";v="8", "Chromium";v="132", "Microsoft Edge";v="132"'
# -H 'sec-ch-ua-mobile: ?0'
# -H 'sec-ch-ua-platform: "Windows"'
# -H 'sec-fetch-dest: empty'
# -H 'sec-fetch-mode: cors'
# -H 'sec-fetch-site: same-site'
# -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0'
# -H 'x-biz-retry: 0'
GET https://fast-api.uc.cn/1/transfer/member?fr=pc&pr=UCBrowser&fetch_rights=ALL
accept: application/json, text/plain, */*
accept-language: zh-CN,zh;q=0.9
cache-control: no-cache
cookie: __pus=52e1ead14f116cf7c9e1f661e94cd253AAT2jmfclZedBkubcvIXwKTFo7XJmjaf4bHgaMR/vSLdC1iXn192H+d3SgVIFkiWWjUAlSInoboPn7Zg5KU1Cbis;
dnt: 1
###
# curl 'https://fast.uc.cn/api/info?fr=pc&pr=UCBrowser'
# -H 'accept: application/json, text/plain, */*'
# -H 'accept-language: zh-CN,zh;q=0.9'
# -H 'cache-control: no-cache'
# -H 'content-type: application/json'
# -H 'cookie: UDRIVE_TRANSFER_SESS=PjvNRi7KTc55QvE9cxLKQKTWRNH_9C8dTVuWdgOJm9eKVLxXZy7_bXk92ma8wNw9XIOlqhtVTZ8BXNkV4jbTQjYjTrG8Z0FqcE_PMPDsctcmnxujbLa1jnm7SpVB2i3i-fltzwwwoI9RhkkfLZVMW3_cw2llA6Yip847Pr-auhXC-ZJpNp3nzPLANTgn19lz; b-user-id=d3b7a19e-c576-0fb1-602a-e3cf7821d90e'
# -H 'dnt: 1'
# -H 'origin: https://fast.uc.cn'
# -H 'pragma: no-cache'
# -H 'priority: u=1, i'
# -H 'referer: https://fast.uc.cn/s/33197dd53ace4'
# -H 'sec-ch-ua: "Not A(Brand";v="8", "Chromium";v="132", "Microsoft Edge";v="132"'
# -H 'sec-ch-ua-mobile: ?0'
# -H 'sec-ch-ua-platform: "Windows"'
# -H 'sec-fetch-dest: empty'
# -H 'sec-fetch-mode: cors'
# -H 'sec-fetch-site: same-origin'
# -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0'
# -H 'x-biz-retry: 0'
# --data-raw '{"st":"st9c5631ad6j032w5rdr0978zxcl1qjt"}'
# 不限跨域
POST https://fast.uc.cn/api/info?fr=pc&pr=UCBrowser
accept: application/json, text/plain, */*
accept-language: zh-CN,zh;q=0.9
cache-control: no-cache
cookie: UDRIVE_TRANSFER_SESS=PjvNRi7KTc55QvE9cxLKQKTWRNH_9C8dTVuWdgOJm9eKVLxXZy7_bXk92ma8wNw9XIOlqhtVTZ8BXNkV4jbTQjYjTrG8Z0FqcE_PMPDsctcmnxujbLa1jnm7SpVB2i3i-fltzwwwoI9RhkkfLZVMW3_cw2llA6Yip847Pr-auhXC-ZJpNp3nzPLANTgn19lz; b-user-id=d3b7a19e-c576-0fb1-602a-e3cf7821d90e
dnt: 1
origin: https://fast.qqq.cn
pragma: no-cache
priority: u=1, i
referer: https://fast.qqq.cn/s/33197dd53ace4
sec-ch-ua: "Not A(Brand";v="8", "Chromium";v="132", "Microsoft Edge";v="132"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-origin
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0
x-biz-retry: 0
Content-Type: application/json
{
"st": "xx"
}
###
wx -> st -> pus->puus
pus-> st + /info
https://fast-api.uc.cn/1/transfer/member puus
###