diff --git a/knotmirror/xrpc/proxy.go b/knotmirror/xrpc/proxy.go index 4fc6a2d4..ff1cd67b 100644 --- a/knotmirror/xrpc/proxy.go +++ b/knotmirror/xrpc/proxy.go @@ -25,7 +25,6 @@ var mirrorToKnotNSID = map[string]string{ tangled.GitTempGetBranchNSID: tangled.RepoBranchNSID, tangled.GitTempGetTagNSID: tangled.RepoTagNSID, tangled.GitTempGetArchiveNSID: tangled.RepoArchiveNSID, - tangled.RepoBlobNSID: tangled.RepoBlobNSID, tangled.GitTempListLanguagesNSID: tangled.RepoLanguagesNSID, } diff --git a/knotmirror/xrpc/repo_blob.go b/knotmirror/xrpc/repo_blob.go deleted file mode 100644 index c53b5404..00000000 --- a/knotmirror/xrpc/repo_blob.go +++ /dev/null @@ -1,187 +0,0 @@ -package xrpc - -import ( - "context" - "encoding/base64" - "fmt" - "io" - "net/http" - "path/filepath" - "strings" - "time" - - "github.com/bluesky-social/indigo/atproto/atclient" - "github.com/bluesky-social/indigo/atproto/syntax" - "github.com/go-git/go-git/v5/plumbing/filemode" - "tangled.org/core/api/tangled" - "tangled.org/core/knotmirror/xrpc/gitea" - "tangled.org/core/knotserver/git" -) - -// TODO(boltless): rewrite lexicon in new NSID -func (x *Xrpc) RepoBlob(w http.ResponseWriter, r *http.Request) { - var ( - repoQuery = r.URL.Query().Get("repo") - ref = r.URL.Query().Get("ref") // ref can be empty (git.Open handles this) - path = r.URL.Query().Get("path") - ) - - repo, err := syntax.ParseDID(repoQuery) - if err != nil { - writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) - return - } - - l := x.logger.With("method", "repo.blob", "repo", repo, "ref", ref, "path", path) - - if path == "" { - writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: "missing path parameter"}) - return - } - - gr, err := x.getRepo(r.Context(), repo, ref) - if err != nil { - l.Warn("local mirror failed, trying proxy", "err", err) - if x.proxyToKnot(w, r, repo) { - return - } - writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to get blob"}) - return - } - - ctx := r.Context() - - repoPath, err := x.makeRepoPath(ctx, repo) - if err != nil { - writeJson(w, http.StatusNotFound, atclient.ErrorBody{Name: "RepoNotFound", Message: fmt.Sprintf("unknown repository: %s", repo)}) - return - } - - entry, err := gitea.GetEntry(ctx, repoPath, ref, path) - if err != nil { - l.Warn("local mirror failed, trying proxy", "err", err) - if x.proxyToKnot(w, r, repo) { - return - } - writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to get blob"}) - return - } - - if entry.Mode == filemode.Submodule { - submodule, err := gr.Submodule(path) - if err != nil { - l.Warn("failed to load submodule", "err", err) - writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to load submodule"}) - return - } - writeJson(w, http.StatusOK, tangled.RepoBlob_Output{ - Ref: ref, - Path: path, - Submodule: &tangled.RepoBlob_Submodule{ - Name: submodule.Name, - Url: submodule.URL, - Branch: &submodule.Branch, - }, - }) - return - } - - size, reader, err := gitea.ReadBlob(ctx, repoPath, entry.Hash) - if err != nil { - l.Warn("local mirror failed, trying proxy", "err", err) - if x.proxyToKnot(w, r, repo) { - return - } - writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to get blob"}) - return - } - defer reader.Close() - - if size > 1000*1000 { // 1MB - fileTooLarge := true - writeJson(w, http.StatusOK, tangled.RepoBlob_Output{ - Ref: ref, - Path: path, - Size: &size, - FileTooLarge: &fileTooLarge, - }) - return - } - - contents, err := io.ReadAll(reader) - if err != nil { - l.Error("failed to read blob content", "err", err) - writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to read the blob"}) - return - } - - mimeType := http.DetectContentType(contents) - // override MIME types for formats that http.DetectContentType does not recognize - switch filepath.Ext(path) { - case ".svg": - mimeType = "image/svg+xml" - case ".avif": - mimeType = "image/avif" - case ".jxl": - mimeType = "image/jxl" - case ".heic", ".heif": - mimeType = "image/heif" - } - - isBinary := !(strings.HasPrefix(mimeType, "text/") || isTextualMimeType(mimeType)) - - // include content for text blob or svg - var content *string - if !isBinary { - content = new(string) - *content = string(contents) - } else if filepath.Ext(path) == ".svg" { - content = new(string) - *content = base64.StdEncoding.EncodeToString(contents) - } - - response := tangled.RepoBlob_Output{ - Ref: ref, - Path: path, - Size: &size, - IsBinary: &isBinary, - Content: content, - } - - ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second) - defer cancel() - - lastCommit, err := gr.LastCommitFile(ctx, path) - if err == nil && lastCommit != nil { - response.LastCommit = &tangled.RepoBlob_LastCommit{ - Hash: lastCommit.Hash.String(), - Message: lastCommit.Message, - When: lastCommit.When.Format(time.RFC3339), - } - - // try to get author information - commit, err := gr.Commit(lastCommit.Hash) - if err == nil { - response.LastCommit.Author = &tangled.RepoBlob_Signature{ - Name: commit.Author.Name, - Email: commit.Author.Email, - } - } - } - - writeJson(w, http.StatusOK, response) -} - -func (x *Xrpc) getRepo(ctx context.Context, repo syntax.DID, ref string) (*git.GitRepo, error) { - repoPath, err := x.makeRepoPath(ctx, repo) - if err != nil { - return nil, fmt.Errorf("resolving repo did: %w", err) - } - - gr, err := git.Open(repoPath, ref) - if err != nil { - return nil, fmt.Errorf("opening git repo: %w", err) - } - - return gr, nil -} diff --git a/knotmirror/xrpc/xrpc.go b/knotmirror/xrpc/xrpc.go index 21e4cf1d..115a4002 100644 --- a/knotmirror/xrpc/xrpc.go +++ b/knotmirror/xrpc/xrpc.go @@ -72,7 +72,6 @@ func (x *Xrpc) Router() http.Handler { r.Get("/"+tangled.GitTempListCommitsNSID, x.ListCommits) r.Get("/"+tangled.GitTempListLanguagesNSID, x.ListLanguages) r.Get("/"+tangled.GitTempListTagsNSID, x.ListTags) - r.Get("/"+tangled.RepoBlobNSID, x.RepoBlob) r.Post("/"+tangled.SyncRequestCrawlNSID, x.RequestCrawl) })