Created
December 5, 2019 14:56
-
-
Save megaherz/c3fa078f6658addf79bb2cbc267b4e81 to your computer and use it in GitHub Desktop.
Ironsource https://www.ironsrc.com/ API Golang client
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ironsource | |
import ( | |
"encoding/csv" | |
"encoding/json" | |
"fmt" | |
"github.com/pkg/errors" | |
"io" | |
"io/ioutil" | |
"net/http" | |
"strconv" | |
"strings" | |
"time" | |
) | |
type Client struct { | |
client http.Client | |
secretKey string | |
refreshToken string | |
token string | |
} | |
type httpError struct { | |
Code int | |
Body string | |
} | |
func (e httpError) Error() string { | |
return fmt.Sprintf("unexpected status code=%d body=%s", e.Code, e.Body) | |
} | |
var ErrRevenueNotFound = errors.New("revenue not found") | |
type AdRevenue struct { | |
// The ad unit from which the revenue was generate from | |
AdUnit string | |
// The unique ID of the user’s device | |
AdvertisingID string | |
// The unique ID type of the user’s device | |
AdvertisingIDType string | |
// The user ID being set by the developer | |
UserID string | |
// The segment the user is related to as defined on the platform | |
Segment string | |
// The placement the user is related to as defined on the platform | |
Placement string | |
// The placement the user is related to as defined on the platform | |
AdNetwork string | |
// A/B testing group the user was allocated to (can be ‘A’ or ‘B’) | |
ABTesting string | |
// The number of ads displayed to the user | |
Impressions int64 | |
// The Revenue generated by the user (USD) | |
Revenue float64 | |
} | |
type Application struct { | |
AppKey string `json:"appKey"` | |
AppName string `json:"appName"` | |
AppStatus string `json:"appStatus"` | |
Platform string `json:"platform"` | |
BundleID string `json:"bundleId"` | |
CreationDate string `json:"creationDate"` | |
Icon string `json:"icon"` | |
AdUnits map[string]interface{} `json:"adUnits"` | |
NetworkReportingAPI interface{} `json:"networkReportingApi"` | |
} | |
func NewClient(secretKey, refreshToken string) (*Client, error) { | |
var err error | |
c := &Client{ | |
client: http.Client{Timeout: 30 * time.Second}, | |
secretKey: secretKey, | |
refreshToken: refreshToken, | |
} | |
c.token, err = c.requestToken() | |
if err != nil { | |
return nil, errors.Wrap(err, "failed to request auth token") | |
} | |
return c, nil | |
} | |
func (c *Client) requestToken() (string, error) { | |
req, err := http.NewRequest("GET", "https://platform.ironsrc.com/partners/publisher/auth", nil) | |
if err != nil { | |
return "", err | |
} | |
req.Header.Add("secretkey", c.secretKey) | |
req.Header.Add("refreshToken", c.refreshToken) | |
resp, err := c.client.Do(req) | |
if err != nil { | |
return "", err | |
} | |
defer resp.Body.Close() | |
if resp.StatusCode != http.StatusOK { | |
body, _ := ioutil.ReadAll(resp.Body) | |
return "", fmt.Errorf("unexpected status code=%d body=%s", resp.StatusCode, body) | |
} | |
token, err := ioutil.ReadAll(resp.Body) | |
if err != nil { | |
return "", err | |
} | |
return strings.Replace(string(token), "\"", "", -1), nil | |
} | |
func (c *Client) exec(req *http.Request) ([]byte, error) { | |
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.token)) | |
resp, err := c.client.Do(req) | |
if err != nil { | |
return nil, err | |
} | |
defer resp.Body.Close() | |
if resp.StatusCode != http.StatusOK { | |
body, _ := ioutil.ReadAll(resp.Body) | |
if resp.StatusCode == http.StatusUnauthorized { | |
// IronSource does not have any specific code to detect expired token | |
if strings.Contains(string(body), "Unauthorized request, access token is expired") { | |
//token expired, request a new one | |
c.token, err = c.requestToken() | |
if err != nil { | |
return nil, err | |
} | |
req.Header.Del("Authorization") | |
return c.exec(req) | |
} | |
} | |
return nil, httpError{ | |
Code: resp.StatusCode, | |
Body: string(body)} | |
} | |
return ioutil.ReadAll(resp.Body) | |
} | |
func (c *Client) AdRevenue(appKey string, date time.Time) ([]*AdRevenue, error) { | |
req, err := http.NewRequest("GET", fmt.Sprintf("https://platform.ironsrc.com/partners/userAdRevenue/v3?appKey=%s&date=%s&reportType=1", | |
appKey, date.Format("2006-01-02")), nil) | |
if err != nil { | |
return nil, err | |
} | |
reportUrl, err := c.exec(req) | |
if err != nil { | |
return nil, err | |
} | |
if hErr, ok := err.(httpError); ok && hErr.Code == http.StatusNotFound { | |
return nil, ErrRevenueNotFound | |
} | |
reportResponse, err := c.client.Get(string(reportUrl)) | |
if err != nil { | |
return nil, err | |
} | |
defer reportResponse.Body.Close() | |
var out []*AdRevenue | |
reader := csv.NewReader(reportResponse.Body) | |
for { | |
record, err := reader.Read() | |
if err == io.EOF { | |
break | |
} | |
if err != nil { | |
return nil, errors.Wrap(err, "failed to read csv record") | |
} | |
if len(record) != 10 { | |
return nil, fmt.Errorf("invalid records len=%d", len(record)) | |
} | |
impressions, err := strconv.ParseInt(record[8], 10, 64) | |
if err != nil { | |
return nil, errors.Wrapf(err, "failed to parse impression=%s", record[8]) | |
} | |
revenue, err := strconv.ParseFloat(record[9], 10) | |
if err != nil { | |
return nil, errors.Wrapf(err, "failed to parse revenue=%s", record[9]) | |
} | |
out = append(out, &AdRevenue{ | |
AdUnit: record[0], | |
AdvertisingID: record[1], | |
AdvertisingIDType: record[2], | |
UserID: record[3], | |
Segment: record[4], | |
Placement: record[5], | |
AdNetwork: record[6], | |
ABTesting: record[7], | |
Impressions: impressions, | |
Revenue: revenue, | |
}) | |
} | |
return out, nil | |
} | |
func (c *Client) Applications() ([]*Application, error) { | |
req, err := http.NewRequest("GET", "https://platform.ironsrc.com/partners/publisher/applications/v4", nil) | |
if err != nil { | |
return nil, err | |
} | |
data, err := c.exec(req) | |
if err != nil { | |
return nil, err | |
} | |
var apps []*Application | |
if err := json.Unmarshal(data, &apps); err != nil { | |
return nil, err | |
} | |
return apps, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment