Skip to content

Commit f2be56b

Browse files
committed
improved inspector
1 parent 363a34a commit f2be56b

File tree

6 files changed

+5374
-55
lines changed

6 files changed

+5374
-55
lines changed

.env.example

-2
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,3 @@ DATABASE_MIN_CONNECTIONS=1
1111
DATABASE_MAX_CONNECTIONS=10
1212

1313
STEAM_API_KEY=
14-
15-
INSPECT_TIMEOUT_MS=3000

config/default.js

-4
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,4 @@ module.exports = {
2424
steam: {
2525
apiKey: env.STEAM_API_KEY,
2626
},
27-
28-
inspect: {
29-
timeoutMs: env.INSPECT_TIMEOUT_MS || 3000,
30-
},
3127
};

controllers/testLinkController.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ exports.store = async (req, res) => {
1616
let inspection;
1717

1818
try {
19-
inspection = await Inspector.inspect(link, config.get('inspect.timeoutMs'));
19+
inspection = await Inspector.inspect(link);
2020

2121
logger.info('Inspected link', inspection);
2222
} catch (error) {

modules/Inspector.js

+56-36
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ const SteamAccount = require('../database/models/SteamAccount');
88

99
class Inspector {
1010
constructor() {
11+
// The time in milliseconds between two inspection attempts.
12+
this.inspectionInterval = 1100;
13+
// The time in milliseconds after which an inspection is considered a failure.
14+
this.inspectionTimeout = 3000;
15+
// The time in milliseconds between two select attempts.
16+
this.selectInterval = 100;
17+
// The time in milliseconds after which selecting a non-busy bot is considered a failure.
18+
this.selectTimeout = 5000;
19+
1120
this.clients = [];
1221

1322
SteamAccount.query().then((steamAccounts) => {
@@ -21,14 +30,28 @@ class Inspector {
2130
});
2231

2332
setInterval(() => {
33+
const gracePeriod = this.inspectionTimeout + 1000;
34+
2435
for (let i = 0; i < this.clients.length; i += 1) {
25-
// Mark clients as not busy if they have been busy for more than 10 seconds.
26-
if (this.clients[i].busySince && Date.now() > (this.clients[i].busySince + 10000)) {
27-
this.clients[i].busySince = null;
28-
logger.info(`Marked client ${i} as not busy after 10 second timeout`);
36+
// Mark clients as not busy if they have been busy for too long.
37+
if (this.clients[i].busy && Date.now() > (this.clients[i].startedAt + gracePeriod)) {
38+
this.clients[i].busy = false;
39+
logger.info(`Marked client ${i} as not busy after ${gracePeriod} ms timeout`);
2940
}
3041
}
3142
}, 1000);
43+
44+
setInterval(() => {
45+
logger.info('Inspector bot status', {
46+
total: this.clients.length,
47+
connectedToSteam: this.clients.filter((client) => !!client.client.steamID).length,
48+
connectedToCsgo: this.clients.filter((client) => client.csgo.haveGCSession).length,
49+
busy: this.clients.filter((client) => client.busy === true).length,
50+
busyCooldown: this.clients.filter(
51+
(client) => client.startedAt + this.inspectionInterval >= Date.now(),
52+
).length,
53+
});
54+
}, 10000);
3255
}
3356

3457
addClient(username, password, sharedSecret) {
@@ -47,7 +70,7 @@ class Inspector {
4770
});
4871

4972
client.on('loggedOn', () => {
50-
logger.info(`Logged into Steam as ${client.steamID.getSteam3RenderedID()}`);
73+
logger.info(`Logged into Steam as ${client.steamID.getSteamID64()}`);
5174
client.setPersona(SteamUser.EPersonaState.Online);
5275
client.gamesPlayed(730, true);
5376
});
@@ -59,7 +82,7 @@ class Inspector {
5982
if (!client.ownsApp(730)) {
6083
client.requestFreeLicense(730, (err) => {
6184
if (err) {
62-
logger.warn('Failed to acquire lisence for CS:GO');
85+
logger.warning('Failed to acquire license for CS:GO');
6386
logger.error(err);
6487
} else {
6588
logger.info('Successfully acquired license for CS:GO');
@@ -77,7 +100,7 @@ class Inspector {
77100

78101
client.on('disconnected', (eresult, msg) => {
79102
// We got disconnected from Steam.
80-
logger.warn('Disconnected from Steam', {
103+
logger.warning('Disconnected from Steam', {
81104
eresult,
82105
msg,
83106
});
@@ -93,43 +116,33 @@ class Inspector {
93116
});
94117

95118
csgo.on('disconnectedFromGC', (reason) => {
96-
logger.warn('Disconnected from CS:GO game coordinator', { reason });
119+
logger.warning('Disconnected from CS:GO game coordinator', { reason });
97120
});
98121

99122
csgo.on('inspectItemTimedOut', (assetid) => {
100-
logger.warn(`Inspect timed out for assetid ${assetid}`);
123+
logger.warning(`Inspect timed out for assetid ${assetid}`);
101124
});
102125

103126
this.clients.push({
104127
client,
105128
csgo,
106-
busySince: null,
129+
startedAt: 0,
130+
busy: false,
107131
});
108132
}
109133

110-
inspect(url, timeoutMs = 3000) {
134+
inspect(url) {
111135
return new Promise((resolve, reject) => {
112-
// We'll want a timeout of at least 1500 ms.
113-
if (timeoutMs < 1500) {
114-
throw new Error('The specified timeout must be at least 1500 ms');
115-
}
116-
117-
// Make sure that the promise is rejected after the timeout.
118-
setTimeout(() => {
119-
reject(new Error(`Inspection timed out after ${timeoutMs} ms`));
120-
}, timeoutMs);
121-
122-
// Set the retry interval and the number of retries.
123-
// We subtract 1000 ms from the `timeoutMs` because we'll need some time
124-
// for the inspection too.
125-
const retryInterval = 100;
126-
const retryTimes = Math.round((timeoutMs - 1000 / retryInterval));
136+
// Set the number of retries.
137+
const retryTimes = Math.round(this.selectTimeout / this.selectInterval);
127138

128139
// Find an index of a client that is currently not busy and has a GC connection.
129140
async
130-
.retry({ times: retryTimes, interval: retryInterval }, async () => {
141+
.retry({ times: retryTimes, interval: this.selectInterval }, async () => {
131142
const index = this.clients.findIndex(
132-
(client) => client.busySince === null && client.csgo.haveGCSession,
143+
(client) => client.busy === false
144+
&& client.startedAt + this.inspectionInterval < Date.now()
145+
&& client.csgo.haveGCSession,
133146
);
134147

135148
if (index === -1) {
@@ -138,20 +151,27 @@ class Inspector {
138151
);
139152
}
140153

141-
return index;
142-
})
143-
.then((index) => {
144154
// Mark the client as busy so that it won't be used for other inspections.
145-
// If the inspection succeeds, `busySince` will be cleared immediately.
146-
// If the inspection times out, `busySince` will be cleared after within
155+
// If the inspection succeeds, `busy` will be cleared immediately.
156+
// If the inspection times out, `busy` will be cleared after within
147157
// 1 second after the timeout.
148-
this.clients[index].busySince = Date.now();
158+
this.clients[index].busy = true;
159+
this.clients[index].startedAt = Date.now();
149160

161+
return index;
162+
})
163+
.then((index) => {
150164
this.clients[index].csgo.inspectItem(url, (item) => {
151-
this.clients[index].busySince = null;
165+
this.clients[index].busy = false;
152166
resolve(item);
153167
});
154-
});
168+
169+
// Make sure that the promise is rejected after the timeout.
170+
setTimeout(() => {
171+
reject(new Error(`Inspection timed out after ${this.inspectionTimeout} ms`));
172+
}, this.inspectionTimeout);
173+
})
174+
.catch((error) => reject(error));
155175
});
156176
}
157177
}

0 commit comments

Comments
 (0)