bluesky appview implementation using microcosm and other services server.reddwarf.app
appview bluesky reddwarf microcosm
at main 2.4 kB view raw
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}