this repo has no description
0
fork

Configure Feed

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

carstore aka clowncar implementation

+1889 -100
+31 -1
api/atproto.go
··· 42 42 DeclarationCid string `json:"declarationCid"` 43 43 } 44 44 45 - func (atp *ATProto) CreateAccount(ctx context.Context, email, handle, password string) (*CreateAccountResp, error) { 45 + func (atp *ATProto) CreateAccount(ctx context.Context, email, handle, password string, invite *string) (*CreateAccountResp, error) { 46 46 body := map[string]string{ 47 47 "email": email, 48 48 "handle": handle, 49 49 "password": password, 50 + } 51 + 52 + if invite != nil { 53 + body["inviteCode"] = *invite 50 54 } 51 55 52 56 var resp CreateAccountResp ··· 112 116 113 117 return out.Root, nil 114 118 } 119 + 120 + func (atp *ATProto) HandleResolve(ctx context.Context, handle string) (string, error) { 121 + params := map[string]interface{}{ 122 + "handle": handle, 123 + } 124 + 125 + var out struct { 126 + Did string `json:"did"` 127 + } 128 + if err := atp.C.Do(ctx, xrpc.Query, "com.atproto.handle.resolve", params, nil, &out); err != nil { 129 + return "", err 130 + } 131 + 132 + return out.Did, nil 133 + 134 + } 135 + 136 + func (atp *ATProto) SessionRefresh(ctx context.Context) (*xrpc.AuthInfo, error) { 137 + var out xrpc.AuthInfo 138 + if err := atp.C.Do(ctx, xrpc.Procedure, "com.atproto.session.refresh", nil, nil, &out); err != nil { 139 + return nil, err 140 + } 141 + 142 + return &out, nil 143 + 144 + }
+50 -22
api/bsky.go
··· 12 12 } 13 13 14 14 type PostEntity struct { 15 - Index []int `json:"index"` 16 - Type string `json:"type"` 17 - Value string `json:"value"` 15 + Index []int64 `json:"index"` 16 + Type string `json:"type"` 17 + Value string `json:"value"` 18 18 } 19 19 20 - type replyRef struct { 20 + type ReplyRef struct { 21 21 Root PostRef `json:"root"` 22 22 Parent PostRef `json:"parent"` 23 23 } 24 24 25 25 type PostRecord struct { 26 - Text string `json:"text"` 27 - Entities *PostEntity `json:"entities,omitempty"` 28 - Reply *replyRef `json:"reply,omitempty"` 29 - CreatedAt string `json:"createdAt"` 26 + Type string `json:"$type,omitempty" cborgen:"$type"` 27 + Text string `json:"text" cborgen:"text"` 28 + Entities []*PostEntity `json:"entities,omitempty" cborgen:"entities"` 29 + Reply *ReplyRef `json:"reply,omitempty" cborgen:"reply"` 30 + CreatedAt string `json:"createdAt" cborgen:"createdAt"` 30 31 } 31 32 32 - func (pr PostRecord) Type() string { 33 - return "app.bsky.feed.post" 33 + func (pr *PostRecord) FixType() { 34 + pr.Type = "app.bsky.feed.post" 34 35 } 35 36 36 37 type JsonLD interface { 37 - Type() string 38 + FixType() 38 39 } 39 40 40 41 type RecordWrapper struct { ··· 42 43 } 43 44 44 45 func (rw *RecordWrapper) MarshalJSON() ([]byte, error) { 45 - b, err := json.Marshal(rw.Sub) 46 - if err != nil { 47 - return nil, err 48 - } 49 - 50 - inject := "\"$type\":\"" + rw.Sub.Type() + "\"," 51 - 52 - n := append([]byte("{"), []byte(inject)...) 53 - n = append(n, b[1:]...) 54 - 55 - return n, nil 46 + rw.Sub.FixType() 47 + return json.Marshal(rw.Sub) 56 48 } 57 49 58 50 type PostRef struct { ··· 114 106 115 107 return &out, nil 116 108 } 109 + 110 + type GSADeclaration struct { 111 + Cid string `json:"cid"` 112 + ActorType string `json:"actorType"` 113 + } 114 + 115 + type GetSuggestionsActor struct { 116 + Did string `json:"did"` 117 + Declaration *GSADeclaration `json:"declaration"` 118 + Handle string `json:"handle"` 119 + DisplayName string `json:"displayName"` 120 + Description string `json:"description"` 121 + IndexedAt string `json:"indexedAt"` 122 + } 123 + 124 + type GetSuggestionsResp struct { 125 + Cursor string `json:"cursor"` 126 + Actors []GetSuggestionsActor `json:"actors"` 127 + } 128 + 129 + func (b *BskyApp) ActorGetSuggestions(ctx context.Context, limit int, cursor *string) (*GetSuggestionsResp, error) { 130 + params := map[string]interface{}{ 131 + "limit": limit, 132 + } 133 + 134 + if cursor != nil { 135 + params["cursor"] = *cursor 136 + } 137 + 138 + var out GetSuggestionsResp 139 + if err := b.C.Do(ctx, xrpc.Query, "app.bsky.actor.getSuggestions", params, nil, &out); err != nil { 140 + return nil, err 141 + } 142 + 143 + return &out, nil 144 + }
+723
api/cbor_gen.go
··· 1 + // Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. 2 + 3 + package api 4 + 5 + import ( 6 + "fmt" 7 + "io" 8 + "math" 9 + "sort" 10 + 11 + cid "github.com/ipfs/go-cid" 12 + cbg "github.com/whyrusleeping/cbor-gen" 13 + xerrors "golang.org/x/xerrors" 14 + ) 15 + 16 + var _ = xerrors.Errorf 17 + var _ = cid.Undef 18 + var _ = math.E 19 + var _ = sort.Sort 20 + 21 + func (t *PostRecord) MarshalCBOR(w io.Writer) error { 22 + if t == nil { 23 + _, err := w.Write(cbg.CborNull) 24 + return err 25 + } 26 + 27 + cw := cbg.NewCborWriter(w) 28 + 29 + if _, err := cw.Write([]byte{165}); err != nil { 30 + return err 31 + } 32 + 33 + // t.Type (string) (string) 34 + if len("$type") > cbg.MaxLength { 35 + return xerrors.Errorf("Value in field \"$type\" was too long") 36 + } 37 + 38 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil { 39 + return err 40 + } 41 + if _, err := io.WriteString(w, string("$type")); err != nil { 42 + return err 43 + } 44 + 45 + if len(t.Type) > cbg.MaxLength { 46 + return xerrors.Errorf("Value in field t.Type was too long") 47 + } 48 + 49 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Type))); err != nil { 50 + return err 51 + } 52 + if _, err := io.WriteString(w, string(t.Type)); err != nil { 53 + return err 54 + } 55 + 56 + // t.Text (string) (string) 57 + if len("text") > cbg.MaxLength { 58 + return xerrors.Errorf("Value in field \"text\" was too long") 59 + } 60 + 61 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("text"))); err != nil { 62 + return err 63 + } 64 + if _, err := io.WriteString(w, string("text")); err != nil { 65 + return err 66 + } 67 + 68 + if len(t.Text) > cbg.MaxLength { 69 + return xerrors.Errorf("Value in field t.Text was too long") 70 + } 71 + 72 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Text))); err != nil { 73 + return err 74 + } 75 + if _, err := io.WriteString(w, string(t.Text)); err != nil { 76 + return err 77 + } 78 + 79 + // t.Entities ([]*api.PostEntity) (slice) 80 + if len("entities") > cbg.MaxLength { 81 + return xerrors.Errorf("Value in field \"entities\" was too long") 82 + } 83 + 84 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("entities"))); err != nil { 85 + return err 86 + } 87 + if _, err := io.WriteString(w, string("entities")); err != nil { 88 + return err 89 + } 90 + 91 + if len(t.Entities) > cbg.MaxLength { 92 + return xerrors.Errorf("Slice value in field t.Entities was too long") 93 + } 94 + 95 + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Entities))); err != nil { 96 + return err 97 + } 98 + for _, v := range t.Entities { 99 + if err := v.MarshalCBOR(cw); err != nil { 100 + return err 101 + } 102 + } 103 + 104 + // t.Reply (api.ReplyRef) (struct) 105 + if len("reply") > cbg.MaxLength { 106 + return xerrors.Errorf("Value in field \"reply\" was too long") 107 + } 108 + 109 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("reply"))); err != nil { 110 + return err 111 + } 112 + if _, err := io.WriteString(w, string("reply")); err != nil { 113 + return err 114 + } 115 + 116 + if err := t.Reply.MarshalCBOR(cw); err != nil { 117 + return err 118 + } 119 + 120 + // t.CreatedAt (string) (string) 121 + if len("createdAt") > cbg.MaxLength { 122 + return xerrors.Errorf("Value in field \"createdAt\" was too long") 123 + } 124 + 125 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("createdAt"))); err != nil { 126 + return err 127 + } 128 + if _, err := io.WriteString(w, string("createdAt")); err != nil { 129 + return err 130 + } 131 + 132 + if len(t.CreatedAt) > cbg.MaxLength { 133 + return xerrors.Errorf("Value in field t.CreatedAt was too long") 134 + } 135 + 136 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.CreatedAt))); err != nil { 137 + return err 138 + } 139 + if _, err := io.WriteString(w, string(t.CreatedAt)); err != nil { 140 + return err 141 + } 142 + return nil 143 + } 144 + 145 + func (t *PostRecord) UnmarshalCBOR(r io.Reader) (err error) { 146 + *t = PostRecord{} 147 + 148 + cr := cbg.NewCborReader(r) 149 + 150 + maj, extra, err := cr.ReadHeader() 151 + if err != nil { 152 + return err 153 + } 154 + defer func() { 155 + if err == io.EOF { 156 + err = io.ErrUnexpectedEOF 157 + } 158 + }() 159 + 160 + if maj != cbg.MajMap { 161 + return fmt.Errorf("cbor input should be of type map") 162 + } 163 + 164 + if extra > cbg.MaxLength { 165 + return fmt.Errorf("PostRecord: map struct too large (%d)", extra) 166 + } 167 + 168 + var name string 169 + n := extra 170 + 171 + for i := uint64(0); i < n; i++ { 172 + 173 + { 174 + sval, err := cbg.ReadString(cr) 175 + if err != nil { 176 + return err 177 + } 178 + 179 + name = string(sval) 180 + } 181 + 182 + switch name { 183 + // t.Type (string) (string) 184 + case "$type": 185 + 186 + { 187 + sval, err := cbg.ReadString(cr) 188 + if err != nil { 189 + return err 190 + } 191 + 192 + t.Type = string(sval) 193 + } 194 + // t.Text (string) (string) 195 + case "text": 196 + 197 + { 198 + sval, err := cbg.ReadString(cr) 199 + if err != nil { 200 + return err 201 + } 202 + 203 + t.Text = string(sval) 204 + } 205 + // t.Entities ([]*api.PostEntity) (slice) 206 + case "entities": 207 + 208 + maj, extra, err = cr.ReadHeader() 209 + if err != nil { 210 + return err 211 + } 212 + 213 + if extra > cbg.MaxLength { 214 + return fmt.Errorf("t.Entities: array too large (%d)", extra) 215 + } 216 + 217 + if maj != cbg.MajArray { 218 + return fmt.Errorf("expected cbor array") 219 + } 220 + 221 + if extra > 0 { 222 + t.Entities = make([]*PostEntity, extra) 223 + } 224 + 225 + for i := 0; i < int(extra); i++ { 226 + 227 + var v PostEntity 228 + if err := v.UnmarshalCBOR(cr); err != nil { 229 + return err 230 + } 231 + 232 + t.Entities[i] = &v 233 + } 234 + 235 + // t.Reply (api.ReplyRef) (struct) 236 + case "reply": 237 + 238 + { 239 + 240 + b, err := cr.ReadByte() 241 + if err != nil { 242 + return err 243 + } 244 + if b != cbg.CborNull[0] { 245 + if err := cr.UnreadByte(); err != nil { 246 + return err 247 + } 248 + t.Reply = new(ReplyRef) 249 + if err := t.Reply.UnmarshalCBOR(cr); err != nil { 250 + return xerrors.Errorf("unmarshaling t.Reply pointer: %w", err) 251 + } 252 + } 253 + 254 + } 255 + // t.CreatedAt (string) (string) 256 + case "createdAt": 257 + 258 + { 259 + sval, err := cbg.ReadString(cr) 260 + if err != nil { 261 + return err 262 + } 263 + 264 + t.CreatedAt = string(sval) 265 + } 266 + 267 + default: 268 + // Field doesn't exist on this type, so ignore it 269 + cbg.ScanForLinks(r, func(cid.Cid) {}) 270 + } 271 + } 272 + 273 + return nil 274 + } 275 + func (t *PostEntity) MarshalCBOR(w io.Writer) error { 276 + if t == nil { 277 + _, err := w.Write(cbg.CborNull) 278 + return err 279 + } 280 + 281 + cw := cbg.NewCborWriter(w) 282 + 283 + if _, err := cw.Write([]byte{163}); err != nil { 284 + return err 285 + } 286 + 287 + // t.Index ([]int64) (slice) 288 + if len("Index") > cbg.MaxLength { 289 + return xerrors.Errorf("Value in field \"Index\" was too long") 290 + } 291 + 292 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("Index"))); err != nil { 293 + return err 294 + } 295 + if _, err := io.WriteString(w, string("Index")); err != nil { 296 + return err 297 + } 298 + 299 + if len(t.Index) > cbg.MaxLength { 300 + return xerrors.Errorf("Slice value in field t.Index was too long") 301 + } 302 + 303 + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Index))); err != nil { 304 + return err 305 + } 306 + for _, v := range t.Index { 307 + if v >= 0 { 308 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(v)); err != nil { 309 + return err 310 + } 311 + } else { 312 + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-v-1)); err != nil { 313 + return err 314 + } 315 + } 316 + } 317 + 318 + // t.Type (string) (string) 319 + if len("Type") > cbg.MaxLength { 320 + return xerrors.Errorf("Value in field \"Type\" was too long") 321 + } 322 + 323 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("Type"))); err != nil { 324 + return err 325 + } 326 + if _, err := io.WriteString(w, string("Type")); err != nil { 327 + return err 328 + } 329 + 330 + if len(t.Type) > cbg.MaxLength { 331 + return xerrors.Errorf("Value in field t.Type was too long") 332 + } 333 + 334 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Type))); err != nil { 335 + return err 336 + } 337 + if _, err := io.WriteString(w, string(t.Type)); err != nil { 338 + return err 339 + } 340 + 341 + // t.Value (string) (string) 342 + if len("Value") > cbg.MaxLength { 343 + return xerrors.Errorf("Value in field \"Value\" was too long") 344 + } 345 + 346 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("Value"))); err != nil { 347 + return err 348 + } 349 + if _, err := io.WriteString(w, string("Value")); err != nil { 350 + return err 351 + } 352 + 353 + if len(t.Value) > cbg.MaxLength { 354 + return xerrors.Errorf("Value in field t.Value was too long") 355 + } 356 + 357 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Value))); err != nil { 358 + return err 359 + } 360 + if _, err := io.WriteString(w, string(t.Value)); err != nil { 361 + return err 362 + } 363 + return nil 364 + } 365 + 366 + func (t *PostEntity) UnmarshalCBOR(r io.Reader) (err error) { 367 + *t = PostEntity{} 368 + 369 + cr := cbg.NewCborReader(r) 370 + 371 + maj, extra, err := cr.ReadHeader() 372 + if err != nil { 373 + return err 374 + } 375 + defer func() { 376 + if err == io.EOF { 377 + err = io.ErrUnexpectedEOF 378 + } 379 + }() 380 + 381 + if maj != cbg.MajMap { 382 + return fmt.Errorf("cbor input should be of type map") 383 + } 384 + 385 + if extra > cbg.MaxLength { 386 + return fmt.Errorf("PostEntity: map struct too large (%d)", extra) 387 + } 388 + 389 + var name string 390 + n := extra 391 + 392 + for i := uint64(0); i < n; i++ { 393 + 394 + { 395 + sval, err := cbg.ReadString(cr) 396 + if err != nil { 397 + return err 398 + } 399 + 400 + name = string(sval) 401 + } 402 + 403 + switch name { 404 + // t.Index ([]int64) (slice) 405 + case "Index": 406 + 407 + maj, extra, err = cr.ReadHeader() 408 + if err != nil { 409 + return err 410 + } 411 + 412 + if extra > cbg.MaxLength { 413 + return fmt.Errorf("t.Index: array too large (%d)", extra) 414 + } 415 + 416 + if maj != cbg.MajArray { 417 + return fmt.Errorf("expected cbor array") 418 + } 419 + 420 + if extra > 0 { 421 + t.Index = make([]int64, extra) 422 + } 423 + 424 + for i := 0; i < int(extra); i++ { 425 + { 426 + maj, extra, err := cr.ReadHeader() 427 + var extraI int64 428 + if err != nil { 429 + return err 430 + } 431 + switch maj { 432 + case cbg.MajUnsignedInt: 433 + extraI = int64(extra) 434 + if extraI < 0 { 435 + return fmt.Errorf("int64 positive overflow") 436 + } 437 + case cbg.MajNegativeInt: 438 + extraI = int64(extra) 439 + if extraI < 0 { 440 + return fmt.Errorf("int64 negative oveflow") 441 + } 442 + extraI = -1 - extraI 443 + default: 444 + return fmt.Errorf("wrong type for int64 field: %d", maj) 445 + } 446 + 447 + t.Index[i] = int64(extraI) 448 + } 449 + } 450 + 451 + // t.Type (string) (string) 452 + case "Type": 453 + 454 + { 455 + sval, err := cbg.ReadString(cr) 456 + if err != nil { 457 + return err 458 + } 459 + 460 + t.Type = string(sval) 461 + } 462 + // t.Value (string) (string) 463 + case "Value": 464 + 465 + { 466 + sval, err := cbg.ReadString(cr) 467 + if err != nil { 468 + return err 469 + } 470 + 471 + t.Value = string(sval) 472 + } 473 + 474 + default: 475 + // Field doesn't exist on this type, so ignore it 476 + cbg.ScanForLinks(r, func(cid.Cid) {}) 477 + } 478 + } 479 + 480 + return nil 481 + } 482 + func (t *PostRef) MarshalCBOR(w io.Writer) error { 483 + if t == nil { 484 + _, err := w.Write(cbg.CborNull) 485 + return err 486 + } 487 + 488 + cw := cbg.NewCborWriter(w) 489 + 490 + if _, err := cw.Write([]byte{162}); err != nil { 491 + return err 492 + } 493 + 494 + // t.Uri (string) (string) 495 + if len("Uri") > cbg.MaxLength { 496 + return xerrors.Errorf("Value in field \"Uri\" was too long") 497 + } 498 + 499 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("Uri"))); err != nil { 500 + return err 501 + } 502 + if _, err := io.WriteString(w, string("Uri")); err != nil { 503 + return err 504 + } 505 + 506 + if len(t.Uri) > cbg.MaxLength { 507 + return xerrors.Errorf("Value in field t.Uri was too long") 508 + } 509 + 510 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Uri))); err != nil { 511 + return err 512 + } 513 + if _, err := io.WriteString(w, string(t.Uri)); err != nil { 514 + return err 515 + } 516 + 517 + // t.Cid (string) (string) 518 + if len("Cid") > cbg.MaxLength { 519 + return xerrors.Errorf("Value in field \"Cid\" was too long") 520 + } 521 + 522 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("Cid"))); err != nil { 523 + return err 524 + } 525 + if _, err := io.WriteString(w, string("Cid")); err != nil { 526 + return err 527 + } 528 + 529 + if len(t.Cid) > cbg.MaxLength { 530 + return xerrors.Errorf("Value in field t.Cid was too long") 531 + } 532 + 533 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Cid))); err != nil { 534 + return err 535 + } 536 + if _, err := io.WriteString(w, string(t.Cid)); err != nil { 537 + return err 538 + } 539 + return nil 540 + } 541 + 542 + func (t *PostRef) UnmarshalCBOR(r io.Reader) (err error) { 543 + *t = PostRef{} 544 + 545 + cr := cbg.NewCborReader(r) 546 + 547 + maj, extra, err := cr.ReadHeader() 548 + if err != nil { 549 + return err 550 + } 551 + defer func() { 552 + if err == io.EOF { 553 + err = io.ErrUnexpectedEOF 554 + } 555 + }() 556 + 557 + if maj != cbg.MajMap { 558 + return fmt.Errorf("cbor input should be of type map") 559 + } 560 + 561 + if extra > cbg.MaxLength { 562 + return fmt.Errorf("PostRef: map struct too large (%d)", extra) 563 + } 564 + 565 + var name string 566 + n := extra 567 + 568 + for i := uint64(0); i < n; i++ { 569 + 570 + { 571 + sval, err := cbg.ReadString(cr) 572 + if err != nil { 573 + return err 574 + } 575 + 576 + name = string(sval) 577 + } 578 + 579 + switch name { 580 + // t.Uri (string) (string) 581 + case "Uri": 582 + 583 + { 584 + sval, err := cbg.ReadString(cr) 585 + if err != nil { 586 + return err 587 + } 588 + 589 + t.Uri = string(sval) 590 + } 591 + // t.Cid (string) (string) 592 + case "Cid": 593 + 594 + { 595 + sval, err := cbg.ReadString(cr) 596 + if err != nil { 597 + return err 598 + } 599 + 600 + t.Cid = string(sval) 601 + } 602 + 603 + default: 604 + // Field doesn't exist on this type, so ignore it 605 + cbg.ScanForLinks(r, func(cid.Cid) {}) 606 + } 607 + } 608 + 609 + return nil 610 + } 611 + func (t *ReplyRef) MarshalCBOR(w io.Writer) error { 612 + if t == nil { 613 + _, err := w.Write(cbg.CborNull) 614 + return err 615 + } 616 + 617 + cw := cbg.NewCborWriter(w) 618 + 619 + if _, err := cw.Write([]byte{162}); err != nil { 620 + return err 621 + } 622 + 623 + // t.Root (api.PostRef) (struct) 624 + if len("Root") > cbg.MaxLength { 625 + return xerrors.Errorf("Value in field \"Root\" was too long") 626 + } 627 + 628 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("Root"))); err != nil { 629 + return err 630 + } 631 + if _, err := io.WriteString(w, string("Root")); err != nil { 632 + return err 633 + } 634 + 635 + if err := t.Root.MarshalCBOR(cw); err != nil { 636 + return err 637 + } 638 + 639 + // t.Parent (api.PostRef) (struct) 640 + if len("Parent") > cbg.MaxLength { 641 + return xerrors.Errorf("Value in field \"Parent\" was too long") 642 + } 643 + 644 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("Parent"))); err != nil { 645 + return err 646 + } 647 + if _, err := io.WriteString(w, string("Parent")); err != nil { 648 + return err 649 + } 650 + 651 + if err := t.Parent.MarshalCBOR(cw); err != nil { 652 + return err 653 + } 654 + return nil 655 + } 656 + 657 + func (t *ReplyRef) UnmarshalCBOR(r io.Reader) (err error) { 658 + *t = ReplyRef{} 659 + 660 + cr := cbg.NewCborReader(r) 661 + 662 + maj, extra, err := cr.ReadHeader() 663 + if err != nil { 664 + return err 665 + } 666 + defer func() { 667 + if err == io.EOF { 668 + err = io.ErrUnexpectedEOF 669 + } 670 + }() 671 + 672 + if maj != cbg.MajMap { 673 + return fmt.Errorf("cbor input should be of type map") 674 + } 675 + 676 + if extra > cbg.MaxLength { 677 + return fmt.Errorf("ReplyRef: map struct too large (%d)", extra) 678 + } 679 + 680 + var name string 681 + n := extra 682 + 683 + for i := uint64(0); i < n; i++ { 684 + 685 + { 686 + sval, err := cbg.ReadString(cr) 687 + if err != nil { 688 + return err 689 + } 690 + 691 + name = string(sval) 692 + } 693 + 694 + switch name { 695 + // t.Root (api.PostRef) (struct) 696 + case "Root": 697 + 698 + { 699 + 700 + if err := t.Root.UnmarshalCBOR(cr); err != nil { 701 + return xerrors.Errorf("unmarshaling t.Root: %w", err) 702 + } 703 + 704 + } 705 + // t.Parent (api.PostRef) (struct) 706 + case "Parent": 707 + 708 + { 709 + 710 + if err := t.Parent.UnmarshalCBOR(cr); err != nil { 711 + return xerrors.Errorf("unmarshaling t.Parent: %w", err) 712 + } 713 + 714 + } 715 + 716 + default: 717 + // Field doesn't exist on this type, so ignore it 718 + cbg.ScanForLinks(r, func(cid.Cid) {}) 719 + } 720 + } 721 + 722 + return nil 723 + }
+56
api/extra.go
··· 1 + package api 2 + 3 + import ( 4 + "context" 5 + "fmt" 6 + "net/url" 7 + 8 + did "github.com/whyrusleeping/go-did" 9 + ) 10 + 11 + func ResolveDidToHandle(ctx context.Context, atp *ATProto, pls *PLCServer, udid string) (string, string, error) { 12 + doc, err := pls.GetDocument(udid) 13 + if err != nil { 14 + return "", "", err 15 + } 16 + 17 + if len(doc.AlsoKnownAs) == 0 { 18 + return "", "", fmt.Errorf("users did document does not specify a handle") 19 + } 20 + 21 + aka := doc.AlsoKnownAs[0] 22 + 23 + u, err := url.Parse(aka) 24 + if err != nil { 25 + return "", "", fmt.Errorf("aka field in doc was not a valid url: %w", err) 26 + } 27 + 28 + handle := u.Host 29 + 30 + var svc *did.Service 31 + for _, s := range doc.Service { 32 + if s.Type == "AtpPersonalDataServer" { 33 + svc = &s 34 + break 35 + } 36 + } 37 + 38 + if svc == nil { 39 + return "", "", fmt.Errorf("users did document has no pds service set") 40 + } 41 + 42 + if svc.ServiceEndpoint != atp.C.Host { 43 + return "", "", fmt.Errorf("our atp client is authed for a different pds (%s != %s)", svc.ServiceEndpoint, atp.C.Host) 44 + } 45 + 46 + verdid, err := atp.HandleResolve(ctx, handle) 47 + if err != nil { 48 + return "", "", err 49 + } 50 + 51 + if verdid != udid { 52 + return "", "", fmt.Errorf("pds server reported different did for claimed handle") 53 + } 54 + 55 + return handle, svc.ServiceEndpoint, nil 56 + }
+11 -1
api/plc.go
··· 10 10 11 11 type PLCServer struct { 12 12 Host string 13 + C *http.Client 13 14 } 14 15 15 16 func (s *PLCServer) GetDocument(didstr string) (*did.Document, error) { 16 - resp, err := http.Get(s.Host + "/" + didstr) 17 + if s.C == nil { 18 + s.C = http.DefaultClient 19 + } 20 + 21 + req, err := http.NewRequest("GET", s.Host+"/"+didstr, nil) 22 + if err != nil { 23 + return nil, err 24 + } 25 + 26 + resp, err := s.C.Do(req) 17 27 if err != nil { 18 28 return nil, err 19 29 }
+407
carstore/bs.go
··· 1 + package carstore 2 + 3 + import ( 4 + "bufio" 5 + "context" 6 + "encoding/binary" 7 + "fmt" 8 + "io" 9 + "os" 10 + "path/filepath" 11 + 12 + blocks "github.com/ipfs/go-block-format" 13 + "github.com/ipfs/go-car/util" 14 + "github.com/ipfs/go-cid" 15 + "github.com/ipfs/go-datastore" 16 + blockstore "github.com/ipfs/go-ipfs-blockstore" 17 + cbor "github.com/ipfs/go-ipld-cbor" 18 + ipld "github.com/ipfs/go-ipld-format" 19 + car "github.com/ipld/go-car" 20 + "gorm.io/gorm" 21 + ) 22 + 23 + type CarStore struct { 24 + meta *gorm.DB 25 + rootDir string 26 + } 27 + 28 + func NewCarStore(meta *gorm.DB, root string) (*CarStore, error) { 29 + if err := meta.AutoMigrate(&CarShard{}, &blockRef{}); err != nil { 30 + return nil, err 31 + } 32 + return &CarStore{ 33 + meta: meta, 34 + rootDir: root, 35 + }, nil 36 + } 37 + 38 + type UserInfo struct { 39 + gorm.Model 40 + Head string 41 + } 42 + 43 + type CarShard struct { 44 + gorm.Model 45 + 46 + Root string 47 + DataStart int64 48 + Seq int 49 + Path string 50 + User uint 51 + } 52 + 53 + type blockRef struct { 54 + gorm.Model 55 + Cid string 56 + Shard uint 57 + Offset int64 58 + } 59 + 60 + type userView struct { 61 + cs *CarStore 62 + user uint 63 + } 64 + 65 + var _ blockstore.Blockstore = (*userView)(nil) 66 + 67 + func (uv *userView) HashOnRead(hor bool) { 68 + //noop 69 + } 70 + 71 + func (uv *userView) Has(ctx context.Context, k cid.Cid) (bool, error) { 72 + // TODO: for now, im using a join to ensure we only query blocks from the 73 + // correct user. maybe it makes sense to put the user in the blockRef 74 + // directly? tradeoff of time vs space 75 + var count int64 76 + if err := uv.cs.meta. 77 + Model(blockRef{}). 78 + Select("path, offset"). 79 + Joins("left join car_shards on block_refs.shard = car_shards.id"). 80 + Where("user = ? AND cid = ?", uv.user, k.String()). 81 + Count(&count).Error; err != nil { 82 + return false, err 83 + } 84 + 85 + return count > 0, nil 86 + } 87 + 88 + func (uv *userView) Get(ctx context.Context, k cid.Cid) (blocks.Block, error) { 89 + // TODO: for now, im using a join to ensure we only query blocks from the 90 + // correct user. maybe it makes sense to put the user in the blockRef 91 + // directly? tradeoff of time vs space 92 + var info struct { 93 + Path string 94 + Offset int64 95 + } 96 + if err := uv.cs.meta. 97 + Model(blockRef{}). 98 + Select("path, offset"). 99 + Joins("left join car_shards on block_refs.shard = car_shards.id"). 100 + Where("user = ? AND cid = ?", uv.user, k.String()). 101 + First(&info).Error; err != nil { 102 + if err == gorm.ErrRecordNotFound { 103 + return nil, ipld.ErrNotFound{k} 104 + 105 + } 106 + return nil, err 107 + } 108 + 109 + fi, err := os.Open(info.Path) 110 + if err != nil { 111 + return nil, err 112 + } 113 + 114 + seeked, err := fi.Seek(info.Offset, io.SeekStart) 115 + if err != nil { 116 + return nil, err 117 + } 118 + 119 + if seeked != info.Offset { 120 + return nil, fmt.Errorf("failed to seek to offset (%d != %d)", seeked, info.Offset) 121 + } 122 + 123 + bufr := bufio.NewReader(fi) 124 + rcid, data, err := util.ReadNode(bufr) 125 + if err != nil { 126 + return nil, err 127 + } 128 + 129 + if rcid != k { 130 + return nil, fmt.Errorf("mismatch in cid on disk: %s != %s", rcid, k) 131 + } 132 + 133 + return blocks.NewBlockWithCid(data, rcid) 134 + } 135 + 136 + func (uv *userView) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { 137 + return nil, fmt.Errorf("not implemented") 138 + } 139 + 140 + func (uv *userView) Put(ctx context.Context, blk blocks.Block) error { 141 + return fmt.Errorf("puts not supported to car view blockstores") 142 + } 143 + 144 + func (uv *userView) PutMany(ctx context.Context, blks []blocks.Block) error { 145 + return fmt.Errorf("puts not supported to car view blockstores") 146 + } 147 + 148 + func (uv *userView) DeleteBlock(ctx context.Context, k cid.Cid) error { 149 + return fmt.Errorf("deletes not supported to car view blockstore") 150 + } 151 + 152 + func (uv *userView) GetSize(ctx context.Context, k cid.Cid) (int, error) { 153 + // TODO: maybe block size should be in the database record... 154 + blk, err := uv.Get(ctx, k) 155 + if err != nil { 156 + return 0, err 157 + } 158 + 159 + return len(blk.RawData()), nil 160 + } 161 + 162 + type DeltaSession struct { 163 + fresh blockstore.Blockstore 164 + blks map[cid.Cid]blocks.Block 165 + base blockstore.Blockstore 166 + user uint 167 + seq int 168 + cs *CarStore 169 + } 170 + 171 + func (cs *CarStore) NewDeltaSession(user uint, prev cid.Cid) (*DeltaSession, error) { 172 + // TODO: ensure that we don't write updates on top of the wrong head 173 + // this needs to be a compare and swap type operation 174 + var lastShard CarShard 175 + if err := cs.meta.Model(CarShard{}).Limit(1).Order("seq desc").Find(&lastShard).Error; err != nil { 176 + return nil, err 177 + } 178 + 179 + return &DeltaSession{ 180 + fresh: blockstore.NewBlockstore(datastore.NewMapDatastore()), 181 + blks: make(map[cid.Cid]blocks.Block), 182 + base: &userView{ 183 + user: user, 184 + cs: cs, 185 + }, 186 + user: user, 187 + cs: cs, 188 + seq: lastShard.Seq + 1, 189 + }, nil 190 + } 191 + 192 + func (cs *CarStore) ReadUserCar(ctx context.Context, user uint, until cid.Cid, incremental bool, w io.Writer) error { 193 + var untilSeq int 194 + 195 + if until.Defined() { 196 + var untilShard CarShard 197 + if err := cs.meta.First(&untilShard, "root = ? AND user = ?", until.String(), user).Error; err != nil { 198 + return err 199 + } 200 + untilSeq = untilShard.Seq 201 + } 202 + 203 + var shards []CarShard 204 + if err := cs.meta.Order("seq desc").Find(&shards, "user = ? AND seq >= ?", user, untilSeq).Error; err != nil { 205 + return err 206 + } 207 + 208 + if !incremental && until.Defined() { 209 + // have to do it the ugly way 210 + return fmt.Errorf("nyi") 211 + } 212 + 213 + if len(shards) == 0 { 214 + return fmt.Errorf("no data found for user %d", user) 215 + } 216 + 217 + // fast path! 218 + rootcid, err := cid.Decode(shards[0].Root) 219 + if err != nil { 220 + return err 221 + } 222 + 223 + if err := car.WriteHeader(&car.CarHeader{ 224 + Roots: []cid.Cid{rootcid}, 225 + Version: 1, 226 + }, w); err != nil { 227 + return err 228 + } 229 + 230 + for _, sh := range shards { 231 + if err := cs.writeShardBlocks(ctx, &sh, w); err != nil { 232 + return err 233 + } 234 + } 235 + 236 + return nil 237 + } 238 + 239 + func (cs *CarStore) writeShardBlocks(ctx context.Context, sh *CarShard, w io.Writer) error { 240 + fi, err := os.Open(sh.Path) 241 + if err != nil { 242 + return err 243 + } 244 + 245 + _, err = fi.Seek(sh.DataStart, io.SeekStart) 246 + if err != nil { 247 + return err 248 + } 249 + 250 + _, err = io.Copy(w, fi) 251 + if err != nil { 252 + return err 253 + } 254 + 255 + return nil 256 + } 257 + 258 + var _ blockstore.Blockstore = (*DeltaSession)(nil) 259 + 260 + func (ds *DeltaSession) Put(ctx context.Context, b blocks.Block) error { 261 + ds.blks[b.Cid()] = b 262 + return nil 263 + } 264 + 265 + func (ds *DeltaSession) PutMany(ctx context.Context, bs []blocks.Block) error { 266 + for _, b := range bs { 267 + ds.blks[b.Cid()] = b 268 + } 269 + return nil 270 + } 271 + 272 + func (ds *DeltaSession) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { 273 + return nil, fmt.Errorf("AllKeysChan not implemented") 274 + } 275 + 276 + func (ds *DeltaSession) DeleteBlock(ctx context.Context, c cid.Cid) error { 277 + if _, ok := ds.blks[c]; !ok { 278 + return ipld.ErrNotFound{c} 279 + } 280 + 281 + delete(ds.blks, c) 282 + return nil 283 + } 284 + 285 + func (ds *DeltaSession) Get(ctx context.Context, c cid.Cid) (blocks.Block, error) { 286 + b, ok := ds.blks[c] 287 + if ok { 288 + return b, nil 289 + } 290 + 291 + return ds.base.Get(ctx, c) 292 + } 293 + 294 + func (ds *DeltaSession) Has(ctx context.Context, c cid.Cid) (bool, error) { 295 + _, ok := ds.blks[c] 296 + if ok { 297 + return true, nil 298 + } 299 + 300 + return ds.base.Has(ctx, c) 301 + } 302 + 303 + func (ds *DeltaSession) HashOnRead(hor bool) { 304 + // noop? 305 + } 306 + 307 + func (ds *DeltaSession) GetSize(ctx context.Context, c cid.Cid) (int, error) { 308 + b, ok := ds.blks[c] 309 + if ok { 310 + return len(b.RawData()), nil 311 + } 312 + 313 + return ds.base.GetSize(ctx, c) 314 + } 315 + 316 + func (cs *CarStore) openNewShardFile(ctx context.Context, user uint, seq int) (*os.File, string, error) { 317 + // TODO: some overwrite protections 318 + fname := filepath.Join(cs.rootDir, fmt.Sprintf("sh-%d-%d", user, seq)) 319 + fi, err := os.Create(fname) 320 + if err != nil { 321 + return nil, "", err 322 + } 323 + 324 + return fi, fname, nil 325 + } 326 + 327 + // CloseWithRoot writes all new blocks in a car file to the writer with the 328 + // given cid as the 'root' 329 + func (ds *DeltaSession) CloseWithRoot(ctx context.Context, root cid.Cid) error { 330 + fi, path, err := ds.cs.openNewShardFile(ctx, ds.user, ds.seq) 331 + if err != nil { 332 + return err 333 + } 334 + // TODO: if this method fails delete the file 335 + defer fi.Close() 336 + 337 + h := &car.CarHeader{ 338 + Roots: []cid.Cid{root}, 339 + Version: 1, 340 + } 341 + hb, err := cbor.DumpObject(h) 342 + if err != nil { 343 + return err 344 + } 345 + 346 + hnw, err := LdWrite(fi, hb) 347 + if err != nil { 348 + return err 349 + } 350 + 351 + // TODO: all this database work needs to be in a single transaction 352 + shard := CarShard{ 353 + Root: root.String(), 354 + DataStart: hnw, 355 + Seq: ds.seq, 356 + Path: path, 357 + User: ds.user, 358 + } 359 + 360 + if err := ds.cs.meta.Create(&shard).Error; err != nil { 361 + return err 362 + } 363 + 364 + var offset int64 = hnw 365 + for k, blk := range ds.blks { 366 + nw, err := LdWrite(fi, k.Bytes(), blk.RawData()) 367 + if err != nil { 368 + return err 369 + } 370 + 371 + if err := ds.cs.meta.Create(&blockRef{ 372 + Cid: k.String(), 373 + Offset: offset, 374 + Shard: shard.ID, 375 + }).Error; err != nil { 376 + return err 377 + } 378 + 379 + offset += nw 380 + } 381 + 382 + return nil 383 + } 384 + 385 + func LdWrite(w io.Writer, d ...[]byte) (int64, error) { 386 + var sum uint64 387 + for _, s := range d { 388 + sum += uint64(len(s)) 389 + } 390 + 391 + buf := make([]byte, 8) 392 + n := binary.PutUvarint(buf, sum) 393 + nw, err := w.Write(buf[:n]) 394 + if err != nil { 395 + return 0, err 396 + } 397 + 398 + for _, s := range d { 399 + onw, err := w.Write(s) 400 + if err != nil { 401 + return int64(nw), err 402 + } 403 + nw += onw 404 + } 405 + 406 + return int64(nw), nil 407 + }
+112
carstore/repo_test.go
··· 1 + package carstore 2 + 3 + import ( 4 + "bytes" 5 + "context" 6 + "fmt" 7 + "io/ioutil" 8 + "os" 9 + "path/filepath" 10 + "testing" 11 + "time" 12 + 13 + "github.com/ipfs/go-cid" 14 + "github.com/whyrusleeping/gosky/api" 15 + "github.com/whyrusleeping/gosky/repo" 16 + "gorm.io/driver/sqlite" 17 + "gorm.io/gorm" 18 + ) 19 + 20 + func TestBasicOperation(t *testing.T) { 21 + tempdir, err := ioutil.TempDir("", "msttest-") 22 + if err != nil { 23 + t.Fatal(err) 24 + } 25 + 26 + defer func() { 27 + _ = os.RemoveAll(tempdir) 28 + }() 29 + 30 + sharddir := filepath.Join(tempdir, "shards") 31 + if err := os.MkdirAll(sharddir, 0775); err != nil { 32 + t.Fatal(err) 33 + } 34 + 35 + db, err := gorm.Open(sqlite.Open(filepath.Join(tempdir, "foo.db"))) 36 + if err != nil { 37 + t.Fatal(err) 38 + } 39 + 40 + cs, err := NewCarStore(db, sharddir) 41 + if err != nil { 42 + t.Fatal(err) 43 + } 44 + 45 + ds, err := cs.NewDeltaSession(1, cid.Undef) 46 + if err != nil { 47 + t.Fatal(err) 48 + } 49 + 50 + ctx := context.TODO() 51 + 52 + nr := repo.NewRepo(ctx, ds) 53 + 54 + if err := nr.CreateRecord(ctx, "app.bsky.feed.post", &api.PostRecord{ 55 + Text: fmt.Sprintf("hey look its a tweet %s", time.Now()), 56 + }); err != nil { 57 + t.Fatal(err) 58 + } 59 + 60 + ncid, err := nr.Commit(ctx) 61 + if err != nil { 62 + t.Fatal(err) 63 + } 64 + 65 + if err := ds.CloseWithRoot(ctx, ncid); err != nil { 66 + t.Fatal(err) 67 + } 68 + 69 + buf := new(bytes.Buffer) 70 + if err := cs.ReadUserCar(ctx, 1, cid.Undef, true, buf); err != nil { 71 + t.Fatal(err) 72 + } 73 + fmt.Println(buf.Len()) 74 + 75 + head := ncid 76 + for i := 0; i < 10; i++ { 77 + fmt.Println("head: ", head) 78 + ds, err := cs.NewDeltaSession(1, head) 79 + if err != nil { 80 + t.Fatal(err) 81 + } 82 + 83 + rr, err := repo.OpenRepo(ctx, ds, head) 84 + if err != nil { 85 + t.Fatal(err) 86 + } 87 + 88 + if err := rr.CreateRecord(ctx, "app.bsky.feed.post", &api.PostRecord{ 89 + Text: fmt.Sprintf("hey look its a tweet %s", time.Now()), 90 + }); err != nil { 91 + t.Fatal(err) 92 + } 93 + 94 + nroot, err := rr.Commit(ctx) 95 + if err != nil { 96 + t.Fatal(err) 97 + } 98 + 99 + if err := ds.CloseWithRoot(ctx, nroot); err != nil { 100 + t.Fatal(err) 101 + } 102 + 103 + head = nroot 104 + } 105 + 106 + buf = new(bytes.Buffer) 107 + if err := cs.ReadUserCar(ctx, 1, cid.Undef, true, buf); err != nil { 108 + t.Fatal(err) 109 + } 110 + 111 + fmt.Println(buf.Len()) 112 + }
+48 -1
cmd/gosky/main.go
··· 16 16 func main() { 17 17 app := cli.NewApp() 18 18 19 + app.Flags = []cli.Flag{ 20 + &cli.StringFlag{ 21 + Name: "pds", 22 + Value: "https://pds.staging.bsky.dev", 23 + }, 24 + &cli.StringFlag{ 25 + Name: "account", 26 + }, 27 + } 19 28 app.Commands = []*cli.Command{ 20 29 createSessionCmd, 21 30 newAccountCmd, ··· 24 33 syncCmd, 25 34 feedGetCmd, 26 35 feedGetAuthorCmd, 36 + actorGetSuggestionsCmd, 27 37 } 28 38 29 39 app.RunAndExitOnError() ··· 41 51 handle := cctx.Args().Get(1) 42 52 password := cctx.Args().Get(2) 43 53 44 - acc, err := atp.CreateAccount(context.TODO(), email, handle, password) 54 + var invite *string 55 + if inv := cctx.Args().Get(3); inv != "" { 56 + invite = &inv 57 + } 58 + 59 + acc, err := atp.CreateAccount(context.TODO(), email, handle, password, invite) 45 60 if err != nil { 46 61 return err 47 62 } ··· 260 275 261 276 }, 262 277 } 278 + 279 + var actorGetSuggestionsCmd = &cli.Command{ 280 + Name: "actorGetSuggestions", 281 + Action: func(cctx *cli.Context) error { 282 + bsky, err := cliutil.GetBskyClient(cctx, true) 283 + if err != nil { 284 + return err 285 + } 286 + 287 + ctx := context.TODO() 288 + 289 + author := cctx.Args().First() 290 + if author == "" { 291 + author = bsky.C.Auth.Did 292 + } 293 + 294 + resp, err := bsky.ActorGetSuggestions(ctx, 100, nil) 295 + if err != nil { 296 + return err 297 + } 298 + 299 + b, err := json.MarshalIndent(resp.Actors, "", " ") 300 + if err != nil { 301 + return err 302 + } 303 + 304 + fmt.Println(string(b)) 305 + 306 + return nil 307 + 308 + }, 309 + }
+45 -11
cmd/gosky/util/util.go
··· 3 3 import ( 4 4 "encoding/json" 5 5 "fmt" 6 + "io/ioutil" 7 + "net/http" 6 8 "os" 9 + "time" 7 10 8 11 "github.com/urfave/cli/v2" 9 12 "github.com/whyrusleeping/gosky/api" ··· 11 14 ) 12 15 13 16 func GetPLCClient(cctx *cli.Context) *api.PLCServer { 14 - h := "https://plc.staging.bsky.dev" 17 + h := "https://plc.directory" 15 18 16 19 if envh := os.Getenv("BSK_PLC_URL"); envh != "" { 17 20 h = envh ··· 22 25 } 23 26 } 24 27 28 + func NewHttpClient() *http.Client { 29 + return &http.Client{ 30 + Transport: &http.Transport{ 31 + Proxy: http.ProxyFromEnvironment, 32 + ForceAttemptHTTP2: true, 33 + MaxIdleConns: 100, 34 + IdleConnTimeout: 90 * time.Second, 35 + TLSHandshakeTimeout: 10 * time.Second, 36 + ExpectContinueTimeout: 1 * time.Second, 37 + }, 38 + } 39 + } 40 + 25 41 func GetATPClient(cctx *cli.Context, authreq bool) (*api.ATProto, error) { 26 - h := "https://pds.staging.bsky.dev" 27 - if envh := os.Getenv("BSKY_PDS_URL"); envh != "" { 28 - h = envh 42 + h := "https://staging.bsky.dev" 43 + if pdsurl := cctx.String("pds"); pdsurl != "" { 44 + h = pdsurl 29 45 } 30 46 31 - auth, err := loadAuthFromEnv(authreq) 47 + auth, err := loadAuthFromEnv(cctx, authreq) 32 48 if err != nil { 33 49 return nil, err 34 50 } 35 51 36 52 return &api.ATProto{ 37 53 C: &xrpc.Client{ 38 - Host: h, 39 - Auth: auth, 54 + Client: NewHttpClient(), 55 + Host: h, 56 + Auth: auth, 40 57 }, 41 58 }, nil 42 59 } 43 60 44 - func loadAuthFromEnv(req bool) (*xrpc.AuthInfo, error) { 61 + func loadAuthFromEnv(cctx *cli.Context, req bool) (*xrpc.AuthInfo, error) { 62 + if a := cctx.String("auth"); a != "" { 63 + return ReadAuth(a) 64 + } 65 + 45 66 val := os.Getenv("BSKY_AUTH") 46 67 if val == "" { 47 68 if req { ··· 61 82 62 83 func GetBskyClient(cctx *cli.Context, authreq bool) (*api.BskyApp, error) { 63 84 h := "https://pds.staging.bsky.dev" 64 - if envh := os.Getenv("BSKY_PDS_URL"); envh != "" { 65 - h = envh 85 + if pdsurl := cctx.String("pds"); pdsurl != "" { 86 + h = pdsurl 66 87 } 67 88 68 - auth, err := loadAuthFromEnv(authreq) 89 + auth, err := loadAuthFromEnv(cctx, authreq) 69 90 if err != nil { 70 91 return nil, err 71 92 } ··· 77 98 }, 78 99 }, nil 79 100 } 101 + 102 + func ReadAuth(fname string) (*xrpc.AuthInfo, error) { 103 + b, err := ioutil.ReadFile(fname) 104 + if err != nil { 105 + return nil, err 106 + } 107 + var auth xrpc.AuthInfo 108 + if err := json.Unmarshal(b, &auth); err != nil { 109 + return nil, err 110 + } 111 + 112 + return &auth, nil 113 + }
+1 -1
cmd/lexgen/main.go
··· 85 85 for _, arg := range paths { 86 86 s, err := lex.ReadSchema(arg) 87 87 if err != nil { 88 - return err 88 + return fmt.Errorf("failed to read file %q: %w", arg, err) 89 89 } 90 90 91 91 schemas = append(schemas, s)
+5
gen/main.go
··· 2 2 3 3 import ( 4 4 cbg "github.com/whyrusleeping/cbor-gen" 5 + "github.com/whyrusleeping/gosky/api" 5 6 mst "github.com/whyrusleeping/gosky/mst" 6 7 "github.com/whyrusleeping/gosky/repo" 7 8 ) ··· 12 13 } 13 14 14 15 if err := cbg.WriteMapEncodersToFile("repo/cbor_gen.go", "repo", repo.SignedRoot{}, repo.Meta{}, repo.Commit{}); err != nil { 16 + panic(err) 17 + } 18 + 19 + if err := cbg.WriteMapEncodersToFile("api/cbor_gen.go", "api", api.PostRecord{}, api.PostEntity{}, api.PostRef{}, api.ReplyRef{}); err != nil { 15 20 panic(err) 16 21 } 17 22 }
+12 -5
go.mod
··· 3 3 go 1.18 4 4 5 5 require ( 6 + github.com/ipfs/go-block-format v0.0.3 7 + github.com/ipfs/go-car v0.0.4 6 8 github.com/ipfs/go-cid v0.1.0 7 - github.com/ipfs/go-datastore v0.5.0 9 + github.com/ipfs/go-datastore v0.5.1 8 10 github.com/ipfs/go-ipfs-blockstore v1.2.1-0.20220823165003-9904c18f1d0a 9 11 github.com/ipfs/go-ipld-cbor v0.0.6 12 + github.com/ipfs/go-ipld-format v0.3.0 13 + github.com/ipld/go-car v0.5.0 10 14 github.com/ipld/go-car/v2 v2.5.1 11 15 github.com/multiformats/go-multihash v0.1.0 12 16 github.com/urfave/cli/v2 v2.23.0 13 - github.com/whyrusleeping/cbor-gen v0.0.0-20221107235327-d52321526af2 14 - github.com/whyrusleeping/go-did v0.0.0-20220426230951-797e826b4c63 17 + github.com/whyrusleeping/cbor-gen v0.0.0-20221120232258-33755d0abe95 18 + github.com/whyrusleeping/go-did v0.0.0-20221105001742-8d9e0ffb0d59 15 19 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 20 + gorm.io/driver/sqlite v1.4.3 21 + gorm.io/gorm v1.24.1 16 22 ) 17 23 18 24 require ( ··· 23 29 github.com/google/uuid v1.2.0 // indirect 24 30 github.com/hashicorp/golang-lru v0.5.4 // indirect 25 31 github.com/ipfs/bbloom v0.0.4 // indirect 26 - github.com/ipfs/go-block-format v0.0.3 // indirect 27 32 github.com/ipfs/go-blockservice v0.3.0 // indirect 28 33 github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect 29 34 github.com/ipfs/go-ipfs-exchange-interface v0.1.0 // indirect 30 35 github.com/ipfs/go-ipfs-util v0.0.2 // indirect 31 - github.com/ipfs/go-ipld-format v0.3.0 // indirect 32 36 github.com/ipfs/go-ipld-legacy v0.1.0 // indirect 33 37 github.com/ipfs/go-log v1.0.5 // indirect 34 38 github.com/ipfs/go-log/v2 v2.3.0 // indirect ··· 38 42 github.com/ipld/go-codec-dagpb v1.3.1 // indirect 39 43 github.com/ipld/go-ipld-prime v0.16.0 // indirect 40 44 github.com/jbenet/goprocess v0.1.4 // indirect 45 + github.com/jinzhu/inflection v1.0.0 // indirect 46 + github.com/jinzhu/now v1.1.5 // indirect 41 47 github.com/klauspost/cpuid/v2 v2.0.9 // indirect 42 48 github.com/lestrrat-go/blackmagic v1.0.1 // indirect 43 49 github.com/lestrrat-go/httpcc v1.0.1 // indirect ··· 46 52 github.com/lestrrat-go/jwx/v2 v2.0.0 // indirect 47 53 github.com/lestrrat-go/option v1.0.0 // indirect 48 54 github.com/mattn/go-isatty v0.0.14 // indirect 55 + github.com/mattn/go-sqlite3 v1.14.15 // indirect 49 56 github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect 50 57 github.com/minio/sha256-simd v1.0.0 // indirect 51 58 github.com/mr-tron/base58 v1.2.0 // indirect
+56 -7
go.sum
··· 208 208 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 209 209 github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 210 210 github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 211 + github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 211 212 github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 212 213 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 213 214 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= ··· 247 248 github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= 248 249 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 249 250 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= 251 + github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= 250 252 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= 251 253 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= 252 254 github.com/ipfs/go-bitfield v1.0.0 h1:y/XHm2GEmD9wKngheWNNCNL0pzrWXZwCdQGv1ikXknQ= 255 + github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= 253 256 github.com/ipfs/go-bitswap v0.6.0 h1:f2rc6GZtoSFhEIzQmddgGiel9xntj02Dg0ZNf2hSC+w= 254 257 github.com/ipfs/go-bitswap v0.6.0/go.mod h1:Hj3ZXdOC5wBJvENtdqsixmzzRukqd8EHLxZLZc3mzRA= 258 + github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= 255 259 github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= 256 260 github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= 257 261 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= 262 + github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= 258 263 github.com/ipfs/go-blockservice v0.3.0 h1:cDgcZ+0P0Ih3sl8+qjFr2sVaMdysg/YZpLj5WJ8kiiw= 259 264 github.com/ipfs/go-blockservice v0.3.0/go.mod h1:P5ppi8IHDC7O+pA0AlGTF09jruB2h+oP3wVVaZl8sfk= 265 + github.com/ipfs/go-car v0.0.4 h1:zLhxykvk4SFU4oIpgcIoiolVL3jqcK0hjqcQfUSs4dk= 266 + github.com/ipfs/go-car v0.0.4/go.mod h1:eZX0EppfsvSQN8IsJnx57bheogWMgQjJVWU/fDA7ySQ= 260 267 github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= 261 268 github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= 262 269 github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= ··· 267 274 github.com/ipfs/go-cid v0.1.0 h1:YN33LQulcRHjfom/i25yoOZR4Telp1Hr/2RU3d0PnC0= 268 275 github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o= 269 276 github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= 277 + github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= 270 278 github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= 271 279 github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= 272 280 github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= 273 281 github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= 274 282 github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= 275 - github.com/ipfs/go-datastore v0.5.0 h1:rQicVCEacWyk4JZ6G5bD9TKR7lZEG1MWcG7UdWYrFAU= 276 283 github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= 284 + github.com/ipfs/go-datastore v0.5.1 h1:WkRhLuISI+XPD0uk3OskB0fYFSyqK8Ob5ZYew9Qa1nQ= 285 + github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= 277 286 github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= 278 287 github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= 279 288 github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= ··· 283 292 github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= 284 293 github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= 285 294 github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= 295 + github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= 286 296 github.com/ipfs/go-ipfs-blockstore v1.2.0/go.mod h1:eh8eTFLiINYNSNawfZOC7HOxNTxpB1PFuA5E1m/7exE= 287 297 github.com/ipfs/go-ipfs-blockstore v1.2.1-0.20220823165003-9904c18f1d0a h1:pZfq7BUNp1fyCayhqF5oUcr1/WMA6FPQWn7gPl4ymNw= 288 298 github.com/ipfs/go-ipfs-blockstore v1.2.1-0.20220823165003-9904c18f1d0a/go.mod h1:EOIrmnNV3Y+wfNPzHMvT1iKHGFCOU1QFgZJSQ0IzWp4= ··· 292 302 github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= 293 303 github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= 294 304 github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= 305 + github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= 295 306 github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= 296 307 github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q= 297 308 github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU= 309 + github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= 298 310 github.com/ipfs/go-ipfs-exchange-interface v0.1.0 h1:TiMekCrOGQuWYtZO3mf4YJXDIdNgnKWZ9IE3fGlnWfo= 299 311 github.com/ipfs/go-ipfs-exchange-interface v0.1.0/go.mod h1:ych7WPlyHqFvCi/uQI48zLZuAWVP5iTQPXEfVaw5WEI= 312 + github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= 300 313 github.com/ipfs/go-ipfs-exchange-offline v0.2.0 h1:2PF4o4A7W656rC0RxuhUace997FTcDTcIQ6NoEtyjAI= 301 314 github.com/ipfs/go-ipfs-exchange-offline v0.2.0/go.mod h1:HjwBeW0dvZvfOMwDP0TSKXIHf2s+ksdP4E3MLDRtLKY= 315 + github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= 302 316 github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= 303 317 github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= 318 + github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= 304 319 github.com/ipfs/go-ipfs-routing v0.2.1 h1:E+whHWhJkdN9YeoHZNj5itzc+OR292AJ2uE9FFiW0BY= 305 320 github.com/ipfs/go-ipfs-routing v0.2.1/go.mod h1:xiNNiwgjmLqPS1cimvAw6EyB9rkVDbiocA4yY+wRNLM= 306 321 github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= 307 322 github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= 308 323 github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= 324 + github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= 309 325 github.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= 310 326 github.com/ipfs/go-ipld-cbor v0.0.6 h1:pYuWHyvSpIsOOLw4Jy7NbBkCyzLDcl64Bf/LZW7eBQ0= 311 327 github.com/ipfs/go-ipld-cbor v0.0.6/go.mod h1:ssdxxaLJPXH7OjF5V4NSjBbcfh+evoR4ukuru0oPXMA= 312 328 github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= 329 + github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= 313 330 github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= 314 331 github.com/ipfs/go-ipld-format v0.3.0 h1:Mwm2oRLzIuUwEPewWAWyMuuBQUsn3awfFEYVb8akMOQ= 315 332 github.com/ipfs/go-ipld-format v0.3.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= ··· 328 345 github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= 329 346 github.com/ipfs/go-log/v2 v2.3.0 h1:31Re/cPqFHpsRHgyVwjWADPoF0otB1WrjTy8ZFYwEZU= 330 347 github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72gynbe/g= 348 + github.com/ipfs/go-merkledag v0.2.4/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= 331 349 github.com/ipfs/go-merkledag v0.6.0 h1:oV5WT2321tS4YQVOPgIrWHvJ0lJobRTerU+i9nmUCuA= 332 350 github.com/ipfs/go-merkledag v0.6.0/go.mod h1:9HSEwRd5sV+lbykiYP+2NC/3o6MZbKNaa4hfNcH5iH0= 333 351 github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= 334 352 github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= 353 + github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= 335 354 github.com/ipfs/go-peertaskqueue v0.7.0 h1:VyO6G4sbzX80K58N60cCaHsSsypbUNs1GjO5seGNsQ0= 336 355 github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= 337 356 github.com/ipfs/go-unixfsnode v1.4.0 h1:9BUxHBXrbNi8mWHc6j+5C580WJqtVw9uoeEKn4tMhwA= 338 357 github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= 339 358 github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= 359 + github.com/ipld/go-car v0.0.4/go.mod h1:kgp82Cpd0TgoxgCsr7yndUXMkMgNP/aAwVBtJtsNR6g= 360 + github.com/ipld/go-car v0.5.0 h1:kcCEa3CvYMs0iE5BzD5sV7O2EwMiCIp3uF8tA6APQT8= 361 + github.com/ipld/go-car v0.5.0/go.mod h1:ppiN5GWpjOZU9PgpAZ9HbZd9ZgSpwPMr48fGRJOWmvE= 340 362 github.com/ipld/go-car/v2 v2.5.1 h1:U2ux9JS23upEgrJScW8VQuxmE94560kYxj9CQUpcfmk= 341 363 github.com/ipld/go-car/v2 v2.5.1/go.mod h1:jKjGOqoCj5zn6KjnabD6JbnCsMntqU2hLiU6baZVO3E= 342 364 github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA= ··· 362 384 github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= 363 385 github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 364 386 github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 387 + github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 388 + github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 389 + github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 390 + github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= 391 + github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 365 392 github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 366 393 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 367 394 github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= ··· 387 414 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 388 415 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 389 416 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 417 + github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= 390 418 github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ= 391 419 github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= 392 420 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= ··· 426 454 github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= 427 455 github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= 428 456 github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= 457 + github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= 429 458 github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= 430 459 github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= 431 460 github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= 432 461 github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= 433 462 github.com/libp2p/go-libp2p v0.14.3 h1:NST/bkwGSyaOt+stT7GBHY1+OqaANZ+QUOjpsmjXVC4= 434 463 github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= 464 + github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= 435 465 github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= 436 466 github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= 437 467 github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= ··· 441 471 github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= 442 472 github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= 443 473 github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= 474 + github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= 444 475 github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= 445 476 github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= 446 477 github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= ··· 467 498 github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= 468 499 github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= 469 500 github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= 501 + github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= 470 502 github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= 471 503 github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= 472 504 github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= ··· 478 510 github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= 479 511 github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= 480 512 github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= 513 + github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= 481 514 github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= 482 515 github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= 483 516 github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= ··· 542 575 github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= 543 576 github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= 544 577 github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= 578 + github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= 545 579 github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= 546 580 github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= 547 581 github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= ··· 572 606 github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= 573 607 github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= 574 608 github.com/libp2p/go-tcp-transport v0.2.3/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= 609 + github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= 610 + github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= 575 611 github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= 576 612 github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= 577 613 github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= ··· 597 633 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= 598 634 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 599 635 github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 636 + github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 600 637 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 601 638 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 602 639 github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 640 + github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 603 641 github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 604 642 github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 605 643 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 606 644 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 645 + github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= 646 + github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= 607 647 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 608 648 github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 609 649 github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= ··· 755 795 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 756 796 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 757 797 github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= 798 + github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= 758 799 github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= 759 800 github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls= 760 801 github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= ··· 875 916 github.com/warpfork/go-testmark v0.3.0 h1:Q81c4u7hT+BR5kNfNQhEF0VT2pmL7+Kk0wD+ORYl7iA= 876 917 github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= 877 918 github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= 919 + github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= 878 920 github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= 879 921 github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= 880 922 github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= 881 923 github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= 882 - github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c h1:6VPKXBDRt7mDUyiHx9X8ROnPYFDf3L7OfEuKCI5dZDI= 883 - github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= 884 - github.com/whyrusleeping/cbor-gen v0.0.0-20221021053955-c138aae13722 h1:0HEhvpGQJ2Gd0ngPW83aduQQuF/V9v13+3zpSrR3lrA= 885 - github.com/whyrusleeping/cbor-gen v0.0.0-20221021053955-c138aae13722/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= 886 924 github.com/whyrusleeping/cbor-gen v0.0.0-20221107235327-d52321526af2 h1:uKKSmHNmtxSf6+3MDfYmU7HYiV5q3DgIKjDRPkc5OIU= 887 925 github.com/whyrusleeping/cbor-gen v0.0.0-20221107235327-d52321526af2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= 926 + github.com/whyrusleeping/cbor-gen v0.0.0-20221120232258-33755d0abe95 h1:f4dFX0UniZ3T3TswZsQJ82hJUII2cQOcNVZsMTxus3g= 927 + github.com/whyrusleeping/cbor-gen v0.0.0-20221120232258-33755d0abe95/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= 888 928 github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= 889 - github.com/whyrusleeping/go-did v0.0.0-20220426230951-797e826b4c63 h1:kmLT9xYcMMJXT3c6bPJFREY4Mp2w04xU9yrhllMHoMU= 890 - github.com/whyrusleeping/go-did v0.0.0-20220426230951-797e826b4c63/go.mod h1:mX/AQ/SS9KrCwO8V+IWyIozytxw5gw75cMHymoJvMGo= 929 + github.com/whyrusleeping/go-did v0.0.0-20221105001742-8d9e0ffb0d59 h1:dRYr/sfpZjX8evmbFrOG7ldkzdk5TLMGRVM40k1AZPQ= 930 + github.com/whyrusleeping/go-did v0.0.0-20221105001742-8d9e0ffb0d59/go.mod h1:mX/AQ/SS9KrCwO8V+IWyIozytxw5gw75cMHymoJvMGo= 891 931 github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= 892 932 github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= 893 933 github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= 934 + github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= 894 935 github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= 936 + github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= 895 937 github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= 896 938 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= 897 939 github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= ··· 995 1037 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 996 1038 golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 997 1039 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 1040 + golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 998 1041 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 999 1042 golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1000 1043 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= ··· 1046 1089 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1047 1090 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1048 1091 golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1092 + golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1049 1093 golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1050 1094 golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1051 1095 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= ··· 1193 1237 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 1194 1238 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 1195 1239 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 1240 + gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= 1241 + gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= 1242 + gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= 1243 + gorm.io/gorm v1.24.1 h1:CgvzRniUdG67hBAzsxDGOAuq4Te1osVMYsa1eQbd4fs= 1244 + gorm.io/gorm v1.24.1/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= 1196 1245 grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= 1197 1246 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 1198 1247 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+63 -18
lex/gen.go
··· 10 10 ) 11 11 12 12 type Schema struct { 13 + prefix string 14 + 13 15 Lexicon int `json:"lexicon"` 14 16 ID string `json:"id"` 15 17 Type string `json:"type"` 16 18 Key string `json:"key"` 17 19 Description string `json:"description"` 18 - Parameters map[string]Param `json:"parameters"` 20 + Parameters *TypeSchema `json:"parameters"` 19 21 Input *InputType `json:"input"` 20 22 Output *OutputType `json:"output"` 21 23 Defs map[string]TypeSchema `json:"defs"` ··· 83 85 } 84 86 } 85 87 88 + tname := s.nameFromID(s.ID, prefix) 89 + 86 90 for name, def := range s.Defs { 87 - walk(name, def) 91 + walk(tname+"_"+strings.Title(name), def) 88 92 } 89 - 90 - tname := s.nameFromID(s.ID, prefix) 91 93 92 94 if s.Input != nil { 93 95 walk(tname+"_Input", s.Input.Schema) ··· 124 126 } 125 127 defer fi.Close() 126 128 129 + s.prefix = prefix 130 + 127 131 fmt.Fprintf(fi, "package %s\n\n", pkg) 128 132 fmt.Fprintf(fi, "import (\n") 129 133 fmt.Fprintf(fi, "\t\"context\"\n") ··· 172 176 } 173 177 174 178 func (s *Schema) WriteRPC(w io.Writer, prefix string) error { 175 - fname := s.nameFromID(s.ID, prefix) 179 + fname := s.nameFromID(s.ID, s.prefix) 176 180 177 181 params := "ctx context.Context, c *xrpc.Client" 178 182 inpvar := "nil" ··· 221 225 } 222 226 223 227 func (s *Schema) typeNameFromRef(r string) string { 228 + sname := s.nameFromID(s.ID, s.prefix) 224 229 p := strings.Split(r, "/") 225 - return strings.Title(p[len(p)-1]) 230 + return sname + "_" + strings.Title(p[len(p)-1]) 226 231 } 227 232 228 233 func (s *Schema) typeNameForField(name, k string, v TypeSchema) (string, error) { ··· 250 255 251 256 return "", fmt.Errorf("field %q in %s does not have discernable type name", k, name) 252 257 case "array": 253 - subt, err := s.typeNameForField(name+"_"+strings.Title(k), "", *v.Items) 258 + subt, err := s.typeNameForField(name+"_"+strings.Title(k), "Elem", *v.Items) 254 259 if err != nil { 255 260 return "", err 256 261 } ··· 261 266 } 262 267 } 263 268 269 + func (s *Schema) lookupRef(ref string) (*TypeSchema, error) { 270 + parts := strings.Split(ref, "/") 271 + if len(parts) < 3 { 272 + return nil, fmt.Errorf("invalid ref: %q", ref) 273 + } 274 + 275 + if parts[1] != "defs" { 276 + return nil, fmt.Errorf("ref lookups outside of defs not supported") 277 + } 278 + t, ok := s.Defs[parts[2]] 279 + if !ok { 280 + return nil, fmt.Errorf("no such def: %q", ref) 281 + } 282 + 283 + return &t, nil 284 + } 285 + 264 286 func (s *Schema) WriteType(name string, t TypeSchema, w io.Writer) error { 265 287 name = strings.Title(name) 266 288 if err := s.writeTypeDefinition(name, t, w); err != nil { ··· 313 335 314 336 case "": 315 337 if len(t.OneOf) > 0 { 316 - fmt.Fprintf(w, "type %s struct {\n", name) 317 - for _, e := range t.OneOf { 318 - // TODO: for now, asserting that all enum options are refs 319 - if e.Ref == "" { 320 - return fmt.Errorf("Enums must only contain refs") 338 + // check if this is actually just a string enum 339 + first, err := s.lookupRef(t.OneOf[0].Ref) 340 + if err != nil { 341 + return fmt.Errorf("oneOf pre-check failed: %w", err) 342 + } 343 + 344 + if first.Type == "string" { 345 + // okay, this is just a string enum, do something different 346 + fmt.Fprintf(w, "type %s string\n", name) 347 + } else { 348 + 349 + fmt.Fprintf(w, "type %s struct {\n", name) 350 + for _, e := range t.OneOf { 351 + // TODO: for now, asserting that all enum options are refs 352 + if e.Ref == "" { 353 + return fmt.Errorf("Enums must only contain refs") 354 + } 355 + 356 + tname := s.typeNameFromRef(e.Ref) 357 + fmt.Fprintf(w, "\t%s *%s\n", tname, tname) 321 358 } 322 - tname := s.typeNameFromRef(e.Ref) 323 - fmt.Fprintf(w, "\t%s *%s\n", tname, tname) 359 + fmt.Fprintf(w, "}\n\n") 324 360 } 325 361 326 - fmt.Fprintf(w, "}\n\n") 327 362 } 328 363 default: 329 364 return fmt.Errorf("%s has unrecognized type type %s", name, t.Type) ··· 348 383 return nil 349 384 case "": 350 385 if len(t.OneOf) > 0 { 386 + reft, err := s.lookupRef(t.OneOf[0].Ref) 387 + if err != nil { 388 + return err 389 + } 390 + 391 + if reft.Type == "string" { 392 + return nil 393 + } 394 + 351 395 if err := s.writeJsonMarshalerEnum(name, t, w); err != nil { 352 396 return err 353 397 } ··· 478 522 479 523 if len(nots) > 0 { 480 524 if i == len(t.OneOf)-1 { 525 + tnref := s.typeNameFromRef(e.Ref) 481 526 fmt.Fprintf(w, ` 482 527 default: 483 - var out interface{} 528 + var out %s 484 529 if err := json.Unmarshal(b, &out); err != nil { 485 530 return err 486 531 } 487 - t.%s = out 532 + t.%s = &out 488 533 return nil 489 - `, s.typeNameFromRef(e.Ref)) 534 + `, tnref, tnref) 490 535 491 536 } else { 492 537 return fmt.Errorf("enum member with a not clause must be the last in a oneOf")
+31
mst/mst.go
··· 46 46 return NewMST(mst.cst, mst.fanout, cid.Undef, entries, mst.layer) 47 47 } 48 48 49 + func (mst *MerkleSearchTree) GetPointer(ctx context.Context) (cid.Cid, error) { 50 + if mst.validPtr { 51 + return mst.pointer, nil 52 + } 53 + 54 + entries, err := mst.getEntries(ctx) 55 + if err != nil { 56 + return cid.Undef, err 57 + } 58 + 59 + for _, e := range entries { 60 + if e.isTree() { 61 + if !e.Tree.validPtr { 62 + _, err := e.Tree.GetPointer(ctx) 63 + if err != nil { 64 + return cid.Undef, err 65 + } 66 + } 67 + } 68 + } 69 + 70 + nptr, err := cidForEntries(ctx, entries, mst.cst) 71 + if err != nil { 72 + return cid.Undef, err 73 + } 74 + mst.pointer = nptr 75 + mst.validPtr = true 76 + 77 + return mst.pointer, nil 78 + } 79 + 49 80 func create(ctx context.Context, cst cbor.IpldStore, entries []NodeEntry, layer int, fanout int) (*MerkleSearchTree, error) { 50 81 ptr, err := cidForEntries(ctx, entries, cst) 51 82 if err != nil {
+40 -16
repo/cbor_gen.go
··· 338 338 } 339 339 340 340 cw := cbg.NewCborWriter(w) 341 + var emptyFieldCount int 341 342 342 - if _, err := cw.Write([]byte{164}); err != nil { 343 + if t.Prev == nil { 344 + emptyFieldCount++ 345 + } 346 + 347 + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(4-emptyFieldCount))); err != nil { 343 348 return err 344 349 } 345 350 ··· 405 410 } 406 411 407 412 // t.Prev (cid.Cid) (struct) 408 - if len("prev") > cbg.MaxLength { 409 - return xerrors.Errorf("Value in field \"prev\" was too long") 410 - } 413 + if t.Prev != nil { 411 414 412 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("prev"))); err != nil { 413 - return err 414 - } 415 - if _, err := io.WriteString(w, string("prev")); err != nil { 416 - return err 417 - } 415 + if len("prev") > cbg.MaxLength { 416 + return xerrors.Errorf("Value in field \"prev\" was too long") 417 + } 418 418 419 - if err := cbg.WriteCid(cw, t.Prev); err != nil { 420 - return xerrors.Errorf("failed to write cid field t.Prev: %w", err) 421 - } 419 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("prev"))); err != nil { 420 + return err 421 + } 422 + if _, err := io.WriteString(w, string("prev")); err != nil { 423 + return err 424 + } 422 425 426 + if t.Prev == nil { 427 + if _, err := cw.Write(cbg.CborNull); err != nil { 428 + return err 429 + } 430 + } else { 431 + if err := cbg.WriteCid(cw, *t.Prev); err != nil { 432 + return xerrors.Errorf("failed to write cid field t.Prev: %w", err) 433 + } 434 + } 435 + 436 + } 423 437 return nil 424 438 } 425 439 ··· 513 527 514 528 { 515 529 516 - c, err := cbg.ReadCid(cr) 530 + b, err := cr.ReadByte() 517 531 if err != nil { 518 - return xerrors.Errorf("failed to read cid field t.Prev: %w", err) 532 + return err 519 533 } 534 + if b != cbg.CborNull[0] { 535 + if err := cr.UnreadByte(); err != nil { 536 + return err 537 + } 520 538 521 - t.Prev = c 539 + c, err := cbg.ReadCid(cr) 540 + if err != nil { 541 + return xerrors.Errorf("failed to read cid field t.Prev: %w", err) 542 + } 543 + 544 + t.Prev = &c 545 + } 522 546 523 547 } 524 548
+133 -12
repo/repo.go
··· 2 2 3 3 import ( 4 4 "context" 5 + "fmt" 5 6 "io" 6 7 7 8 "github.com/ipfs/go-cid" ··· 18 19 } 19 20 20 21 type Commit struct { 21 - AuthToken *string `cborgen:"auth_token"` 22 - Data cid.Cid `cborgen:"data"` 23 - Meta cid.Cid `cborgen:"meta"` 24 - Prev cid.Cid `cborgen:"prev"` 22 + AuthToken *string `cborgen:"auth_token"` 23 + Data cid.Cid `cborgen:"data"` 24 + Meta cid.Cid `cborgen:"meta"` 25 + Prev *cid.Cid `cborgen:"prev,omitempty"` 25 26 } 26 27 27 28 type Meta struct { ··· 33 34 type Repo struct { 34 35 sr SignedRoot 35 36 cst cbor.IpldStore 37 + 38 + meta Meta 39 + 40 + mst *mst.MerkleSearchTree 41 + 42 + dirty bool 36 43 } 37 44 38 - func ReadRepoFromCar(ctx context.Context, r io.Reader) (*Repo, error) { 45 + func IngestRepo(ctx context.Context, bs blockstore.Blockstore, r io.Reader) (cid.Cid, error) { 39 46 br, err := car.NewBlockReader(r) 40 47 if err != nil { 41 - return nil, err 48 + return cid.Undef, err 42 49 } 43 50 44 - bs := blockstore.NewBlockstore(datastore.NewMapDatastore()) 45 - 46 51 for { 47 52 blk, err := br.Next() 48 53 if err != nil { 49 54 if err == io.EOF { 50 55 break 51 56 } 52 - return nil, err 57 + return cid.Undef, err 53 58 } 54 59 55 60 if err := bs.Put(ctx, blk); err != nil { 56 - return nil, err 61 + return cid.Undef, err 57 62 } 58 63 } 59 64 65 + return br.Roots[0], nil 66 + } 67 + 68 + func ReadRepoFromCar(ctx context.Context, r io.Reader) (*Repo, error) { 69 + bs := blockstore.NewBlockstore(datastore.NewMapDatastore()) 70 + root, err := IngestRepo(ctx, bs, r) 71 + if err != nil { 72 + return nil, err 73 + } 74 + 75 + return OpenRepo(ctx, bs, root) 76 + } 77 + 78 + func NewRepo(ctx context.Context, bs blockstore.Blockstore) *Repo { 79 + cst := cbor.NewCborStore(bs) 80 + 81 + t := mst.NewMST(cst, 32, cid.Undef, []mst.NodeEntry{}, 0) 82 + 83 + return &Repo{ 84 + cst: cst, 85 + mst: t, 86 + dirty: true, 87 + } 88 + } 89 + 90 + func OpenRepo(ctx context.Context, bs blockstore.Blockstore, root cid.Cid) (*Repo, error) { 60 91 cst := cbor.NewCborStore(bs) 61 92 62 93 var sr SignedRoot 63 - if err := cst.Get(ctx, br.Roots[0], &sr); err != nil { 64 - return nil, err 94 + if err := cst.Get(ctx, root, &sr); err != nil { 95 + return nil, fmt.Errorf("loading root from blockstore: %w", err) 65 96 } 66 97 67 98 return &Repo{ 68 99 sr: sr, 69 100 cst: cst, 70 101 }, nil 102 + } 103 + 104 + type CborMarshaler interface { 105 + MarshalCBOR(w io.Writer) error 106 + } 107 + 108 + func (r *Repo) CreateRecord(ctx context.Context, nsid string, rec CborMarshaler) error { 109 + r.dirty = true 110 + t, err := r.getMst(ctx) 111 + if err != nil { 112 + return fmt.Errorf("failed to get mst: %w", err) 113 + } 114 + 115 + k, err := r.cst.Put(ctx, rec) 116 + if err != nil { 117 + return err 118 + } 119 + 120 + nmst, err := t.Add(ctx, nsid+"/"+NextTID(), k, -1) 121 + if err != nil { 122 + return fmt.Errorf("mst.Add failed: %w", err) 123 + } 124 + 125 + r.mst = nmst 126 + return nil 127 + } 128 + 129 + func (r *Repo) Commit(ctx context.Context) (cid.Cid, error) { 130 + t, err := r.getMst(ctx) 131 + if err != nil { 132 + return cid.Undef, err 133 + } 134 + 135 + rcid, err := t.GetPointer(ctx) 136 + if err != nil { 137 + return cid.Undef, err 138 + } 139 + 140 + ncom := Commit{ 141 + Data: rcid, 142 + } 143 + if r.sr.Root.Defined() { 144 + var com Commit 145 + if err := r.cst.Get(ctx, r.sr.Root, &com); err != nil { 146 + return cid.Undef, err 147 + } 148 + ncom.Prev = &r.sr.Root 149 + ncom.Meta = com.Meta 150 + } else { 151 + mcid, err := r.cst.Put(ctx, &r.meta) 152 + if err != nil { 153 + return cid.Undef, err 154 + } 155 + ncom.Meta = mcid 156 + } 157 + 158 + ncomcid, err := r.cst.Put(ctx, &ncom) 159 + if err != nil { 160 + return cid.Undef, err 161 + } 162 + 163 + nsroot := SignedRoot{ 164 + Root: ncomcid, 165 + } 166 + 167 + nsrootcid, err := r.cst.Put(ctx, &nsroot) 168 + if err != nil { 169 + return cid.Undef, err 170 + } 171 + fmt.Println("rootcid output: ", nsrootcid) 172 + 173 + r.sr = nsroot 174 + r.dirty = false 175 + 176 + return nsrootcid, nil 177 + } 178 + 179 + func (r *Repo) getMst(ctx context.Context) (*mst.MerkleSearchTree, error) { 180 + if r.mst != nil { 181 + return r.mst, nil 182 + } 183 + 184 + var com Commit 185 + if err := r.cst.Get(ctx, r.sr.Root, &com); err != nil { 186 + return nil, err 187 + } 188 + 189 + t := mst.LoadMST(r.cst, 32, com.Data) 190 + r.mst = t 191 + return t, nil 71 192 } 72 193 73 194 func (r *Repo) ForEach(ctx context.Context, prefix string, cb func(k string, v cid.Cid) error) error {
+30
repo/repo_test.go
··· 1 + package repo 2 + 3 + import ( 4 + "context" 5 + "fmt" 6 + "os" 7 + "testing" 8 + 9 + cid "github.com/ipfs/go-cid" 10 + ) 11 + 12 + func TestRepo(t *testing.T) { 13 + fi, err := os.Open("repo.car") 14 + if err != nil { 15 + t.Fatal(err) 16 + } 17 + 18 + ctx := context.TODO() 19 + r, err := ReadRepoFromCar(ctx, fi) 20 + if err != nil { 21 + t.Fatal(err) 22 + } 23 + 24 + if err := r.ForEach(ctx, "app.bsky.feed.post", func(k string, v cid.Cid) error { 25 + fmt.Println(k, v) 26 + return nil 27 + }); err != nil { 28 + t.Fatal(err) 29 + } 30 + }
+26
repo/tid.go
··· 1 + package repo 2 + 3 + import ( 4 + "math/rand" 5 + "time" 6 + ) 7 + 8 + const alpha = "234567abcdefghijklmnopqrstuvwxyz" 9 + 10 + func s32encode(i uint64) string { 11 + var s string 12 + for i > 0 { 13 + c := i & 0x1f 14 + i = i >> 5 15 + s = alpha[c:c+1] + s 16 + } 17 + return s 18 + } 19 + 20 + func NextTID() string { 21 + t := time.Now() 22 + 23 + clockid := uint64(rand.Uint32() & 0x1f) 24 + 25 + return s32encode(uint64(t.UnixMilli())) + s32encode(clockid) 26 + }
+9 -5
xrpc/xrpc.go
··· 50 50 func (c *Client) Do(ctx context.Context, kind XRPCRequestType, method string, params map[string]interface{}, bodyobj interface{}, out interface{}) error { 51 51 var body io.Reader 52 52 if bodyobj != nil { 53 - b, err := json.Marshal(bodyobj) 54 - if err != nil { 55 - return err 56 - } 53 + if rr, ok := bodyobj.(io.Reader); ok { 54 + body = rr 55 + } else { 56 + b, err := json.Marshal(bodyobj) 57 + if err != nil { 58 + return err 59 + } 57 60 58 - body = bytes.NewReader(b) 61 + body = bytes.NewReader(b) 62 + } 59 63 } 60 64 61 65 var m string