4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-06-27 19:19:24 +00:00

Add vendor (steam)

This commit is contained in:
Wim
2017-06-22 01:00:27 +02:00
parent 1f9874102a
commit 1f91461853
117 changed files with 115543 additions and 0 deletions

84
vendor/github.com/Philipp15b/go-steam/trade/actions.go generated vendored Normal file
View File

@ -0,0 +1,84 @@
package trade
import (
"github.com/Philipp15b/go-steam/economy/inventory"
"github.com/Philipp15b/go-steam/trade/tradeapi"
"time"
)
type Slot uint
func (t *Trade) action(status *tradeapi.Status, err error) error {
if err != nil {
return err
}
t.onStatus(status)
return nil
}
// Returns the next batch of events to process. These can be queued from calls to methods
// like `AddItem` or, if there are no queued events, from a new HTTP request to Steam's API (blocking!).
// If the latter is the case, this method may also sleep before the request
// to conform to the polling interval of the official Steam client.
func (t *Trade) Poll() ([]interface{}, error) {
if t.queuedEvents != nil {
return t.Events(), nil
}
if d := time.Since(t.lastPoll); d < pollTimeout {
time.Sleep(pollTimeout - d)
}
t.lastPoll = time.Now()
err := t.action(t.api.GetStatus())
if err != nil {
return nil, err
}
return t.Events(), nil
}
func (t *Trade) GetTheirInventory(contextId uint64, appId uint32) (*inventory.Inventory, error) {
return inventory.GetFullInventory(func() (*inventory.PartialInventory, error) {
return t.api.GetForeignInventory(contextId, appId, nil)
}, func(start uint) (*inventory.PartialInventory, error) {
return t.api.GetForeignInventory(contextId, appId, &start)
})
}
func (t *Trade) GetOwnInventory(contextId uint64, appId uint32) (*inventory.Inventory, error) {
return t.api.GetOwnInventory(contextId, appId)
}
func (t *Trade) GetMain() (*tradeapi.Main, error) {
return t.api.GetMain()
}
func (t *Trade) AddItem(slot Slot, item *Item) error {
return t.action(t.api.AddItem(uint(slot), item.AssetId, item.ContextId, item.AppId))
}
func (t *Trade) RemoveItem(slot Slot, item *Item) error {
return t.action(t.api.RemoveItem(uint(slot), item.AssetId, item.ContextId, item.AppId))
}
func (t *Trade) Chat(message string) error {
return t.action(t.api.Chat(message))
}
func (t *Trade) SetCurrency(amount uint, currency *Currency) error {
return t.action(t.api.SetCurrency(amount, currency.CurrencyId, currency.ContextId, currency.AppId))
}
func (t *Trade) SetReady(ready bool) error {
return t.action(t.api.SetReady(ready))
}
// This may only be called after a successful `SetReady(true)`.
func (t *Trade) Confirm() error {
return t.action(t.api.Confirm())
}
func (t *Trade) Cancel() error {
return t.action(t.api.Cancel())
}

40
vendor/github.com/Philipp15b/go-steam/trade/doc.go generated vendored Normal file
View File

@ -0,0 +1,40 @@
/*
Allows automation of Steam Trading.
Usage
Like go-steam, this package is event-based. Call Poll() until the trade has ended, that is until the TradeEndedEvent is emitted.
// After receiving the steam.TradeSessionStartEvent
t := trade.New(sessionIdCookie, steamLoginCookie, steamLoginSecure, event.Other)
for {
eventList, err := t.Poll()
if err != nil {
// error handling here
continue
}
for _, event := range eventList {
switch e := event.(type) {
case *trade.ChatEvent:
// respond to any chat message
t.Chat("Trading is awesome!")
case *trade.TradeEndedEvent:
return
// other event handlers here
}
}
}
You can either log into steamcommunity.com and use the values of the `sessionId` and `steamLogin` cookies,
or use go-steam and after logging in with client.Web.LogOn() and receiving the WebLoggedOnEvent use the `SessionId`
and `SteamLogin` fields of steam.Web for the respective cookies.
It is important that there is no delay between the Poll() calls greater than the timeout of the Steam client
(currently five seconds before the trade partner sees a warning) or the trade will be closed automatically by Steam.
Notes
All method calls to Steam APIs are blocking. This packages' and its subpackages' types are not thread-safe and no calls to any method of the same
trade instance may be done concurrently except when otherwise noted.
*/
package trade

122
vendor/github.com/Philipp15b/go-steam/trade/trade.go generated vendored Normal file
View File

@ -0,0 +1,122 @@
package trade
import (
"errors"
"time"
"github.com/Philipp15b/go-steam/steamid"
"github.com/Philipp15b/go-steam/trade/tradeapi"
)
const pollTimeout = time.Second
type Trade struct {
ThemId steamid.SteamId
MeReady, ThemReady bool
lastPoll time.Time
queuedEvents []interface{}
api *tradeapi.Trade
}
func New(sessionId, steamLogin, steamLoginSecure string, other steamid.SteamId) *Trade {
return &Trade{
other,
false, false,
time.Unix(0, 0),
nil,
tradeapi.New(sessionId, steamLogin, steamLoginSecure, other),
}
}
func (t *Trade) Version() uint {
return t.api.Version
}
// Returns all queued events and removes them from the queue without performing a HTTP request, like Poll() would.
func (t *Trade) Events() []interface{} {
qe := t.queuedEvents
t.queuedEvents = nil
return qe
}
func (t *Trade) onStatus(status *tradeapi.Status) error {
if !status.Success {
return errors.New("trade: returned status not successful! error message: " + status.Error)
}
if status.NewVersion {
t.api.Version = status.Version
t.MeReady = status.Me.Ready == true
t.ThemReady = status.Them.Ready == true
}
switch status.TradeStatus {
case tradeapi.TradeStatus_Complete:
t.addEvent(&TradeEndedEvent{TradeEndReason_Complete})
case tradeapi.TradeStatus_Cancelled:
t.addEvent(&TradeEndedEvent{TradeEndReason_Cancelled})
case tradeapi.TradeStatus_Timeout:
t.addEvent(&TradeEndedEvent{TradeEndReason_Timeout})
case tradeapi.TradeStatus_Failed:
t.addEvent(&TradeEndedEvent{TradeEndReason_Failed})
case tradeapi.TradeStatus_Open:
// nothing
default:
// ignore too
}
t.updateEvents(status.Events)
return nil
}
func (t *Trade) updateEvents(events tradeapi.EventList) {
if len(events) == 0 {
return
}
var lastLogPos uint
for i, event := range events {
if i < t.api.LogPos {
continue
}
if event.SteamId != t.ThemId {
continue
}
if lastLogPos < i {
lastLogPos = i
}
switch event.Action {
case tradeapi.Action_AddItem:
t.addEvent(&ItemAddedEvent{newItem(event)})
case tradeapi.Action_RemoveItem:
t.addEvent(&ItemRemovedEvent{newItem(event)})
case tradeapi.Action_Ready:
t.ThemReady = true
t.addEvent(new(ReadyEvent))
case tradeapi.Action_Unready:
t.ThemReady = false
t.addEvent(new(UnreadyEvent))
case tradeapi.Action_SetCurrency:
t.addEvent(&SetCurrencyEvent{
newCurrency(event),
event.OldAmount,
event.NewAmount,
})
case tradeapi.Action_ChatMessage:
t.addEvent(&ChatEvent{
event.Text,
})
}
}
t.api.LogPos = uint(lastLogPos) + 1
}
func (t *Trade) addEvent(event interface{}) {
t.queuedEvents = append(t.queuedEvents, event)
}

View File

@ -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"`
}

View File

@ -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
}

67
vendor/github.com/Philipp15b/go-steam/trade/types.go generated vendored Normal file
View File

@ -0,0 +1,67 @@
package trade
import (
"github.com/Philipp15b/go-steam/trade/tradeapi"
)
type TradeEndedEvent struct {
Reason TradeEndReason
}
type TradeEndReason uint
const (
TradeEndReason_Complete TradeEndReason = 1
TradeEndReason_Cancelled = 2
TradeEndReason_Timeout = 3
TradeEndReason_Failed = 4
)
func newItem(event *tradeapi.Event) *Item {
return &Item{
event.AppId,
event.ContextId,
event.AssetId,
}
}
type Item struct {
AppId uint32
ContextId uint64
AssetId uint64
}
type ItemAddedEvent struct {
Item *Item
}
type ItemRemovedEvent struct {
Item *Item
}
type ReadyEvent struct{}
type UnreadyEvent struct{}
func newCurrency(event *tradeapi.Event) *Currency {
return &Currency{
event.AppId,
event.ContextId,
event.CurrencyId,
}
}
type Currency struct {
AppId uint32
ContextId uint64
CurrencyId uint64
}
type SetCurrencyEvent struct {
Currency *Currency
OldAmount uint64
NewAmount uint64
}
type ChatEvent struct {
Message string
}