Monorepo for Tangled tangled.org
5

Configure Feed

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

1package xrpc 2 3import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strings" 8 9 "github.com/bluesky-social/indigo/api/atproto" 10 "github.com/bluesky-social/indigo/atproto/atclient" 11 "github.com/bluesky-social/indigo/atproto/syntax" 12 "github.com/bluesky-social/indigo/xrpc" 13 "tangled.org/core/api/tangled" 14 "tangled.org/core/hostutil" 15 "tangled.org/core/knotmirror/db" 16 "tangled.org/core/knotmirror/models" 17) 18 19func (x *Xrpc) RequestCrawl(w http.ResponseWriter, r *http.Request) { 20 var input tangled.SyncRequestCrawl_Input 21 if err := json.NewDecoder(r.Body).Decode(&input); err != nil { 22 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: "failed to decode json body"}) 23 return 24 } 25 26 ctx := r.Context() 27 28 l := x.logger.With("input", input) 29 30 hostname, noSSL, err := hostutil.ParseHostname(input.Hostname) 31 if err != nil { 32 l.Error("invalid hostname", "err", err) 33 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("hostname field empty or invalid: %s", input.Hostname)}) 34 return 35 } 36 37 // TODO: check if host is Knot with knot.describeServer 38 39 // store given repoAt to db 40 // this will allow knotmirror to ingest repo creation event bypassing tap. 41 // this step won't be needed once we introduce did-for-repo 42 // TODO(boltless): remove this section 43 if input.EnsureRepo != nil { 44 repoAt, err := syntax.ParseATURI(*input.EnsureRepo) 45 if err != nil { 46 l.Error("invalid repo at-uri", "err", err) 47 writeJson(w, http.StatusBadRequest, atclient.ErrorBody{Name: "BadRequest", Message: fmt.Sprintf("repo parameter invalid: %s", *input.EnsureRepo)}) 48 return 49 } 50 owner, err := x.resolver.ResolveIdent(ctx, repoAt.Authority().String()) 51 if err != nil || owner.Handle.IsInvalidHandle() { 52 l.Error("failed to resolve ident", "err", err, "owner", repoAt.Authority().String()) 53 writeErr(w, fmt.Errorf("failed to resolve repo owner")) 54 return 55 } 56 xrpcc := xrpc.Client{Host: owner.PDSEndpoint()} 57 out, err := atproto.RepoGetRecord(ctx, &xrpcc, "", tangled.RepoNSID, repoAt.Authority().String(), repoAt.RecordKey().String()) 58 if err != nil { 59 l.Error("failed to get repo record", "err", err, "repo", repoAt) 60 writeErr(w, fmt.Errorf("failed to get repo record")) 61 return 62 } 63 record := out.Value.Val.(*tangled.Repo) 64 65 knotUrl := record.Knot 66 if !strings.Contains(record.Knot, "://") { 67 if noSSL { 68 knotUrl = "http://" + knotUrl 69 } else { 70 knotUrl = "https://" + knotUrl 71 } 72 } 73 74 if record.RepoDid == nil || *record.RepoDid == "" { 75 l.Warn("dropping repo crawl request without repo_did", "did", owner.DID, "rkey", repoAt.RecordKey()) 76 writeErr(w, fmt.Errorf("repo record missing repo_did")) 77 return 78 } 79 80 repo := &models.Repo{ 81 Did: owner.DID, 82 Rkey: repoAt.RecordKey(), 83 Cid: (*syntax.CID)(out.Cid), 84 Name: repoAt.RecordKey().String(), 85 KnotDomain: knotUrl, 86 RepoDid: syntax.DID(*record.RepoDid), 87 State: models.RepoStatePending, 88 ErrorMsg: "", 89 RetryAfter: 0, 90 RetryCount: 0, 91 } 92 93 x.logger.Debug("requestCrawl: upserting repo with knot", "knot", repo.KnotDomain) 94 if err := db.UpsertRepo(ctx, x.db, repo); err != nil { 95 l.Error("failed to upsert repo", "err", err) 96 writeErr(w, err) 97 return 98 } 99 } 100 101 // subscribe to requested host 102 if !x.ks.CheckIfSubscribed(hostname) { 103 if err := x.ks.SubscribeHost(ctx, hostname, noSSL); err != nil { 104 // TODO(boltless): return HostBanned on banned hosts 105 l.Error("failed to subscribe host", "err", err) 106 writeErr(w, err) 107 return 108 } 109 } 110 111 w.WriteHeader(http.StatusOK) 112}