···
···
comatproto "github.com/bluesky-social/indigo/api/atproto"
lexutil "github.com/bluesky-social/indigo/lex/util"
23
+
indigoxrpc "github.com/bluesky-social/indigo/xrpc"
"tangled.sh/tangled.sh/core/api/tangled"
"tangled.sh/tangled.sh/core/appview/commitverify"
"tangled.sh/tangled.sh/core/appview/config"
···
xrpcclient "tangled.sh/tangled.sh/core/appview/xrpcclient"
"tangled.sh/tangled.sh/core/eventconsumer"
"tangled.sh/tangled.sh/core/idresolver"
34
-
"tangled.sh/tangled.sh/core/knotclient"
"tangled.sh/tangled.sh/core/patchutil"
"tangled.sh/tangled.sh/core/rbac"
"tangled.sh/tangled.sh/core/tid"
···
96
-
if rp.config.Core.Dev {
97
+
if !rp.config.Core.Dev {
100
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
101
+
xrpcc := &indigoxrpc.Client{
105
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
106
+
archiveBytes, err := tangled.RepoArchive(r.Context(), xrpcc, "tar.gz", "", refParam, repo)
108
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
109
+
log.Println("failed to call XRPC repo.archive", xrpcerr)
110
+
rp.pages.Error503(w)
113
+
rp.pages.Error404(w)
101
-
url := fmt.Sprintf("%s://%s/%s/%s/archive/%s.tar.gz", uri, f.Knot, f.OwnerDid(), f.Name, url.PathEscape(refParam))
103
-
http.Redirect(w, r, url, http.StatusFound)
117
+
// Set headers for file download
118
+
filename := fmt.Sprintf("%s-%s.tar.gz", f.Name, refParam)
119
+
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
120
+
w.Header().Set("Content-Type", "application/gzip")
121
+
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(archiveBytes)))
123
+
// Write the archive data directly
124
+
w.Write(archiveBytes)
func (rp *Repo) RepoLog(w http.ResponseWriter, r *http.Request) {
···
ref := chi.URLParam(r, "ref")
123
-
us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev)
145
+
if !rp.config.Core.Dev {
148
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
149
+
xrpcc := &indigoxrpc.Client{
156
+
// Convert page number to cursor (offset)
157
+
offset := (page - 1) * int(limit)
158
+
cursor = strconv.Itoa(offset)
161
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
162
+
xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, repo)
125
-
log.Println("failed to create unsigned client", err)
164
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
165
+
log.Println("failed to call XRPC repo.log", xrpcerr)
166
+
rp.pages.Error503(w)
169
+
rp.pages.Error404(w)
129
-
repolog, err := us.Log(f.OwnerDid(), f.Name, ref, page)
173
+
var xrpcResp types.RepoLogResponse
174
+
if err := json.Unmarshal(xrpcBytes, &xrpcResp); err != nil {
175
+
log.Println("failed to decode XRPC response", err)
132
-
log.Println("failed to reach knotserver", err)
136
-
tagResult, err := us.Tags(f.OwnerDid(), f.Name)
180
+
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
138
-
rp.pages.Error503(w)
139
-
log.Println("failed to reach knotserver", err)
182
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
183
+
log.Println("failed to call XRPC repo.tags", xrpcerr)
184
+
rp.pages.Error503(w)
tagMap := make(map[string][]string)
144
-
for _, tag := range tagResult.Tags {
146
-
if tag.Tag != nil {
147
-
hash = tag.Tag.Target.String()
190
+
if tagBytes != nil {
191
+
var tagResp types.RepoTagsResponse
192
+
if err := json.Unmarshal(tagBytes, &tagResp); err == nil {
193
+
for _, tag := range tagResp.Tags {
194
+
tagMap[tag.Hash] = append(tagMap[tag.Hash], tag.Name)
149
-
tagMap[hash] = append(tagMap[hash], tag.Name)
152
-
branchResult, err := us.Branches(f.OwnerDid(), f.Name)
199
+
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
154
-
rp.pages.Error503(w)
155
-
log.Println("failed to reach knotserver", err)
201
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
202
+
log.Println("failed to call XRPC repo.branches", xrpcerr)
203
+
rp.pages.Error503(w)
159
-
for _, branch := range branchResult.Branches {
160
-
hash := branch.Hash
161
-
tagMap[hash] = append(tagMap[hash], branch.Name)
208
+
if branchBytes != nil {
209
+
var branchResp types.RepoBranchesResponse
210
+
if err := json.Unmarshal(branchBytes, &branchResp); err == nil {
211
+
for _, branch := range branchResp.Branches {
212
+
tagMap[branch.Hash] = append(tagMap[branch.Hash], branch.Name)
user := rp.oauth.GetUser(r)
166
-
emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(repolog.Commits), true)
219
+
emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(xrpcResp.Commits), true)
log.Println("failed to fetch email to did mapping", err)
171
-
vc, err := commitverify.GetVerifiedObjectCommits(rp.db, emailToDidMap, repolog.Commits)
224
+
vc, err := commitverify.GetVerifiedObjectCommits(rp.db, emailToDidMap, xrpcResp.Commits)
···
repoInfo := f.RepoInfo(user)
179
-
for _, c := range repolog.Commits {
232
+
for _, c := range xrpcResp.Commits {
shas = append(shas, c.Hash.String())
pipelines, err := getPipelineStatuses(rp.db, repoInfo, shas)
···
192
-
RepoLogResponse: *repolog,
245
+
RepoLogResponse: xrpcResp,
EmailToDidOrHandle: emailToDidOrHandle(rp, emailToDidMap),
···
ref := chi.URLParam(r, "ref")
305
-
if !rp.config.Core.Dev {
var diffOpts types.DiffOpts
if d := r.URL.Query().Get("diff"); d == "split" {
···
319
-
resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/commit/%s", protocol, f.Knot, f.OwnerDid(), f.Repo.Name, ref))
321
-
rp.pages.Error503(w)
322
-
log.Println("failed to reach knotserver", err)
369
+
if !rp.config.Core.Dev {
372
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
373
+
xrpcc := &indigoxrpc.Client{
326
-
body, err := io.ReadAll(resp.Body)
377
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
378
+
xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo)
328
-
log.Printf("Error reading response body: %v", err)
380
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
381
+
log.Println("failed to call XRPC repo.diff", xrpcerr)
382
+
rp.pages.Error503(w)
385
+
rp.pages.Error404(w)
var result types.RepoCommitResponse
333
-
err = json.Unmarshal(body, &result)
335
-
log.Println("failed to parse response:", err)
390
+
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
391
+
log.Println("failed to decode XRPC response", err)
392
+
rp.pages.Error503(w)
···
ref := chi.URLParam(r, "ref")
treePath := chi.URLParam(r, "*")
382
-
if !rp.config.Core.Dev {
// if the tree path has a trailing slash, let's strip it
treePath = strings.TrimSuffix(treePath, "/")
390
-
resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/tree/%s/%s", protocol, f.Knot, f.OwnerDid(), f.Repo.Name, ref, treePath))
392
-
rp.pages.Error503(w)
393
-
log.Println("failed to reach knotserver", err)
444
+
if !rp.config.Core.Dev {
447
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
448
+
xrpcc := &indigoxrpc.Client{
397
-
// uhhh so knotserver returns a 500 if the entry isn't found in
398
-
// the requested tree path, so let's stick to not-OK here.
399
-
// we can fix this once we build out the xrpc apis for these operations.
400
-
if resp.StatusCode != http.StatusOK {
452
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
453
+
xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, repo)
455
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
456
+
log.Println("failed to call XRPC repo.tree", xrpcerr)
457
+
rp.pages.Error503(w)
405
-
body, err := io.ReadAll(resp.Body)
407
-
log.Printf("Error reading response body: %v", err)
464
+
// Convert XRPC response to internal types.RepoTreeResponse
465
+
files := make([]types.NiceTree, len(xrpcResp.Files))
466
+
for i, xrpcFile := range xrpcResp.Files {
467
+
file := types.NiceTree{
468
+
Name: xrpcFile.Name,
469
+
Mode: xrpcFile.Mode,
470
+
Size: int64(xrpcFile.Size),
471
+
IsFile: xrpcFile.Is_file,
472
+
IsSubtree: xrpcFile.Is_subtree,
475
+
// Convert last commit info if present
476
+
if xrpcFile.Last_commit != nil {
477
+
commitWhen, _ := time.Parse(time.RFC3339, xrpcFile.Last_commit.When)
478
+
file.LastCommit = &types.LastCommitInfo{
479
+
Hash: plumbing.NewHash(xrpcFile.Last_commit.Hash),
480
+
Message: xrpcFile.Last_commit.Message,
411
-
var result types.RepoTreeResponse
412
-
err = json.Unmarshal(body, &result)
414
-
log.Println("failed to parse response:", err)
488
+
result := types.RepoTreeResponse{
493
+
if xrpcResp.Parent != nil {
494
+
result.Parent = *xrpcResp.Parent
496
+
if xrpcResp.Dotdot != nil {
497
+
result.DotDot = *xrpcResp.Dotdot
// redirects tree paths trying to access a blob; in this case the result.Files is unpopulated,
···
454
-
us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev)
537
+
if !rp.config.Core.Dev {
540
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
541
+
xrpcc := &indigoxrpc.Client{
545
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
546
+
xrpcBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
456
-
log.Println("failed to create unsigned client", err)
548
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
549
+
log.Println("failed to call XRPC repo.tags", xrpcerr)
550
+
rp.pages.Error503(w)
553
+
rp.pages.Error404(w)
460
-
result, err := us.Tags(f.OwnerDid(), f.Name)
557
+
var result types.RepoTagsResponse
558
+
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
559
+
log.Println("failed to decode XRPC response", err)
463
-
log.Println("failed to reach knotserver", err)
···
rp.pages.RepoTags(w, pages.RepoTagsParams{
RepoInfo: f.RepoInfo(user),
499
-
RepoTagsResponse: *result,
596
+
RepoTagsResponse: result,
ArtifactMap: artifactMap,
DanglingArtifacts: danglingArtifacts,
···
512
-
us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev)
610
+
if !rp.config.Core.Dev {
613
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
614
+
xrpcc := &indigoxrpc.Client{
618
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
619
+
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
514
-
log.Println("failed to create unsigned client", err)
621
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
622
+
log.Println("failed to call XRPC repo.branches", xrpcerr)
623
+
rp.pages.Error503(w)
626
+
rp.pages.Error404(w)
518
-
result, err := us.Branches(f.OwnerDid(), f.Name)
630
+
var result types.RepoBranchesResponse
631
+
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
632
+
log.Println("failed to decode XRPC response", err)
521
-
log.Println("failed to reach knotserver", err)
···
rp.pages.RepoBranches(w, pages.RepoBranchesParams{
RepoInfo: f.RepoInfo(user),
531
-
RepoBranchesResponse: *result,
643
+
RepoBranchesResponse: result,
···
ref := chi.URLParam(r, "ref")
filePath := chi.URLParam(r, "*")
548
-
resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.Repo.Name, ref, filePath))
550
-
rp.pages.Error503(w)
551
-
log.Println("failed to reach knotserver", err)
555
-
if resp.StatusCode == http.StatusNotFound {
556
-
rp.pages.Error404(w)
661
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
662
+
xrpcc := &indigoxrpc.Client{
560
-
body, err := io.ReadAll(resp.Body)
666
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Repo.Name)
667
+
resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, repo)
562
-
log.Printf("Error reading response body: %v", err)
669
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
670
+
log.Println("failed to call XRPC repo.blob", xrpcerr)
671
+
rp.pages.Error503(w)
674
+
rp.pages.Error404(w)
566
-
var result types.RepoBlobResponse
567
-
err = json.Unmarshal(body, &result)
569
-
log.Println("failed to parse response:", err)
678
+
// Use XRPC response directly instead of converting to internal types
var breadcrumbs [][]string
breadcrumbs = append(breadcrumbs, []string{f.Name, fmt.Sprintf("/%s/tree/%s", f.OwnerSlashRepo(), ref)})
···
584
-
if markup.GetFormat(result.Path) == markup.FormatMarkdown {
691
+
if markup.GetFormat(resp.Path) == markup.FormatMarkdown {
showRendered = r.URL.Query().Get("code") != "true"
···
594
-
if result.IsBinary {
595
-
ext := strings.ToLower(filepath.Ext(result.Path))
701
+
if resp.IsBinary != nil && *resp.IsBinary {
702
+
ext := strings.ToLower(filepath.Ext(resp.Path))
case ".jpg", ".jpeg", ".png", ".gif", ".svg", ".webp":
···
605
-
// fetch the actual binary content like in RepoBlobRaw
712
+
// fetch the raw binary content using sh.tangled.repo.blob xrpc
713
+
repoName := path.Join("%s/%s", f.OwnerDid(), f.Name)
714
+
blobURL := fmt.Sprintf("%s://%s/xrpc/sh.tangled.repo.blob?repo=%s&ref=%s&path=%s&raw=true",
715
+
scheme, f.Knot, url.QueryEscape(repoName), url.QueryEscape(ref), url.QueryEscape(filePath))
607
-
blobURL := fmt.Sprintf("%s://%s/%s/%s/raw/%s/%s", protocol, f.Knot, f.OwnerDid(), f.Name, ref, filePath)
contentSrc = markup.GenerateCamoURL(rp.config.Camo.Host, rp.config.Camo.SharedSecret, blobURL)
724
+
if resp.IsBinary == nil || !*resp.IsBinary {
725
+
lines = strings.Count(resp.Content, "\n") + 1
728
+
var sizeHint uint64
729
+
if resp.Size != nil {
730
+
sizeHint = uint64(*resp.Size)
732
+
sizeHint = uint64(len(resp.Content))
user := rp.oauth.GetUser(r)
737
+
// Determine if content is binary (dereference pointer)
739
+
if resp.IsBinary != nil {
740
+
isBinary = *resp.IsBinary
rp.pages.RepoBlob(w, pages.RepoBlobParams{
616
-
LoggedInUser: user,
617
-
RepoInfo: f.RepoInfo(user),
618
-
RepoBlobResponse: result,
619
-
BreadCrumbs: breadcrumbs,
620
-
ShowRendered: showRendered,
621
-
RenderToggle: renderToggle,
622
-
Unsupported: unsupported,
625
-
ContentSrc: contentSrc,
744
+
LoggedInUser: user,
745
+
RepoInfo: f.RepoInfo(user),
746
+
BreadCrumbs: breadcrumbs,
747
+
ShowRendered: showRendered,
748
+
RenderToggle: renderToggle,
749
+
Unsupported: unsupported,
752
+
ContentSrc: contentSrc,
753
+
RepoBlob_Output: resp,
754
+
Contents: resp.Content,
756
+
SizeHint: sizeHint,
757
+
IsBinary: isBinary,
···
ref := chi.URLParam(r, "ref")
filePath := chi.URLParam(r, "*")
645
-
blobURL := fmt.Sprintf("%s://%s/%s/%s/raw/%s/%s", protocol, f.Knot, f.OwnerDid(), f.Repo.Name, ref, filePath)
777
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Repo.Name)
778
+
blobURL := fmt.Sprintf("%s://%s/xrpc/sh.tangled.repo.blob?repo=%s&ref=%s&path=%s&raw=true",
779
+
scheme, f.Knot, url.QueryEscape(repo), url.QueryEscape(ref), url.QueryEscape(filePath))
req, err := http.NewRequest("GET", blobURL, nil)
···
688
-
// Safely serve content based on type
if strings.HasPrefix(contentType, "text/") || isTextualMimeType(contentType) {
690
-
// Serve all textual content as text/plain for security
823
+
// serve all textual content as text/plain
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
} else if strings.HasPrefix(contentType, "image/") || strings.HasPrefix(contentType, "video/") {
694
-
// Serve images and videos with their original content type
827
+
// serve images and videos with their original content type
w.Header().Set("Content-Type", contentType)
698
-
// Block potentially dangerous content types
w.WriteHeader(http.StatusUnsupportedMediaType)
w.Write([]byte("unsupported content type"))
···
719
-
for _, t := range textualTypes {
851
+
return slices.Contains(textualTypes, mimeType)
// modify the spindle configured for this repo
···
f, err := rp.repoResolver.Resolve(r)
user := rp.oauth.GetUser(r)
1230
-
us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev)
1358
+
if !rp.config.Core.Dev {
1361
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
1362
+
xrpcc := &indigoxrpc.Client{
1366
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
1367
+
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
1232
-
log.Println("failed to create unsigned client", err)
1369
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1370
+
log.Println("failed to call XRPC repo.branches", xrpcerr)
1371
+
rp.pages.Error503(w)
1374
+
rp.pages.Error503(w)
1236
-
result, err := us.Branches(f.OwnerDid(), f.Name)
1378
+
var result types.RepoBranchesResponse
1379
+
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
1380
+
log.Println("failed to decode XRPC response", err)
1239
-
log.Println("failed to reach knotserver", err)
···
1610
-
us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev)
1753
+
if !rp.config.Core.Dev {
1756
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
1757
+
xrpcc := &indigoxrpc.Client{
1761
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
1762
+
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
1612
-
log.Printf("failed to create unsigned client for %s", f.Knot)
1613
-
rp.pages.Error503(w)
1764
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1765
+
log.Println("failed to call XRPC repo.branches", xrpcerr)
1766
+
rp.pages.Error503(w)
1769
+
rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
1617
-
result, err := us.Branches(f.OwnerDid(), f.Name)
1773
+
var branchResult types.RepoBranchesResponse
1774
+
if err := json.Unmarshal(branchBytes, &branchResult); err != nil {
1775
+
log.Println("failed to decode XRPC branches response", err)
rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
1620
-
log.Println("failed to reach knotserver", err)
1623
-
branches := result.Branches
1779
+
branches := branchResult.Branches
···
1647
-
tags, err := us.Tags(f.OwnerDid(), f.Name)
1803
+
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
1805
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1806
+
log.Println("failed to call XRPC repo.tags", xrpcerr)
1807
+
rp.pages.Error503(w)
rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
1650
-
log.Println("failed to reach knotserver", err)
1814
+
var tags types.RepoTagsResponse
1815
+
if err := json.Unmarshal(tagBytes, &tags); err != nil {
1816
+
log.Println("failed to decode XRPC tags response", err)
1817
+
rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
···
1702
-
us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev)
1870
+
if !rp.config.Core.Dev {
1873
+
host := fmt.Sprintf("%s://%s", scheme, f.Knot)
1874
+
xrpcc := &indigoxrpc.Client{
1878
+
repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name)
1880
+
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
1704
-
log.Printf("failed to create unsigned client for %s", f.Knot)
1705
-
rp.pages.Error503(w)
1882
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1883
+
log.Println("failed to call XRPC repo.branches", xrpcerr)
1884
+
rp.pages.Error503(w)
1887
+
rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
1891
+
var branches types.RepoBranchesResponse
1892
+
if err := json.Unmarshal(branchBytes, &branches); err != nil {
1893
+
log.Println("failed to decode XRPC branches response", err)
1894
+
rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
1709
-
branches, err := us.Branches(f.OwnerDid(), f.Name)
1898
+
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
1900
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1901
+
log.Println("failed to call XRPC repo.tags", xrpcerr)
1902
+
rp.pages.Error503(w)
rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
1712
-
log.Println("failed to reach knotserver", err)
1909
+
var tags types.RepoTagsResponse
1910
+
if err := json.Unmarshal(tagBytes, &tags); err != nil {
1911
+
log.Println("failed to decode XRPC tags response", err)
1912
+
rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
1716
-
tags, err := us.Tags(f.OwnerDid(), f.Name)
1916
+
compareBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, base, head)
1918
+
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1919
+
log.Println("failed to call XRPC repo.compare", xrpcerr)
1920
+
rp.pages.Error503(w)
rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
1719
-
log.Println("failed to reach knotserver", err)
1723
-
formatPatch, err := us.Compare(f.OwnerDid(), f.Name, base, head)
1927
+
var formatPatch types.RepoFormatPatchResponse
1928
+
if err := json.Unmarshal(compareBytes, &formatPatch); err != nil {
1929
+
log.Println("failed to decode XRPC compare response", err)
rp.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
1726
-
log.Println("failed to compare", err)
diff := patchutil.AsNiceDiff(formatPatch.Patch, base)
repoinfo := f.RepoInfo(user)