bindbox-game/internal/pkg/douyin/phonenumber.go

95 lines
3.2 KiB
Go

package douyin
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
)
const (
// PhoneNumberURL Douyin get phone number interface address
PhoneNumberURL = "https://developer.toutiao.com/api/apps/v1/number_get/bind/"
)
// PhoneNumberRequest request parameters
type PhoneNumberRequest struct {
AppID string `json:"app_id"` // Note: specific parameter name might vary, but usually it's app_id or appid. Docs say `app_id` for some v1 interfaces.
Code string `json:"code"`
}
// PhoneNumberResponse response
type PhoneNumberResponse struct {
ErrNo int `json:"err_no"`
ErrTips string `json:"err_tips"`
Data struct {
PhoneNumber string `json:"phone_number"`
} `json:"data"`
}
// GetPhoneNumber calls Douyin interface to get user phone number
func GetPhoneNumber(ctx context.Context, accessToken, appID, code string) (string, error) {
if accessToken == "" || code == "" {
return "", fmt.Errorf("missing parameters")
}
// Note: Verify the correct endpoint and parameters.
// Commonly for `v1/number_get/bind/`, it might expect `encryptedData`?
// But `tt.getPhoneNumber` provides `code`.
// Let's assume the modern Code-based API which is often similar to `number_get/bind` but with `code`.
// Check if we need to call `https://developer.toutiao.com/api/apps/v1/user/get_phone_number_v1` instead?
// Or `https://developer.open-douyin.com/api/apps/v1/img/get_phone_number_v1`?
// Since I cannot verify the exact URL visually, I will stick to the one I hypothesized or the most "standard" one found in similar Go SDKs.
// Actually, let's try to assume it's `POST /api/apps/v2/jscode2session` style but for phone.
// A common variation for "get phone number by code" in Douyin is sending `code` and `app_id` to an endpoint.
// Let's go with the one stated in many online resources for "Douyin Mini Program Get Phone Number".
reqBody := map[string]string{
"app_id": appID,
"code": code,
}
jsonBody, err := json.Marshal(reqBody)
if err != nil {
return "", fmt.Errorf("failed to marshal request: %w", err)
}
httpClient := &http.Client{Timeout: 10 * time.Second}
// The URL might need `access_token` in query param or header?
// Most `v1` Douyin APIs require `access_token` in header or query. We will put in header `access-token`.
req, err := http.NewRequestWithContext(ctx, "POST", PhoneNumberURL, strings.NewReader(string(jsonBody)))
if err != nil {
return "", fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
// Some docs say `access-token` in header
req.Header.Set("access-token", accessToken)
resp, err := httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("failed to request Douyin interface: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("failed to read response: %w", err)
}
var result PhoneNumberResponse
if err := json.Unmarshal(body, &result); err != nil {
return "", fmt.Errorf("failed to parse response: %w, body: %s", err, string(body))
}
if result.ErrNo != 0 {
return "", fmt.Errorf("failed to get phone number: %s (code: %d)", result.ErrTips, result.ErrNo)
}
return result.Data.PhoneNumber, nil
}