bluesky appview implementation using microcosm and other services
server.reddwarf.app
appview
bluesky
reddwarf
microcosm
1package main
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "net/http"
8 "net/http/httputil"
9 "strings"
10 "sync"
11
12 "github.com/gin-gonic/gin"
13)
14
15type DIDDocument struct {
16 ID string `json:"id"`
17 Service []struct {
18 ID string `json:"id"`
19 Type string `json:"type"`
20 ServiceEndpoint string `json:"serviceEndpoint"`
21 } `json:"service"`
22}
23
24func ResolveDID(did string) (*DIDDocument, error) {
25 var url string
26
27 if strings.HasPrefix(did, "did:plc:") {
28 // Resolve via PLC Directory
29 url = "https://plc.directory/" + did
30 } else if strings.HasPrefix(did, "did:web:") {
31 // Resolve via Web (simplified)
32 domain := strings.TrimPrefix(did, "did:web:")
33 url = "https://" + domain + "/.well-known/did.json"
34 } else {
35 return nil, fmt.Errorf("unsupported DID format: %s", did)
36 }
37
38 resp, err := http.Get(url)
39 if err != nil {
40 return nil, err
41 }
42 defer resp.Body.Close()
43
44 if resp.StatusCode != http.StatusOK {
45 return nil, fmt.Errorf("resolver returned status: %d", resp.StatusCode)
46 }
47
48 var doc DIDDocument
49 if err := json.NewDecoder(resp.Body).Decode(&doc); err != nil {
50 return nil, err
51 }
52
53 return &doc, nil
54}
55
56type AsyncResult[T any] struct {
57 Value T
58 Err error
59}
60
61func MapConcurrent[T any, R any](
62 ctx context.Context,
63 items []T,
64 concurrencyLimit int,
65 mapper func(context.Context, T, int) (R, error),
66) []AsyncResult[R] {
67 if len(items) == 0 {
68 return nil
69 }
70
71 results := make([]AsyncResult[R], len(items))
72 var wg sync.WaitGroup
73
74 sem := make(chan struct{}, concurrencyLimit)
75
76 for i, item := range items {
77 wg.Add(1)
78 go func(idx int, input T) {
79 defer wg.Done()
80
81 sem <- struct{}{}
82 defer func() { <-sem }()
83
84 if ctx.Err() != nil {
85 results[idx] = AsyncResult[R]{Err: ctx.Err()}
86 return
87 }
88
89 val, err := mapper(ctx, input, idx)
90 results[idx] = AsyncResult[R]{Value: val, Err: err}
91 }(i, item)
92 }
93
94 wg.Wait()
95 return results
96}
97
98func RunConcurrent(tasks ...func() error) []error {
99 var wg sync.WaitGroup
100 errs := make([]error, len(tasks))
101
102 wg.Add(len(tasks))
103
104 for i, task := range tasks {
105 go func(i int, t func() error) {
106 defer wg.Done()
107 if err := t(); err != nil {
108 errs[i] = err
109 }
110 }(i, task)
111 }
112
113 wg.Wait()
114 return errs
115}
116
117func DebugMiddleware() gin.HandlerFunc {
118 return func(c *gin.Context) {
119 dump, err := httputil.DumpRequest(c.Request, true)
120 if err == nil {
121 fmt.Println("=== RAW REQUEST ===")
122 fmt.Println(string(dump))
123 }
124
125 c.Next()
126 }
127}