From c86d7b0d2cf918004e17f99fa8827eb1038764a4 Mon Sep 17 00:00:00 2001 From: Timi Date: Fri, 11 Jul 2025 20:23:37 +0800 Subject: [PATCH] add fetch file MimeType for git --- .../modules/common/bean/SettingKey.java | 2 + .../git/controller/RepositoryController.java | 25 ++++++--- .../git/service/RepositoryService.java | 2 + .../implement/RepositoryServiceImplement.java | 56 +++++++++++++++++++ 4 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/imyeyu/server/modules/common/bean/SettingKey.java b/src/main/java/com/imyeyu/server/modules/common/bean/SettingKey.java index 40047f6..89ee8d1 100644 --- a/src/main/java/com/imyeyu/server/modules/common/bean/SettingKey.java +++ b/src/main/java/com/imyeyu/server/modules/common/bean/SettingKey.java @@ -111,6 +111,8 @@ public enum SettingKey { GIT_API, + GIT_REPO_PATH, + // ---------- 远程音乐 ---------- MUSIC_MAX_FRAME_LENGTH, diff --git a/src/main/java/com/imyeyu/server/modules/git/controller/RepositoryController.java b/src/main/java/com/imyeyu/server/modules/git/controller/RepositoryController.java index 1ea6c3e..cff3ed6 100644 --- a/src/main/java/com/imyeyu/server/modules/git/controller/RepositoryController.java +++ b/src/main/java/com/imyeyu/server/modules/git/controller/RepositoryController.java @@ -90,12 +90,10 @@ public class RepositoryController { * @return 文件结构树 */ @AOPLog - @RequestRateLimit + @RequestRateLimit(20) @RequestMapping("/{repoName}:{branch}/file/list/**") public List listFile(@PathVariable String repoName, @PathVariable String branch) { - String cutFlag = "/file/list/"; - String path = TimiSpring.getURI().substring(TimiSpring.getURI().indexOf(cutFlag) + cutFlag.length()); - return service.listFile(repoName, branch, path); + return service.listFile(repoName, branch, TimiSpring.cutURIStartAt("/file/list/")); } /** @@ -107,16 +105,15 @@ public class RepositoryController { */ @RequestRateLimit @IgnoreGlobalReturn - @GetMapping(value = "/{repositoryName}:{branch}/file/raw/**", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + @GetMapping("/{repositoryName}:{branch}/file/raw/**") public void raw(@PathVariable String repositoryName, @PathVariable String branch, HttpServletResponse resp) { try { - String cutFlag = "/file/raw"; - String path = TimiSpring.getURI().substring(TimiSpring.getURI().indexOf(cutFlag) + cutFlag.length()); + String path = TimiSpring.cutURIStartAt("/file/raw"); if (TimiJava.isEmpty(path)) { resp.setStatus(HttpServletResponse.SC_NOT_FOUND); resp.setCharacterEncoding(StandardCharsets.UTF_8.toString()); } else { - // TODO 获取 MIME_TYPE + resp.setContentType(service.getFileMimeType(repositoryName, branch, path)); IO.toOutputStream(service.getFileRaw(repositoryName, branch, path), resp.getOutputStream()); } } catch (Exception e) { @@ -125,6 +122,18 @@ public class RepositoryController { } } + /** + * 获取文件 MimeType + * + * @param repositoryName 仓库名称 + * @param branch 分支名称 + */ + @RequestRateLimit + @GetMapping("/{repositoryName}:{branch}/file/mime/**") + public String mimeType(@PathVariable String repositoryName, @PathVariable String branch) { + return service.getFileMimeType(repositoryName, branch, TimiSpring.cutURIStartAt("/file/mime")); + } + /** * 获取仓库提交消息列表 * diff --git a/src/main/java/com/imyeyu/server/modules/git/service/RepositoryService.java b/src/main/java/com/imyeyu/server/modules/git/service/RepositoryService.java index c9bfc62..185bcd2 100644 --- a/src/main/java/com/imyeyu/server/modules/git/service/RepositoryService.java +++ b/src/main/java/com/imyeyu/server/modules/git/service/RepositoryService.java @@ -38,5 +38,7 @@ public interface RepositoryService extends PageableService { InputStream getFileRaw(String repoName, String branch, String path); + String getFileMimeType(String repoName, String branch, String path); + InputStream getArchive(String repoName, String branch); } diff --git a/src/main/java/com/imyeyu/server/modules/git/service/implement/RepositoryServiceImplement.java b/src/main/java/com/imyeyu/server/modules/git/service/implement/RepositoryServiceImplement.java index da67796..ea7155c 100644 --- a/src/main/java/com/imyeyu/server/modules/git/service/implement/RepositoryServiceImplement.java +++ b/src/main/java/com/imyeyu/server/modules/git/service/implement/RepositoryServiceImplement.java @@ -4,8 +4,11 @@ import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; +import com.imyeyu.java.TimiJava; import com.imyeyu.java.bean.timi.TimiCode; import com.imyeyu.java.bean.timi.TimiException; +import com.imyeyu.network.Network; +import com.imyeyu.server.modules.common.bean.SettingKey; import com.imyeyu.server.modules.common.service.SettingService; import com.imyeyu.server.modules.common.service.UserService; import com.imyeyu.server.modules.git.bean.gitea.API; @@ -18,15 +21,27 @@ import com.imyeyu.server.modules.gitea.entity.User; import com.imyeyu.server.modules.gitea.service.GiteaService; import com.imyeyu.spring.bean.Page; import com.imyeyu.spring.bean.PageResult; +import jakarta.activation.MimetypesFileTypeMap; import jakarta.annotation.PostConstruct; +import lombok.Cleanup; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.hc.client5.http.fluent.Request; import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.tika.Tika; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTree; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; +import org.eclipse.jgit.treewalk.TreeWalk; import org.springframework.stereotype.Service; import java.io.InputStream; +import java.nio.file.Path; import java.util.HashMap; import java.util.List; @@ -152,6 +167,47 @@ public class RepositoryServiceImplement implements RepositoryService { } } + @Override + public String getFileMimeType(String repoName, String branch, String path) { + try { + String repoPath = settingService.getAsString(SettingKey.GIT_REPO_PATH); + if (TimiJava.isEmpty(repoPath)) { + // 根据文件名猜测 + return new MimetypesFileTypeMap().getContentType(Network.uriFileName(path)); + } else { + repoPath = "%s/%s.git".formatted(repoPath, repoName); + // 仓库 + @Cleanup + org.eclipse.jgit.lib.Repository repo = new FileRepositoryBuilder().setGitDir(Path.of(repoPath).toFile()).build(); + TimiException.required(repo, "not found repository: %s".formatted(repoPath)); + + // 分支 + ObjectId commitId = repo.resolve("refs/heads/%s".formatted(branch)); + TimiException.required(commitId, "not found branch: %s".formatted(branch)); + + // 提交 + RevWalk revWalk = new RevWalk(repo); + RevCommit commit = revWalk.parseCommit(commitId); + RevTree tree = commit.getTree(); + + // 文件 + path = path.substring(1); + TreeWalk treeWalk = TreeWalk.forPath(repo, path, tree); + TimiException.required(treeWalk, "not found file: %s".formatted(path)); + ObjectId fileObjectId = treeWalk.getObjectId(0); + + // 读取文件 + ObjectReader reader = repo.newObjectReader(); + ObjectLoader loader = reader.open(fileObjectId); + InputStream stream = loader.openStream(); + return new Tika().detect(stream); + } + } catch (Exception e) { + log.error("get repository file mime error", e); + throw new TimiException(TimiCode.ERROR, "get repository file mime error", e); + } + } + @Override public InputStream getArchive(String repoName, String branch) { try {