feat: Java SDK baseUrl 内置默认值;fix: update-service 大文件APK解析、file-service hash去重

这个提交包含在:
XuqmGroup 2026-05-03 11:00:12 +08:00
父节点 d2dea0c332
当前提交 a8293bb4c4
共有 4 个文件被更改,包括 48 次插入7 次删除

查看文件

@ -6,6 +6,7 @@ WORKDIR /workspace
COPY pom.xml ./pom.xml
COPY common ./common
COPY im-sdk ./im-sdk
COPY tenant-service ./tenant-service
COPY im-service ./im-service
COPY push-service ./push-service

查看文件

@ -76,10 +76,16 @@ public class FileStorageService {
Optional<FileEntity> existing = fileRepository.findByHash(hash);
if (existing.isPresent()) {
FileEntity entity = existing.get();
// 检查磁盘文件是否仍然存在若不存在则重新写入
if (Files.exists(Paths.get(entity.getStoragePath()))) {
entity.setLastAccessedAt(Instant.now());
fileRepository.save(entity);
return toUploadResult(entity);
}
// 文件记录存在但磁盘文件已丢失删除旧记录后重新上传
fileRepository.delete(entity);
fileRepository.flush();
}
String ext = resolveExtension(originalName, mimeType);
Path storageDir = Paths.get(uploadDir);

查看文件

@ -50,7 +50,7 @@ public final class XuqmImServerSdk {
this.objectMapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.baseUrl = trimTrailingSlash(Objects.requireNonNull(builder.baseUrl, "baseUrl"));
this.baseUrl = trimTrailingSlash(builder.baseUrl);
this.pushBaseUrl = trimTrailingSlash(builder.pushBaseUrl == null ? builder.baseUrl : builder.pushBaseUrl);
this.updateBaseUrl = trimTrailingSlash(builder.updateBaseUrl == null ? builder.baseUrl : builder.updateBaseUrl);
this.appId = Objects.requireNonNull(builder.appId, "appId");
@ -1735,8 +1735,10 @@ public final class XuqmImServerSdk {
return value.endsWith("/") ? value.substring(0, value.length() - 1) : value;
}
private static final String DEFAULT_BASE_URL = "https://dev.xuqinmin.com";
public static final class Builder {
private String baseUrl;
private String baseUrl = DEFAULT_BASE_URL;
private String pushBaseUrl;
private String updateBaseUrl;
private String appId;
@ -1776,6 +1778,8 @@ public final class XuqmImServerSdk {
}
public XuqmImServerSdk build() {
Objects.requireNonNull(this.appId, "appId is required");
Objects.requireNonNull(this.appSecret, "appSecret is required");
return new XuqmImServerSdk(this);
}
}

查看文件

@ -50,6 +50,9 @@ public class UpdateAssetService {
@Value("${update.base-url:https://update.dev.xuqinmin.com}")
private String baseUrl;
@Value("${file.service.internal-url:http://127.0.0.1:8086}")
private String fileServiceInternalUrl;
public UpdateAssetService(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@ -180,9 +183,31 @@ public class UpdateAssetService {
if (normalized.endsWith(".ipa")) {
return inspectIpa(file, fileName);
}
// 文件名无后缀时按文件魔数尝试解析APK/IPA 本质都是 ZIP
if (isZipFile(file)) {
try {
return inspectApk(file, fileName);
} catch (Exception ignored) {
}
try {
return inspectIpa(file, fileName);
} catch (Exception ignored) {
}
}
return new AppPackageInspectResult(platformFromFileName(fileName), null, null, null, fileName, false);
}
private boolean isZipFile(Path file) throws IOException {
if (!Files.exists(file) || Files.size(file) < 4) {
return false;
}
try (InputStream in = Files.newInputStream(file)) {
byte[] magic = new byte[4];
int read = in.read(magic);
return read == 4 && magic[0] == 0x50 && magic[1] == 0x4B && magic[2] == 0x03 && magic[3] == 0x04;
}
}
private AppPackageInspectResult inspectIpa(Path file, String fileName) throws Exception {
try (ZipFile zipFile = new ZipFile(file.toFile())) {
ZipEntry entry = zipFile.stream()
@ -338,9 +363,14 @@ public class UpdateAssetService {
}
private RemotePackage downloadRemotePackage(String packageUrl, boolean tempFile) throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(packageUrl).openConnection();
// 同一台服务器上的 file-service 使用内部地址避免 Nginx HTTPS 代理的性能损耗
String internalUrl = packageUrl;
if (packageUrl != null && packageUrl.contains("file.dev.xuqinmin.com")) {
internalUrl = packageUrl.replace("https://file.dev.xuqinmin.com", fileServiceInternalUrl);
}
HttpURLConnection connection = (HttpURLConnection) new URL(internalUrl).openConnection();
connection.setConnectTimeout(15_000);
connection.setReadTimeout(30_000);
connection.setReadTimeout(300_000);
connection.setInstanceFollowRedirects(true);
int status = connection.getResponseCode();