bluesky appview implementation using microcosm and other services server.reddwarf.app
appview bluesky reddwarf microcosm

getFeedGenerators

Changed files
+135
public
+95
main.go
··· 1 1 package main 2 2 3 3 import ( 4 + "bytes" 4 5 "context" 5 6 "encoding/json" 6 7 "flag" ··· 8 9 "io" 9 10 "log" 10 11 "net/http" 12 + "os" 13 + "sync" 11 14 "time" 12 15 13 16 did "github.com/whyrusleeping/go-did" ··· 22 25 // "github.com/bluesky-social/indigo/atproto/atclient" 23 26 // comatproto "github.com/bluesky-social/indigo/api/atproto" 24 27 appbsky "github.com/bluesky-social/indigo/api/bsky" 28 + "github.com/bluesky-social/indigo/atproto/syntax" 29 + 25 30 // "github.com/bluesky-social/indigo/atproto/atclient" 26 31 // "github.com/bluesky-social/indigo/atproto/identity" 27 32 // "github.com/bluesky-social/indigo/atproto/syntax" ··· 280 285 Views: labelers, 281 286 }) 282 287 }) 288 + 289 + router.GET("/xrpc/app.bsky.feed.getFeedGenerators", 290 + func(c *gin.Context) { 291 + feeds := c.QueryArray("feeds") 292 + ctx := c.Request.Context() 293 + 294 + type result struct { 295 + view *appbsky.FeedDefs_GeneratorView 296 + } 297 + 298 + results := make([]result, len(feeds)) 299 + 300 + var wg sync.WaitGroup 301 + wg.Add(len(feeds)) 302 + 303 + for i, raw := range feeds { 304 + go func(i int, raw string) { 305 + defer wg.Done() 306 + 307 + aturi, err := syntax.ParseATURI(raw) 308 + if err != nil { 309 + return 310 + } 311 + 312 + did := aturi.Authority().String() 313 + collection := aturi.Collection().String() 314 + rkey := aturi.RecordKey().String() 315 + 316 + repoDID, err := utils.NewDID(did) 317 + if err != nil { 318 + return 319 + } 320 + 321 + // fetch profile and record in parallel too (optional) 322 + // but to keep it simple, do serial inside this goroutine 323 + profile, _, _ := appbskyactordefs.ProfileView(ctx, repoDID, sl, BSKYIMAGECDN_URL) 324 + 325 + rec, err := agnostic.RepoGetRecord(ctx, sl, "", collection, did, rkey) 326 + if err != nil || rec.Value == nil { 327 + return 328 + } 329 + 330 + var genRec appbsky.FeedGenerator 331 + if err := json.Unmarshal(*rec.Value, &genRec); err != nil { 332 + return 333 + } 334 + 335 + var avatar *string 336 + if genRec.Avatar != nil { 337 + u := utils.MakeImageCDN(repoDID, BSKYIMAGECDN_URL, "avatar", genRec.Avatar.Ref.String()) 338 + avatar = &u 339 + } 340 + 341 + results[i].view = &appbsky.FeedDefs_GeneratorView{ 342 + LexiconTypeID: "app.bsky.feed.defs#generatorView", 343 + AcceptsInteractions: genRec.AcceptsInteractions, 344 + Avatar: avatar, 345 + Cid: *rec.Cid, 346 + ContentMode: genRec.ContentMode, 347 + Creator: profile, 348 + Description: genRec.Description, 349 + DescriptionFacets: genRec.DescriptionFacets, 350 + Did: did, 351 + DisplayName: genRec.DisplayName, 352 + IndexedAt: genRec.CreatedAt, 353 + Uri: rec.Uri, 354 + } 355 + }(i, raw) 356 + } 357 + 358 + wg.Wait() 359 + 360 + // build final slice 361 + out := make([]*appbsky.FeedDefs_GeneratorView, 0, len(results)) 362 + for _, r := range results { 363 + if r.view != nil { 364 + out = append(out, r.view) 365 + } 366 + } 367 + 368 + c.JSON(http.StatusOK, &appbsky.FeedGetFeedGenerators_Output{ 369 + Feeds: out, 370 + }) 371 + }) 372 + 373 + yourJSONBytes, _ := os.ReadFile("./public/getConfig.json") 374 + router.GET("/xrpc/app.bsky.unspecced.getConfig", func(c *gin.Context) { 375 + c.DataFromReader(200, -1, "application/json", 376 + bytes.NewReader(yourJSONBytes), nil) 377 + }) 283 378 284 379 router.GET("/", func(c *gin.Context) { 285 380 log.Println("hello worldio !")
+40
public/getConfig.json
··· 1 + { 2 + "checkEmailConfirmed": true, 3 + "topicsEnabled": true, 4 + "liveNow": [ 5 + { 6 + "did": "did:plc:7sfnardo5xxznxc6esxc5ooe", 7 + "domains": [ 8 + "www.nba.com", 9 + "nba.com", 10 + "nba.smart.link", 11 + "espn.com", 12 + "www.espn.com" 13 + ] 14 + }, 15 + { "did": "did:plc:gx6fyi3jcfxd7ammq2t7mzp2", "domains": ["twitch.tv"] }, 16 + { "did": "did:plc:mc2hhszsfk6iwapfdwrwoj7i", "domains": ["twitch.tv"] }, 17 + { "did": "did:plc:sb54dpdfefflykmf5bcfvr7t", "domains": ["youtube.com"] }, 18 + { "did": "did:plc:dqav4a4ue5cyzgckv3l6fshr", "domains": ["twitch.tv"] }, 19 + { "did": "did:plc:q6f4hsgifb3qs2e3wwdycjtf", "domains": ["twitch.tv"] }, 20 + { "did": "did:plc:7tpvfx7mdbceyzj6kgboirle", "domains": ["twitch.tv"] }, 21 + { 22 + "did": "did:plc:4adlzwqtkv4dirxjwq4c3tlm", 23 + "domains": ["stream.place", "skylight.social"] 24 + }, 25 + { 26 + "did": "did:plc:2zmxikig2sj7gqaezl5gntae", 27 + "domains": ["stream.place", "skylight.social"] 28 + }, 29 + { 30 + "did": "did:plc:jsbkvuuviqj4xooqwcbaftav", 31 + "domains": ["stream.place", "skylight.social"] 32 + }, 33 + { 34 + "did": "did:plc:76iqtegcbbr4pbcxomka5pat", 35 + "domains": ["stream.place", "skylight.social"] 36 + }, 37 + { "did": "did:plc:r2mpjf3gz2ygfaodkzzzfddg", "domains": ["youtube.com"] }, 38 + { "did": "did:plc:wvwvlbeizca367klhhyudf2n", "domains": ["youtube.com"] } 39 + ] 40 + }