init
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
package economy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AdVerifier تأیید میکند که کاربر یک تبلیغ rewarded را کامل دیده است.
|
||||
type AdVerifier interface {
|
||||
Verify(ctx context.Context, userID int64, token string) (bool, error)
|
||||
}
|
||||
|
||||
// IAPVerifier تأیید میکند که یک خرید درونبرنامهای معتبر و پرداختشده است.
|
||||
type IAPVerifier interface {
|
||||
Verify(ctx context.Context, store, productID, purchaseToken string) (bool, error)
|
||||
}
|
||||
|
||||
// --- استاب توسعه: هر توکن غیرخالی را معتبر میداند (فقط برای محیط dev/تست) ---
|
||||
|
||||
type DevAdVerifier struct{}
|
||||
|
||||
func (DevAdVerifier) Verify(_ context.Context, _ int64, token string) (bool, error) {
|
||||
return token != "", nil
|
||||
}
|
||||
|
||||
type DevIAPVerifier struct{}
|
||||
|
||||
func (DevIAPVerifier) Verify(_ context.Context, _ string, _ string, token string) (bool, error) {
|
||||
return token != "", nil
|
||||
}
|
||||
|
||||
// --- آداپتر تپسل (تأیید سمتسرور تبلیغ rewarded) ---
|
||||
//
|
||||
// تپسل پس از پایان کامل تبلیغ، یک توکن/شناسه میدهد که سرور باید آن را
|
||||
// نزد تپسل اعتبارسنجی کند. آدرس و قالب دقیق بسته به پنل تپسل تنظیم میشود؛
|
||||
// اینجا اسکلت فراخوانی با کلید قرار داده شده است.
|
||||
type TapsellAdVerifier struct {
|
||||
APIKey string
|
||||
BaseURL string // پیشفرض اگر خالی باشد ست میشود
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func NewTapsellAdVerifier(apiKey string) *TapsellAdVerifier {
|
||||
return &TapsellAdVerifier{
|
||||
APIKey: apiKey,
|
||||
BaseURL: "https://api.tapsell.ir",
|
||||
client: &http.Client{Timeout: 5 * time.Second},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TapsellAdVerifier) Verify(ctx context.Context, userID int64, token string) (bool, error) {
|
||||
if t.APIKey == "" || token == "" {
|
||||
return false, fmt.Errorf("tapsell: missing api key or token")
|
||||
}
|
||||
// TODO: مسیر دقیق اعتبارسنجی تپسل را مطابق مستندات پنل تنظیم کنید.
|
||||
url := fmt.Sprintf("%s/rewarded/verify?token=%s", t.BaseURL, token)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
req.Header.Set("Authorization", t.APIKey)
|
||||
resp, err := t.client.Do(req)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var out struct {
|
||||
Valid bool `json:"valid"`
|
||||
Completed bool `json:"completed"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return out.Valid && out.Completed, nil
|
||||
}
|
||||
|
||||
// --- آداپتر IAP کافهبازار / مایکت ---
|
||||
//
|
||||
// هر دو فروشگاه API شبیه Google Play دارند: با access_token (که از refresh_token
|
||||
// گرفته میشود) وضعیت یک purchaseToken برای یک محصول را اعتبارسنجی میکنیم.
|
||||
type StoreIAPVerifier struct {
|
||||
// قالب آدرس اعتبارسنجی؛ %s ها به ترتیب: package, product, token
|
||||
ValidateURLFmt string
|
||||
PackageName string
|
||||
AccessToken string // در عمل باید از refresh_token تازهسازی شود
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
// NewBazaarVerifier آداپتر کافهبازار.
|
||||
func NewBazaarVerifier(pkg, accessToken string) *StoreIAPVerifier {
|
||||
return &StoreIAPVerifier{
|
||||
ValidateURLFmt: "https://pardakht.cafebazaar.ir/devapi/v2/api/validate/%s/inapp/%s/purchases/%s/",
|
||||
PackageName: pkg,
|
||||
AccessToken: accessToken,
|
||||
client: &http.Client{Timeout: 6 * time.Second},
|
||||
}
|
||||
}
|
||||
|
||||
// NewMyketVerifier آداپتر مایکت.
|
||||
func NewMyketVerifier(pkg, accessToken string) *StoreIAPVerifier {
|
||||
return &StoreIAPVerifier{
|
||||
ValidateURLFmt: "https://developer.myket.ir/api/applications/%s/purchases/products/%s/tokens/%s/",
|
||||
PackageName: pkg,
|
||||
AccessToken: accessToken,
|
||||
client: &http.Client{Timeout: 6 * time.Second},
|
||||
}
|
||||
}
|
||||
|
||||
func (v *StoreIAPVerifier) Verify(ctx context.Context, _ string, productID, purchaseToken string) (bool, error) {
|
||||
if v.AccessToken == "" || purchaseToken == "" {
|
||||
return false, fmt.Errorf("iap: missing access token or purchase token")
|
||||
}
|
||||
url := fmt.Sprintf(v.ValidateURLFmt, v.PackageName, productID, purchaseToken)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+v.AccessToken)
|
||||
resp, err := v.client.Do(req)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return false, nil
|
||||
}
|
||||
var out struct {
|
||||
// هر دو فروشگاه فیلدی شبیه purchaseState برمیگردانند (۰ = خریداریشده)
|
||||
PurchaseState int `json:"purchaseState"`
|
||||
ConsumptionState int `json:"consumptionState"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return out.PurchaseState == 0, nil
|
||||
}
|
||||
Reference in New Issue
Block a user