collection of golang services under the Red Dwarf umbrella server.reddwarf.app
bluesky reddwarf microcosm appview
16
fork

Configure Feed

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

at a8d05c9c673e85707b9569bb697f2570d7c206a9 127 lines 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) (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) 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}