// !!!ВНИМАНИЕ!!! // Прошу не запускать часто, // чтобы не достовлять неудобств сервису package main import ( "bytes" "context" "encoding/json" "fmt" "io" "log/slog" "net/http" "os" "strings" "sync" "time" ) const ( TIMEOUT int = 5 BASE_URL string = "https://play2go.cloud" SLEEP int = 5 OUT_FOLDER string = "./" ) type JSON string type LinkForParse struct { Url string Method string } func (l LinkForParse) String() string { return fmt.Sprintf("%s %s", strings.ToUpper(l.Method), l.Url) } var parse_links = []LinkForParse{ {"/api/users/me", http.MethodGet}, } func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() var wg sync.WaitGroup token := os.Getenv("ACCESS_TOKEN") resultChan := make(chan JSON, 1) wg.Add(1) go func() { defer wg.Done() defer close(resultChan) parseProccess(ctx, token, TIMEOUT, parse_links, SLEEP, resultChan) }() wg.Add(1) go func() { defer wg.Done() for result := range resultChan { slog.Debug("parsed", "data", result) } }() wg.Wait() slog.Info("All proccessed finished successfully") } func parseProccess(ctx context.Context, token string, timeout int, links []LinkForParse, sleep int, result chan<- JSON) { if ctx.Err() != nil { slog.WarnContext(ctx, "parsing stopped") } for i, link := range parse_links { parsed, err := parse(ctx, link, token, timeout, nil) if err != nil { slog.ErrorContext(ctx, "failed to parse", "link", link.String(), "error", err.Error()) continue } select { case result <- parsed: case <-ctx.Done(): slog.WarnContext(ctx, "failed to send result: context canceled") return } if sleep > 0 && i < len(links)-1 { select { case <-time.After(time.Duration(timeout) * time.Second): case <-ctx.Done(): slog.WarnContext(ctx, "sleep interuppted by context cancellation") return } } } } func parse(ctx context.Context, link LinkForParse, token string, timeout int, data any) (JSON, error) { var reader io.Reader tctx, cancel := context.WithTimeout(ctx, time.Duration(timeout)*time.Second) defer cancel() if data != nil { d, err := json.Marshal(reader) if err != nil { return "", fmt.Errorf("failed to encode: %w", err) } reader = bytes.NewReader(d) } fullUrl := BASE_URL + link.Url req, err := http.NewRequestWithContext(tctx, link.Method, fullUrl, reader) if err != nil { return "", fmt.Errorf("failed to create request: %w", err) } req.Header.Set("Authorization", fmt.Sprintf("Brarer %s", token)) req.Header.Set("Accept", "application/json") if reader != nil { req.Header.Set("Content-Type", "application/json") } resp, err := http.DefaultClient.Do(req) if err != nil { return "", fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 300 { return "", fmt.Errorf("http error: %v", resp.StatusCode) } bodyData, err := io.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("failed to read body: %w", err) } return JSON(bodyData), nil }