Monorepo for Tangled
0

Configure Feed

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

at master 2.8 kB View raw
1package xrpc 2 3import ( 4 "context" 5 "fmt" 6 "net/http" 7 "path/filepath" 8 "strconv" 9 10 "github.com/bluesky-social/indigo/atproto/atclient" 11 "github.com/bluesky-social/indigo/atproto/syntax" 12 "tangled.org/core/knotmirror/db" 13 "tangled.org/core/knotserver/git" 14 "tangled.org/core/types" 15) 16 17func (x *Xrpc) ListBranches(w http.ResponseWriter, r *http.Request) { 18 var ( 19 repoQuery = r.URL.Query().Get("repo") 20 limitQuery = r.URL.Query().Get("limit") 21 cursorQuery = r.URL.Query().Get("cursor") 22 ) 23 24 repo, err := syntax.ParseATURI(repoQuery) 25 if err != nil || repo.RecordKey() == "" { 26 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", repoQuery)}) 27 return 28 } 29 30 limit := 50 31 if limitQuery != "" { 32 limit, err = strconv.Atoi(limitQuery) 33 if err != nil || limit < 1 || limit > 1000 { 34 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("limit parameter invalid: %s", limitQuery)}) 35 return 36 } 37 } 38 39 var cursor int64 40 if cursorQuery != "" { 41 cursor, err = strconv.ParseInt(cursorQuery, 10, 64) 42 if err != nil || cursor < 0 { 43 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("cursor parameter invalid: %s", cursorQuery)}) 44 return 45 } 46 } 47 48 out, err := x.listBranches(r.Context(), repo, limit, cursor) 49 if err != nil { 50 x.logger.Warn("local mirror failed, trying proxy", "repo", repo, "err", err) 51 if x.proxyToKnot(w, r, repo) { 52 return 53 } 54 writeJson(w, http.StatusInternalServerError, atclient.ErrorBody{Name: "InternalServerError", Message: "failed to list branches"}) 55 return 56 } 57 writeJson(w, http.StatusOK, out) 58} 59 60func (x *Xrpc) listBranches(ctx context.Context, repo syntax.ATURI, limit int, cursor int64) (*types.RepoBranchesResponse, error) { 61 repoPath, err := x.makeRepoPath(ctx, repo) 62 if err != nil { 63 return nil, fmt.Errorf("resolving repo at-uri: %w", err) 64 } 65 66 gr, err := git.PlainOpen(repoPath) 67 if err != nil { 68 return nil, fmt.Errorf("opening git repo: %w", err) 69 } 70 71 branches, err := gr.Branches(&git.BranchesOptions{ 72 Limit: limit, 73 Offset: int(cursor), 74 }) 75 if err != nil { 76 return nil, fmt.Errorf("listing git branches: %w", err) 77 } 78 79 return &types.RepoBranchesResponse{ 80 // TODO: include default branch and cursor 81 Branches: branches, 82 }, nil 83} 84 85func (x *Xrpc) makeRepoPath(ctx context.Context, repo syntax.ATURI) (string, error) { 86 r, err := db.GetRepoByAtUri(ctx, x.db, repo) 87 if err != nil { 88 return "", fmt.Errorf("looking up repo: %w", err) 89 } 90 if r == nil { 91 return "", fmt.Errorf("repo not found: %s", repo) 92 } 93 if r.RepoDid == "" { 94 return "", fmt.Errorf("repo missing repo_did: %s", repo) 95 } 96 return filepath.Join(x.cfg.GitRepoBasePath, r.RepoDid.String()), nil 97}