1package xrpc
2
3import (
4 "encoding/json"
5 "net/http"
6 "net/url"
7 "strconv"
8
9 "tangled.sh/tangled.sh/core/knotserver/git"
10 "tangled.sh/tangled.sh/core/types"
11 xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors"
12)
13
14func (x *Xrpc) RepoLog(w http.ResponseWriter, r *http.Request) {
15 repo := r.URL.Query().Get("repo")
16 repoPath, err := x.parseRepoParam(repo)
17 if err != nil {
18 writeError(w, err.(xrpcerr.XrpcError), http.StatusBadRequest)
19 return
20 }
21
22 refParam := r.URL.Query().Get("ref")
23 if refParam == "" {
24 writeError(w, xrpcerr.NewXrpcError(
25 xrpcerr.WithTag("InvalidRequest"),
26 xrpcerr.WithMessage("missing ref parameter"),
27 ), http.StatusBadRequest)
28 return
29 }
30
31 path := r.URL.Query().Get("path")
32 cursor := r.URL.Query().Get("cursor")
33
34 limit := 50 // default
35 if limitStr := r.URL.Query().Get("limit"); limitStr != "" {
36 if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 100 {
37 limit = l
38 }
39 }
40
41 ref, err := url.QueryUnescape(refParam)
42 if err != nil {
43 writeError(w, xrpcerr.NewXrpcError(
44 xrpcerr.WithTag("InvalidRequest"),
45 xrpcerr.WithMessage("invalid ref parameter"),
46 ), http.StatusBadRequest)
47 return
48 }
49
50 gr, err := git.Open(repoPath, ref)
51 if err != nil {
52 writeError(w, xrpcerr.NewXrpcError(
53 xrpcerr.WithTag("RefNotFound"),
54 xrpcerr.WithMessage("repository or ref not found"),
55 ), http.StatusNotFound)
56 return
57 }
58
59 offset := 0
60 if cursor != "" {
61 if o, err := strconv.Atoi(cursor); err == nil && o >= 0 {
62 offset = o
63 }
64 }
65
66 commits, err := gr.Commits(offset, limit)
67 if err != nil {
68 x.Logger.Error("fetching commits", "error", err.Error())
69 writeError(w, xrpcerr.NewXrpcError(
70 xrpcerr.WithTag("PathNotFound"),
71 xrpcerr.WithMessage("failed to read commit log"),
72 ), http.StatusNotFound)
73 return
74 }
75
76 // Create response using existing types.RepoLogResponse
77 response := types.RepoLogResponse{
78 Commits: commits,
79 Ref: ref,
80 Page: (offset / limit) + 1,
81 PerPage: limit,
82 Total: len(commits), // This is not accurate for pagination, but matches existing behavior
83 }
84
85 if path != "" {
86 response.Description = path
87 }
88
89 response.Log = true
90
91 // Write JSON response directly
92 w.Header().Set("Content-Type", "application/json")
93 if err := json.NewEncoder(w).Encode(response); err != nil {
94 x.Logger.Error("failed to encode response", "error", err)
95 writeError(w, xrpcerr.NewXrpcError(
96 xrpcerr.WithTag("InternalServerError"),
97 xrpcerr.WithMessage("failed to encode response"),
98 ), http.StatusInternalServerError)
99 return
100 }
101}