+168
-6
main.go
+168
-6
main.go
···
10
10
"log"
11
11
"net/http"
12
12
"os"
13
+
"strings"
13
14
"sync"
14
15
"time"
15
16
···
79
80
// spacedust is type definitions only
80
81
// jetstream types is probably available from jetstream/pkg/models
81
82
82
-
router := gin.New()
83
-
router.Use(gin.Logger())
84
-
router.Use(gin.Recovery())
85
-
router.Use(cors.Default())
83
+
r_unsafe := gin.New()
84
+
r_unsafe.Use(gin.Logger())
85
+
r_unsafe.Use(gin.Recovery())
86
+
r_unsafe.Use(cors.Default())
86
87
87
-
router.GET("/.well-known/did.json", GetWellKnownDID)
88
+
r_unsafe.GET("/.well-known/did.json", GetWellKnownDID)
88
89
89
90
auther, err := auth.NewAuth(
90
91
100_000,
···
96
97
log.Fatalf("Failed to create Auth: %v", err)
97
98
}
98
99
100
+
router := r_unsafe.Group("/")
101
+
router.Use(auther.AuthenticateGinRequestViaJWT)
99
102
router.Use(auther.AuthenticateGinRequestViaJWT)
100
103
101
104
responsewow, err := agnostic.RepoGetRecord(ctx, sl, "", "app.bsky.actor.profile", "did:web:did12.whey.party", "self")
···
410
413
})
411
414
})
412
415
416
+
r_unsafe.GET("/xrpc/app.bsky.feed.getFeed",
417
+
func(c *gin.Context) {
418
+
ctx := c.Request.Context()
419
+
420
+
feedGenAturiRaw := c.Query("feed")
421
+
if feedGenAturiRaw == "" {
422
+
c.JSON(http.StatusBadRequest, gin.H{"error": "Missing feed param"})
423
+
return
424
+
}
425
+
426
+
feedGenAturi, err := syntax.ParseATURI(feedGenAturiRaw)
427
+
if err != nil {
428
+
return
429
+
}
430
+
431
+
feedGeneratorRecordResponse, err := agnostic.RepoGetRecord(ctx, sl, "", "app.bsky.feed.generator", feedGenAturi.Authority().String(), feedGenAturi.RecordKey().String())
432
+
if err != nil {
433
+
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("Failed to resolve feed generator record: %v", err)})
434
+
return
435
+
}
436
+
437
+
var feedGeneratorRecord appbsky.FeedGenerator
438
+
if err := json.Unmarshal(*feedGeneratorRecordResponse.Value, &feedGeneratorRecord); err != nil {
439
+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to parse feed generator record JSON"})
440
+
return
441
+
}
442
+
443
+
feedGenDID := feedGeneratorRecord.Did
444
+
445
+
didDoc, err := ResolveDID(feedGenDID)
446
+
if err != nil {
447
+
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("Failed to resolve DID: %v", err)})
448
+
return
449
+
}
450
+
451
+
if err != nil {
452
+
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("Failed to resolve DID: %v", err)})
453
+
return
454
+
}
455
+
456
+
var targetEndpoint string
457
+
for _, svc := range didDoc.Service {
458
+
if svc.Type == "BskyFeedGenerator" && strings.HasSuffix(svc.ID, "#bsky_fg") {
459
+
targetEndpoint = svc.ServiceEndpoint
460
+
break
461
+
}
462
+
}
463
+
if targetEndpoint == "" {
464
+
c.JSON(http.StatusBadGateway, gin.H{"error": "Feed Generator service endpoint not found in DID document"})
465
+
return
466
+
}
467
+
upstreamURL := fmt.Sprintf("%s/xrpc/app.bsky.feed.getFeedSkeleton?%s",
468
+
strings.TrimSuffix(targetEndpoint, "/"),
469
+
c.Request.URL.RawQuery,
470
+
)
471
+
req, err := http.NewRequestWithContext(ctx, "GET", upstreamURL, nil)
472
+
if err != nil {
473
+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create upstream request"})
474
+
return
475
+
}
476
+
headersToForward := []string{"Authorization", "Content-Type", "Accept", "User-Agent"}
477
+
for _, k := range headersToForward {
478
+
if v := c.GetHeader(k); v != "" {
479
+
req.Header.Set(k, v)
480
+
}
481
+
}
482
+
client := &http.Client{}
483
+
resp, err := client.Do(req)
484
+
if err != nil {
485
+
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("Upstream request failed: %v", err)})
486
+
return
487
+
}
488
+
defer resp.Body.Close()
489
+
490
+
bodyBytes, err := io.ReadAll(resp.Body)
491
+
if err != nil {
492
+
c.JSON(http.StatusBadGateway, gin.H{"error": "Failed to read upstream body"})
493
+
return
494
+
}
495
+
if resp.StatusCode != http.StatusOK {
496
+
// Forward the upstream error raw
497
+
c.Data(resp.StatusCode, resp.Header.Get("Content-Type"), bodyBytes)
498
+
return
499
+
}
500
+
501
+
var feekskeleton appbsky.FeedGetFeedSkeleton_Output
502
+
if err := json.Unmarshal(bodyBytes, &feekskeleton); err != nil {
503
+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to parse upstream JSON"})
504
+
return
505
+
}
506
+
507
+
skeletonposts := feekskeleton.Feed
508
+
509
+
type result struct {
510
+
view *appbsky.FeedDefs_FeedViewPost
511
+
}
512
+
513
+
results := make([]result, len(skeletonposts))
514
+
515
+
var wg sync.WaitGroup
516
+
wg.Add(len(skeletonposts))
517
+
518
+
for i, raw := range skeletonposts {
519
+
go func(i int, raw appbsky.FeedDefs_SkeletonFeedPost) {
520
+
defer wg.Done()
521
+
522
+
post, _, err := appbskyfeeddefs.PostView(ctx, raw.Post, sl, BSKYIMAGECDN_URL)
523
+
if err != nil || post == nil {
524
+
return
525
+
}
526
+
527
+
feedviewpost := &appbsky.FeedDefs_FeedViewPost{
528
+
// FeedContext *string `json:"feedContext,omitempty" cborgen:"feedContext,omitempty"`
529
+
// Post *FeedDefs_PostView `json:"post" cborgen:"post"`
530
+
Post: post,
531
+
// Reason *FeedDefs_FeedViewPost_Reason `json:"reason,omitempty" cborgen:"reason,omitempty"`
532
+
// Reason: &appbsky.FeedDefs_FeedViewPost_Reason{
533
+
// // FeedDefs_ReasonRepost *FeedDefs_ReasonRepost
534
+
// FeedDefs_ReasonRepost: &appbsky.FeedDefs_ReasonRepost{
535
+
// // LexiconTypeID string `json:"$type" cborgen:"$type,const=app.bsky.feed.defs#reasonRepost"`
536
+
// LexiconTypeID: "app.bsky.feed.defs#reasonRepost",
537
+
// // By *ActorDefs_ProfileViewBasic `json:"by" cborgen:"by"`
538
+
// // Cid *string `json:"cid,omitempty" cborgen:"cid,omitempty"`
539
+
// // IndexedAt string `json:"indexedAt" cborgen:"indexedAt"`
540
+
// // Uri *string `json:"uri,omitempty" cborgen:"uri,omitempty"`
541
+
// Uri: &raw.Reason.FeedDefs_SkeletonReasonRepost.Repost,
542
+
// },
543
+
// // FeedDefs_ReasonPin *FeedDefs_ReasonPin
544
+
// FeedDefs_ReasonPin: &appbsky.FeedDefs_ReasonPin{
545
+
// // LexiconTypeID string `json:"$type" cborgen:"$type,const=app.bsky.feed.defs#reasonPin"`
546
+
// LexiconTypeID: "app.bsky.feed.defs#reasonPin",
547
+
// },
548
+
// },
549
+
// Reply *FeedDefs_ReplyRef `json:"reply,omitempty" cborgen:"reply,omitempty"`
550
+
// // reqId: Unique identifier per request that may be passed back alongside interactions.
551
+
// ReqId *string `json:"reqId,omitempty" cborgen:"reqId,omitempty"`
552
+
553
+
}
554
+
555
+
results[i].view = feedviewpost
556
+
}(i, *raw)
557
+
}
558
+
559
+
wg.Wait()
560
+
561
+
// build final slice
562
+
out := make([]*appbsky.FeedDefs_FeedViewPost, 0, len(results))
563
+
for _, r := range results {
564
+
if r.view != nil && r.view.Post != nil {
565
+
out = append(out, r.view)
566
+
}
567
+
}
568
+
569
+
c.JSON(http.StatusOK, &appbsky.FeedGetFeed_Output{
570
+
Cursor: feekskeleton.Cursor,
571
+
Feed: out,
572
+
})
573
+
})
574
+
413
575
yourJSONBytes, _ := os.ReadFile("./public/getConfig.json")
414
576
router.GET("/xrpc/app.bsky.unspecced.getConfig", func(c *gin.Context) {
415
577
c.DataFromReader(200, -1, "application/json",
···
442
604
}(clientUUID)
443
605
}
444
606
})
445
-
router.Run(":7152")
607
+
r_unsafe.Run(":7152")
446
608
}
447
609
448
610
func getPostThreadV2(w http.ResponseWriter, r *http.Request) {
+49
utils.go
+49
utils.go
···
1
+
package main
2
+
3
+
import (
4
+
"encoding/json"
5
+
"fmt"
6
+
"net/http"
7
+
"strings"
8
+
)
9
+
10
+
type DIDDocument struct {
11
+
ID string `json:"id"`
12
+
Service []struct {
13
+
ID string `json:"id"`
14
+
Type string `json:"type"`
15
+
ServiceEndpoint string `json:"serviceEndpoint"`
16
+
} `json:"service"`
17
+
}
18
+
19
+
func ResolveDID(did string) (*DIDDocument, error) {
20
+
var url string
21
+
22
+
if strings.HasPrefix(did, "did:plc:") {
23
+
// Resolve via PLC Directory
24
+
url = "https://plc.directory/" + did
25
+
} else if strings.HasPrefix(did, "did:web:") {
26
+
// Resolve via Web (simplified)
27
+
domain := strings.TrimPrefix(did, "did:web:")
28
+
url = "https://" + domain + "/.well-known/did.json"
29
+
} else {
30
+
return nil, fmt.Errorf("unsupported DID format: %s", did)
31
+
}
32
+
33
+
resp, err := http.Get(url)
34
+
if err != nil {
35
+
return nil, err
36
+
}
37
+
defer resp.Body.Close()
38
+
39
+
if resp.StatusCode != http.StatusOK {
40
+
return nil, fmt.Errorf("resolver returned status: %d", resp.StatusCode)
41
+
}
42
+
43
+
var doc DIDDocument
44
+
if err := json.NewDecoder(resp.Body).Decode(&doc); err != nil {
45
+
return nil, err
46
+
}
47
+
48
+
return &doc, nil
49
+
}