255 lines
6.6 KiB
Go
255 lines
6.6 KiB
Go
package api
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"net/http"
|
||
"time"
|
||
|
||
"MobileMkch/cache"
|
||
"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) {
|
||
// Поздравляю, кеш
|
||
if boards, exists := cache.GetCache().GetBoards(); exists {
|
||
if c.debug {
|
||
fmt.Printf("[API] Доски загружены из кэша\n")
|
||
}
|
||
return boards, nil
|
||
}
|
||
|
||
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)
|
||
}
|
||
|
||
// Всех победили
|
||
cache.GetCache().SetBoards(boards)
|
||
|
||
if c.debug {
|
||
fmt.Printf("[API] Получено досок: %d\n", len(boards))
|
||
}
|
||
|
||
return boards, nil
|
||
}
|
||
|
||
func (c *Client) GetThreads(boardCode string) ([]models.Thread, error) {
|
||
if threads, exists := cache.GetCache().GetThreads(boardCode); exists {
|
||
if c.debug {
|
||
fmt.Printf("[API] Треды загружены из кэша для /%s/\n", boardCode)
|
||
}
|
||
return threads, nil
|
||
}
|
||
|
||
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 len(threads) > 12 {
|
||
// if c.debug {
|
||
// fmt.Printf("[API] Ограничиваем количество тредов с %d до 5\n", len(threads))
|
||
// }
|
||
// threads = threads[:12]
|
||
// }
|
||
|
||
cache.GetCache().SetThreads(boardCode, threads)
|
||
|
||
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) {
|
||
if thread, exists := cache.GetCache().GetThreadDetail(threadID); exists {
|
||
if c.debug {
|
||
fmt.Printf("[API] Тред %d загружен из кэша\n", threadID)
|
||
}
|
||
return thread, nil
|
||
}
|
||
|
||
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)
|
||
}
|
||
|
||
cache.GetCache().SetThreadDetail(threadID, &thread)
|
||
|
||
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) {
|
||
if comments, exists := cache.GetCache().GetComments(threadID); exists {
|
||
if c.debug {
|
||
fmt.Printf("[API] Комментарии загружены из кэша для треда %d\n", threadID)
|
||
}
|
||
return comments, nil
|
||
}
|
||
|
||
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)
|
||
}
|
||
|
||
cache.GetCache().SetComments(threadID, comments)
|
||
|
||
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
|
||
}
|