MobileMkch/api/client.go
2025-08-05 13:45:18 +03:00

209 lines
5.3 KiB
Go

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
}