diff options
Diffstat (limited to 'vendor/github.com/Philipp15b/go-steam/trade/tradeapi')
-rw-r--r-- | vendor/github.com/Philipp15b/go-steam/trade/tradeapi/status.go | 111 | ||||
-rw-r--r-- | vendor/github.com/Philipp15b/go-steam/trade/tradeapi/trade.go | 200 |
2 files changed, 311 insertions, 0 deletions
diff --git a/vendor/github.com/Philipp15b/go-steam/trade/tradeapi/status.go b/vendor/github.com/Philipp15b/go-steam/trade/tradeapi/status.go new file mode 100644 index 00000000..0a5278de --- /dev/null +++ b/vendor/github.com/Philipp15b/go-steam/trade/tradeapi/status.go @@ -0,0 +1,111 @@ +package tradeapi + +import ( + "encoding/json" + "github.com/Philipp15b/go-steam/jsont" + "github.com/Philipp15b/go-steam/steamid" + "strconv" +) + +type Status struct { + Success bool + Error string + NewVersion bool `json:"newversion"` + TradeStatus TradeStatus `json:"trade_status"` + Version uint + LogPos int + Me User + Them User + Events EventList +} + +type TradeStatus uint + +const ( + TradeStatus_Open TradeStatus = 0 + TradeStatus_Complete = 1 + TradeStatus_Empty = 2 // when both parties trade no items + TradeStatus_Cancelled = 3 + TradeStatus_Timeout = 4 // the partner timed out + TradeStatus_Failed = 5 +) + +type EventList map[uint]*Event + +// The EventList can either be an array or an object of id -> event +func (e *EventList) UnmarshalJSON(data []byte) error { + // initialize the map if it's nil + if *e == nil { + *e = make(EventList) + } + + o := make(map[string]*Event) + err := json.Unmarshal(data, &o) + // it's an object + if err == nil { + for is, event := range o { + i, err := strconv.ParseUint(is, 10, 32) + if err != nil { + panic(err) + } + (*e)[uint(i)] = event + } + return nil + } + + // it's an array + var a []*Event + err = json.Unmarshal(data, &a) + if err != nil { + return err + } + for i, event := range a { + (*e)[uint(i)] = event + } + return nil +} + +type Event struct { + SteamId steamid.SteamId `json:",string"` + Action Action `json:",string"` + Timestamp uint64 + + AppId uint32 + ContextId uint64 `json:",string"` + AssetId uint64 `json:",string"` + + Text string // only used for chat messages + + // The following is used for SetCurrency + CurrencyId uint64 `json:",string"` + OldAmount uint64 `json:"old_amount,string"` + NewAmount uint64 `json:"amount,string"` +} + +type Action uint + +const ( + Action_AddItem Action = 0 + Action_RemoveItem = 1 + Action_Ready = 2 + Action_Unready = 3 + Action_Accept = 4 + Action_SetCurrency = 6 + Action_ChatMessage = 7 +) + +type User struct { + Ready jsont.UintBool + Confirmed jsont.UintBool + SecSinceTouch int `json:"sec_since_touch"` + ConnectionPending bool `json:"connection_pending"` + Assets interface{} + Currency interface{} // either []*Currency or empty string +} + +type Currency struct { + AppId uint64 `json:",string"` + ContextId uint64 `json:",string"` + CurrencyId uint64 `json:",string"` + Amount uint64 `json:",string"` +} 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 +} |