implement server api

This commit is contained in:
p4gefau1t
2020-05-01 07:56:07 -04:00
parent 20ef0b842d
commit c0f46d38b5
8 changed files with 425 additions and 886 deletions
+167 -804
View File
File diff suppressed because it is too large Load Diff
+16 -55
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
}
+91
View File
@@ -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()
}