package operations import ( "fmt" "io" "net/http" "strings" "time" "service-operation/types" ) type HTTPOperation struct { timeout time.Duration client *http.Client } func NewHTTPOperation(timeout time.Duration) *HTTPOperation { return &HTTPOperation{ timeout: timeout, client: &http.Client{ Timeout: timeout, }, } } func (h *HTTPOperation) Execute(url, method string) (*types.OperationResult, error) { result := &types.OperationResult{ Type: types.OperationHTTP, StartTime: time.Now(), HTTPMethod: method, } // Default to GET if no method specified if method == "" { method = "GET" result.HTTPMethod = "GET" } // Ensure URL has protocol if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") { url = "https://" + url } start := time.Now() req, err := http.NewRequest(method, url, nil) if err != nil { result.Error = fmt.Sprintf("Failed to create request: %v", err) result.Success = false result.EndTime = time.Now() return result, nil } // Set a user agent req.Header.Set("User-Agent", "ServiceOperation/1.0") resp, err := h.client.Do(req) result.ResponseTime = time.Since(start) result.EndTime = time.Now() if err != nil { // More detailed error messages if strings.Contains(err.Error(), "timeout") { result.Error = fmt.Sprintf("🕐 Request timeout after %.2fs - Server did not respond within the expected time", h.timeout.Seconds()) } else if strings.Contains(err.Error(), "connection refused") { result.Error = "đŸšĢ Connection refused - Server is not accepting connections on this port" } else if strings.Contains(err.Error(), "no such host") { result.Error = "🌐 DNS resolution failed - Host not found" } else if strings.Contains(err.Error(), "certificate") { result.Error = "🔒 SSL/TLS certificate error - Certificate verification failed" } else { result.Error = fmt.Sprintf("🔌 Connection error: %v", err) } result.Success = false return result, nil } defer resp.Body.Close() result.HTTPStatusCode = resp.StatusCode result.ContentLength = resp.ContentLength result.Success = resp.StatusCode >= 200 && resp.StatusCode < 400 // Capture important headers result.HTTPHeaders = make(map[string]string) for key, values := range resp.Header { if len(values) > 0 { switch strings.ToLower(key) { case "content-type", "server", "cache-control", "content-encoding", "x-powered-by": result.HTTPHeaders[key] = values[0] } } } // Read response body for keyword checking and additional details body, err := io.ReadAll(resp.Body) if err == nil && len(body) > 0 { result.ResponseBody = string(body) // Update content length if not set by server if result.ContentLength <= 0 { result.ContentLength = int64(len(body)) } } // Create detailed status message with emoji if !result.Success { switch { case resp.StatusCode >= 500: result.Error = fmt.Sprintf("đŸ”Ĩ Server Error (HTTP %d): %s - The server encountered an internal error", resp.StatusCode, resp.Status) case resp.StatusCode >= 400: result.Error = fmt.Sprintf("❌ Client Error (HTTP %d): %s - The request was invalid or unauthorized", resp.StatusCode, resp.Status) case resp.StatusCode >= 300: result.Error = fmt.Sprintf("â†Šī¸ Redirect (HTTP %d): %s - Resource has moved", resp.StatusCode, resp.Status) default: result.Error = fmt.Sprintf("âš ī¸ Unexpected Status (HTTP %d): %s", resp.StatusCode, resp.Status) } } else { // Success message with emoji switch resp.StatusCode { case 200: result.Error = "✅ OK - Request successful" case 201: result.Error = "🆕 Created - Resource created successfully" case 202: result.Error = "âŗ Accepted - Request accepted for processing" case 204: result.Error = "📭 No Content - Request successful, no content returned" default: result.Error = fmt.Sprintf("✅ Success (HTTP %d): %s", resp.StatusCode, resp.Status) } } return result, nil }