mirror of
https://github.com/p4gefau1t/trojan-go.git
synced 2024-04-21 12:21:34 +00:00
implement server api
This commit is contained in:
+167
-804
File diff suppressed because it is too large
Load Diff
+16
-55
@@ -14,7 +14,6 @@ message Speed {
|
||||
message User {
|
||||
string password = 1;
|
||||
string hash = 2;
|
||||
bool valid = 3;
|
||||
}
|
||||
|
||||
message GetTrafficRequest {
|
||||
@@ -22,17 +21,11 @@ message GetTrafficRequest {
|
||||
}
|
||||
|
||||
message GetTrafficResponse {
|
||||
Traffic traffic_total = 1;
|
||||
Traffic traffic_quota = 2;
|
||||
}
|
||||
|
||||
message GetSpeedRequest {
|
||||
User user = 1;
|
||||
}
|
||||
|
||||
message GetSpeedResponse {
|
||||
Speed speed_current = 1;
|
||||
Speed speed_limit = 2;
|
||||
bool success = 1;
|
||||
Traffic traffic_total = 2;
|
||||
Speed speed_current = 3;
|
||||
Speed speed_limit = 4;
|
||||
string info = 5;
|
||||
}
|
||||
|
||||
message ListUserRequest {
|
||||
@@ -43,64 +36,32 @@ message ListUserResponse {
|
||||
User user = 1;
|
||||
bool online = 2;
|
||||
Traffic traffic_total = 3;
|
||||
Traffic traffic_quota = 4;
|
||||
Speed speed_current = 5;
|
||||
Speed speed_limit = 6;
|
||||
Speed speed_current = 4;
|
||||
Speed speed_limit = 5;
|
||||
}
|
||||
|
||||
message SetTrafficRequest {
|
||||
User user = 1;
|
||||
Traffic traffic_quota = 2;
|
||||
}
|
||||
|
||||
message SetTrafficReponse {
|
||||
bool success = 1;
|
||||
string info = 2;
|
||||
}
|
||||
|
||||
message SetSpeedRequest {
|
||||
message SetUserRequest {
|
||||
User user = 1;
|
||||
Speed speed_limit = 2;
|
||||
enum Operation {
|
||||
Add = 0;
|
||||
Delete = 1;
|
||||
Modify = 2;
|
||||
}
|
||||
Operation operation = 3;
|
||||
}
|
||||
|
||||
message SetSpeedResponse {
|
||||
bool success = 1;
|
||||
string info = 2;
|
||||
}
|
||||
|
||||
message AddUserRequest {
|
||||
User user = 1;
|
||||
Traffic traffic_quota = 4;
|
||||
Speed speed_limit = 6;
|
||||
}
|
||||
|
||||
message AddUserResponse {
|
||||
User user = 1;
|
||||
}
|
||||
|
||||
message DeleteUserRequest {
|
||||
User user = 1;
|
||||
}
|
||||
|
||||
message DeleteUserResponse {
|
||||
message SetUserResponse {
|
||||
bool success = 1;
|
||||
string info = 2;
|
||||
}
|
||||
|
||||
service TrojanClientService {
|
||||
rpc GetTraffic(GetTrafficRequest) returns(GetTrafficResponse){}
|
||||
rpc GetSpeed(GetSpeedRequest) returns(GetSpeedResponse){}
|
||||
}
|
||||
|
||||
service TrojanServerService {
|
||||
rpc ListUsers(ListUserRequest) returns(stream ListUserResponse){}
|
||||
|
||||
rpc GetTraffic(stream GetTrafficRequest) returns(stream GetTrafficResponse){}
|
||||
rpc SetTraffic(stream SetTrafficRequest) returns(stream SetTrafficReponse) {}
|
||||
|
||||
rpc GetSpeed(stream GetSpeedRequest) returns(stream GetSpeedResponse){}
|
||||
rpc SetSpeed(stream SetSpeedRequest) returns(stream SetSpeedResponse) {}
|
||||
|
||||
rpc AddUsers(stream AddUserRequest) returns(stream AddUserResponse){}
|
||||
rpc DeleteUsers(stream DeleteUserRequest) returns(stream DeleteUserResponse){}
|
||||
rpc SetUsers(stream SetUserRequest) returns(stream SetUserResponse){}
|
||||
}
|
||||
|
||||
+8
-14
@@ -26,36 +26,30 @@ func (s *ClientAPI) GetTraffic(ctx context.Context, req *GetTrafficRequest) (*Ge
|
||||
if req.User == nil {
|
||||
return nil, common.NewError("user is unspecified")
|
||||
}
|
||||
if req.User.Hash == "" {
|
||||
req.User.Hash = common.SHA224String(req.User.Password)
|
||||
}
|
||||
valid, meter := s.auth.AuthUser(req.User.Hash)
|
||||
if !valid {
|
||||
return nil, common.NewError("user " + req.User.Hash + " not found")
|
||||
}
|
||||
sent, recv := meter.Get()
|
||||
sentSpeed, recvSpeed := meter.GetSpeed()
|
||||
resp := &GetTrafficResponse{
|
||||
Success: true,
|
||||
TrafficTotal: &Traffic{
|
||||
UploadTraffic: sent,
|
||||
DownloadTraffic: recv,
|
||||
},
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *ClientAPI) GetSpeed(ctx context.Context, req *GetSpeedRequest) (*GetSpeedResponse, error) {
|
||||
valid, meter := s.auth.AuthUser(req.User.Hash)
|
||||
if !valid {
|
||||
return &GetSpeedResponse{}, nil
|
||||
}
|
||||
sent, recv := meter.GetSpeed()
|
||||
resp := &GetSpeedResponse{
|
||||
SpeedCurrent: &Speed{
|
||||
UploadSpeed: sent,
|
||||
DownloadSpeed: recv,
|
||||
UploadSpeed: sentSpeed,
|
||||
DownloadSpeed: recvSpeed,
|
||||
},
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func RunClientAPIService(ctx context.Context, config *conf.GlobalConfig, auth stat.Authenticator) error {
|
||||
func RunClientAPI(ctx context.Context, config *conf.GlobalConfig, auth stat.Authenticator) error {
|
||||
server := grpc.NewServer()
|
||||
service := &ClientAPI{
|
||||
ctx: ctx,
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ func TestClientAPI(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
auth, err := memory.NewMemoryAuth(ctx, &conf.GlobalConfig{})
|
||||
common.Must(err)
|
||||
go RunClientAPIService(ctx, &conf.GlobalConfig{
|
||||
go RunClientAPI(ctx, &conf.GlobalConfig{
|
||||
API: conf.APIConfig{
|
||||
APIAddress: common.NewAddress("127.0.0.1", 10000, "tcp"),
|
||||
},
|
||||
|
||||
+133
-12
@@ -1,24 +1,145 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/p4gefau1t/trojan-go/common"
|
||||
"github.com/p4gefau1t/trojan-go/conf"
|
||||
"github.com/p4gefau1t/trojan-go/log"
|
||||
"github.com/p4gefau1t/trojan-go/stat"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type MemoryTraffic struct {
|
||||
downloadTraffic uint64
|
||||
uploadTraffic uint64
|
||||
type ServerAPI struct {
|
||||
TrojanServerServiceServer
|
||||
auth stat.Authenticator
|
||||
}
|
||||
|
||||
type MemoryUser struct {
|
||||
password string
|
||||
hash string
|
||||
trafficTotal MemoryTraffic
|
||||
trafficQuota MemoryTraffic
|
||||
func (s *ServerAPI) GetTraffic(stream TrojanServerService_GetTrafficServer) error {
|
||||
for {
|
||||
req, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if req.User == nil {
|
||||
return common.NewError("user is unspecified")
|
||||
}
|
||||
if req.User.Hash == "" {
|
||||
req.User.Hash = common.SHA224String(req.User.Password)
|
||||
}
|
||||
valid, meter := s.auth.AuthUser(req.User.Hash)
|
||||
if !valid {
|
||||
stream.Send(&GetTrafficResponse{
|
||||
Success: false,
|
||||
Info: "invalid user",
|
||||
})
|
||||
continue
|
||||
}
|
||||
downloadTraffic, uploadTraffic := meter.Get()
|
||||
downloadSpeed, uploadSpeed := meter.GetSpeed()
|
||||
err = stream.Send(&GetTrafficResponse{
|
||||
Success: true,
|
||||
TrafficTotal: &Traffic{
|
||||
UploadTraffic: uploadTraffic,
|
||||
DownloadTraffic: downloadTraffic,
|
||||
},
|
||||
SpeedCurrent: &Speed{
|
||||
DownloadSpeed: downloadSpeed,
|
||||
UploadSpeed: uploadSpeed,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type APIAuth struct {
|
||||
stat.Authenticator
|
||||
users sync.Map
|
||||
func (s *ServerAPI) SetUsers(stream TrojanServerService_SetUsersServer) error {
|
||||
for {
|
||||
req, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if req.User == nil {
|
||||
return common.NewError("user is unspecified")
|
||||
}
|
||||
if req.User.Hash == "" {
|
||||
req.User.Hash = common.SHA224String(req.User.Password)
|
||||
}
|
||||
switch req.Operation {
|
||||
case SetUserRequest_Add:
|
||||
err = s.auth.AddUser(req.User.Hash)
|
||||
case SetUserRequest_Delete:
|
||||
err = s.auth.DelUser(req.User.Hash)
|
||||
case SetUserRequest_Modify:
|
||||
err = common.NewError("not support yet")
|
||||
}
|
||||
if err != nil {
|
||||
stream.Send(&SetUserResponse{
|
||||
Success: false,
|
||||
Info: err.Error(),
|
||||
})
|
||||
continue
|
||||
}
|
||||
stream.Send(&SetUserResponse{
|
||||
Success: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServerAPI) ListUsers(req *ListUserRequest, stream TrojanServerService_ListUsersServer) error {
|
||||
users := s.auth.ListUsers()
|
||||
for _, meter := range users {
|
||||
downloadTraffic, uploadTraffic := meter.Get()
|
||||
downloadSpeed, uploadSpeed := meter.GetSpeed()
|
||||
err := stream.Send(&ListUserResponse{
|
||||
User: &User{
|
||||
Hash: meter.Hash(),
|
||||
},
|
||||
TrafficTotal: &Traffic{
|
||||
DownloadTraffic: downloadTraffic,
|
||||
UploadTraffic: uploadTraffic,
|
||||
},
|
||||
SpeedCurrent: &Speed{
|
||||
DownloadSpeed: downloadSpeed,
|
||||
UploadSpeed: uploadSpeed,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RunServerAPI(ctx context.Context, config *conf.GlobalConfig, auth stat.Authenticator) error {
|
||||
server := grpc.NewServer()
|
||||
service := &ServerAPI{
|
||||
auth: auth,
|
||||
}
|
||||
RegisterTrojanServerServiceServer(server, service)
|
||||
listener, err := net.Listen("tcp", config.API.APIAddress.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("server api service is running at", config.API.APIAddress)
|
||||
errChan := make(chan error, 1)
|
||||
go func() {
|
||||
errChan <- server.Serve(listener)
|
||||
}()
|
||||
select {
|
||||
case err := <-errChan:
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
server.Stop()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
context "context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/p4gefau1t/trojan-go/common"
|
||||
"github.com/p4gefau1t/trojan-go/conf"
|
||||
"github.com/p4gefau1t/trojan-go/stat/memory"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func TestServerAPI(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
auth, err := memory.NewMemoryAuth(ctx, &conf.GlobalConfig{})
|
||||
common.Must(err)
|
||||
go RunServerAPI(ctx, &conf.GlobalConfig{
|
||||
API: conf.APIConfig{
|
||||
APIAddress: common.NewAddress("127.0.0.1", 10000, "tcp"),
|
||||
},
|
||||
}, auth)
|
||||
common.Must(auth.AddUser("hash1234"))
|
||||
_, meter := auth.AuthUser("hash1234")
|
||||
conn, err := grpc.Dial("127.0.0.1:10000", grpc.WithInsecure())
|
||||
server := NewTrojanServerServiceClient(conn)
|
||||
stream1, err := server.ListUsers(ctx, &ListUserRequest{})
|
||||
common.Must(err)
|
||||
for {
|
||||
resp, err := stream1.Recv()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
fmt.Println(resp.User.Hash)
|
||||
if resp.User.Hash != "hash1234" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
stream1.CloseSend()
|
||||
|
||||
meter.Count(1234, 5678)
|
||||
time.Sleep(time.Millisecond * 400)
|
||||
stream2, err := server.GetTraffic(ctx)
|
||||
common.Must(err)
|
||||
stream2.Send(&GetTrafficRequest{
|
||||
User: &User{
|
||||
Hash: "hash1234",
|
||||
},
|
||||
})
|
||||
resp2, err := stream2.Recv()
|
||||
common.Must(err)
|
||||
if resp2.TrafficTotal.DownloadTraffic != 1234 || resp2.TrafficTotal.UploadTraffic != 5678 {
|
||||
t.Fail()
|
||||
}
|
||||
if resp2.SpeedCurrent.DownloadSpeed != 1234 || resp2.TrafficTotal.UploadTraffic != 5678 {
|
||||
t.Fail()
|
||||
}
|
||||
stream2.CloseSend()
|
||||
|
||||
stream3, err := server.SetUsers(ctx)
|
||||
stream3.Send(&SetUserRequest{
|
||||
User: &User{
|
||||
Hash: "hash1234",
|
||||
},
|
||||
Operation: SetUserRequest_Delete,
|
||||
})
|
||||
resp3, err := stream3.Recv()
|
||||
if err != nil || !resp3.Success {
|
||||
t.Fail()
|
||||
}
|
||||
valid, _ := auth.AuthUser("hash1234")
|
||||
if valid {
|
||||
t.Fail()
|
||||
}
|
||||
stream3.Send(&SetUserRequest{
|
||||
User: &User{
|
||||
Hash: "newhash",
|
||||
},
|
||||
Operation: SetUserRequest_Add,
|
||||
})
|
||||
resp3, err = stream3.Recv()
|
||||
if err != nil || !resp3.Success {
|
||||
t.Fail()
|
||||
}
|
||||
valid, _ = auth.AuthUser("newhash")
|
||||
if !valid {
|
||||
t.Fail()
|
||||
}
|
||||
cancel()
|
||||
}
|
||||
Reference in New Issue
Block a user