Monorepo for Tangled tangled.org
5

Configure Feed

Select the types of activity you want to include in your feed.

knotmirror/xrpc: load submodule only when entry type is submodule.

This still uses go-git, but at least only when we know the entry is
submodule type. This change can improve performance of `getBlob` in most
of the cases.

Signed-off-by: Seongmin Lee <git@boltless.me>

author
Seongmin Lee
committer
Lewis
date (May 29, 2026, 2:50 PM +0300) commit bcee7195 parent 400819bc change-id vzswszsk
+50 -19
+23 -14
knotmirror/xrpc/git_get_blob.go
··· 37 37 return 38 38 } 39 39 40 - size, reader, err := x.getFile(r.Context(), repo, ref, path) 40 + ctx := r.Context() 41 + 42 + repoPath, err := x.makeRepoPath(ctx, repo) 43 + if err != nil { 44 + writeJson(w, http.StatusNotFound, atclient.ErrorBody{Name: "RepoNotFound", Message: fmt.Sprintf("unknown repository: %s", repo)}) 45 + return 46 + } 47 + 48 + entry, err := x.getFile(ctx, repoPath, ref, path) 49 + if err != nil { 50 + l.Warn("local mirror failed, trying proxy", "err", err) 51 + if x.proxyToKnot(w, r, repo) { 52 + return 53 + } 54 + writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to get blob"}) 55 + return 56 + } 57 + size, reader, err := gitea.ReadBlob(ctx, repoPath, entry.Hash) 41 58 if err != nil { 42 59 l.Warn("local mirror failed, trying proxy", "err", err) 43 60 if x.proxyToKnot(w, r, repo) { ··· 100 117 w.Write(contents) 101 118 } 102 119 103 - func (x *Xrpc) getFile(ctx context.Context, repo syntax.DID, ref, path string) (int64, io.ReadCloser, error) { 104 - repoPath, err := x.makeRepoPath(ctx, repo) 105 - if err != nil { 106 - return 0, nil, fmt.Errorf("resolving repo did: %w", err) 107 - } 108 - 120 + func (x *Xrpc) getFile(ctx context.Context, repoPath, ref, path string) (*object.TreeEntry, error) { 109 121 rev := ref 110 122 if rev == "" { 111 123 rev = "HEAD" ··· 113 125 114 126 head, err := gitea.GetCommit(ctx, repoPath, rev) 115 127 if err != nil { 116 - return 0, nil, fmt.Errorf("get head commit: %w", err) 128 + return nil, fmt.Errorf("get head commit: %w", err) 117 129 } 118 130 119 131 treePath := filepath.Dir(path) ··· 126 138 } 127 139 subTree, err := gitea.GetTree(ctx, repoPath, subRev) 128 140 if err != nil { 129 - return 0, nil, fmt.Errorf("get subtree %s: %w", subRev, err) 141 + return nil, fmt.Errorf("get subtree %s: %w", subRev, err) 130 142 } 131 143 132 144 // find entry ··· 139 151 return nil, fmt.Errorf("object doesn't exist") 140 152 }(subTree) 141 153 if err != nil { 142 - return 0, nil, fmt.Errorf("get file: %w", err) 154 + return nil, fmt.Errorf("get file: %w", err) 143 155 } 144 156 145 - x.logger.Debug("ReadBlob", "name", entry.Name, "mode", entry.Mode.String(), "hash", entry.Hash.String()) 146 - 147 - // find blob 148 - return gitea.ReadBlob(ctx, repoPath, entry.Hash) 157 + return entry, nil 149 158 } 150 159 151 160 var textualMimeTypes = []string{
+27 -5
knotmirror/xrpc/repo_blob.go
··· 12 12 13 13 "github.com/bluesky-social/indigo/atproto/atclient" 14 14 "github.com/bluesky-social/indigo/atproto/syntax" 15 + "github.com/go-git/go-git/v5/plumbing/filemode" 15 16 "tangled.org/core/api/tangled" 17 + "tangled.org/core/knotmirror/xrpc/gitea" 16 18 "tangled.org/core/knotserver/git" 17 19 ) 18 20 ··· 47 49 return 48 50 } 49 51 50 - // first check if this path is a submodule 51 - submodule, err := gr.Submodule(path) 52 + ctx := r.Context() 53 + 54 + repoPath, err := x.makeRepoPath(ctx, repo) 52 55 if err != nil { 53 - // this is okay, continue and try to treat it as a regular file 54 - } else { 56 + writeJson(w, http.StatusNotFound, atclient.ErrorBody{Name: "RepoNotFound", Message: fmt.Sprintf("unknown repository: %s", repo)}) 57 + return 58 + } 59 + 60 + entry, err := x.getFile(ctx, repoPath, ref, path) 61 + if err != nil { 62 + l.Warn("local mirror failed, trying proxy", "err", err) 63 + if x.proxyToKnot(w, r, repo) { 64 + return 65 + } 66 + writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to get blob"}) 67 + return 68 + } 69 + 70 + if entry.Mode == filemode.Submodule { 71 + submodule, err := gr.Submodule(path) 72 + if err != nil { 73 + l.Warn("failed to load submodule", "err", err) 74 + writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to load submodule"}) 75 + return 76 + } 55 77 writeJson(w, http.StatusOK, tangled.RepoBlob_Output{ 56 78 Ref: ref, 57 79 Path: path, ··· 64 86 return 65 87 } 66 88 67 - size, reader, err := x.getFile(r.Context(), repo, ref, path) 89 + size, reader, err := gitea.ReadBlob(ctx, repoPath, entry.Hash) 68 90 if err != nil { 69 91 l.Warn("local mirror failed, trying proxy", "err", err) 70 92 if x.proxyToKnot(w, r, repo) {