summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/Philipp15b/go-steam/trade/tradeapi/trade.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/Philipp15b/go-steam/trade/tradeapi/trade.go')
-rw-r--r--vendor/github.com/Philipp15b/go-steam/trade/tradeapi/trade.go200
1 files changed, 200 insertions, 0 deletions
diff --git a/vendor/github.com/Philipp15b/go-steam/trade/tradeapi/trade.go b/vendor/github.com/Philipp15b/go-steam/trade/tradeapi/trade.go
new file mode 100644
index 00000000..5e9f2a98
--- /dev/null
+++ b/vendor/github.com/Philipp15b/go-steam/trade/tradeapi/trade.go
@@ -0,0 +1,200 @@
+/*
+Wrapper around the HTTP trading API for type safety 'n' stuff.
+*/
+package tradeapi
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "github.com/Philipp15b/go-steam/community"
+ "github.com/Philipp15b/go-steam/economy/inventory"
+ "github.com/Philipp15b/go-steam/netutil"
+ "github.com/Philipp15b/go-steam/steamid"
+ "io/ioutil"
+ "net/http"
+ "regexp"
+ "strconv"
+ "time"
+)
+
+const tradeUrl = "https://steamcommunity.com/trade/%d/"
+
+type Trade struct {
+ client *http.Client
+ other steamid.SteamId
+
+ LogPos uint // not automatically updated
+ Version uint // Incremented for each item change by Steam; not automatically updated.
+
+ // the `sessionid` cookie is sent as a parameter/POST data for CSRF protection.
+ sessionId string
+ baseUrl string
+}
+
+// Creates a new Trade based on the given cookies `sessionid`, `steamLogin`, `steamLoginSecure` and the trade partner's Steam ID.
+func New(sessionId, steamLogin, steamLoginSecure string, other steamid.SteamId) *Trade {
+ client := new(http.Client)
+ client.Timeout = 10 * time.Second
+
+ t := &Trade{
+ client: client,
+ other: other,
+ sessionId: sessionId,
+ baseUrl: fmt.Sprintf(tradeUrl, other),
+ Version: 1,
+ }
+ community.SetCookies(t.client, sessionId, steamLogin, steamLoginSecure)
+ return t
+}
+
+type Main struct {
+ PartnerOnProbation bool
+}
+
+var onProbationRegex = regexp.MustCompile(`var g_bTradePartnerProbation = (\w+);`)
+
+// Fetches the main HTML page and parses it. Thread-safe.
+func (t *Trade) GetMain() (*Main, error) {
+ resp, err := t.client.Get(t.baseUrl)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ match := onProbationRegex.FindSubmatch(body)
+ if len(match) == 0 {
+ return nil, errors.New("tradeapi.GetMain: Could not find probation info")
+ }
+
+ return &Main{
+ string(match[1]) == "true",
+ }, nil
+}
+
+// Ajax POSTs to an API endpoint that should return a status
+func (t *Trade) postWithStatus(url string, data map[string]string) (*Status, error) {
+ status := new(Status)
+
+ req := netutil.NewPostForm(url, netutil.ToUrlValues(data))
+ // Tales of Madness and Pain, Episode 1: If you forget this, Steam will return an error
+ // saying "missing required parameter", even though they are all there. IT WAS JUST THE HEADER, ARGH!
+ req.Header.Add("Referer", t.baseUrl)
+
+ resp, err := t.client.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ err = json.NewDecoder(resp.Body).Decode(status)
+ if err != nil {
+ return nil, err
+ }
+ return status, nil
+}
+
+func (t *Trade) GetStatus() (*Status, error) {
+ return t.postWithStatus(t.baseUrl+"tradestatus/", map[string]string{
+ "sessionid": t.sessionId,
+ "logpos": strconv.FormatUint(uint64(t.LogPos), 10),
+ "version": strconv.FormatUint(uint64(t.Version), 10),
+ })
+}
+
+// Thread-safe.
+func (t *Trade) GetForeignInventory(contextId uint64, appId uint32, start *uint) (*inventory.PartialInventory, error) {
+ data := map[string]string{
+ "sessionid": t.sessionId,
+ "steamid": fmt.Sprintf("%d", t.other),
+ "contextid": strconv.FormatUint(contextId, 10),
+ "appid": strconv.FormatUint(uint64(appId), 10),
+ }
+ if start != nil {
+ data["start"] = strconv.FormatUint(uint64(*start), 10)
+ }
+
+ req, err := http.NewRequest("GET", t.baseUrl+"foreigninventory?"+netutil.ToUrlValues(data).Encode(), nil)
+ if err != nil {
+ panic(err)
+ }
+ req.Header.Add("Referer", t.baseUrl)
+
+ return inventory.DoInventoryRequest(t.client, req)
+}
+
+// Thread-safe.
+func (t *Trade) GetOwnInventory(contextId uint64, appId uint32) (*inventory.Inventory, error) {
+ return inventory.GetOwnInventory(t.client, contextId, appId)
+}
+
+func (t *Trade) Chat(message string) (*Status, error) {
+ return t.postWithStatus(t.baseUrl+"chat", map[string]string{
+ "sessionid": t.sessionId,
+ "logpos": strconv.FormatUint(uint64(t.LogPos), 10),
+ "version": strconv.FormatUint(uint64(t.Version), 10),
+ "message": message,
+ })
+}
+
+func (t *Trade) AddItem(slot uint, itemId, contextId uint64, appId uint32) (*Status, error) {
+ return t.postWithStatus(t.baseUrl+"additem", map[string]string{
+ "sessionid": t.sessionId,
+ "slot": strconv.FormatUint(uint64(slot), 10),
+ "itemid": strconv.FormatUint(itemId, 10),
+ "contextid": strconv.FormatUint(contextId, 10),
+ "appid": strconv.FormatUint(uint64(appId), 10),
+ })
+}
+
+func (t *Trade) RemoveItem(slot uint, itemId, contextId uint64, appId uint32) (*Status, error) {
+ return t.postWithStatus(t.baseUrl+"removeitem", map[string]string{
+ "sessionid": t.sessionId,
+ "slot": strconv.FormatUint(uint64(slot), 10),
+ "itemid": strconv.FormatUint(itemId, 10),
+ "contextid": strconv.FormatUint(contextId, 10),
+ "appid": strconv.FormatUint(uint64(appId), 10),
+ })
+}
+
+func (t *Trade) SetCurrency(amount uint, currencyId, contextId uint64, appId uint32) (*Status, error) {
+ return t.postWithStatus(t.baseUrl+"setcurrency", map[string]string{
+ "sessionid": t.sessionId,
+ "amount": strconv.FormatUint(uint64(amount), 10),
+ "currencyid": strconv.FormatUint(uint64(currencyId), 10),
+ "contextid": strconv.FormatUint(contextId, 10),
+ "appid": strconv.FormatUint(uint64(appId), 10),
+ })
+}
+
+func (t *Trade) SetReady(ready bool) (*Status, error) {
+ return t.postWithStatus(t.baseUrl+"toggleready", map[string]string{
+ "sessionid": t.sessionId,
+ "version": strconv.FormatUint(uint64(t.Version), 10),
+ "ready": fmt.Sprint(ready),
+ })
+}
+
+func (t *Trade) Confirm() (*Status, error) {
+ return t.postWithStatus(t.baseUrl+"confirm", map[string]string{
+ "sessionid": t.sessionId,
+ "version": strconv.FormatUint(uint64(t.Version), 10),
+ })
+}
+
+func (t *Trade) Cancel() (*Status, error) {
+ return t.postWithStatus(t.baseUrl+"cancel", map[string]string{
+ "sessionid": t.sessionId,
+ })
+}
+
+func isSuccess(v interface{}) bool {
+ if m, ok := v.(map[string]interface{}); ok {
+ return m["success"] == true
+ }
+ return false
+}