Skip to content

Commit 487e990

Browse files
committed
fix(stats): derive Xray onlineUsers from per-user traffic deltas
1 parent f2d6175 commit 487e990

1 file changed

Lines changed: 17 additions & 18 deletions

File tree

src/services/syncService.js

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,12 @@ class SyncService {
111111
agentVersion: data.agent_version || '',
112112
agentStatus: 'online',
113113
agentLastSeen: new Date(),
114-
onlineUsers: data.users_count || 0,
115114
status: 'online',
116115
healthFailures: 0,
117116
},
118117
});
119118

120-
return { online: true, xrayVersion: data.xray_version, usersCount: data.users_count };
119+
return { online: true, xrayVersion: data.xray_version };
121120
} catch (error) {
122121
logger.warn(`[Agent] ${node.name} health check failed: ${error.message}`);
123122

@@ -397,8 +396,6 @@ class SyncService {
397396
const nodeRx = nodeTraffic.rx || 0;
398397

399398
const userEntries = Object.entries(users);
400-
if (userEntries.length === 0 && nodeTx === 0 && nodeRx === 0) return;
401-
402399
const bulkOps = [];
403400
const now = new Date();
404401

@@ -425,24 +422,29 @@ class SyncService {
425422
this._checkUserLimits(userEntries.map(([email]) => email)).catch(() => {});
426423
}
427424

425+
// Online = users with non-zero traffic in the last poll interval.
426+
// Always update (even to 0) so the counter falls back after idle intervals.
427+
const activeUsers = bulkOps.length;
428+
const nodeUpdate = { $set: { onlineUsers: activeUsers } };
428429
if (nodeTx > 0 || nodeRx > 0) {
429-
await HyNode.updateOne(
430-
{ _id: node._id },
431-
{
432-
$inc: { 'traffic.tx': nodeTx, 'traffic.rx': nodeRx },
433-
$set: { 'traffic.lastUpdate': now },
434-
}
435-
);
436-
logger.info(`[Agent Stats] ${node.name}: ${bulkOps.length} users, node ↑${(nodeTx / 1024 / 1024).toFixed(1)}MB ↓${(nodeRx / 1024 / 1024).toFixed(1)}MB`);
430+
nodeUpdate.$inc = { 'traffic.tx': nodeTx, 'traffic.rx': nodeRx };
431+
nodeUpdate.$set['traffic.lastUpdate'] = now;
432+
}
433+
await HyNode.updateOne({ _id: node._id }, nodeUpdate);
434+
435+
if (nodeTx > 0 || nodeRx > 0) {
436+
logger.info(`[Agent Stats] ${node.name}: ${activeUsers} online, node ↑${(nodeTx / 1024 / 1024).toFixed(1)}MB ↓${(nodeRx / 1024 / 1024).toFixed(1)}MB`);
437437
}
438438
} catch (error) {
439439
logger.error(`[Agent Stats] ${node.name} error: ${error.message}`);
440440
}
441441
}
442442

443443
/**
444-
* Get online users and health info from Xray node via Agent GET /info.
445-
* Also updates xrayVersion and agentStatus in DB.
444+
* Health-check an Xray node via Agent GET /info and refresh metadata
445+
* (xrayVersion, agentVersion, agentStatus, status). Does NOT touch
446+
* `onlineUsers` — that counter is owned by collectXrayTrafficStats,
447+
* which derives it from per-user traffic deltas over the poll interval.
446448
*/
447449
async getXrayOnlineUsers(node) {
448450
if (!(node.xray?.agentToken)) {
@@ -454,13 +456,10 @@ class SyncService {
454456
const response = await this._agentRequest(node, 'GET', '/info');
455457
const data = response.data || {};
456458

457-
const usersCount = data.users_count || 0;
458-
459459
const prevNode = await HyNode.findOneAndUpdate(
460460
{ _id: node._id },
461461
{
462462
$set: {
463-
onlineUsers: usersCount,
464463
status: 'online',
465464
healthFailures: 0,
466465
xrayVersion: data.xray_version || '',
@@ -475,7 +474,7 @@ class SyncService {
475474
webhook.emit(webhook.EVENTS.NODE_ONLINE, { nodeId: node._id, name: node.name });
476475
}
477476

478-
return usersCount;
477+
return 0;
479478
} catch (error) {
480479
logger.warn(`[Agent] ${node.name}: unavailable - ${error.message}`);
481480

0 commit comments

Comments
 (0)