(ctx context.Context, urlStr string, userID string)
| 198 | if err != nil { |
| 199 | return nil, "", err |
| 200 | } |
| 201 | if int64(len(data)) > limit { |
| 202 | return nil, "", fmt.Errorf("response exceeds allowed size (%d bytes)", limit) |
| 203 | } |
| 204 | |
| 205 | contentType := resp.Header.Get("Content-Type") |
| 206 | if contentType == "" { |
| 207 | contentType = http.DetectContentType(data) |
| 208 | } |
| 209 | |
| 210 | return data, contentType, nil |
| 211 | } |
| 212 | |
| 213 | func getOpenGraphData(ctx context.Context, urlStr string, userID string) openGraphResult { |
| 214 | // Check cache first |
| 215 | if cachedData, found := openGraphCache.Get(urlStr); found { |
| 216 | if data, ok := cachedData.(openGraphResult); ok { |
| 217 | log.Debug().Str("url", urlStr).Msg("Open Graph data fetched from cache") |
| 218 | return data |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | v, err, _ := openGraphGroup.Do(urlStr, func() (res any, err error) { |
| 223 | ctx, cancel := context.WithTimeout(ctx, openGraphFetchTimeout) |
| 224 | defer cancel() |
| 225 | |
| 226 | // Acquire a token from the semaphore pool |
| 227 | userPool := userSemaphoreManager.ForUser(userID) |
| 228 | select { |
| 229 | case userPool <- struct{}{}: |
| 230 | defer func() { <-userPool }() |
| 231 | case <-ctx.Done(): |
| 232 | log.Warn().Str("url", urlStr).Msg("Open Graph data fetch timed out while waiting for a worker") |
| 233 | return nil, ctx.Err() |
| 234 | } |
| 235 | |
| 236 | // Recover from panics and convert to error |
| 237 | defer func() { |
| 238 | if r := recover(); r != nil { |
| 239 | stack := debug.Stack() |
| 240 | log.Error(). |
| 241 | Interface("panic_info", r). |
| 242 | Str("url", urlStr). |
| 243 | Bytes("stack", stack). |
| 244 | Msg("Panic recovered while fetching Open Graph data") |
| 245 | err = fmt.Errorf("panic: %v", r) |
| 246 | } |
| 247 | }() |
| 248 | |
| 249 | // Fetch Open Graph data |
| 250 | result := fetchOpenGraphData(ctx, urlStr) |
| 251 | |
| 252 | // Store in cache |
| 253 | openGraphCache.Set(urlStr, result, cache.DefaultExpiration) |
| 254 | |
| 255 | return result, nil |
| 256 | }) |
| 257 |
no test coverage detected