├── README.md ├── docs ├── HandlerService.md ├── LoggerService.md └── StatsService.md ├── examples ├── addInbound.go ├── addInbound_test.go ├── alterInbound.go ├── alterInbound_test.go ├── getSystemStats.go ├── getSystemStats_test.go ├── init.go ├── queryTraffic.go ├── queryTraffic_test.go ├── removeInbound.go ├── removeInbound_test.go ├── restartLogger.go ├── restartLogger_test.go └── structures.go └── go.mod /README.md: -------------------------------------------------------------------------------- 1 | # Xray-API-documents 2 | ## 写在开头 3 | 使用API是一个技术活, 请在编写相关程序前对 Xray 配置有所了解
4 | [点我了解](https://xtls.github.io/about/)
5 | 以及你至少会一门支持grpc的语言, 这里以 Golang 为例, ~~因为他比较方便~~. 6 | 7 | ## 文档 8 | 说明文档在 docs 目录下
9 | 相关示例在 example 目录下, 每一个方法都对应一个test文件演示完整的过程
10 | 11 | ## 其他说明 12 | - 请尽量不要并发执行, 经过测试,大约在第10个线程后,Xray内核会丢弃多余的请求 13 | 14 | 相关问题请提issue. -------------------------------------------------------------------------------- /docs/HandlerService.md: -------------------------------------------------------------------------------- 1 | # HandlerService 2 | > 这部分控制由 HandlerServiceClient 承载 3 | 4 | 支持的接口方法 5 | ```shell 6 | AddInbound() 7 | RemoveInbound() 8 | AlterInbound() 9 | AddOutbound() 10 | RemoveOutbound() 11 | AlterOutbound() 12 | ``` 13 | 14 | ## AddInbound 15 | 此方法使用 InboundHandlerConfig 配置增加一个入站。 16 | 17 | ## RemoveInbound 18 | 移除一个入站,使用 Tag 区分。 19 | 20 | ## AlterInbound 21 | 在一个入站代理中添加一个用户 (VMess, VLESS, Trojan, ShadowSocks) 22 | 23 | > Outbound 同理 -------------------------------------------------------------------------------- /docs/LoggerService.md: -------------------------------------------------------------------------------- 1 | # LoggerService 2 | > 这部分控制由 LoggerServiceClient 承载 3 | 4 | 支持的接口方法 5 | ```shell 6 | restartLogger() 7 | ``` 8 | ## restartLogger 9 | 重启日志服务。 10 | -------------------------------------------------------------------------------- /docs/StatsService.md: -------------------------------------------------------------------------------- 1 | # StatsService 2 | > 这部分控制由 StatsServiceClient 承载 3 | 4 | 支持接口的方法: 5 | ```shell 6 | QueryStats() 7 | GetSysStats() 8 | ``` 9 | 10 | ## QueryStats 11 | 查询用户的上下行流量,与 Inbound 和 Outbound 上下行流量。 12 | 13 | ## GetSysStats 14 | 获取Xray运行数据。 15 | -------------------------------------------------------------------------------- /examples/addInbound.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "context" 5 | "github.com/xtls/xray-core/app/proxyman" 6 | "github.com/xtls/xray-core/app/proxyman/command" 7 | "github.com/xtls/xray-core/common/net" 8 | protocol "github.com/xtls/xray-core/common/protocol" 9 | "github.com/xtls/xray-core/common/protocol/tls/cert" 10 | "github.com/xtls/xray-core/common/serial" 11 | "github.com/xtls/xray-core/core" 12 | _ "github.com/xtls/xray-core/infra/conf" 13 | "github.com/xtls/xray-core/proxy/vmess" 14 | //ssInbound "github.com/xtls/xray-core/proxy/shadowsocks" 15 | //trojanInbound "github.com/xtls/xray-core/proxy/trojan" 16 | vmessInbound "github.com/xtls/xray-core/proxy/vmess/inbound" 17 | "github.com/xtls/xray-core/transport/internet" 18 | _ "github.com/xtls/xray-core/transport/internet/tcp" 19 | "github.com/xtls/xray-core/transport/internet/tls" 20 | "github.com/xtls/xray-core/transport/internet/websocket" 21 | ) 22 | 23 | func addInbound(client command.HandlerServiceClient) error { 24 | 25 | _, err := client.AddInbound(context.Background(), &command.AddInboundRequest{ 26 | Inbound: &core.InboundHandlerConfig{ 27 | Tag: "proxy0", 28 | ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ 29 | // 监听端口 12345 30 | PortRange: net.SinglePortRange(net.Port(12360)), 31 | // 监听地址, 默认0.0.0.0 32 | Listen: net.NewIPOrDomain(net.AnyIP), 33 | // 流量探测 34 | SniffingSettings: &proxyman.SniffingConfig{ 35 | Enabled: true, 36 | DestinationOverride: []string{"http", "tls"}, 37 | }, 38 | // 传输方式 39 | StreamSettings: &internet.StreamConfig{ 40 | /* 41 | 传输方式名称 42 | 请自行在 github.com/xtls/xray-core/transport/internet/config.pb.go 中寻找支持的协议 43 | 截至 1.3.0 目前支持 44 | "TCP", 45 | "UDP", 46 | "MKCP", 47 | "WebSocket", 48 | "HTTP", 49 | "DomainSocket" 50 | 使用时请一律小写 51 | 52 | */ 53 | ProtocolName: "websocket", 54 | TransportSettings: []*internet.TransportConfig{ 55 | { 56 | ProtocolName: "websocket", 57 | /* 58 | 选定传输方式后,请去 github.com/xtls/xray-core/transport/internet 下你选定方式的文件夹中导入config结构 59 | 如选定WebSocket则需要使用 github.com/xtls/xray-core/transport/internet/websocket/config.pb.go 中的 Config struct 60 | 结构内容请自行翻看代码(Ctrl + 左键) 61 | */ 62 | Settings: serial.ToTypedMessage(&websocket.Config{ 63 | Path: "/web", 64 | Header: []*websocket.Header{ 65 | { 66 | Key: "Host", 67 | Value: "www.xray.best", 68 | }, 69 | }, 70 | AcceptProxyProtocol: false, 71 | }, 72 | ), 73 | }, 74 | }, 75 | /* 76 | 传输层加密 77 | 请在 github.com/xtls/xray-core/transport/internet/ 中选择合适的传输层加密方式 78 | 截至1.3.0 目前支持 79 | TLS 80 | XTLS 81 | 留空即为None 82 | */ 83 | SecurityType: serial.GetMessageType(&tls.Config{}), 84 | SecuritySettings: []*serial.TypedMessage{ 85 | serial.ToTypedMessage(&tls.Config{ 86 | //Auto build 87 | Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))}, 88 | }), 89 | }, 90 | }, 91 | }), 92 | /* 93 | 代理设置, 请到 github.com/xtls/xray-core/proxy/ 寻找你想要添加的入站代理类型 94 | 某些类型需要区分 Inbound 与 Outbound 的配置, 95 | 需要区分使用 github.com/xtls/xray-core/proxy/PROXYTYPE/inbound/config.pb.go 中的 Config 结构 96 | 无须区分的使用 github.com/xtls/xray-core/proxy/PROXYTYPE/config.pb.go 的 ServerConfig 结构 97 | */ 98 | ProxySettings: serial.ToTypedMessage(&vmessInbound.Config{ 99 | User: []*protocol.User{ 100 | { 101 | Level: 0, 102 | Email: "love@xray.com", 103 | Account: serial.ToTypedMessage(&vmess.Account{ 104 | Id: "10354ac4-9ec1-4864-ba3e-f5fd35869ef8", 105 | AlterId: 1, 106 | }), 107 | }, 108 | }, 109 | }), 110 | }, 111 | }) 112 | 113 | return err 114 | } 115 | -------------------------------------------------------------------------------- /examples/addInbound_test.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import "testing" 4 | 5 | func TestAddInbound(t *testing.T) { 6 | // 先指定 API 端口和地址 7 | var ( 8 | xrayCtl *XrayController 9 | cfg = &BaseConfig{ 10 | APIAddress: "127.0.0.1", 11 | APIPort: 10085, 12 | } 13 | ) 14 | // 初始化 Clients 15 | xrayCtl = new(XrayController) 16 | err := xrayCtl.Init(cfg) 17 | defer xrayCtl.CmdConn.Close() 18 | if err != nil { 19 | t.Errorf("Failed %s", err) 20 | } 21 | // 此处为执行命令部分 22 | err = addInbound(xrayCtl.HsClient) 23 | if err != nil { 24 | t.Errorf("Failed %s", err) 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /examples/alterInbound.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "context" 5 | "github.com/xtls/xray-core/app/proxyman/command" 6 | "github.com/xtls/xray-core/common/protocol" 7 | "github.com/xtls/xray-core/common/serial" 8 | "github.com/xtls/xray-core/proxy/shadowsocks" 9 | "github.com/xtls/xray-core/proxy/trojan" 10 | "github.com/xtls/xray-core/proxy/vmess" 11 | ) 12 | 13 | // 这部分非常简单, 请先去 structure.go 下查看 UserInfo 结构信息 14 | 15 | func addVmessUser(client command.HandlerServiceClient, user *UserInfo) error { 16 | _, err := client.AlterInbound(context.Background(), &command.AlterInboundRequest{ 17 | // 先确定哪个入站端口将要添加用户 18 | Tag: user.InTag, 19 | // 添加用户操作 github.com/xtls/xray-core/app/proxyman/command 中的 AddUserOperation 20 | Operation: serial.ToTypedMessage(&command.AddUserOperation{ 21 | User: &protocol.User{ 22 | // 用户信息(Level和Email为所有入站用户都需要的信息) 23 | Level: user.Level, 24 | Email: user.Email, 25 | /* 不同代理类型使用不同的用户信息结构 26 | 请在 github.com/xtls/xray-core/proxy/PROXYTYPE 下寻找 Account 结构体 27 | */ 28 | Account: serial.ToTypedMessage(&vmess.Account{ 29 | Id: user.Uuid, 30 | AlterId: user.AlertId, 31 | }), 32 | }, 33 | }), 34 | }) 35 | return err 36 | } 37 | 38 | func addSSUser(client command.HandlerServiceClient, user *UserInfo) error { 39 | var ssCipherType shadowsocks.CipherType 40 | switch user.CipherType { 41 | case "aes-128-gcm": 42 | ssCipherType = shadowsocks.CipherType_AES_128_GCM 43 | case "aes-256-gcm": 44 | ssCipherType = shadowsocks.CipherType_AES_256_GCM 45 | case "chacha20-ietf-poly1305": 46 | ssCipherType = shadowsocks.CipherType_CHACHA20_POLY1305 47 | } 48 | 49 | _, err := client.AlterInbound(context.Background(), &command.AlterInboundRequest{ 50 | Tag: user.InTag, 51 | Operation: serial.ToTypedMessage(&command.AddUserOperation{ 52 | User: &protocol.User{ 53 | Level: user.Level, 54 | Email: user.Email, 55 | Account: serial.ToTypedMessage(&shadowsocks.Account{ 56 | Password: user.Password, 57 | CipherType: ssCipherType, 58 | }), 59 | }, 60 | }), 61 | }) 62 | return err 63 | } 64 | 65 | func addTrojanUser(client command.HandlerServiceClient, user *UserInfo) error { 66 | _, err := client.AlterInbound(context.Background(), &command.AlterInboundRequest{ 67 | Tag: user.InTag, 68 | Operation: serial.ToTypedMessage(&command.AddUserOperation{ 69 | User: &protocol.User{ 70 | Level: user.Level, 71 | Email: user.Email, 72 | Account: serial.ToTypedMessage(&trojan.Account{ 73 | Password: user.Uuid, 74 | }), 75 | }, 76 | }), 77 | }) 78 | return err 79 | } 80 | 81 | // Email 为用户唯一标识符, 使用Email配合用户入站Tag来删除用户 82 | 83 | func removeUser(client command.HandlerServiceClient, user *UserInfo) error { 84 | _, err := client.AlterInbound(context.Background(), &command.AlterInboundRequest{ 85 | Tag: user.InTag, 86 | Operation: serial.ToTypedMessage(&command.RemoveUserOperation{ 87 | Email: user.Email, 88 | }), 89 | }) 90 | return err 91 | } 92 | -------------------------------------------------------------------------------- /examples/alterInbound_test.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import "testing" 4 | 5 | func TestAlertInbound(t *testing.T) { 6 | var ( 7 | xrayCtl *XrayController 8 | cfg = &BaseConfig{ 9 | APIAddress: "127.0.0.1", 10 | APIPort: 10085, 11 | } 12 | user = UserInfo{ 13 | Uuid: "10354ac4-9ec1-4864-ba3e-f5fd35869ef8", 14 | AlertId: 0, 15 | Level: 0, 16 | InTag: "proxy0", 17 | Email: "love@xray.com", 18 | CipherType: "aes-256-gcm", 19 | Password: "xrayisthebest", 20 | } 21 | ) 22 | xrayCtl = new(XrayController) 23 | err := xrayCtl.Init(cfg) 24 | defer xrayCtl.CmdConn.Close() 25 | if err != nil { 26 | t.Errorf("Failed %s", err) 27 | } 28 | err = addVmessUser(xrayCtl.HsClient, &user) 29 | if err != nil { 30 | t.Errorf("Failed %s", err) 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /examples/getSystemStats.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "context" 5 | statsService "github.com/xtls/xray-core/app/stats/command" 6 | ) 7 | 8 | /* 9 | 获取运行数据, 如下 10 | NumGoroutine:17 NumGC:2 Alloc:1711192 TotalAlloc:2359880 Sys:14440840 Mallocs:19101 Frees:7242 LiveObjects:11859 PauseTotalNs:4983200 Uptime:31 11 | */ 12 | func getSysStats(c statsService.StatsServiceClient) (stats *statsService.SysStatsResponse, err error) { 13 | stats, err = c.GetSysStats(context.Background(), &statsService.SysStatsRequest{}) 14 | 15 | return 16 | } 17 | -------------------------------------------------------------------------------- /examples/getSystemStats_test.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestGetSysStats(t *testing.T) { 9 | var ( 10 | xrayCtl *XrayController 11 | cfg = &BaseConfig{ 12 | APIAddress: "127.0.0.1", 13 | APIPort: 10085, 14 | } 15 | ) 16 | xrayCtl = new(XrayController) 17 | err := xrayCtl.Init(cfg) 18 | defer xrayCtl.CmdConn.Close() 19 | if err != nil { 20 | t.Errorf("Failed %s", err) 21 | } 22 | SysStats, err := getSysStats(xrayCtl.SsClient) 23 | if err != nil { 24 | t.Errorf("Failed %s", err) 25 | } 26 | fmt.Println(SysStats) 27 | 28 | } 29 | -------------------------------------------------------------------------------- /examples/init.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "fmt" 5 | loggerService "github.com/xtls/xray-core/app/log/command" 6 | handlerService "github.com/xtls/xray-core/app/proxyman/command" 7 | routingService "github.com/xtls/xray-core/app/router/command" 8 | statsService "github.com/xtls/xray-core/app/stats/command" 9 | "google.golang.org/grpc" 10 | ) 11 | 12 | // 取得API操作的Client 13 | 14 | func (xrayCtl *XrayController) Init(cfg *BaseConfig) (err error) { 15 | // 先取得ClientConn, 用完记得close 16 | xrayCtl.CmdConn, err = grpc.Dial(fmt.Sprintf("%s:%d", cfg.APIAddress, cfg.APIPort), grpc.WithInsecure()) 17 | if err != nil { 18 | return err 19 | } 20 | 21 | // 依次获取API Client, 可根据需求删减 22 | xrayCtl.HsClient = handlerService.NewHandlerServiceClient(xrayCtl.CmdConn) 23 | xrayCtl.SsClient = statsService.NewStatsServiceClient(xrayCtl.CmdConn) 24 | xrayCtl.LsClient = loggerService.NewLoggerServiceClient(xrayCtl.CmdConn) 25 | //Not implement 26 | xrayCtl.RsClient = routingService.NewRoutingServiceClient(xrayCtl.CmdConn) 27 | 28 | return 29 | } 30 | -------------------------------------------------------------------------------- /examples/queryTraffic.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "context" 5 | statsService "github.com/xtls/xray-core/app/stats/command" 6 | ) 7 | 8 | /* 9 | 先按照 https://xtls.github.io/config/base/policy/ 打开入/出 站或用户流量统计 10 | 请参照 https://xtls.github.io/config/base/stats/ 来生成一条查询语句, 例如 11 | “user>>>love@xray.com>>>traffic>>>uplink” 查询 email 为 love@xray.com 的用户在所有的入站中的上行流量 12 | 可以选择在查询完之后重置流量信息。 13 | 14 | 目前支持 User, Inbound, Outbound 的上下行流量查询 15 | */ 16 | 17 | func queryTraffic(c statsService.StatsServiceClient, ptn string, reset bool) (traffic int64, err error) { 18 | // 如果查无此用户或 bound 则返回-1, 默认值 -1 19 | traffic = -1 20 | resp, err := c.QueryStats(context.Background(), &statsService.QueryStatsRequest{ 21 | // 这里是查询语句,例如 “user>>>love@xray.com>>>traffic>>>uplink” 表示查询用户 email 为 love@xray.com 在所有入站中的上行流量 22 | Pattern: ptn, 23 | // 是否重置流量信息(true, false),即完成查询后是否把流量统计归零 24 | Reset_: reset, // reset traffic data everytime 25 | }) 26 | if err != nil { 27 | return 28 | } 29 | // Get traffic data 30 | stat := resp.GetStat() 31 | // 判断返回 是否成功 32 | // 返回样例,value 值是我们需要的: [name:"inbound>>>proxy0>>>traffic>>>downlink" value:348789] 33 | if len(stat) != 0 { 34 | // 返回流量数据 byte 35 | traffic = stat[0].Value 36 | } 37 | 38 | return 39 | } 40 | -------------------------------------------------------------------------------- /examples/queryTraffic_test.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestQueryTraffic(t *testing.T) { 9 | var ( 10 | xrayCtl *XrayController 11 | cfg = &BaseConfig{ 12 | APIAddress: "127.0.0.1", 13 | APIPort: 10085, 14 | } 15 | ) 16 | xrayCtl = new(XrayController) 17 | err := xrayCtl.Init(cfg) 18 | defer xrayCtl.CmdConn.Close() 19 | if err != nil { 20 | t.Errorf("Failed %s", err) 21 | } 22 | ptn := "inbound>>>proxy0>>>traffic>>>downlink" 23 | trafficData, err := queryTraffic(xrayCtl.SsClient, ptn, false) 24 | if err != nil { 25 | t.Errorf("Failed %s", err) 26 | } 27 | fmt.Println(trafficData) 28 | 29 | } 30 | -------------------------------------------------------------------------------- /examples/removeInbound.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "context" 5 | "github.com/xtls/xray-core/app/proxyman/command" 6 | ) 7 | 8 | // 使用 Tag 操作,非常简单 9 | func removeInbound(client command.HandlerServiceClient, tag string) error { 10 | _, err := client.RemoveInbound(context.Background(), &command.RemoveInboundRequest{ 11 | Tag: tag, 12 | }) 13 | return err 14 | } 15 | -------------------------------------------------------------------------------- /examples/removeInbound_test.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import "testing" 4 | 5 | func TestRemoveInbound(t *testing.T) { 6 | var ( 7 | xrayCtl *XrayController 8 | cfg = &BaseConfig{ 9 | APIAddress: "127.0.0.1", 10 | APIPort: 10085, 11 | } 12 | tag = "proxy0" 13 | ) 14 | xrayCtl = new(XrayController) 15 | err := xrayCtl.Init(cfg) 16 | defer xrayCtl.CmdConn.Close() 17 | if err != nil { 18 | t.Errorf("Failed %s", err) 19 | } 20 | err = removeInbound(xrayCtl.HsClient, tag) 21 | if err != nil { 22 | t.Errorf("Failed %s", err) 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /examples/restartLogger.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "context" 5 | loggerService "github.com/xtls/xray-core/app/log/command" 6 | ) 7 | 8 | func restartLogger(c loggerService.LoggerServiceClient) (err error) { 9 | _, err = c.RestartLogger(context.Background(), &loggerService.RestartLoggerRequest{}) 10 | 11 | return 12 | } 13 | -------------------------------------------------------------------------------- /examples/restartLogger_test.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestRestartLogger(t *testing.T) { 8 | var ( 9 | xrayCtl *XrayController 10 | cfg = &BaseConfig{ 11 | APIAddress: "127.0.0.1", 12 | APIPort: 10085, 13 | } 14 | ) 15 | xrayCtl = new(XrayController) 16 | err := xrayCtl.Init(cfg) 17 | defer xrayCtl.CmdConn.Close() 18 | if err != nil { 19 | t.Errorf("Failed %s", err) 20 | } 21 | err = restartLogger(xrayCtl.LsClient) 22 | if err != nil { 23 | t.Errorf("Failed %s", err) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /examples/structures.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | loggerService "github.com/xtls/xray-core/app/log/command" 5 | handlerService "github.com/xtls/xray-core/app/proxyman/command" 6 | routingService "github.com/xtls/xray-core/app/router/command" 7 | statsService "github.com/xtls/xray-core/app/stats/command" 8 | "google.golang.org/grpc" 9 | ) 10 | 11 | // Xray API 监听地址及端口 12 | type BaseConfig struct { 13 | APIAddress string 14 | APIPort uint16 15 | } 16 | 17 | type UserInfo struct { 18 | // For VMess & Trojan 19 | Uuid string 20 | // For VMess 21 | AlertId uint32 22 | Level uint32 23 | // Which Inbound will add this user 24 | InTag string 25 | // User's Email, it's a unique identifier for users 26 | Email string 27 | // For ShadowSocks 28 | CipherType string 29 | // For ShadowSocks 30 | Password string 31 | } 32 | 33 | // Xray API 操作 34 | type XrayController struct { 35 | HsClient handlerService.HandlerServiceClient 36 | SsClient statsService.StatsServiceClient 37 | LsClient loggerService.LoggerServiceClient 38 | RsClient routingService.RoutingServiceClient 39 | CmdConn *grpc.ClientConn 40 | } 41 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/crossfw/Xray-API-documents 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/xtls/xray-core v1.3.0 7 | google.golang.org/grpc v1.35.0 8 | ) 9 | --------------------------------------------------------------------------------