This repository has no description
0

Configure Feed

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

Some lexgen to get started

author
pds.dad
date (Jun 30, 2026, 10:01 PM -0500) commit 67c26477 parent 64b465b4 change-id nolvuzlx
+1249 -29
+1
.gitignore
··· 5 5 puzzles.db-shm 6 6 puzzles.db-journal 7 7 tmp 8 + tangled
+16
Makefile
··· 1 + GOBIN := $(shell go env GOPATH)/bin 2 + LEXGEN := go run github.com/bluesky-social/indigo/cmd/lexgen --build-file lexicon-build-config.json lexicons 3 + 4 + # Generate Go types + CBOR encoders from the atproto lexicons in ./lexicons. 5 + # 6 + # Requires goimports: go install golang.org/x/tools/cmd/goimports@latest 7 + .PHONY: lexgen 8 + lexgen: 9 + mkdir -p api/lichess /tmp/atproto 10 + rm -f api/lichess/*.go 11 + $(LEXGEN) 12 + perl -i -pe 's{^(\s*)(lexutil\.RegisterType)}{$$1// $$2}' api/lichess/*.go 13 + $(GOBIN)/goimports -w ./api/lichess 14 + CGO_ENABLED=0 go run ./cmd/cborgen/ 15 + $(LEXGEN) 16 + $(GOBIN)/goimports -w ./api/lichess
+936
api/lichess/cbor_gen.go
··· 1 + // Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. 2 + 3 + package lichess 4 + 5 + import ( 6 + "fmt" 7 + "io" 8 + "math" 9 + "sort" 10 + 11 + atproto "github.com/bluesky-social/indigo/api/atproto" 12 + cid "github.com/ipfs/go-cid" 13 + cbg "github.com/whyrusleeping/cbor-gen" 14 + xerrors "golang.org/x/xerrors" 15 + ) 16 + 17 + var _ = xerrors.Errorf 18 + var _ = cid.Undef 19 + var _ = math.E 20 + var _ = sort.Sort 21 + 22 + func (t *Puzzle) MarshalCBOR(w io.Writer) error { 23 + if t == nil { 24 + _, err := w.Write(cbg.CborNull) 25 + return err 26 + } 27 + 28 + cw := cbg.NewCborWriter(w) 29 + fieldCount := 11 30 + 31 + if t.GameId == nil { 32 + fieldCount-- 33 + } 34 + 35 + if t.NbPlays == nil { 36 + fieldCount-- 37 + } 38 + 39 + if t.OpeningTags == nil { 40 + fieldCount-- 41 + } 42 + 43 + if t.Popularity == nil { 44 + fieldCount-- 45 + } 46 + 47 + if t.Themes == nil { 48 + fieldCount-- 49 + } 50 + 51 + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 52 + return err 53 + } 54 + 55 + // t.Fen (string) (string) 56 + if len("fen") > 1000000 { 57 + return xerrors.Errorf("Value in field \"fen\" was too long") 58 + } 59 + 60 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("fen"))); err != nil { 61 + return err 62 + } 63 + if _, err := cw.WriteString(string("fen")); err != nil { 64 + return err 65 + } 66 + 67 + if len(t.Fen) > 1000000 { 68 + return xerrors.Errorf("Value in field t.Fen was too long") 69 + } 70 + 71 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Fen))); err != nil { 72 + return err 73 + } 74 + if _, err := cw.WriteString(string(t.Fen)); err != nil { 75 + return err 76 + } 77 + 78 + // t.LexiconTypeID (string) (string) 79 + if len("$type") > 1000000 { 80 + return xerrors.Errorf("Value in field \"$type\" was too long") 81 + } 82 + 83 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil { 84 + return err 85 + } 86 + if _, err := cw.WriteString(string("$type")); err != nil { 87 + return err 88 + } 89 + 90 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("org.lichess.puzzle"))); err != nil { 91 + return err 92 + } 93 + if _, err := cw.WriteString(string("org.lichess.puzzle")); err != nil { 94 + return err 95 + } 96 + 97 + // t.Moves (string) (string) 98 + if len("moves") > 1000000 { 99 + return xerrors.Errorf("Value in field \"moves\" was too long") 100 + } 101 + 102 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("moves"))); err != nil { 103 + return err 104 + } 105 + if _, err := cw.WriteString(string("moves")); err != nil { 106 + return err 107 + } 108 + 109 + if len(t.Moves) > 1000000 { 110 + return xerrors.Errorf("Value in field t.Moves was too long") 111 + } 112 + 113 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Moves))); err != nil { 114 + return err 115 + } 116 + if _, err := cw.WriteString(string(t.Moves)); err != nil { 117 + return err 118 + } 119 + 120 + // t.GameId (string) (string) 121 + if t.GameId != nil { 122 + 123 + if len("gameId") > 1000000 { 124 + return xerrors.Errorf("Value in field \"gameId\" was too long") 125 + } 126 + 127 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("gameId"))); err != nil { 128 + return err 129 + } 130 + if _, err := cw.WriteString(string("gameId")); err != nil { 131 + return err 132 + } 133 + 134 + if t.GameId == nil { 135 + if _, err := cw.Write(cbg.CborNull); err != nil { 136 + return err 137 + } 138 + } else { 139 + if len(*t.GameId) > 1000000 { 140 + return xerrors.Errorf("Value in field t.GameId was too long") 141 + } 142 + 143 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.GameId))); err != nil { 144 + return err 145 + } 146 + if _, err := cw.WriteString(string(*t.GameId)); err != nil { 147 + return err 148 + } 149 + } 150 + } 151 + 152 + // t.Rating (int64) (int64) 153 + if len("rating") > 1000000 { 154 + return xerrors.Errorf("Value in field \"rating\" was too long") 155 + } 156 + 157 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("rating"))); err != nil { 158 + return err 159 + } 160 + if _, err := cw.WriteString(string("rating")); err != nil { 161 + return err 162 + } 163 + 164 + if t.Rating >= 0 { 165 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Rating)); err != nil { 166 + return err 167 + } 168 + } else { 169 + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.Rating-1)); err != nil { 170 + return err 171 + } 172 + } 173 + 174 + // t.Themes ([]string) (slice) 175 + if t.Themes != nil { 176 + 177 + if len("themes") > 1000000 { 178 + return xerrors.Errorf("Value in field \"themes\" was too long") 179 + } 180 + 181 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("themes"))); err != nil { 182 + return err 183 + } 184 + if _, err := cw.WriteString(string("themes")); err != nil { 185 + return err 186 + } 187 + 188 + if len(t.Themes) > 8192 { 189 + return xerrors.Errorf("Slice value in field t.Themes was too long") 190 + } 191 + 192 + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Themes))); err != nil { 193 + return err 194 + } 195 + for _, v := range t.Themes { 196 + if len(v) > 1000000 { 197 + return xerrors.Errorf("Value in field v was too long") 198 + } 199 + 200 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(v))); err != nil { 201 + return err 202 + } 203 + if _, err := cw.WriteString(string(v)); err != nil { 204 + return err 205 + } 206 + 207 + } 208 + } 209 + 210 + // t.NbPlays (int64) (int64) 211 + if t.NbPlays != nil { 212 + 213 + if len("nbPlays") > 1000000 { 214 + return xerrors.Errorf("Value in field \"nbPlays\" was too long") 215 + } 216 + 217 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("nbPlays"))); err != nil { 218 + return err 219 + } 220 + if _, err := cw.WriteString(string("nbPlays")); err != nil { 221 + return err 222 + } 223 + 224 + if t.NbPlays == nil { 225 + if _, err := cw.Write(cbg.CborNull); err != nil { 226 + return err 227 + } 228 + } else { 229 + if *t.NbPlays >= 0 { 230 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(*t.NbPlays)); err != nil { 231 + return err 232 + } 233 + } else { 234 + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-*t.NbPlays-1)); err != nil { 235 + return err 236 + } 237 + } 238 + } 239 + 240 + } 241 + 242 + // t.CreatedAt (string) (string) 243 + if len("createdAt") > 1000000 { 244 + return xerrors.Errorf("Value in field \"createdAt\" was too long") 245 + } 246 + 247 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("createdAt"))); err != nil { 248 + return err 249 + } 250 + if _, err := cw.WriteString(string("createdAt")); err != nil { 251 + return err 252 + } 253 + 254 + if len(t.CreatedAt) > 1000000 { 255 + return xerrors.Errorf("Value in field t.CreatedAt was too long") 256 + } 257 + 258 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.CreatedAt))); err != nil { 259 + return err 260 + } 261 + if _, err := cw.WriteString(string(t.CreatedAt)); err != nil { 262 + return err 263 + } 264 + 265 + // t.Popularity (int64) (int64) 266 + if t.Popularity != nil { 267 + 268 + if len("popularity") > 1000000 { 269 + return xerrors.Errorf("Value in field \"popularity\" was too long") 270 + } 271 + 272 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("popularity"))); err != nil { 273 + return err 274 + } 275 + if _, err := cw.WriteString(string("popularity")); err != nil { 276 + return err 277 + } 278 + 279 + if t.Popularity == nil { 280 + if _, err := cw.Write(cbg.CborNull); err != nil { 281 + return err 282 + } 283 + } else { 284 + if *t.Popularity >= 0 { 285 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(*t.Popularity)); err != nil { 286 + return err 287 + } 288 + } else { 289 + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-*t.Popularity-1)); err != nil { 290 + return err 291 + } 292 + } 293 + } 294 + 295 + } 296 + 297 + // t.OpeningTags ([]string) (slice) 298 + if t.OpeningTags != nil { 299 + 300 + if len("openingTags") > 1000000 { 301 + return xerrors.Errorf("Value in field \"openingTags\" was too long") 302 + } 303 + 304 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("openingTags"))); err != nil { 305 + return err 306 + } 307 + if _, err := cw.WriteString(string("openingTags")); err != nil { 308 + return err 309 + } 310 + 311 + if len(t.OpeningTags) > 8192 { 312 + return xerrors.Errorf("Slice value in field t.OpeningTags was too long") 313 + } 314 + 315 + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.OpeningTags))); err != nil { 316 + return err 317 + } 318 + for _, v := range t.OpeningTags { 319 + if len(v) > 1000000 { 320 + return xerrors.Errorf("Value in field v was too long") 321 + } 322 + 323 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(v))); err != nil { 324 + return err 325 + } 326 + if _, err := cw.WriteString(string(v)); err != nil { 327 + return err 328 + } 329 + 330 + } 331 + } 332 + 333 + // t.RatingDeviation (int64) (int64) 334 + if len("ratingDeviation") > 1000000 { 335 + return xerrors.Errorf("Value in field \"ratingDeviation\" was too long") 336 + } 337 + 338 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("ratingDeviation"))); err != nil { 339 + return err 340 + } 341 + if _, err := cw.WriteString(string("ratingDeviation")); err != nil { 342 + return err 343 + } 344 + 345 + if t.RatingDeviation >= 0 { 346 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.RatingDeviation)); err != nil { 347 + return err 348 + } 349 + } else { 350 + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.RatingDeviation-1)); err != nil { 351 + return err 352 + } 353 + } 354 + 355 + return nil 356 + } 357 + 358 + func (t *Puzzle) UnmarshalCBOR(r io.Reader) (err error) { 359 + *t = Puzzle{} 360 + 361 + cr := cbg.NewCborReader(r) 362 + 363 + maj, extra, err := cr.ReadHeader() 364 + if err != nil { 365 + return err 366 + } 367 + defer func() { 368 + if err == io.EOF { 369 + err = io.ErrUnexpectedEOF 370 + } 371 + }() 372 + 373 + if maj != cbg.MajMap { 374 + return fmt.Errorf("cbor input should be of type map") 375 + } 376 + 377 + if extra > cbg.MaxLength { 378 + return fmt.Errorf("Puzzle: map struct too large (%d)", extra) 379 + } 380 + 381 + n := extra 382 + 383 + nameBuf := make([]byte, 15) 384 + for i := uint64(0); i < n; i++ { 385 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 1000000) 386 + if err != nil { 387 + return err 388 + } 389 + 390 + if !ok { 391 + // Field doesn't exist on this type, so ignore it 392 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 393 + return err 394 + } 395 + continue 396 + } 397 + 398 + switch string(nameBuf[:nameLen]) { 399 + // t.Fen (string) (string) 400 + case "fen": 401 + 402 + { 403 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 404 + if err != nil { 405 + return err 406 + } 407 + 408 + t.Fen = string(sval) 409 + } 410 + // t.LexiconTypeID (string) (string) 411 + case "$type": 412 + 413 + { 414 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 415 + if err != nil { 416 + return err 417 + } 418 + 419 + t.LexiconTypeID = string(sval) 420 + } 421 + // t.Moves (string) (string) 422 + case "moves": 423 + 424 + { 425 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 426 + if err != nil { 427 + return err 428 + } 429 + 430 + t.Moves = string(sval) 431 + } 432 + // t.GameId (string) (string) 433 + case "gameId": 434 + 435 + { 436 + b, err := cr.ReadByte() 437 + if err != nil { 438 + return err 439 + } 440 + if b != cbg.CborNull[0] { 441 + if err := cr.UnreadByte(); err != nil { 442 + return err 443 + } 444 + 445 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 446 + if err != nil { 447 + return err 448 + } 449 + 450 + t.GameId = (*string)(&sval) 451 + } 452 + } 453 + // t.Rating (int64) (int64) 454 + case "rating": 455 + { 456 + maj, extra, err := cr.ReadHeader() 457 + if err != nil { 458 + return err 459 + } 460 + var extraI int64 461 + switch maj { 462 + case cbg.MajUnsignedInt: 463 + extraI = int64(extra) 464 + if extraI < 0 { 465 + return fmt.Errorf("int64 positive overflow") 466 + } 467 + case cbg.MajNegativeInt: 468 + extraI = int64(extra) 469 + if extraI < 0 { 470 + return fmt.Errorf("int64 negative overflow") 471 + } 472 + extraI = -1 - extraI 473 + default: 474 + return fmt.Errorf("wrong type for int64 field: %d", maj) 475 + } 476 + 477 + t.Rating = int64(extraI) 478 + } 479 + // t.Themes ([]string) (slice) 480 + case "themes": 481 + 482 + maj, extra, err = cr.ReadHeader() 483 + if err != nil { 484 + return err 485 + } 486 + 487 + if extra > 8192 { 488 + return fmt.Errorf("t.Themes: array too large (%d)", extra) 489 + } 490 + 491 + if maj != cbg.MajArray { 492 + return fmt.Errorf("expected cbor array") 493 + } 494 + 495 + if extra > 0 { 496 + t.Themes = make([]string, extra) 497 + } 498 + 499 + for i := 0; i < int(extra); i++ { 500 + { 501 + var maj byte 502 + var extra uint64 503 + var err error 504 + _ = maj 505 + _ = extra 506 + _ = err 507 + 508 + { 509 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 510 + if err != nil { 511 + return err 512 + } 513 + 514 + t.Themes[i] = string(sval) 515 + } 516 + 517 + } 518 + } 519 + // t.NbPlays (int64) (int64) 520 + case "nbPlays": 521 + { 522 + 523 + b, err := cr.ReadByte() 524 + if err != nil { 525 + return err 526 + } 527 + if b != cbg.CborNull[0] { 528 + if err := cr.UnreadByte(); err != nil { 529 + return err 530 + } 531 + maj, extra, err := cr.ReadHeader() 532 + if err != nil { 533 + return err 534 + } 535 + var extraI int64 536 + switch maj { 537 + case cbg.MajUnsignedInt: 538 + extraI = int64(extra) 539 + if extraI < 0 { 540 + return fmt.Errorf("int64 positive overflow") 541 + } 542 + case cbg.MajNegativeInt: 543 + extraI = int64(extra) 544 + if extraI < 0 { 545 + return fmt.Errorf("int64 negative overflow") 546 + } 547 + extraI = -1 - extraI 548 + default: 549 + return fmt.Errorf("wrong type for int64 field: %d", maj) 550 + } 551 + 552 + t.NbPlays = (*int64)(&extraI) 553 + } 554 + } 555 + // t.CreatedAt (string) (string) 556 + case "createdAt": 557 + 558 + { 559 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 560 + if err != nil { 561 + return err 562 + } 563 + 564 + t.CreatedAt = string(sval) 565 + } 566 + // t.Popularity (int64) (int64) 567 + case "popularity": 568 + { 569 + 570 + b, err := cr.ReadByte() 571 + if err != nil { 572 + return err 573 + } 574 + if b != cbg.CborNull[0] { 575 + if err := cr.UnreadByte(); err != nil { 576 + return err 577 + } 578 + maj, extra, err := cr.ReadHeader() 579 + if err != nil { 580 + return err 581 + } 582 + var extraI int64 583 + switch maj { 584 + case cbg.MajUnsignedInt: 585 + extraI = int64(extra) 586 + if extraI < 0 { 587 + return fmt.Errorf("int64 positive overflow") 588 + } 589 + case cbg.MajNegativeInt: 590 + extraI = int64(extra) 591 + if extraI < 0 { 592 + return fmt.Errorf("int64 negative overflow") 593 + } 594 + extraI = -1 - extraI 595 + default: 596 + return fmt.Errorf("wrong type for int64 field: %d", maj) 597 + } 598 + 599 + t.Popularity = (*int64)(&extraI) 600 + } 601 + } 602 + // t.OpeningTags ([]string) (slice) 603 + case "openingTags": 604 + 605 + maj, extra, err = cr.ReadHeader() 606 + if err != nil { 607 + return err 608 + } 609 + 610 + if extra > 8192 { 611 + return fmt.Errorf("t.OpeningTags: array too large (%d)", extra) 612 + } 613 + 614 + if maj != cbg.MajArray { 615 + return fmt.Errorf("expected cbor array") 616 + } 617 + 618 + if extra > 0 { 619 + t.OpeningTags = make([]string, extra) 620 + } 621 + 622 + for i := 0; i < int(extra); i++ { 623 + { 624 + var maj byte 625 + var extra uint64 626 + var err error 627 + _ = maj 628 + _ = extra 629 + _ = err 630 + 631 + { 632 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 633 + if err != nil { 634 + return err 635 + } 636 + 637 + t.OpeningTags[i] = string(sval) 638 + } 639 + 640 + } 641 + } 642 + // t.RatingDeviation (int64) (int64) 643 + case "ratingDeviation": 644 + { 645 + maj, extra, err := cr.ReadHeader() 646 + if err != nil { 647 + return err 648 + } 649 + var extraI int64 650 + switch maj { 651 + case cbg.MajUnsignedInt: 652 + extraI = int64(extra) 653 + if extraI < 0 { 654 + return fmt.Errorf("int64 positive overflow") 655 + } 656 + case cbg.MajNegativeInt: 657 + extraI = int64(extra) 658 + if extraI < 0 { 659 + return fmt.Errorf("int64 negative overflow") 660 + } 661 + extraI = -1 - extraI 662 + default: 663 + return fmt.Errorf("wrong type for int64 field: %d", maj) 664 + } 665 + 666 + t.RatingDeviation = int64(extraI) 667 + } 668 + 669 + default: 670 + // Field doesn't exist on this type, so ignore it 671 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 672 + return err 673 + } 674 + } 675 + } 676 + 677 + return nil 678 + } 679 + func (t *PuzzleAttempt) MarshalCBOR(w io.Writer) error { 680 + if t == nil { 681 + _, err := w.Write(cbg.CborNull) 682 + return err 683 + } 684 + 685 + cw := cbg.NewCborWriter(w) 686 + fieldCount := 5 687 + 688 + if t.PlayerMoves == nil { 689 + fieldCount-- 690 + } 691 + 692 + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 693 + return err 694 + } 695 + 696 + // t.LexiconTypeID (string) (string) 697 + if len("$type") > 1000000 { 698 + return xerrors.Errorf("Value in field \"$type\" was too long") 699 + } 700 + 701 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil { 702 + return err 703 + } 704 + if _, err := cw.WriteString(string("$type")); err != nil { 705 + return err 706 + } 707 + 708 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("org.lichess.puzzle.attempt"))); err != nil { 709 + return err 710 + } 711 + if _, err := cw.WriteString(string("org.lichess.puzzle.attempt")); err != nil { 712 + return err 713 + } 714 + 715 + // t.Puzzle (atproto.RepoStrongRef) (struct) 716 + if len("puzzle") > 1000000 { 717 + return xerrors.Errorf("Value in field \"puzzle\" was too long") 718 + } 719 + 720 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("puzzle"))); err != nil { 721 + return err 722 + } 723 + if _, err := cw.WriteString(string("puzzle")); err != nil { 724 + return err 725 + } 726 + 727 + if err := t.Puzzle.MarshalCBOR(cw); err != nil { 728 + return err 729 + } 730 + 731 + // t.Result (string) (string) 732 + if len("result") > 1000000 { 733 + return xerrors.Errorf("Value in field \"result\" was too long") 734 + } 735 + 736 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("result"))); err != nil { 737 + return err 738 + } 739 + if _, err := cw.WriteString(string("result")); err != nil { 740 + return err 741 + } 742 + 743 + if len(t.Result) > 1000000 { 744 + return xerrors.Errorf("Value in field t.Result was too long") 745 + } 746 + 747 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Result))); err != nil { 748 + return err 749 + } 750 + if _, err := cw.WriteString(string(t.Result)); err != nil { 751 + return err 752 + } 753 + 754 + // t.CreatedAt (string) (string) 755 + if len("createdAt") > 1000000 { 756 + return xerrors.Errorf("Value in field \"createdAt\" was too long") 757 + } 758 + 759 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("createdAt"))); err != nil { 760 + return err 761 + } 762 + if _, err := cw.WriteString(string("createdAt")); err != nil { 763 + return err 764 + } 765 + 766 + if len(t.CreatedAt) > 1000000 { 767 + return xerrors.Errorf("Value in field t.CreatedAt was too long") 768 + } 769 + 770 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.CreatedAt))); err != nil { 771 + return err 772 + } 773 + if _, err := cw.WriteString(string(t.CreatedAt)); err != nil { 774 + return err 775 + } 776 + 777 + // t.PlayerMoves (string) (string) 778 + if t.PlayerMoves != nil { 779 + 780 + if len("playerMoves") > 1000000 { 781 + return xerrors.Errorf("Value in field \"playerMoves\" was too long") 782 + } 783 + 784 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("playerMoves"))); err != nil { 785 + return err 786 + } 787 + if _, err := cw.WriteString(string("playerMoves")); err != nil { 788 + return err 789 + } 790 + 791 + if t.PlayerMoves == nil { 792 + if _, err := cw.Write(cbg.CborNull); err != nil { 793 + return err 794 + } 795 + } else { 796 + if len(*t.PlayerMoves) > 1000000 { 797 + return xerrors.Errorf("Value in field t.PlayerMoves was too long") 798 + } 799 + 800 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.PlayerMoves))); err != nil { 801 + return err 802 + } 803 + if _, err := cw.WriteString(string(*t.PlayerMoves)); err != nil { 804 + return err 805 + } 806 + } 807 + } 808 + return nil 809 + } 810 + 811 + func (t *PuzzleAttempt) UnmarshalCBOR(r io.Reader) (err error) { 812 + *t = PuzzleAttempt{} 813 + 814 + cr := cbg.NewCborReader(r) 815 + 816 + maj, extra, err := cr.ReadHeader() 817 + if err != nil { 818 + return err 819 + } 820 + defer func() { 821 + if err == io.EOF { 822 + err = io.ErrUnexpectedEOF 823 + } 824 + }() 825 + 826 + if maj != cbg.MajMap { 827 + return fmt.Errorf("cbor input should be of type map") 828 + } 829 + 830 + if extra > cbg.MaxLength { 831 + return fmt.Errorf("PuzzleAttempt: map struct too large (%d)", extra) 832 + } 833 + 834 + n := extra 835 + 836 + nameBuf := make([]byte, 11) 837 + for i := uint64(0); i < n; i++ { 838 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 1000000) 839 + if err != nil { 840 + return err 841 + } 842 + 843 + if !ok { 844 + // Field doesn't exist on this type, so ignore it 845 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 846 + return err 847 + } 848 + continue 849 + } 850 + 851 + switch string(nameBuf[:nameLen]) { 852 + // t.LexiconTypeID (string) (string) 853 + case "$type": 854 + 855 + { 856 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 857 + if err != nil { 858 + return err 859 + } 860 + 861 + t.LexiconTypeID = string(sval) 862 + } 863 + // t.Puzzle (atproto.RepoStrongRef) (struct) 864 + case "puzzle": 865 + 866 + { 867 + 868 + b, err := cr.ReadByte() 869 + if err != nil { 870 + return err 871 + } 872 + if b != cbg.CborNull[0] { 873 + if err := cr.UnreadByte(); err != nil { 874 + return err 875 + } 876 + t.Puzzle = new(atproto.RepoStrongRef) 877 + if err := t.Puzzle.UnmarshalCBOR(cr); err != nil { 878 + return xerrors.Errorf("unmarshaling t.Puzzle pointer: %w", err) 879 + } 880 + } 881 + 882 + } 883 + // t.Result (string) (string) 884 + case "result": 885 + 886 + { 887 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 888 + if err != nil { 889 + return err 890 + } 891 + 892 + t.Result = string(sval) 893 + } 894 + // t.CreatedAt (string) (string) 895 + case "createdAt": 896 + 897 + { 898 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 899 + if err != nil { 900 + return err 901 + } 902 + 903 + t.CreatedAt = string(sval) 904 + } 905 + // t.PlayerMoves (string) (string) 906 + case "playerMoves": 907 + 908 + { 909 + b, err := cr.ReadByte() 910 + if err != nil { 911 + return err 912 + } 913 + if b != cbg.CborNull[0] { 914 + if err := cr.UnreadByte(); err != nil { 915 + return err 916 + } 917 + 918 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 919 + if err != nil { 920 + return err 921 + } 922 + 923 + t.PlayerMoves = (*string)(&sval) 924 + } 925 + } 926 + 927 + default: 928 + // Field doesn't exist on this type, so ignore it 929 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 930 + return err 931 + } 932 + } 933 + } 934 + 935 + return nil 936 + }
+50
api/lichess/lichessgetPuzzle.go
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + // Lexicon schema: org.lichess.getPuzzle 4 + 5 + package lichess 6 + 7 + import ( 8 + "context" 9 + 10 + lexutil "github.com/bluesky-social/indigo/lex/util" 11 + ) 12 + 13 + // GetPuzzle_Output is the output of a org.lichess.getPuzzle call. 14 + type GetPuzzle_Output struct { 15 + // fen: the FEN string of the position before the opponent makes their move. 16 + Fen string `json:"fen" cborgen:"fen"` 17 + // gameId: the unique identifier of the specific game and move the puzzle was extracted from. The game would be accessible at https://lichess.org/{GameId} 18 + GameId *string `json:"gameId,omitempty" cborgen:"gameId,omitempty"` 19 + // isOriginalLichessPuzzle: whether this puzzle is unedited from lichess.org's original puzzle dataset, as opposed to having been modified or not sourced from Lichess. 20 + IsOriginalLichessPuzzle bool `json:"isOriginalLichessPuzzle" cborgen:"isOriginalLichessPuzzle"` 21 + // moves: the solution to the puzzle. All player moves of the solution are "only moves", i.e. playing any other move would considerably worsen the player position. An exception is made for mates in one: there can be several. Any move that checkmates should win the puzzle. 22 + Moves string `json:"moves" cborgen:"moves"` 23 + // nbPlays: the number of times a puzzle was played. 24 + NbPlays *int64 `json:"nbPlays,omitempty" cborgen:"nbPlays,omitempty"` 25 + // openingTags: a list of openings. This is only set for puzzles starting before move 20. 26 + OpeningTags []string `json:"openingTags,omitempty" cborgen:"openingTags,omitempty"` 27 + // popularity: a number between 100 (best) and -100 (worst), calculated as 100 * (upvotes - downvotes)/(upvotes + downvotes). Votes are weighted by various factors such as whether the puzzle was solved successfully or the solver's puzzle rating in comparison to the puzzle's. 28 + Popularity *int64 `json:"popularity,omitempty" cborgen:"popularity,omitempty"` 29 + // rating: the Glicko-2 rating of the puzzle. 30 + Rating int64 `json:"rating" cborgen:"rating"` 31 + // ratingDeviation: the Glicko-2 rating deviation of the puzzle. 32 + RatingDeviation int64 `json:"ratingDeviation" cborgen:"ratingDeviation"` 33 + // themes: a list of puzzle themes. 34 + Themes []string `json:"themes,omitempty" cborgen:"themes,omitempty"` 35 + } 36 + 37 + // GetPuzzle calls the XRPC method "org.lichess.getPuzzle". 38 + // 39 + // id: the id of the puzzle to fetch. 40 + func GetPuzzle(ctx context.Context, c lexutil.LexClient, id string) (*GetPuzzle_Output, error) { 41 + var out GetPuzzle_Output 42 + 43 + params := map[string]interface{}{} 44 + params["id"] = id 45 + if err := c.LexDo(ctx, lexutil.Query, "", "org.lichess.getPuzzle", params, nil, &out); err != nil { 46 + return nil, err 47 + } 48 + 49 + return &out, nil 50 + }
+36
api/lichess/lichesspuzzle.go
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + // Lexicon schema: org.lichess.puzzle 4 + 5 + package lichess 6 + 7 + import ( 8 + lexutil "github.com/bluesky-social/indigo/lex/util" 9 + ) 10 + 11 + func init() { 12 + lexutil.RegisterType("org.lichess.puzzle", &Puzzle{}) 13 + } 14 + 15 + type Puzzle struct { 16 + LexiconTypeID string `json:"$type" cborgen:"$type,const=org.lichess.puzzle"` 17 + CreatedAt string `json:"createdAt" cborgen:"createdAt"` 18 + // fen: the FEN string of the position before the opponent makes their move. 19 + Fen string `json:"fen" cborgen:"fen"` 20 + // gameId: the unique identifier of the specific game and move the puzzle was extracted from. The game would be accessible at https://lichess.org/{GameId} 21 + GameId *string `json:"gameId,omitempty" cborgen:"gameId,omitempty"` 22 + // moves: the solution to the puzzle. All player moves of the solution are "only moves", i.e. playing any other move would considerably worsen the player position. An exception is made for mates in one: there can be several. Any move that checkmates should win the puzzle. 23 + Moves string `json:"moves" cborgen:"moves"` 24 + // nbPlays: the number of times a puzzle was played. 25 + NbPlays *int64 `json:"nbPlays,omitempty" cborgen:"nbPlays,omitempty"` 26 + // openingTags: a list of openings. This is only set for puzzles starting before move 20. 27 + OpeningTags []string `json:"openingTags,omitempty" cborgen:"openingTags,omitempty"` 28 + // popularity: a number between 100 (best) and -100 (worst), calculated as 100 * (upvotes - downvotes)/(upvotes + downvotes). Votes are weighted by various factors such as whether the puzzle was solved successfully or the solver's puzzle rating in comparison to the puzzle's. 29 + Popularity *int64 `json:"popularity,omitempty" cborgen:"popularity,omitempty"` 30 + // rating: the Glicko-2 rating of the puzzle. 31 + Rating int64 `json:"rating" cborgen:"rating"` 32 + // ratingDeviation: the Glicko-2 rating deviation of the puzzle. 33 + RatingDeviation int64 `json:"ratingDeviation" cborgen:"ratingDeviation"` 34 + // themes: a list of puzzle themes. 35 + Themes []string `json:"themes,omitempty" cborgen:"themes,omitempty"` 36 + }
+26
api/lichess/puzzleattempt.go
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + // Lexicon schema: org.lichess.puzzle.attempt 4 + 5 + package lichess 6 + 7 + import ( 8 + comatproto "github.com/bluesky-social/indigo/api/atproto" 9 + lexutil "github.com/bluesky-social/indigo/lex/util" 10 + ) 11 + 12 + func init() { 13 + lexutil.RegisterType("org.lichess.puzzle.attempt", &PuzzleAttempt{}) 14 + } 15 + 16 + type PuzzleAttempt struct { 17 + LexiconTypeID string `json:"$type" cborgen:"$type,const=org.lichess.puzzle.attempt"` 18 + // createdAt: client-declared timestamp when this attempt record was created. 19 + CreatedAt string `json:"createdAt" cborgen:"createdAt"` 20 + // playerMoves: the moves played by the solver during the attempt, in the same notation as the puzzle's solution moves. 21 + PlayerMoves *string `json:"playerMoves,omitempty" cborgen:"playerMoves,omitempty"` 22 + // puzzle: a strong reference to the org.lichess.puzzle record this attempt is for. 23 + Puzzle *comatproto.RepoStrongRef `json:"puzzle" cborgen:"puzzle"` 24 + // result: the current outcome of the attempt. 25 + Result string `json:"result" cborgen:"result"` 26 + }
+18
cmd/cborgen/cborgen.go
··· 1 + package main 2 + 3 + import ( 4 + cbg "github.com/whyrusleeping/cbor-gen" 5 + "tangled.org/pds.dad/PuzzleMeThis/api/lichess" 6 + ) 7 + 8 + func main() { 9 + genCfg := cbg.Gen{MaxStringLength: 1_000_000} 10 + 11 + if err := genCfg.WriteMapEncodersToFile( 12 + "api/lichess/cbor_gen.go", "lichess", 13 + lichess.Puzzle{}, 14 + lichess.PuzzleAttempt{}, 15 + ); err != nil { 16 + panic(err) 17 + } 18 + }
+24 -11
go.mod
··· 1 1 module tangled.org/pds.dad/PuzzleMeThis 2 2 3 - go 1.25.5 3 + go 1.26 4 4 5 5 require ( 6 + github.com/bluesky-social/indigo v0.0.0-20260629160527-dfe5578fd537 6 7 github.com/earthboundkid/versioninfo/v2 v2.24.1 8 + github.com/ipfs/go-cid v0.4.1 9 + github.com/joho/godotenv v1.5.1 7 10 github.com/parquet-go/parquet-go v0.30.1 11 + github.com/spf13/viper v1.21.0 8 12 github.com/urfave/cli/v3 v3.10.1 13 + github.com/whyrusleeping/cbor-gen v0.3.1 14 + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 9 15 gorm.io/driver/sqlite v1.6.0 10 16 gorm.io/gorm v1.31.2 11 17 ) 12 18 13 19 require ( 20 + github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect 14 21 github.com/fsnotify/fsnotify v1.9.0 // indirect 15 22 github.com/go-viper/mapstructure/v2 v2.4.0 // indirect 16 - github.com/joho/godotenv v1.5.1 // indirect 17 - github.com/labstack/gommon v0.5.0 // indirect 18 - github.com/mattn/go-colorable v0.1.15 // indirect 19 - github.com/mattn/go-isatty v0.0.22 // indirect 23 + github.com/klauspost/cpuid/v2 v2.2.7 // indirect 24 + github.com/minio/sha256-simd v1.0.1 // indirect 25 + github.com/mr-tron/base58 v1.2.0 // indirect 26 + github.com/multiformats/go-base32 v0.1.0 // indirect 27 + github.com/multiformats/go-base36 v0.2.0 // indirect 28 + github.com/multiformats/go-multibase v0.2.0 // indirect 29 + github.com/multiformats/go-multihash v0.2.3 // indirect 30 + github.com/multiformats/go-varint v0.0.7 // indirect 20 31 github.com/pelletier/go-toml/v2 v2.2.4 // indirect 32 + github.com/russross/blackfriday/v2 v2.1.0 // indirect 21 33 github.com/sagikazarmark/locafero v0.11.0 // indirect 22 34 github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect 35 + github.com/spaolacci/murmur3 v1.1.0 // indirect 23 36 github.com/spf13/afero v1.15.0 // indirect 24 37 github.com/spf13/cast v1.10.0 // indirect 25 38 github.com/spf13/pflag v1.0.10 // indirect 26 - github.com/spf13/viper v1.21.0 // indirect 27 39 github.com/subosito/gotenv v1.6.0 // indirect 28 - github.com/valyala/bytebufferpool v1.0.0 // indirect 29 - github.com/valyala/fasttemplate v1.2.2 // indirect 40 + github.com/urfave/cli/v2 v2.27.7 // indirect 41 + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect 30 42 go.yaml.in/yaml/v3 v3.0.4 // indirect 31 43 golang.org/x/crypto v0.53.0 // indirect 44 + golang.org/x/mod v0.36.0 // indirect 32 45 golang.org/x/net v0.56.0 // indirect 46 + golang.org/x/sync v0.21.0 // indirect 33 47 golang.org/x/time v0.15.0 // indirect 48 + golang.org/x/tools v0.45.0 // indirect 49 + lukechampine.com/blake3 v1.2.1 // indirect 34 50 ) 35 51 36 52 require ( 37 53 github.com/andybalholm/brotli v1.1.1 // indirect 38 - github.com/go-chi/chi/v5 v5.3.0 39 - github.com/google/go-cmp v0.6.0 // indirect 40 54 github.com/google/uuid v1.6.0 // indirect 41 55 github.com/jinzhu/inflection v1.0.0 // indirect 42 56 github.com/jinzhu/now v1.1.5 // indirect 43 57 github.com/klauspost/compress v1.17.9 // indirect 44 - github.com/labstack/echo/v4 v4.15.4 45 58 github.com/labstack/echo/v5 v5.2.1 46 59 github.com/mattn/go-sqlite3 v1.14.22 // indirect 47 60 github.com/parquet-go/bitpack v1.0.0 // indirect
+53 -18
go.sum
··· 6 6 github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= 7 7 github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= 8 8 github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= 9 + github.com/bluesky-social/indigo v0.0.0-20260629160527-dfe5578fd537 h1:rHaND0argSxgbmE2ix/YuF11xXTtiP3oGUz4fS2Diqo= 10 + github.com/bluesky-social/indigo v0.0.0-20260629160527-dfe5578fd537/go.mod h1:JqQkz8lrOI6YZivP38GHmtVOTtzsNToITKj1gMpU5Jo= 11 + github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= 12 + github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 9 13 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 10 14 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 11 15 github.com/earthboundkid/versioninfo/v2 v2.24.1 h1:SJTMHaoUx3GzjjnUO1QzP3ZXK6Ee/nbWyCm58eY3oUg= 12 16 github.com/earthboundkid/versioninfo/v2 v2.24.1/go.mod h1:VcWEooDEuyUJnMfbdTh0uFN4cfEIg+kHMuWB2CDCLjw= 17 + github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= 18 + github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 13 19 github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= 14 20 github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= 15 - github.com/go-chi/chi/v5 v5.3.0 h1:halUjDxhshgXHMrao5bB8eNBXo/rnzwr8m5m36glehM= 16 - github.com/go-chi/chi/v5 v5.3.0/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto= 17 21 github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= 18 22 github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 19 23 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= ··· 22 26 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 23 27 github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= 24 28 github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= 29 + github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= 30 + github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= 25 31 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 26 32 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 27 33 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= ··· 30 36 github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 31 37 github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= 32 38 github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= 33 - github.com/labstack/echo/v4 v4.15.4 h1:DL45vVYa+BWE+XuW+zZNd9H0YEdZ80UAWJGcTVW4EVs= 34 - github.com/labstack/echo/v4 v4.15.4/go.mod h1:CuMetKIRwsuO/qlAgMq+KTAalwGoB/h4tC+yPdrTj1g= 39 + github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= 40 + github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 41 + github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 42 + github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 43 + github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 44 + github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 35 45 github.com/labstack/echo/v5 v5.2.1 h1:TzpIksY6zLMzV0T0ycYbvTEoj9w6o6AcL5twg182VTY= 36 46 github.com/labstack/echo/v5 v5.2.1/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo= 37 - github.com/labstack/gommon v0.5.0 h1:6VSQ2NOzsnEJ5W6+84E0RbcaDDmgB6NIAzWCczTEe6c= 38 - github.com/labstack/gommon v0.5.0/go.mod h1:Rzlg7HHy1maLfzBYGg9NZcVuz1sA68HHhLjhcEllYE0= 39 - github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= 40 - github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 41 - github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= 42 - github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= 43 47 github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= 44 48 github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 49 + github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= 50 + github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= 51 + github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 52 + github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 53 + github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= 54 + github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= 55 + github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= 56 + github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= 57 + github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= 58 + github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= 59 + github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= 60 + github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= 61 + github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= 62 + github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= 45 63 github.com/parquet-go/bitpack v1.0.0 h1:AUqzlKzPPXf2bCdjfj4sTeacrUwsT7NlcYDMUQxPcQA= 46 64 github.com/parquet-go/bitpack v1.0.0/go.mod h1:XnVk9TH+O40eOOmvpAVZ7K2ocQFrQwysLMnc6M/8lgs= 47 65 github.com/parquet-go/jsonlite v1.0.0 h1:87QNdi56wOfsE5bdgas0vRzHPxfJgzrXGml1zZdd7VU= ··· 54 72 github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 55 73 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 56 74 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 75 + github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= 76 + github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= 77 + github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= 78 + github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 57 79 github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= 58 80 github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= 59 81 github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= 60 82 github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= 83 + github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= 84 + github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 61 85 github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= 62 86 github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= 63 87 github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= ··· 72 96 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= 73 97 github.com/twpayne/go-geom v1.6.1 h1:iLE+Opv0Ihm/ABIcvQFGIiFBXd76oBIar9drAwHFhR4= 74 98 github.com/twpayne/go-geom v1.6.1/go.mod h1:Kr+Nly6BswFsKM5sd31YaoWS5PeDDH2NftJTK7Gd028= 99 + github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= 100 + github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= 75 101 github.com/urfave/cli/v3 v3.10.1 h1:7Kx9H50hrHbRbyxgO1KP6/BcbiGRz0uYh5YyQ30JEEY= 76 102 github.com/urfave/cli/v3 v3.10.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= 77 - github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 78 - github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 79 - github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= 80 - github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 103 + github.com/whyrusleeping/cbor-gen v0.3.1 h1:82ioxmhEYut7LBVGhGq8xoRkXPLElVuh5mV67AFfdv0= 104 + github.com/whyrusleeping/cbor-gen v0.3.1/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= 105 + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= 106 + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= 81 107 github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= 82 108 github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= 83 109 go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= 84 110 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 85 111 golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= 86 112 golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= 113 + golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= 114 + golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= 87 115 golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= 88 116 golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= 89 - golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= 90 - golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 117 + golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= 118 + golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= 119 + golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 91 120 golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= 92 121 golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= 93 - golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= 94 - golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= 95 122 golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= 96 123 golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= 97 124 golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= 98 125 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= 126 + golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= 127 + golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= 128 + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= 129 + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= 99 130 google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= 100 131 google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 101 132 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 133 + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 134 + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 102 135 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 103 136 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 104 137 gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= 105 138 gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= 106 139 gorm.io/gorm v1.31.2 h1:3o8FXNo9v9S858gil+3LlZA1LkCOzgb4g5BL64FgaCo= 107 140 gorm.io/gorm v1.31.2/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= 141 + lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= 142 + lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
+55
internal/server/puzzleHandlers.go
··· 1 + package server 2 + 3 + import ( 4 + "errors" 5 + "net/http" 6 + 7 + "github.com/labstack/echo/v5" 8 + "gorm.io/gorm" 9 + 10 + "tangled.org/pds.dad/PuzzleMeThis/api/lichess" 11 + "tangled.org/pds.dad/PuzzleMeThis/internal/models" 12 + ) 13 + 14 + // xrpcError renders an atproto-style XRPC error body: {"error": ..., "message": ...}. 15 + func xrpcError(c *echo.Context, status int, name, message string) error { 16 + return c.JSON(status, map[string]string{"error": name, "message": message}) 17 + } 18 + 19 + // getPuzzle implements the org.lichess.getPuzzle XRPC query: it looks up a single 20 + // puzzle by id in the SQLite database and returns the generated output type. 21 + func (s *Server) getPuzzle(c *echo.Context) error { 22 + id := c.QueryParam("id") 23 + if id == "" { 24 + return xrpcError(c, http.StatusBadRequest, "InvalidRequest", "missing id parameter") 25 + } 26 + 27 + var p models.Puzzle 28 + err := s.db.First(&p, "puzzle_id = ?", id).Error 29 + if errors.Is(err, gorm.ErrRecordNotFound) { 30 + return xrpcError(c, http.StatusNotFound, "PuzzleNotFound", "No puzzle exists with the given id.") 31 + } 32 + if err != nil { 33 + c.Logger().Error("getPuzzle db lookup failed", "err", err) 34 + return xrpcError(c, http.StatusInternalServerError, "InternalServerError", "failed to load puzzle") 35 + } 36 + 37 + nbPlays := int64(p.NbPlays) 38 + popularity := int64(p.Popularity) 39 + out := lichess.GetPuzzle_Output{ 40 + Fen: p.FEN, 41 + Moves: p.Moves, 42 + Rating: int64(p.Rating), 43 + RatingDeviation: int64(p.RatingDeviation), 44 + // Every imported row comes straight from Lichess's puzzle dataset, so this 45 + // is always true today. Revisit if non-Lichess puzzles are ever stored. 46 + IsOriginalLichessPuzzle: true, 47 + GameId: &p.GameID, 48 + NbPlays: &nbPlays, 49 + Popularity: &popularity, 50 + Themes: p.Themes, 51 + OpeningTags: p.OpeningTags, 52 + } 53 + 54 + return c.JSON(http.StatusOK, out) 55 + }
+4
internal/server/server.go
··· 29 29 //Handlers 30 30 e.GET("/", srv.home) 31 31 32 + // XRPC query endpoints (atproto convention: /xrpc/<nsid>) 33 + xrpc := e.Group("/xrpc") 34 + xrpc.GET("/org.lichess.getPuzzle", srv.getPuzzle) 35 + 32 36 port := viper.Get("server.port") 33 37 host := viper.Get("server.host") 34 38 address := fmt.Sprintf("%s:%s", host, port)
+15
lexicon-build-config.json
··· 1 + [ 2 + { 3 + "package": "atproto", 4 + "prefix": "com.atproto", 5 + "outdir": "/tmp/atproto", 6 + "import": "github.com/bluesky-social/indigo/api/atproto" 7 + }, 8 + { 9 + "package": "lichess", 10 + "prefix": "org.lichess", 11 + "outdir": "api/lichess", 12 + "import": "tangled.org/pds.dad/PuzzleMeThis/api/lichess", 13 + "gen-server": true 14 + } 15 + ]
+15
lexicons/com/atproto/repo/strongRef.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.strongRef", 4 + "description": "A URI with a content-hash fingerprint.", 5 + "defs": { 6 + "main": { 7 + "type": "object", 8 + "required": ["uri", "cid"], 9 + "properties": { 10 + "uri": { "type": "string", "format": "at-uri" }, 11 + "cid": { "type": "string", "format": "cid" } 12 + } 13 + } 14 + } 15 + }