This commit is contained in:
jimleerx
2026-01-28 13:13:58 +08:00
commit e605cd07bf
21 changed files with 5320 additions and 0 deletions

41
internal/xrpc/client.go Normal file
View File

@@ -0,0 +1,41 @@
package xrpc
import (
"context"
"fmt"
loggerpb "github.com/xtls/xray-core/app/log/command"
handlerpb "github.com/xtls/xray-core/app/proxyman/command"
statspb "github.com/xtls/xray-core/app/stats/command"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
// Clients groups the gRPC stubs that the samples rely on.
type Clients struct {
Connection *grpc.ClientConn
Handler handlerpb.HandlerServiceClient
Logger loggerpb.LoggerServiceClient
Stats statspb.StatsServiceClient
}
// New establishes an insecure (plaintext) connection against a running Xray API endpoint.
func New(ctx context.Context, addr string, port uint16, dialOpts ...grpc.DialOption) (*Clients, error) {
target := fmt.Sprintf("%s:%d", addr, port)
opts := []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
}
opts = append(opts, dialOpts...)
conn, err := grpc.DialContext(ctx, target, opts...)
if err != nil {
return nil, err
}
return &Clients{
Connection: conn,
Handler: handlerpb.NewHandlerServiceClient(conn),
Logger: loggerpb.NewLoggerServiceClient(conn),
Stats: statspb.NewStatsServiceClient(conn),
}, nil
}

View File

@@ -0,0 +1,76 @@
package handler
import (
"github.com/xtls/xray-core/app/proxyman"
cnet "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/transport/internet"
)
func receiverSettings(port uint32, enableSniff bool) *serial.TypedMessage {
pr := cnet.SinglePortRange(cnet.Port(port))
rc := &proxyman.ReceiverConfig{
PortList: &cnet.PortList{Range: []*cnet.PortRange{pr}},
Listen: cnet.NewIPOrDomain(cnet.AnyIP),
StreamSettings: &internet.StreamConfig{
ProtocolName: "tcp",
},
}
if enableSniff {
rc.SniffingSettings = &proxyman.SniffingConfig{
Enabled: true,
DestinationOverride: []string{"http", "tls"},
}
}
return serial.ToTypedMessage(rc)
}
func senderSettings() *serial.TypedMessage {
return serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
ProtocolName: "tcp",
},
MultiplexSettings: &proxyman.MultiplexingConfig{
Enabled: true,
Concurrency: 8,
XudpProxyUDP443: "reject",
},
TargetStrategy: internet.DomainStrategy_USE_IP,
})
}
func endpoint(address string, port uint32, user *protocol.User) *protocol.ServerEndpoint {
return &protocol.ServerEndpoint{
Address: cnet.NewIPOrDomain(cnet.ParseAddress(address)),
Port: port,
User: user,
}
}
func randomUUID() string {
u := uuid.New()
return (&u).String()
}
func cnetOrDomain(value string) *cnet.IPOrDomain {
return cnet.NewIPOrDomain(cnet.ParseAddress(value))
}
func inboundConfig(tag string, receiver *serial.TypedMessage, proxy *serial.TypedMessage) *core.InboundHandlerConfig {
return &core.InboundHandlerConfig{
Tag: tag,
ReceiverSettings: receiver,
ProxySettings: proxy,
}
}
func outboundConfig(tag string, sender *serial.TypedMessage, proxy *serial.TypedMessage) *core.OutboundHandlerConfig {
return &core.OutboundHandlerConfig{
Tag: tag,
SenderSettings: sender,
ProxySettings: proxy,
}
}

View File

@@ -0,0 +1,274 @@
package handler
import (
"context"
"github.com/xtls/xray-core/app/proxyman/command"
cnet "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/proxy/dns"
"github.com/xtls/xray-core/proxy/dokodemo"
"github.com/xtls/xray-core/proxy/http"
"github.com/xtls/xray-core/proxy/loopback"
"github.com/xtls/xray-core/proxy/shadowsocks"
ss2022 "github.com/xtls/xray-core/proxy/shadowsocks_2022"
"github.com/xtls/xray-core/proxy/socks"
"github.com/xtls/xray-core/proxy/trojan"
"github.com/xtls/xray-core/proxy/vless"
vlessin "github.com/xtls/xray-core/proxy/vless/inbound"
"github.com/xtls/xray-core/proxy/vmess"
vmessin "github.com/xtls/xray-core/proxy/vmess/inbound"
"github.com/xtls/xray-core/proxy/wireguard"
)
// AddVMessInbound demonstrates HandlerServiceClient.AddInbound for VMess inbound.
func AddVMessInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
inbound := inboundConfig(
tag,
receiverSettings(port, true),
serial.ToTypedMessage(&vmessin.Config{
User: []*protocol.User{
{
Level: 0,
Email: "demo@vmess.local",
Account: serial.ToTypedMessage(&vmess.Account{
Id: randomUUID(),
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AUTO,
},
}),
},
},
Default: &vmessin.DefaultConfig{Level: 0},
}),
)
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
return err
}
// AddVLESSInbound adds a VLESS inbound with Vision style fallbacks.
func AddVLESSInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
inbound := inboundConfig(
tag,
receiverSettings(port, true),
serial.ToTypedMessage(&vlessin.Config{
Clients: []*protocol.User{
{
Level: 1,
Email: "client@vless.local",
Account: serial.ToTypedMessage(&vless.Account{
Id: randomUUID(),
Encryption: "none",
}),
},
},
Fallbacks: []*vlessin.Fallback{
{
Name: "websocket",
Alpn: "h2",
Path: "/ws",
Type: "http",
Dest: "127.0.0.1:8080",
Xver: 1,
},
},
Decryption: "none",
Padding: "enable",
}),
)
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
return err
}
// AddTrojanInbound registers a Trojan inbound with two users and ALPN fallback.
func AddTrojanInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
inbound := inboundConfig(
tag,
receiverSettings(port, true),
serial.ToTypedMessage(&trojan.ServerConfig{
Users: []*protocol.User{
{
Level: 0,
Email: "alice@trojan.local",
Account: serial.ToTypedMessage(&trojan.Account{
Password: randomUUID(),
}),
},
{
Level: 0,
Email: "bob@trojan.local",
Account: serial.ToTypedMessage(&trojan.Account{
Password: randomUUID(),
}),
},
},
Fallbacks: []*trojan.Fallback{
{
Name: "http",
Alpn: "http/1.1",
Dest: "127.0.0.1:8081",
},
},
}),
)
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
return err
}
// AddShadowsocksInbound adds an AEAD Shadowsocks inbound supporting both TCP and UDP.
func AddShadowsocksInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
inbound := inboundConfig(
tag,
receiverSettings(port, false),
serial.ToTypedMessage(&shadowsocks.ServerConfig{
Users: []*protocol.User{
{
Level: 0,
Email: "ss@demo.local",
Account: serial.ToTypedMessage(&shadowsocks.Account{
Password: "s3cret-pass",
CipherType: shadowsocks.CipherType_AES_128_GCM,
}),
},
},
}),
)
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
return err
}
// AddShadowsocks2022Inbound covers both single user and multi-user deployment.
func AddShadowsocks2022Inbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
server := &ss2022.MultiUserServerConfig{
Method: "2022-blake3-aes-128-gcm",
Key: "0123456789abcdef0123456789abcdef",
Users: []*protocol.User{
{
Level: 0,
Email: "user1@ss2022.local",
Account: serial.ToTypedMessage(&ss2022.Account{
Key: randomUUID(),
}),
},
{
Level: 0,
Email: "user2@ss2022.local",
Account: serial.ToTypedMessage(&ss2022.Account{
Key: randomUUID(),
}),
},
},
}
inbound := inboundConfig(
tag,
receiverSettings(port, false),
serial.ToTypedMessage(server),
)
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
return err
}
// AddSocksInbound exposes a SOCKS5 server with username/password authentication.
func AddSocksInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
inbound := inboundConfig(
tag,
receiverSettings(port, false),
serial.ToTypedMessage(&socks.ServerConfig{
AuthType: socks.AuthType_PASSWORD,
Accounts: map[string]string{"demo": "passw0rd"},
UdpEnabled: true,
UserLevel: 0,
}),
)
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
return err
}
// AddHTTPInbound adds an HTTP proxy inbound with basic auth.
func AddHTTPInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
inbound := inboundConfig(
tag,
receiverSettings(port, false),
serial.ToTypedMessage(&http.ServerConfig{
Accounts: map[string]string{"demo": "http-pass"},
AllowTransparent: true,
UserLevel: 0,
}),
)
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
return err
}
// AddDokodemoInbound configures a dokodemo-door mirror port.
func AddDokodemoInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32, targetPort uint32) error {
inbound := inboundConfig(
tag,
receiverSettings(port, false),
serial.ToTypedMessage(&dokodemo.Config{
Address: cnetOrDomain("example.com"),
Port: targetPort,
Networks: []cnet.Network{cnet.Network_TCP, cnet.Network_UDP},
FollowRedirect: false,
UserLevel: 0,
}),
)
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
return err
}
// AddDNSInbound exposes the built-in DNS server on an API port.
func AddDNSInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
inbound := inboundConfig(
tag,
receiverSettings(port, false),
serial.ToTypedMessage(&dns.Config{
Server: &cnet.Endpoint{
Network: cnet.Network_UDP,
Address: cnetOrDomain("1.1.1.1"),
Port: 53,
},
Non_IPQuery: "drop",
BlockTypes: []int32{65, 28},
}),
)
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
return err
}
// AddLoopbackInbound ties an inbound to an existing outbound chain.
func AddLoopbackInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32, targetInbound string) error {
inbound := inboundConfig(
tag,
receiverSettings(port, false),
serial.ToTypedMessage(&loopback.Config{InboundTag: targetInbound}),
)
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
return err
}
// AddWireGuardInbound sets up a WireGuard entry point with a single peer.
func AddWireGuardInbound(ctx context.Context, client command.HandlerServiceClient, tag string, port uint32) error {
cfg := &wireguard.DeviceConfig{
SecretKey: "yAnExampleSecretKeyBase64==",
Endpoint: []string{":51820"},
Mtu: 1420,
NumWorkers: 2,
DomainStrategy: wireguard.DeviceConfig_FORCE_IP46,
Peers: []*wireguard.PeerConfig{
{
PublicKey: "peerPublicKeyBase64==",
Endpoint: "203.0.113.1:51820",
KeepAlive: 25,
AllowedIps: []string{"0.0.0.0/0", "::/0"},
},
},
}
inbound := inboundConfig(
tag,
receiverSettings(port, false),
serial.ToTypedMessage(cfg),
)
_, err := client.AddInbound(ctx, &command.AddInboundRequest{Inbound: inbound})
return err
}

View File

@@ -0,0 +1,59 @@
package handler
import (
"context"
"github.com/xtls/xray-core/app/proxyman/command"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
)
func RemoveInbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
_, err := client.RemoveInbound(ctx, &command.RemoveInboundRequest{Tag: tag})
return err
}
func RemoveOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
_, err := client.RemoveOutbound(ctx, &command.RemoveOutboundRequest{Tag: tag})
return err
}
func ListInboundTags(ctx context.Context, client command.HandlerServiceClient) ([]string, error) {
resp, err := client.ListInbounds(ctx, &command.ListInboundsRequest{IsOnlyTags: true})
if err != nil {
return nil, err
}
tags := make([]string, 0, len(resp.GetInbounds()))
for _, inbound := range resp.GetInbounds() {
tags = append(tags, inbound.GetTag())
}
return tags, nil
}
func GetInboundUsers(ctx context.Context, client command.HandlerServiceClient, inboundTag string) ([]*protocol.User, error) {
resp, err := client.GetInboundUsers(ctx, &command.GetInboundUserRequest{
Tag: inboundTag,
})
if err != nil {
return nil, err
}
return resp.GetUsers(), nil
}
func GetInboundUsersCount(ctx context.Context, client command.HandlerServiceClient, inboundTag string) (int64, error) {
resp, err := client.GetInboundUsersCount(ctx, &command.GetInboundUserRequest{
Tag: inboundTag,
})
if err != nil {
return 0, err
}
return resp.GetCount(), nil
}
func AlterOutbound(ctx context.Context, client command.HandlerServiceClient, tag string, operation *serial.TypedMessage) error {
_, err := client.AlterOutbound(ctx, &command.AlterOutboundRequest{
Tag: tag,
Operation: operation,
})
return err
}

View File

@@ -0,0 +1,221 @@
package handler
import (
"context"
"github.com/xtls/xray-core/app/proxyman/command"
cnet "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/proxy/blackhole"
"github.com/xtls/xray-core/proxy/dns"
"github.com/xtls/xray-core/proxy/freedom"
"github.com/xtls/xray-core/proxy/http"
"github.com/xtls/xray-core/proxy/shadowsocks"
ss2022 "github.com/xtls/xray-core/proxy/shadowsocks_2022"
"github.com/xtls/xray-core/proxy/socks"
"github.com/xtls/xray-core/proxy/trojan"
"github.com/xtls/xray-core/proxy/vless"
vlessout "github.com/xtls/xray-core/proxy/vless/outbound"
"github.com/xtls/xray-core/proxy/vmess"
vmessout "github.com/xtls/xray-core/proxy/vmess/outbound"
"github.com/xtls/xray-core/proxy/wireguard"
"github.com/xtls/xray-core/transport/internet"
)
func AddFreedomOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
cfg := outboundConfig(
tag,
senderSettings(),
serial.ToTypedMessage(&freedom.Config{
DomainStrategy: internet.DomainStrategy_AS_IS,
UserLevel: 0,
Fragment: &freedom.Fragment{
PacketsFrom: 5,
PacketsTo: 10,
LengthMin: 50,
LengthMax: 150,
IntervalMin: 10,
IntervalMax: 20,
},
}),
)
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
return err
}
func AddBlackholeOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
cfg := outboundConfig(
tag,
senderSettings(),
serial.ToTypedMessage(&blackhole.Config{
Response: serial.ToTypedMessage(&blackhole.HTTPResponse{}),
}),
)
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
return err
}
func AddDNSOutbound(ctx context.Context, client command.HandlerServiceClient, tag string, upstream string) error {
endpointCfg := &cnet.Endpoint{
Network: cnet.Network_UDP,
Address: cnet.NewIPOrDomain(cnet.ParseAddress(upstream)),
Port: 53,
}
cfg := outboundConfig(
tag,
senderSettings(),
serial.ToTypedMessage(&dns.Config{
Server: endpointCfg,
UserLevel: 0,
BlockTypes: []int32{1, 28},
}),
)
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
return err
}
func AddHTTPOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
cfg := outboundConfig(
tag,
senderSettings(),
serial.ToTypedMessage(&http.ClientConfig{
Server: endpoint("example.com", 80, nil),
Header: []*http.Header{
{Key: "User-Agent", Value: "miaomiaowu"},
},
}),
)
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
return err
}
func AddSocksOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
cfg := outboundConfig(
tag,
senderSettings(),
serial.ToTypedMessage(&socks.ClientConfig{
Server: endpoint("127.0.0.1", 1080, nil),
}),
)
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
return err
}
func AddTrojanOutbound(ctx context.Context, client command.HandlerServiceClient, tag string, password string) error {
user := &protocol.User{
Email: "trojan@client.local",
Level: 0,
Account: serial.ToTypedMessage(&trojan.Account{
Password: password,
}),
}
cfg := outboundConfig(
tag,
senderSettings(),
serial.ToTypedMessage(&trojan.ClientConfig{
Server: endpoint("trojan.example.com", 443, user),
}),
)
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
return err
}
func AddShadowsocksOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
user := &protocol.User{
Email: "ss@client.local",
Account: serial.ToTypedMessage(&shadowsocks.Account{
Password: "client-pass",
CipherType: shadowsocks.CipherType_AES_256_GCM,
}),
}
cfg := outboundConfig(
tag,
senderSettings(),
serial.ToTypedMessage(&shadowsocks.ClientConfig{
Server: endpoint("ss.example.com", 8388, user),
}),
)
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
return err
}
func AddShadowsocks2022Outbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
cfg := outboundConfig(
tag,
senderSettings(),
serial.ToTypedMessage(&ss2022.ClientConfig{
Address: cnetOrDomain("203.0.113.2"),
Port: 8389,
Method: "2022-blake3-aes-256-gcm",
Key: "clientkeybase64==",
UdpOverTcp: true,
UdpOverTcpVersion: 2,
}),
)
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
return err
}
func AddVLESSOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
user := &protocol.User{
Email: "vless@client.local",
Account: serial.ToTypedMessage(&vless.Account{
Id: randomUUID(),
Encryption: "none",
}),
}
cfg := outboundConfig(
tag,
senderSettings(),
serial.ToTypedMessage(&vlessout.Config{
Vnext: endpoint("vless.example.com", 443, user),
}),
)
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
return err
}
func AddVMessOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
user := &protocol.User{
Email: "vmess@client.local",
Account: serial.ToTypedMessage(&vmess.Account{
Id: randomUUID(),
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AUTO,
},
}),
}
cfg := outboundConfig(
tag,
senderSettings(),
serial.ToTypedMessage(&vmessout.Config{
Receiver: endpoint("vmess.example.com", 443, user),
}),
)
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
return err
}
func AddWireGuardOutbound(ctx context.Context, client command.HandlerServiceClient, tag string) error {
cfg := outboundConfig(
tag,
senderSettings(),
serial.ToTypedMessage(&wireguard.DeviceConfig{
SecretKey: "clientSecretKeyBase64==",
Endpoint: []string{"198.51.100.2:51820"},
IsClient: true,
Mtu: 1420,
DomainStrategy: wireguard.DeviceConfig_FORCE_IP4,
Peers: []*wireguard.PeerConfig{
{
PublicKey: "serverPublicKeyBase64==",
AllowedIps: []string{"0.0.0.0/0"},
KeepAlive: 30,
},
},
}),
)
_, err := client.AddOutbound(ctx, &command.AddOutboundRequest{Outbound: cfg})
return err
}

View File

@@ -0,0 +1,120 @@
package handler
import (
"context"
"github.com/xtls/xray-core/app/proxyman/command"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/proxy/shadowsocks"
ss2022 "github.com/xtls/xray-core/proxy/shadowsocks_2022"
"github.com/xtls/xray-core/proxy/trojan"
"github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vmess"
)
// AddVMessUser demonstrates AlterInbound(AddUserOperation) for VMess.
func AddVMessUser(ctx context.Context, client command.HandlerServiceClient, inboundTag, email string) error {
req := &command.AlterInboundRequest{
Tag: inboundTag,
Operation: serial.ToTypedMessage(&command.AddUserOperation{
User: &protocol.User{
Level: 0,
Email: email,
Account: serial.ToTypedMessage(&vmess.Account{
Id: randomUUID(),
SecuritySettings: &protocol.SecurityConfig{
Type: protocol.SecurityType_AUTO,
},
}),
},
}),
}
_, err := client.AlterInbound(ctx, req)
return err
}
// AddVLESSUser shows how to add VLESS users dynamically.
func AddVLESSUser(ctx context.Context, client command.HandlerServiceClient, inboundTag, email string) error {
req := &command.AlterInboundRequest{
Tag: inboundTag,
Operation: serial.ToTypedMessage(&command.AddUserOperation{
User: &protocol.User{
Level: 0,
Email: email,
Account: serial.ToTypedMessage(&vless.Account{
Id: randomUUID(),
Encryption: "none",
}),
},
}),
}
_, err := client.AlterInbound(ctx, req)
return err
}
// AddTrojanUser adds a Trojan password to an inbound handler.
func AddTrojanUser(ctx context.Context, client command.HandlerServiceClient, inboundTag, email, password string) error {
req := &command.AlterInboundRequest{
Tag: inboundTag,
Operation: serial.ToTypedMessage(&command.AddUserOperation{
User: &protocol.User{
Level: 0,
Email: email,
Account: serial.ToTypedMessage(&trojan.Account{
Password: password,
}),
},
}),
}
_, err := client.AlterInbound(ctx, req)
return err
}
// AddShadowsocksUser sets up a Shadowsocks AEAD credential.
func AddShadowsocksUser(ctx context.Context, client command.HandlerServiceClient, inboundTag, email, password string) error {
req := &command.AlterInboundRequest{
Tag: inboundTag,
Operation: serial.ToTypedMessage(&command.AddUserOperation{
User: &protocol.User{
Level: 0,
Email: email,
Account: serial.ToTypedMessage(&shadowsocks.Account{
Password: password,
CipherType: shadowsocks.CipherType_CHACHA20_POLY1305,
}),
},
}),
}
_, err := client.AlterInbound(ctx, req)
return err
}
// AddShadowsocks2022User covers key rotation for SS2022.
func AddShadowsocks2022User(ctx context.Context, client command.HandlerServiceClient, inboundTag, email string) error {
req := &command.AlterInboundRequest{
Tag: inboundTag,
Operation: serial.ToTypedMessage(&command.AddUserOperation{
User: &protocol.User{
Email: email,
Account: serial.ToTypedMessage(&ss2022.Account{
Key: randomUUID(),
}),
},
}),
}
_, err := client.AlterInbound(ctx, req)
return err
}
// RemoveUser removes any user (identified by email) from an inbound.
func RemoveUser(ctx context.Context, client command.HandlerServiceClient, inboundTag, email string) error {
req := &command.AlterInboundRequest{
Tag: inboundTag,
Operation: serial.ToTypedMessage(&command.RemoveUserOperation{
Email: email,
}),
}
_, err := client.AlterInbound(ctx, req)
return err
}

View File

@@ -0,0 +1,16 @@
package logger
import (
"context"
"time"
loggerpb "github.com/xtls/xray-core/app/log/command"
)
// RestartLogger triggers the LoggerService restartLogger RPC and waits for completion.
func RestartLogger(ctx context.Context, client loggerpb.LoggerServiceClient) error {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
_, err := client.RestartLogger(ctx, &loggerpb.RestartLoggerRequest{})
return err
}

View File

@@ -0,0 +1,30 @@
package stats
import (
"context"
"time"
statspb "github.com/xtls/xray-core/app/stats/command"
)
func QueryTraffic(ctx context.Context, client statspb.StatsServiceClient, pattern string, reset bool) (int64, error) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
resp, err := client.QueryStats(ctx, &statspb.QueryStatsRequest{
Pattern: pattern,
Reset_: reset,
})
if err != nil {
return -1, err
}
if len(resp.GetStat()) == 0 {
return -1, nil
}
return resp.GetStat()[0].GetValue(), nil
}
func GetSystemStats(ctx context.Context, client statspb.StatsServiceClient) (*statspb.SysStatsResponse, error) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
return client.GetSysStats(ctx, &statspb.SysStatsRequest{})
}