package api import ( "encoding/json" "fmt" "io" "net/http" "time" "MobileMkch/models" ) const ( BaseURL = "https://mkch.pooziqo.xyz" ApiURL = BaseURL + "/api" ) type Client struct { httpClient *http.Client baseURL string debug bool } func NewClient() *Client { return &Client{ httpClient: &http.Client{ Timeout: 30 * time.Second, }, baseURL: ApiURL, debug: false, } } func (c *Client) EnableDebug(enable bool) { c.debug = enable } func (c *Client) makeRequest(url string) ([]byte, error) { if c.debug { fmt.Printf("[API] Запрос: %s\n", url) } resp, err := c.httpClient.Get(url) if err != nil { return nil, fmt.Errorf("ошибка запроса: %w", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("ошибка чтения ответа: %w", err) } if c.debug { fmt.Printf("[API] Статус: %d, Длина ответа: %d байт\n", resp.StatusCode, len(body)) if len(body) < 500 { fmt.Printf("[API] Ответ: %s\n", string(body)) } } if resp.StatusCode != http.StatusOK { return nil, &models.APIError{ Message: fmt.Sprintf("HTTP %d: %s", resp.StatusCode, string(body)), Code: resp.StatusCode, } } return body, nil } func (c *Client) GetBoards() ([]models.Board, error) { url := c.baseURL + "/boards/" body, err := c.makeRequest(url) if err != nil { return nil, fmt.Errorf("ошибка получения досок: %w", err) } var boards []models.Board if err := json.Unmarshal(body, &boards); err != nil { if c.debug { fmt.Printf("[API] Ошибка парсинга JSON: %v\n", err) fmt.Printf("[API] Ответ был: %s\n", string(body)) } return nil, fmt.Errorf("ошибка парсинга досок: %w", err) } if c.debug { fmt.Printf("[API] Получено досок: %d\n", len(boards)) } return boards, nil } func (c *Client) GetThreads(boardCode string) ([]models.Thread, error) { url := fmt.Sprintf("%s/board/%s", c.baseURL, boardCode) body, err := c.makeRequest(url) if err != nil { return nil, fmt.Errorf("ошибка получения тредов доски %s: %w", boardCode, err) } var threads []models.Thread if err := json.Unmarshal(body, &threads); err != nil { if c.debug { fmt.Printf("[API] Ошибка парсинга JSON тредов: %v\n", err) fmt.Printf("[API] Ответ был: %s\n", string(body)) } return nil, fmt.Errorf("ошибка парсинга тредов: %w", err) } if c.debug { fmt.Printf("[API] Получено тредов в /%s/: %d\n", boardCode, len(threads)) } return threads, nil } func (c *Client) GetThread(boardCode string, threadID int) (*models.ThreadDetail, error) { url := fmt.Sprintf("%s/board/%s/thread/%d", c.baseURL, boardCode, threadID) body, err := c.makeRequest(url) if err != nil { return nil, fmt.Errorf("ошибка получения треда %d: %w", threadID, err) } var thread models.ThreadDetail if err := json.Unmarshal(body, &thread); err != nil { if c.debug { fmt.Printf("[API] Ошибка парсинга JSON треда: %v\n", err) fmt.Printf("[API] Ответ был: %s\n", string(body)) } return nil, fmt.Errorf("ошибка парсинга треда: %w", err) } if c.debug { fmt.Printf("[API] Получен тред: ID=%d, Title=%s\n", thread.ID, thread.Title) } return &thread, nil } func (c *Client) GetComments(boardCode string, threadID int) ([]models.Comment, error) { url := fmt.Sprintf("%s/board/%s/thread/%d/comments", c.baseURL, boardCode, threadID) body, err := c.makeRequest(url) if err != nil { return nil, fmt.Errorf("ошибка получения комментариев треда %d: %w", threadID, err) } var comments []models.Comment if err := json.Unmarshal(body, &comments); err != nil { if c.debug { fmt.Printf("[API] Ошибка парсинга JSON комментариев: %v\n", err) fmt.Printf("[API] Ответ был: %s\n", string(body)) } return nil, fmt.Errorf("ошибка парсинга комментариев: %w", err) } if c.debug { fmt.Printf("[API] Получено комментариев: %d\n", len(comments)) } return comments, nil } func (c *Client) GetFullThread(boardCode string, threadID int) (*models.ThreadDetail, []models.Comment, error) { threadChan := make(chan *models.ThreadDetail, 1) commentsChan := make(chan []models.Comment, 1) errorChan := make(chan error, 2) go func() { thread, err := c.GetThread(boardCode, threadID) if err != nil { errorChan <- fmt.Errorf("ошибка получения треда: %w", err) return } threadChan <- thread }() go func() { comments, err := c.GetComments(boardCode, threadID) if err != nil { errorChan <- fmt.Errorf("ошибка получения комментариев: %w", err) return } commentsChan <- comments }() var thread *models.ThreadDetail var comments []models.Comment var errors []error for i := 0; i < 2; i++ { select { case t := <-threadChan: thread = t case c := <-commentsChan: comments = c case err := <-errorChan: errors = append(errors, err) case <-time.After(30 * time.Second): return nil, nil, fmt.Errorf("тайм-аут получения треда") } } if len(errors) > 0 { return nil, nil, errors[0] } return thread, comments, nil }