steam-js-api
Version:
A wrapper for Steam Web API, with additional CSGO functionality.
223 lines (184 loc) • 8.75 kB
JavaScript
const {urls, request} = require('./util.js')
const {requireKey} = require('./../app.js')
function getMapPlaytime(interval, gameMode, mapGroup, callback) {
let intervals = {
1: 'day',
2: 'week',
3: 'month'
}
let gameModes = {
1: 'competitive',
2: 'casual'
}
let mapGroups = {
1: 'operation'
}
if (typeof interval === 'function') {
callback = interval
interval = 1
gameMode = 1
mapGroup = 1
} else if (typeof gameMode === 'function') {
callback = gameMode
gameMode = 1
mapGroup = 1
} else if (typeof mapGroup === 'function') {
callback = mapGroup
mapGroup = 1
}
if (!interval) interval = 1
if (!gameMode) gameMode = 1
if (!mapGroup) mapGroup = 1
function run(resolve, reject) {
let _key = requireKey()
if (!intervals.hasOwnProperty(interval)) {
if (typeof interval !== 'string' || !Object.values(intervals).includes(interval)) {
let result = {error: 'Requested interval does not correlate to a possible interval.'}
if (reject) reject(result)
else resolve(result)
return
}
} else {
interval = intervals[interval]
}
if (!gameModes.hasOwnProperty(gameMode)) {
if (typeof gameMode !== 'string' || !Object.values(gameModes).includes(gameMode)) {
let result = {error: 'Requested gameMode does not correlate to a possible gameMode.'}
if (reject) reject(result)
else resolve(result)
return
}
} else {
gameMode = gameModes[gameMode]
}
if (!mapGroups.hasOwnProperty(mapGroup)) {
if (typeof mapGroup !== 'string' || !Object.values(mapGroups).includes(mapGroup)) {
let result = {error: 'Requested mapGroup does not correlate to a possible mapGroup.'}
if (reject) reject(result)
else resolve(result)
return
}
} else {
mapGroup = mapGroups[mapGroup]
}
request('ICSGOServers_730/GetGameMapsPlaytime/v1', {key: _key, interval, gamemode: gameMode, mapgroup: mapGroup}, result => {
if (result.error) {
if (reject) reject(result)
else resolve(result)
return
}
if (typeof result.data === 'object' && result.data.hasOwnProperty('result')){
let response = result.data.result
let data = {start: 0, maps: {}, raw:[]}
// So here's the deal, the way Valve has created this API is super self-describing.
// Sounds good, right? Actually this is a major problem... let me explain.
// Because the format is essentially a 'build-your-own-table' puzzle, I can't rely
// on the keys to never change, let alone the order of the results. But, I also
// don't want to sacrifice ease-of-use by requiring callers to do the same nonsense.
// As such, I'm combining the two. I will create a custom object structure that
// callers can use, but still include the raw 'key-row' results in case they change
// stuff around and my structure no longer works. Thanks, Volvo.
// Build custom object first
try {
data.start = response.Rows[0][0] // use first interval; they're all the same anyway
for (index in response.Rows) {
let r = response.Rows[index]
data.maps[r[1]] = (r[2] / 100) // convert to actual percentage
}
} catch (e) {
// This will likely result in crashes on the caller's end if they don't already
// have checks in place. The least I can do is to inform them before the whole
// app crashes. If they do have checks and fallbacks, good!
//throw new Error('API structure has changed. This is critical. Please inform the library developer of \'steam-js-api\'.', { cause: e })
console.log('API structure has changed. This is critical. Please inform the library developer. If there are any more errors besides this in the console, the app developer should implement fixes immediately.')
}
// Build raw data
for (a in response.Rows) {
let r = response.Rows[a]
data.raw[a] = {}
for (b in r) {
data.raw[a][response.Keys[b]] = r[b]
}
}
resolve({data})
} else {
result.error = 'Unexpected response. Data may have still been returned.'
if (reject) reject(result)
else resolve(result)
}
})
}
if (typeof callback === 'function') {
run(callback)
} else {
return new Promise((resolve, reject) => {
run(resolve, reject)
})
}
}
// Steam only refreshes this about every minute. Therefore, you should probably wait at least a minute
// between calls to this function. If the time hasn't changed yet, then you should call every few
// seconds until it does, then go back to waiting a minute.
function getServerStatus(callback) {
function run(resolve, reject) {
let _key = requireKey()
request('ICSGOServers_730/GetGameServersStatus/v1', {key: _key}, result => {
if (result.error) {
if (reject) reject(result)
else resolve(result)
return
}
if (typeof result.data === 'object' && result.data.hasOwnProperty('result')){
let response = result.data.result
let data = {
version: response.app.version,
timestamp: response.app.timestamp,
time: response.app.time,
logon: response.services.SessionsLogon,
inventory: response.services.SteamCommunity,
perfectWorld: {
logon: response.perfectworld.logon.availability,
logonLatency: response.perfectworld.logon.latency,
purchase: response.perfectworld.purchase.availability,
purchaseLatency: response.perfectworld.purchase.latency
},
matchmaking: {
status: response.matchmaking.scheduler,
players: response.matchmaking.online_players,
servers: response.matchmaking.online_servers,
searching: response.matchmaking.searching_players,
searchTime: response.matchmaking.search_seconds_avg
},
servers: response.datacenters
}
resolve({data})
} else {
result.error = 'Unexpected response. Data may have still been returned.'
if (reject) reject(result)
else resolve(result)
}
})
}
if (typeof callback === 'function') {
run(callback)
} else {
return new Promise((resolve, reject) => {
run(resolve, reject)
})
}
}
const lib = {}
// Add primary functions
lib.getMapPlaytime = getMapPlaytime
lib.getServerStatus = getServerStatus
// Add shortcut functions
const Sus = require('./SteamUserStats.js')
lib.getGlobalAchievements = callback => {return Sus.getGlobalAchievements(730, callback)}
lib.getCurrentPlayers = callback => {return Sus.getCurrentPlayers(730, callback)}
lib.getAchievements = (steamID, callback) => {return SUS.getAchievements(steamID, 730, callback)}
lib.getGameSchema = callback => {return Sus.getGameSchema(730, callback)}
lib.getStats = (steamID, callback) => {return SUS.getStats(steamID, 730, callback)}
const Se = require('./SteamEconomy.js')
lib.getItemInfo = (items, callback) => {return Se.getItemInfo(730, items, callback)}
lib.getGameItemPrices = (currencyFilter, callback) => {return Se.getGameItemPrices(730, currencyFilter, callback)}
module.exports = lib