package integration import ( "bytes" "chatapp-cron/internal/config" "context" "encoding/json" "fmt" "io" "net/http" "net/url" "strconv" "strings" ) type Client struct { cfg config.Config httpClient *http.Client } type SendActivityRewardRequest struct { TrackID int64 `json:"trackId"` Origin string `json:"origin"` SysOrigin string `json:"sysOrigin"` SourceGroupID int64 `json:"sourceGroupId"` AcceptUserID int64 `json:"acceptUserId"` } type UserProfile struct { ID Int64Value `json:"id"` UserAvatar string `json:"userAvatar"` UserNickname string `json:"userNickname"` } type resultResponse[T any] struct { Code int `json:"code"` Message string `json:"message"` Body T `json:"body"` Success *bool `json:"success"` } type Int64Value int64 func (v *Int64Value) UnmarshalJSON(data []byte) error { raw := strings.TrimSpace(string(data)) if raw == "" || raw == "null" { *v = 0 return nil } if strings.HasPrefix(raw, "\"") && strings.HasSuffix(raw, "\"") { raw = strings.Trim(raw, "\"") } parsed, err := strconv.ParseInt(raw, 10, 64) if err != nil { return err } *v = Int64Value(parsed) return nil } func New(cfg config.Config) *Client { return &Client{ cfg: cfg, httpClient: &http.Client{ Timeout: cfg.Timeout, }, } } func (c *Client) SendActivityReward(ctx context.Context, req SendActivityRewardRequest) error { return c.postJSON(ctx, c.cfg.JavaOtherBaseURL+"/props-activity-cnf/client/sendActivityReward", req, nil) } func (c *Client) GetUserProfile(ctx context.Context, userID int64) (UserProfile, error) { endpoint := c.cfg.JavaOtherBaseURL + "/user-profile/client/getByUserId?userId=" + url.QueryEscape(strconv.FormatInt(userID, 10)) var resp resultResponse[UserProfile] if err := c.getJSON(ctx, endpoint, &resp); err != nil { return UserProfile{}, err } if int64(resp.Body.ID) == 0 { return UserProfile{}, fmt.Errorf("empty user profile response") } return resp.Body, nil } func (c *Client) getJSON(ctx context.Context, endpoint string, out any) error { req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil) if err != nil { return err } resp, err := c.httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() return decodeResponse(resp, out) } func (c *Client) postJSON(ctx context.Context, endpoint string, payload any, out any) error { data, err := json.Marshal(payload) if err != nil { return err } req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(data)) if err != nil { return err } req.Header.Set("Content-Type", "application/json") resp, err := c.httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() return decodeResponse(resp, out) } func decodeResponse(resp *http.Response, out any) error { body, err := io.ReadAll(resp.Body) if err != nil { return err } if resp.StatusCode >= http.StatusBadRequest { return fmt.Errorf("java api failed: status=%d body=%s", resp.StatusCode, strings.TrimSpace(string(body))) } if out == nil || len(body) == 0 { return nil } if err := json.Unmarshal(body, out); err != nil { return fmt.Errorf("decode response failed: %w body=%s", err, strings.TrimSpace(string(body))) } return nil }