This commit is contained in:
Oskar Eichler 2026-08-30 08:01:41 +00:00 • committed by GitHub
commit b2858e59ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 38 additions and 7 deletions

View file

@ -208,7 +208,8 @@ paths:
type: object
properties:
accessKeyId:
type: integer
description: Exact access key ID.
type: string
tunnelTime:
type: object
properties:

View file

@ -194,7 +194,7 @@ describe('PrometheusManagerMetrics', () => {
},
"accessKeys": [
{
"accessKeyId": 0,
"accessKeyId": "0",
"dataTransferred": {
"bytes": 1000
},
@ -380,7 +380,7 @@ describe('PrometheusManagerMetrics', () => {
},
"accessKeys": [
{
"accessKeyId": 1,
"accessKeyId": "1",
"dataTransferred": {
"bytes": 0
},
@ -396,7 +396,7 @@ describe('PrometheusManagerMetrics', () => {
}
},
{
"accessKeyId": 0,
"accessKeyId": "0",
"dataTransferred": {
"bytes": 1000
},
@ -427,4 +427,33 @@ describe('PrometheusManagerMetrics', () => {
expect(bytesTransferredByUserId['access-key-2']).toEqual(10000);
done();
});
it('preserves custom access key IDs in server metrics', async () => {
const accessKeyIds = ['custom-id', '001', '9007199254740993'];
const prometheusClient = {
query: async (query: string): Promise<QueryResultData> => {
if (query.includes('shadowsocks_data_bytes{')) {
return {
resultType: 'vector',
result: accessKeyIds.map((accessKey, index) => ({
metric: {access_key: accessKey},
value: [1, String(index + 1)],
})),
};
}
return {resultType: 'vector', result: []};
},
queryRange: async (query: string): Promise<QueryResultData> => {
if (query.includes('shadowsocks_data_bytes_per_location')) {
return {resultType: 'matrix', result: [{metric: {}, values: []}]};
}
return {resultType: 'matrix', result: []};
},
} as PrometheusClient;
const managerMetrics = new PrometheusManagerMetrics(prometheusClient);
const serverMetrics = await managerMetrics.getServerMetrics({seconds: 0});
expect(serverMetrics.accessKeys.map((entry) => entry.accessKeyId)).toEqual(accessKeyIds);
});
});

View file

@ -61,7 +61,7 @@ interface ServerMetricsLocationEntry {
}
interface ServerMetricsAccessKeyEntry {
accessKeyId: number;
accessKeyId: string;
tunnelTime: Duration;
dataTransferred: Data;
connection: ConnectionStats;
@ -88,7 +88,8 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
const result = await this.prometheusClient.query(
`sum(increase(shadowsocks_data_bytes{dir=~"c<p|p>t"}[${timeframe.hours}h])) by (access_key)`
);
const usage = {} as {[userId: string]: number};
// Custom IDs such as __proto__ must remain ordinary own properties.
const usage: {[userId: string]: number} = Object.create(null);
for (const entry of result.result) {
const bytes = Math.round(parseFloat(entry.value[1]));
if (bytes === 0) {
@ -297,7 +298,7 @@ function getServerMetricsAccessKeyEntry(
let entry = map.get(accessKey);
if (entry === undefined) {
entry = {
accessKeyId: parseInt(accessKey),
accessKeyId: accessKey,
dataTransferred: {bytes: 0},
tunnelTime: {seconds: 0},
connection: {