An atproto PDS written in Go

return correct responses for writes

+11 -2
server/handle_repo_apply_writes.go
··· 20 20 Value *MarshalableMap `json:"value,omitempty"` 21 21 } 22 22 23 + type ComAtprotoRepoApplyWritesResponse struct { 24 + Commit RepoCommit `json:"commit"` 25 + Results []ApplyWriteResult `json:"results"` 26 + } 27 + 23 28 func (s *Server) handleApplyWrites(e echo.Context) error { 24 29 repo := e.Get("repo").(*models.RepoActor) 25 30 ··· 49 54 }) 50 55 } 51 56 52 - if err := s.repoman.applyWrites(repo.Repo, ops, req.SwapCommit); err != nil { 57 + results, err := s.repoman.applyWrites(repo.Repo, ops, req.SwapCommit) 58 + if err != nil { 53 59 s.logger.Error("error applying writes", "error", err) 54 60 return helpers.ServerError(e, nil) 55 61 } 56 62 57 - return nil 63 + return e.JSON(200, ComAtprotoRepoApplyWritesResponse{ 64 + Commit: *results[0].Commit, 65 + Results: results, 66 + }) 58 67 }
+5 -2
server/handle_repo_create_record.go
··· 40 40 optype = OpTypeUpdate 41 41 } 42 42 43 - if err := s.repoman.applyWrites(repo.Repo, []Op{ 43 + results, err := s.repoman.applyWrites(repo.Repo, []Op{ 44 44 { 45 45 Type: optype, 46 46 Collection: req.Collection, ··· 49 49 Record: &req.Record, 50 50 SwapRecord: req.SwapRecord, 51 51 }, 52 - }, req.SwapCommit); err != nil { 52 + }, req.SwapCommit) 53 + if err != nil { 53 54 s.logger.Error("error applying writes", "error", err) 54 55 return helpers.ServerError(e, nil) 55 56 } 57 + 58 + return e.JSON(200, results[0]) 56 59 57 60 return nil 58 61 }
+4 -3
server/handle_repo_put_record.go
··· 40 40 optype = OpTypeUpdate 41 41 } 42 42 43 - if err := s.repoman.applyWrites(repo.Repo, []Op{ 43 + results, err := s.repoman.applyWrites(repo.Repo, []Op{ 44 44 { 45 45 Type: optype, 46 46 Collection: req.Collection, ··· 49 49 Record: &req.Record, 50 50 SwapRecord: req.SwapRecord, 51 51 }, 52 - }, req.SwapCommit); err != nil { 52 + }, req.SwapCommit) 53 + if err != nil { 53 54 s.logger.Error("error applying writes", "error", err) 54 55 return helpers.ServerError(e, nil) 55 56 } 56 57 57 - return nil 58 + return e.JSON(200, results[0]) 58 59 }
+41 -17
server/repo.go
··· 82 82 return nil 83 83 } 84 84 85 + type ApplyWriteResult struct { 86 + Uri string `json:"string"` 87 + Cid string `json:"cid"` 88 + Commit *RepoCommit `json:"commit"` 89 + ValidationStatus *string `json:"validationStatus"` 90 + } 91 + 92 + type RepoCommit struct { 93 + Cid string `json:"cid"` 94 + Rev string `json:"rev"` 95 + } 96 + 85 97 // TODO make use of swap commit 86 - func (rm *RepoMan) applyWrites(urepo models.Repo, writes []Op, swapCommit *string) error { 98 + func (rm *RepoMan) applyWrites(urepo models.Repo, writes []Op, swapCommit *string) ([]ApplyWriteResult, error) { 87 99 rootcid, err := cid.Cast(urepo.Root) 88 100 if err != nil { 89 - return err 101 + return nil, err 90 102 } 91 103 92 104 dbs := blockstore.New(urepo.Did, rm.db) ··· 96 108 97 109 for i, op := range writes { 98 110 if op.Type != OpTypeCreate && op.Rkey == nil { 99 - return fmt.Errorf("invalid rkey") 111 + return nil, fmt.Errorf("invalid rkey") 100 112 } else if op.Rkey == nil { 101 113 op.Rkey = to.StringPtr(rm.clock.Next().String()) 102 114 writes[i].Rkey = op.Rkey ··· 104 116 105 117 _, err := syntax.ParseRecordKey(*op.Rkey) 106 118 if err != nil { 107 - return err 119 + return nil, err 108 120 } 109 121 110 122 switch op.Type { 111 123 case OpTypeCreate: 112 124 nc, err := r.PutRecord(context.TODO(), op.Collection+"/"+*op.Rkey, op.Record) 113 125 if err != nil { 114 - return err 126 + return nil, err 115 127 } 116 128 117 129 d, _ := data.MarshalCBOR(*op.Record) ··· 126 138 case OpTypeDelete: 127 139 err := r.DeleteRecord(context.TODO(), op.Collection+"/"+*op.Rkey) 128 140 if err != nil { 129 - return err 141 + return nil, err 130 142 } 131 143 case OpTypeUpdate: 132 144 nc, err := r.UpdateRecord(context.TODO(), op.Collection+"/"+*op.Rkey, op.Record) 133 145 if err != nil { 134 - return err 146 + return nil, err 135 147 } 136 148 137 149 d, _ := data.MarshalCBOR(*op.Record) ··· 148 160 149 161 newroot, rev, err := r.Commit(context.TODO(), urepo.SignFor) 150 162 if err != nil { 151 - return err 163 + return nil, err 152 164 } 153 165 154 166 buf := new(bytes.Buffer) ··· 159 171 }) 160 172 161 173 if _, err := carstore.LdWrite(buf, hb); err != nil { 162 - return err 174 + return nil, err 163 175 } 164 176 165 177 diffops, err := r.DiffSince(context.TODO(), rootcid) 166 178 if err != nil { 167 - return err 179 + return nil, err 168 180 } 169 181 170 182 ops := make([]*atproto.SyncSubscribeRepos_RepoOp, 0, len(diffops)) ··· 194 206 195 207 blk, err := dbs.Get(context.TODO(), op.NewCid) 196 208 if err != nil { 197 - return err 209 + return nil, err 198 210 } 199 211 200 212 if _, err := carstore.LdWrite(buf, blk.Cid().Bytes(), blk.RawData()); err != nil { 201 - return err 213 + return nil, err 202 214 } 203 215 } 204 216 205 217 for _, op := range dbs.GetLog() { 206 218 if _, err := carstore.LdWrite(buf, op.Cid().Bytes(), op.RawData()); err != nil { 207 - return err 219 + return nil, err 208 220 } 209 221 } 222 + 223 + var results []ApplyWriteResult 210 224 211 225 var blobs []lexutil.LexLink 212 226 for _, entry := range entries { ··· 214 228 Columns: []clause.Column{{Name: "did"}, {Name: "nsid"}, {Name: "rkey"}}, 215 229 UpdateAll: true, 216 230 }).Create(&entry).Error; err != nil { 217 - return err 231 + return nil, err 218 232 } 219 233 220 234 // we should actually check the type (i.e. delete, create,., update) here but we'll do it later 221 235 cids, err := rm.incrementBlobRefs(urepo, entry.Value) 222 236 if err != nil { 223 - return err 237 + return nil, err 224 238 } 225 239 226 240 for _, c := range cids { 227 241 blobs = append(blobs, lexutil.LexLink(c)) 228 242 } 243 + 244 + results = append(results, ApplyWriteResult{ 245 + Uri: "at://" + urepo.Did + "/" + entry.Nsid + "/" + entry.Rkey, 246 + Cid: entry.Cid, 247 + Commit: &RepoCommit{ 248 + Cid: newroot.String(), 249 + Rev: rev, 250 + }, 251 + ValidationStatus: to.StringPtr("valid"), // TODO: obviously this might not be true atm lol 252 + }) 229 253 } 230 254 231 255 rm.s.evtman.AddEvent(context.TODO(), &events.XRPCStreamEvent{ ··· 243 267 }) 244 268 245 269 if err := dbs.UpdateRepo(context.TODO(), newroot, rev); err != nil { 246 - return err 270 + return nil, err 247 271 } 248 272 249 - return nil 273 + return results, nil 250 274 } 251 275 252 276 func (rm *RepoMan) getRecordProof(urepo models.Repo, collection, rkey string) (cid.Cid, []blocks.Block, error) {