Browse Source

first commit

master
gsd 2 years ago
commit
f42fecb137
  1. 3
      .gitignore
  2. 11
      Dockerfile
  3. 56
      backend_integration.js
  4. 5
      docker-compose.yaml
  5. 11
      package.json
  6. 62
      trade_checker.js
  7. 131
      tradebot.js
  8. 1
      version.js

3
.gitignore

@ -0,0 +1,3 @@
/auth_data/
/package-lock.json
/Facti13.SteamTradeBot.JS.v1.iml

11
Dockerfile

@ -0,0 +1,11 @@
FROM node:18.18-bullseye
RUN git clone https://git.pblr-nyk.pro/gsd/Facti13.SteamTradeBot.JS.v1 && \
mv Facti13.SteamTradeBot.JS.v1 /app && chown node:node -R /app && chmod 770 -R /app && \
echo "const VERSION = $(date +%s);module.exports = VERSION;" > /app/version.js
USER node
WORKDIR /app
RUN npm install
CMD ["nodejs", "tradebot.js"]

56
backend_integration.js

@ -0,0 +1,56 @@
const axios = require("axios");
class BackendIntegration {
url = "";
secret_key = "";
up = false;
prices = {};
constructor() {
this.url = process.env.BACKEND_URL;
this.secret_key = process.env.SECRET_KEY;
}
async pulse() {
console.log("request pulse");
return await axios.get(`${this.url}/api/pulse/db`, {headers:{Cookie:`secretkey=${this.secret_key};`}}).then(
response => {
this.up = response.status === 200;
}
).catch((e)=>{console.log("pulse failed!")})
}
getPrices(tc) {
axios.get(`${this.url}/api/external/vip`, {headers:{Cookie:`secretkey=${this.secret_key};`}}).then(
response => {
if (response.status === 200) {
tc.setPrices(response.data);
} else {console.log("cannot get prices"); process.exit(200)}
}
).catch(()=>{this.prices = {}; console.log("set prices to null");});
}
vip(steam64, amount, extra, uniq) {
axios.post(`${this.url}/api/external/vip?steam=${steam64}&amount=${amount}&service=steam&extra=${extra}&unique=${uniq}`, {}, {headers:{Cookie:`secretkey=${this.secret_key};`}}).then(
response => {
if (response.status === 200) {
if (response.data === 0) {
console.log(`[S64:${steam64}] VIP as not be added, maybe permition already exists`)
return 99;
} else if (response.data > 0) {
console.log(`[S64:${steam64}] VIP has be added!`);
return 100;
} else if (response.data < 0) {
console.log(`[S64:${steam64}] VIP has be extends!`);
return 101;
}
} else {
console.log(`[S64:${steam64}] Cannot add VIP`);
}
}
).catch((e)=>{console.log("cannot add vip"); console.log(e)});
}
}
module.exports = BackendIntegration;

5
docker-compose.yaml

@ -0,0 +1,5 @@
services:
facti13_steambot_js:
build: ./
container_name: facti13_steambot_js
restart: always

11
package.json

@ -0,0 +1,11 @@
{
"name": "Facti13.SteamTradeBot.JS.v1",
"version": "1.0.0",
"dependencies": {
"axios": "^1.6.0",
"steam-totp": "^2.1.2",
"steam-tradeoffer-manager": "^2.10.6",
"steam-user": "^5.0.4",
"steamcommunity": "^3.47.1"
}
}

62
trade_checker.js

@ -0,0 +1,62 @@
class TradeChecker {
APP_ID = 440;
MONTH = 2678400;
WEEK = 604800;
DAY = 86400;
prices_map = {}
constructor() {
}
setPrices(prices) {
for (const pos in prices) {
if (prices[pos]["money_price"] === 0){
continue
}
this.prices_map[prices[pos]['period']] = parseInt(prices[pos]["item_price"].split()[0])
}
if (this.prices_map.length === 0) {
console.log("cannot parse prices");
}
}
mannco_key(items) {
const class_id = 101785959;
const instance_id = 11040578;
let count = 0;
for (const item_id in items) {
if (items[item_id].appid === this.APP_ID && parseInt(items[item_id].classid) === class_id && parseInt(items[item_id].instanceid) === instance_id) count++;
}
return count;
}
pure_metal(items) {
const class_id = 2674;
const instance_id = 11040547;
let count = 0;
for (const item_id in items) {
if (items[item_id].appid === this.APP_ID && parseInt(items[item_id].classid) === class_id && parseInt(items[item_id].instanceid) === instance_id) count++;
}
return count;
}
Items2Seconds(items) {
const key_count = this.mannco_key(items);
const metal_count = this.pure_metal(items);
let final_amount = 0;
if(key_count >= this.prices_map["month"])
final_amount += key_count * this.MONTH
if(metal_count >= this.prices_map["week"])
final_amount += (metal_count / self.prices_map["week"]) * this.WEEK;
else if(metal_count >= this.prices_map["day"])
final_amount += (metal_count / this.prices_map["day"]) * this.DAY;
return final_amount;
}
}
module.exports = TradeChecker;

131
tradebot.js

@ -0,0 +1,131 @@
'use strict';
////////////////////////////////////////////////////////////////
var backend_integration = require("./backend_integration")
var trade_checker_imp = require("./trade_checker")
var backend = new backend_integration();
var trade_checker = new trade_checker_imp();
const VERSION = require("./version");
console.log(`Build date: ${VERSION}`);
async function sync(timeout) {
let sleep = function sleep (howLong) {
return new Promise(function (resolve) {
setTimeout(() => {resolve()}, howLong)
})
}
while (true) {
try {
await backend.pulse().then(() => {
if (backend.up) {
backend.getPrices(trade_checker);
}
});
} catch (e) {
console.log(e);
} finally {
if (!backend.up) {console.log(`wait ${timeout} seconds after destroy, where pulse failed`)}
await sleep(timeout * 1000);
if (!backend.up) {process.exit(228);}
}
}
}
sync(60);
/////////////////////////////////////////////////////////////////
var SteamUser = require('steam-user');
var SteamCommunity = require('steamcommunity');
var SteamTradeOfferManager = require('steam-tradeoffer-manager');
var SteamTOTP = require('steam-totp');
/////////////////////////////////////////////////////////////////
var client = new SteamUser();
var community = new SteamCommunity();
var manager = new SteamTradeOfferManager({
steam: client,
language: 'en'
});
console.log('connecting to steam account...');
const config = require("./auth_data/auth.json")
client.logOn({
accountName: config.login,
password: config.password,
twoFactorCode: SteamTOTP.getAuthCode(config.shared_secret)
});
/////////////////////////////////////////////////////////////////
client.on('loggedOn', function(details, parental) {
console.log('SteamID64 :', client.steamID.getSteamID64());
client.setPersona(SteamUser.EPersonaState.Online);
});
client.on('webSession', function(sessionID, cookies) {
manager.setCookies(cookies, function(err) {
if (err) {
console.log(err);
process.exit(1); // Fatal error since we couldn't get our API key
return;
}
console.log("Got API key: " + manager.apiKey);
});
community.setCookies(cookies);
});
client.on('error', function(error) {
console.log('connection error\n');
console.log(error);
});
////////////////////////////////////////////////////////////////////
function calculate(offer) {
if (offer.state !== SteamTradeOfferManager.ETradeOfferState.Active) {
console.log(`[${offer.id}] trade have not active stats`)
return false;
}
if (offer.itemsToGive.length>0) {
console.log(`[${offer.id}] partner wanna get bot items, decine trade`);
return false;
}
if (offer.itemsToReceive.length>50) {
console.log(`[${offer.id}] cannot accept trade with more 50 items`)
return false;
}
const seconds = trade_checker.Items2Seconds(offer.itemsToReceive);
if (seconds === 0) {
console.log(`[${offer.id}] cannot accept trade not valid items`)
return false;
}
return seconds > 0;
}
manager.on('newOffer', function(offer) {
console.log(`[${offer.id}] Incoming trade from ${offer.partner.getSteamID64()}`);
if (calculate(offer)) {
console.log(`[${offer.id}] Try accept trade`);
offer.accept(false, function(error, status) {});
} else {
console.log(`[${offer.id}] Try decline trade`);
offer.decline(function(error, status) {})
}
})
manager.on('receivedOfferChanged', function(offer, oldState) {
console.log(`[${offer.id}] changed: ${SteamTradeOfferManager.ETradeOfferState[oldState]} -> ${SteamTradeOfferManager.ETradeOfferState[offer.state]}`);
if (offer.state === SteamTradeOfferManager.ETradeOfferState.Accepted) {
offer.getExchangeDetails((err, status, tradeInitTime, receivedItems, sentItems) => {
const seconds = trade_checker.Items2Seconds(receivedItems);
if (seconds > 0) {
const extra = `keys=${trade_checker.mannco_key(receivedItems)};metal=${trade_checker.pure_metal(receivedItems)};`;
backend.vip(offer.partner.getSteamID64(), seconds, extra, offer.id);
} else {
console.log(`[${offer.id}] Trade accepted, but vip not gived!`);
}
})
}
});

1
version.js

@ -0,0 +1 @@
const VERSION = 0;module.exports = VERSION;
Loading…
Cancel
Save