Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@

grpcio
grpcio-tools<2.0.0
protobuf==5.28.3
protobuf==5.29.0
7 changes: 7 additions & 0 deletions test2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from xtlsapi import XrayClient


xray = XrayClient("127.0.0.1", 53357)


print(xray.stats_online_ip_list("1"))
9 changes: 9 additions & 0 deletions tests/test_stats_online_ip_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import pytest
from unittest.mock import patch
from xtlsapi import XrayClient

def test_stats_online_ip_list():
xray = XrayClient("127.0.0.1", 53357)
with patch.object(xray, 'stats_online_ip_list', return_value={'212.58.119.246': 1763418412}):
result = xray.stats_online_ip_list("1")
assert result == {'212.58.119.246': 1763418412}
4 changes: 3 additions & 1 deletion xtlsapi/api_services/stats/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .get_total_download_traffic import GetTotalDownloadTraffic
from .get_statsquery import StatsQuery
from .get_statsonline import StatsOnline
from .get_stats_online_ip_list import StatsOnlineIpList

class StatsAPIService(
GetClientUploadTraffic,
Expand All @@ -15,6 +16,7 @@ class StatsAPIService(
GetTotalUploadTraffic,
GetTotalDownloadTraffic,
StatsQuery,
StatsOnline
StatsOnline,
StatsOnlineIpList
):
pass
28 changes: 28 additions & 0 deletions xtlsapi/api_services/stats/get_stats_online_ip_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import grpc
from xtlsapi.xray_api.app.stats.command import command_pb2

from .._base import BaseService


class StatsOnlineIpList(BaseService):
def stats_online_ip_list(self, user, reset=False) -> dict:
"""
Returns a dictionary of online IPs for the given user.

Args:
user: The email of the user to query.

Returns:
A dictionary mapping IP addresses to last cleanup time of expired ip's.
"""

try:
return self.stats_stub.GetStatsOnlineIpList(
command_pb2.GetStatsRequest(
name=f"user>>>{user}>>>online",
reset=reset
)
).ips
except grpc.RpcError:
raise
return None
62 changes: 62 additions & 0 deletions xtlsapi/xray_api/app/stats/command/command.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
syntax = "proto3";

package xray.app.stats.command;
option csharp_namespace = "Xray.App.Stats.Command";
option go_package = "github.com/xtls/xray-core/app/stats/command";
option java_package = "com.xray.app.stats.command";
option java_multiple_files = true;

message GetStatsRequest {
// Name of the stat counter.
string name = 1;
// Whether or not to reset the counter to fetching its value.
bool reset = 2;
}

message Stat {
string name = 1;
int64 value = 2;
}

message GetStatsResponse {
Stat stat = 1;
}

message QueryStatsRequest {
string pattern = 1;
bool reset = 2;
}

message QueryStatsResponse {
repeated Stat stat = 1;
}

message SysStatsRequest {}

message SysStatsResponse {
uint32 NumGoroutine = 1;
uint32 NumGC = 2;
uint64 Alloc = 3;
uint64 TotalAlloc = 4;
uint64 Sys = 5;
uint64 Mallocs = 6;
uint64 Frees = 7;
uint64 LiveObjects = 8;
uint64 PauseTotalNs = 9;
uint32 Uptime = 10;
}

message GetStatsOnlineIpListResponse {
string name = 1;
map<string, int64> ips = 2;
}

service StatsService {
rpc GetStats(GetStatsRequest) returns (GetStatsResponse) {}
rpc GetStatsOnline(GetStatsRequest) returns (GetStatsResponse) {}
rpc QueryStats(QueryStatsRequest) returns (QueryStatsResponse) {}
rpc GetSysStats(SysStatsRequest) returns (SysStatsResponse) {}
rpc GetStatsOnlineIpList(GetStatsRequest) returns (GetStatsOnlineIpListResponse) {}
}

message Config {}
56 changes: 31 additions & 25 deletions xtlsapi/xray_api/app/stats/command/command_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

97 changes: 70 additions & 27 deletions xtlsapi/xray_api/app/stats/command/command_pb2_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import grpc
import warnings

from xtlsapi.xray_api.app.stats.command import command_pb2 as app_dot_stats_dot_command_dot_command__pb2
from . import command_pb2 as command__pb2

GRPC_GENERATED_VERSION = '1.67.1'
GRPC_GENERATED_VERSION = '1.71.2'
GRPC_VERSION = grpc.__version__
_version_not_supported = False

Expand All @@ -18,7 +18,7 @@
if _version_not_supported:
raise RuntimeError(
f'The grpc package installed is at version {GRPC_VERSION},'
+ f' but the generated code in app/stats/command/command_pb2_grpc.py depends on'
+ f' but the generated code in command_pb2_grpc.py depends on'
+ f' grpcio>={GRPC_GENERATED_VERSION}.'
+ f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
+ f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
Expand All @@ -36,23 +36,28 @@ def __init__(self, channel):
"""
self.GetStats = channel.unary_unary(
'/xray.app.stats.command.StatsService/GetStats',
request_serializer=app_dot_stats_dot_command_dot_command__pb2.GetStatsRequest.SerializeToString,
response_deserializer=app_dot_stats_dot_command_dot_command__pb2.GetStatsResponse.FromString,
request_serializer=command__pb2.GetStatsRequest.SerializeToString,
response_deserializer=command__pb2.GetStatsResponse.FromString,
_registered_method=True)
self.GetStatsOnline = channel.unary_unary(
'/xray.app.stats.command.StatsService/GetStatsOnline',
request_serializer=app_dot_stats_dot_command_dot_command__pb2.GetStatsRequest.SerializeToString,
response_deserializer=app_dot_stats_dot_command_dot_command__pb2.GetStatsResponse.FromString,
request_serializer=command__pb2.GetStatsRequest.SerializeToString,
response_deserializer=command__pb2.GetStatsResponse.FromString,
_registered_method=True)
self.QueryStats = channel.unary_unary(
'/xray.app.stats.command.StatsService/QueryStats',
request_serializer=app_dot_stats_dot_command_dot_command__pb2.QueryStatsRequest.SerializeToString,
response_deserializer=app_dot_stats_dot_command_dot_command__pb2.QueryStatsResponse.FromString,
request_serializer=command__pb2.QueryStatsRequest.SerializeToString,
response_deserializer=command__pb2.QueryStatsResponse.FromString,
_registered_method=True)
self.GetSysStats = channel.unary_unary(
'/xray.app.stats.command.StatsService/GetSysStats',
request_serializer=app_dot_stats_dot_command_dot_command__pb2.SysStatsRequest.SerializeToString,
response_deserializer=app_dot_stats_dot_command_dot_command__pb2.SysStatsResponse.FromString,
request_serializer=command__pb2.SysStatsRequest.SerializeToString,
response_deserializer=command__pb2.SysStatsResponse.FromString,
_registered_method=True)
self.GetStatsOnlineIpList = channel.unary_unary(
'/xray.app.stats.command.StatsService/GetStatsOnlineIpList',
request_serializer=command__pb2.GetStatsRequest.SerializeToString,
response_deserializer=command__pb2.GetStatsOnlineIpListResponse.FromString,
_registered_method=True)


Expand Down Expand Up @@ -83,28 +88,39 @@ def GetSysStats(self, request, context):
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')

def GetStatsOnlineIpList(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')


def add_StatsServiceServicer_to_server(servicer, server):
rpc_method_handlers = {
'GetStats': grpc.unary_unary_rpc_method_handler(
servicer.GetStats,
request_deserializer=app_dot_stats_dot_command_dot_command__pb2.GetStatsRequest.FromString,
response_serializer=app_dot_stats_dot_command_dot_command__pb2.GetStatsResponse.SerializeToString,
request_deserializer=command__pb2.GetStatsRequest.FromString,
response_serializer=command__pb2.GetStatsResponse.SerializeToString,
),
'GetStatsOnline': grpc.unary_unary_rpc_method_handler(
servicer.GetStatsOnline,
request_deserializer=app_dot_stats_dot_command_dot_command__pb2.GetStatsRequest.FromString,
response_serializer=app_dot_stats_dot_command_dot_command__pb2.GetStatsResponse.SerializeToString,
request_deserializer=command__pb2.GetStatsRequest.FromString,
response_serializer=command__pb2.GetStatsResponse.SerializeToString,
),
'QueryStats': grpc.unary_unary_rpc_method_handler(
servicer.QueryStats,
request_deserializer=app_dot_stats_dot_command_dot_command__pb2.QueryStatsRequest.FromString,
response_serializer=app_dot_stats_dot_command_dot_command__pb2.QueryStatsResponse.SerializeToString,
request_deserializer=command__pb2.QueryStatsRequest.FromString,
response_serializer=command__pb2.QueryStatsResponse.SerializeToString,
),
'GetSysStats': grpc.unary_unary_rpc_method_handler(
servicer.GetSysStats,
request_deserializer=app_dot_stats_dot_command_dot_command__pb2.SysStatsRequest.FromString,
response_serializer=app_dot_stats_dot_command_dot_command__pb2.SysStatsResponse.SerializeToString,
request_deserializer=command__pb2.SysStatsRequest.FromString,
response_serializer=command__pb2.SysStatsResponse.SerializeToString,
),
'GetStatsOnlineIpList': grpc.unary_unary_rpc_method_handler(
servicer.GetStatsOnlineIpList,
request_deserializer=command__pb2.GetStatsRequest.FromString,
response_serializer=command__pb2.GetStatsOnlineIpListResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
Expand Down Expand Up @@ -132,8 +148,8 @@ def GetStats(request,
request,
target,
'/xray.app.stats.command.StatsService/GetStats',
app_dot_stats_dot_command_dot_command__pb2.GetStatsRequest.SerializeToString,
app_dot_stats_dot_command_dot_command__pb2.GetStatsResponse.FromString,
command__pb2.GetStatsRequest.SerializeToString,
command__pb2.GetStatsResponse.FromString,
options,
channel_credentials,
insecure,
Expand All @@ -159,8 +175,8 @@ def GetStatsOnline(request,
request,
target,
'/xray.app.stats.command.StatsService/GetStatsOnline',
app_dot_stats_dot_command_dot_command__pb2.GetStatsRequest.SerializeToString,
app_dot_stats_dot_command_dot_command__pb2.GetStatsResponse.FromString,
command__pb2.GetStatsRequest.SerializeToString,
command__pb2.GetStatsResponse.FromString,
options,
channel_credentials,
insecure,
Expand All @@ -186,8 +202,8 @@ def QueryStats(request,
request,
target,
'/xray.app.stats.command.StatsService/QueryStats',
app_dot_stats_dot_command_dot_command__pb2.QueryStatsRequest.SerializeToString,
app_dot_stats_dot_command_dot_command__pb2.QueryStatsResponse.FromString,
command__pb2.QueryStatsRequest.SerializeToString,
command__pb2.QueryStatsResponse.FromString,
options,
channel_credentials,
insecure,
Expand All @@ -213,8 +229,35 @@ def GetSysStats(request,
request,
target,
'/xray.app.stats.command.StatsService/GetSysStats',
app_dot_stats_dot_command_dot_command__pb2.SysStatsRequest.SerializeToString,
app_dot_stats_dot_command_dot_command__pb2.SysStatsResponse.FromString,
command__pb2.SysStatsRequest.SerializeToString,
command__pb2.SysStatsResponse.FromString,
options,
channel_credentials,
insecure,
call_credentials,
compression,
wait_for_ready,
timeout,
metadata,
_registered_method=True)

@staticmethod
def GetStatsOnlineIpList(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(
request,
target,
'/xray.app.stats.command.StatsService/GetStatsOnlineIpList',
command__pb2.GetStatsRequest.SerializeToString,
command__pb2.GetStatsOnlineIpListResponse.FromString,
options,
channel_credentials,
insecure,
Expand Down