From a884cc909544d24bd0c7ae9006669eabd5af357d Mon Sep 17 00:00:00 2001 From: lc-1010 <532398960@qq.com> Date: Mon, 10 Jul 2023 18:07:55 +0800 Subject: [PATCH] feat: Add grpc client & server - Add grpc client and server #16 --- client/client.go | 24 +++++++++++++ cmd/multiple/main.go | 66 ++++++++++++++++++++++++++++++++++++ cmd/rpc/main.go | 30 +++++++++++++++++ pkg/blog_api/api.go | 69 ++++++++++++++++++++++++++++++++++++++ pkg/errcode/common_code.go | 10 +++--- pkg/errcode/rpc_error.go | 57 +++++++++++++++++++++++++++++++ server/tag.go | 40 ++++++++++++++++++++++ 7 files changed, 291 insertions(+), 5 deletions(-) create mode 100644 client/client.go create mode 100644 cmd/multiple/main.go create mode 100644 cmd/rpc/main.go create mode 100644 pkg/blog_api/api.go create mode 100644 pkg/errcode/rpc_error.go create mode 100644 server/tag.go diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..1b9ab88 --- /dev/null +++ b/client/client.go @@ -0,0 +1,24 @@ +package main + +import ( + "context" + "log" + + pb "github.com/lc-1010/OneBlogService/proto" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func main() { + ctx := context.Background() + clientConn, _ := GetClientConn(ctx, "localhost:8004", nil) + defer clientConn.Close() + tagServiceClient := pb.NewTagServiceClient(clientConn) + resp, _ := tagServiceClient.GetTagList(ctx, &pb.GetTagListRequst{Name: "rust"}) + log.Printf("resp:%v", resp) +} + +func GetClientConn(ctx context.Context, target string, opts []grpc.DialOption) (*grpc.ClientConn, error) { + opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) + return grpc.DialContext(ctx, target, opts...) +} diff --git a/cmd/multiple/main.go b/cmd/multiple/main.go new file mode 100644 index 0000000..35bbf5f --- /dev/null +++ b/cmd/multiple/main.go @@ -0,0 +1,66 @@ +package main + +import ( + "flag" + "log" + "net" + "net/http" + + pb "github.com/lc-1010/OneBlogService/proto" + "github.com/lc-1010/OneBlogService/server" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var grpcPort string +var httpPort string + +func init() { + flag.StringVar(&grpcPort, "grpc_port", "8001", "grpc启动端口") + flag.StringVar(&httpPort, "http_port", "8002", "http启动端口") + flag.Parse() +} + +func RunHttpServer(port string) error { + serveMux := http.NewServeMux() //多路复用 + + serveMux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte(`pong`)) + }) + return http.ListenAndServe(":"+port, serveMux) +} + +func RunGrpcServer(port string) error { + s := grpc.NewServer() + pb.RegisterTagServiceServer(s, server.NewTagServer()) + reflection.Register(s) + lis, err := net.Listen("tcp", ":"+port) + if err != nil { + return err + } + return s.Serve(lis) +} + +// grpcurl -plaintext localhost:8001 proto.TagService.GetTagList +// curl 127.0.0.1:8002/ping +func main() { + + errs := make(chan error) + go func() { + err := RunHttpServer(httpPort) + if err != nil { + errs <- err + } + }() + go func() { + err := RunGrpcServer(grpcPort) + if err != nil { + errs <- err + } + }() + + err := <-errs + if err != nil { + log.Fatalf("Run Server err:%v", err) + } +} diff --git a/cmd/rpc/main.go b/cmd/rpc/main.go new file mode 100644 index 0000000..c0e6980 --- /dev/null +++ b/cmd/rpc/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "log" + "net" + + pb "github.com/lc-1010/OneBlogService/proto" + "github.com/lc-1010/OneBlogService/server" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var port string + +func main() { + port = "8004" + s := grpc.NewServer() + tag := server.NewTagServer() + pb.RegisterTagServiceServer(s, tag) + reflection.Register(s) + lis, err := net.Listen("tcp", ":"+port) + if err != nil { + log.Fatalf("net.Listen err:%v", err) + + } + err = s.Serve(lis) + if err != nil { + log.Fatalf("serve err:%v", err) + } +} diff --git a/pkg/blog_api/api.go b/pkg/blog_api/api.go new file mode 100644 index 0000000..e5e6d25 --- /dev/null +++ b/pkg/blog_api/api.go @@ -0,0 +1,69 @@ +package blog_api + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" +) + +const ( + APP_KEY = "APP_KEY" + APP_SECRET = "APP_SECRET" +) + +// API blog api sdk +type API struct { + URL string + Client *http.Client +} + +// AccessToken +type AccessToken struct { + Token string `json:"token"` +} + +// NewAPI creates a new API instance. +// +// It takes a URL string as a parameter and returns a pointer to an API object. +func NewAPI(url string) *API { + return &API{URL: url, Client: http.DefaultClient} +} + +func (a *API) getAccessToken(c context.Context) (string, error) { + + body, err := a.httpGet(c, fmt.Sprintf("%s?app_key=%s&app_secret=%s", "auth", APP_KEY, APP_SECRET)) + if err != nil { + return "", err + } + var accessToken AccessToken + _ = json.Unmarshal(body, &accessToken) + return accessToken.Token, nil +} + +// httpGet get function +func (a *API) httpGet(ctx context.Context, path string) ([]byte, error) { + resp, err := http.Get(fmt.Sprintf("%s/%s", a.URL, path)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, _ := ioutil.ReadAll(resp.Body) + return body, nil +} + +func (a *API) GetTagList(ctx context.Context, name string) ([]byte, error) { + token, err := a.getAccessToken(ctx) + if err != nil { + log.Println(err) + return nil, err + } + + body, err := a.httpGet(ctx, fmt.Sprintf("%s?token=%s&name=%s", "api/v1/tags", token, name)) + if err != nil { + return nil, err + } + return body, nil +} diff --git a/pkg/errcode/common_code.go b/pkg/errcode/common_code.go index 6f09a16..0d9ad8a 100644 --- a/pkg/errcode/common_code.go +++ b/pkg/errcode/common_code.go @@ -12,7 +12,7 @@ type Error struct { details []string } -var codes = map[int]string{} +var b_codes = map[int]string{} // NewError creates a new Error object with the given code and message. // @@ -23,10 +23,10 @@ var codes = map[int]string{} // Returns: // - *Error: a pointer to the newly created Error object. func NewError(code int, msg string) *Error { - if _, ok := codes[code]; ok { + if _, ok := b_codes[code]; ok { panic(fmt.Sprintf("This code %d already exists. Please try another one", code)) } - codes[code] = msg + b_codes[code] = msg return &Error{ code: code, msg: msg, @@ -59,8 +59,8 @@ var ( UnauthoerizedTokenGenerate = NewError(1000006, "Unauthorized Token Generate") // TooManyRequests 表示请求过多 - TooManyRequests = NewError(1000007, "Too Many Requests") - + TooManyRequests = NewError(1000007, "Too Many Requests") + MethodNotAllowed = NewError(10000008, "不支持该方法") //ServerError = NewError(1000000, "server error") ) diff --git a/pkg/errcode/rpc_error.go b/pkg/errcode/rpc_error.go new file mode 100644 index 0000000..f7321e1 --- /dev/null +++ b/pkg/errcode/rpc_error.go @@ -0,0 +1,57 @@ +package errcode + +import ( + pb "github.com/lc-1010/OneBlogService/proto" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TogRPCError(err *Error) error { + s, _ := status.New(ToRPCCode(err.Code()), err.Msg()). + WithDetails(&pb.Error{ + Code: int32(err.Code()), + Message: err.Msg()}) + return s.Err() +} + +func ToRPCCode(code int) codes.Code { + var statusCode codes.Code + + switch code { + case ServerError.Code(): + statusCode = codes.Internal + case InvalidParams.Code(): + statusCode = codes.InvalidArgument + case UnauthoerizedTokenError.Code(): + statusCode = codes.Unauthenticated + case UnauthoerizedTokenTimeout.Code(): + statusCode = codes.DeadlineExceeded + case NotFound.Code(): + statusCode = codes.NotFound + case TooManyRequests.Code(): + statusCode = codes.ResourceExhausted + case MethodNotAllowed.Code(): + statusCode = codes.Unimplemented + default: + statusCode = codes.Unknown + + } + return statusCode +} + +type Status struct { + *status.Status +} + +func ToRPCStatus(code int, msg string) *Status { + s, _ := status.New(ToRPCCode((code)), msg). + WithDetails(&pb.Error{Code: int32(code), + Message: msg}) + return &Status{s} +} + +func FromError(err error) *Status { + s, _ := status.FromError(err) + return &Status{s} +} diff --git a/server/tag.go b/server/tag.go new file mode 100644 index 0000000..142a013 --- /dev/null +++ b/server/tag.go @@ -0,0 +1,40 @@ +package server + +import ( + "context" + "encoding/json" + + "github.com/lc-1010/OneBlogService/pkg/blog_api" + "github.com/lc-1010/OneBlogService/pkg/errcode" + pb "github.com/lc-1010/OneBlogService/proto" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type TagService struct { + pb.UnimplementedTagServiceServer +} + +func NewTagServer() *TagService { + return &TagService{} +} + +// GetTagList(context.Context, *GetTagListRequst) (*GetTagListReply, error) +func (t *TagService) GetTagList(c context.Context, r *pb.GetTagListRequst) (*pb.GetTagListReply, error) { + api := blog_api.NewAPI("http://127.0.0.1:8000") + body, err := api.GetTagList(c, r.GetName()) + if err != nil { + return nil, errcode.TogRPCError(errcode.ErrorGetTagListFail) + } + tagList := pb.GetTagListReply{} + err = json.Unmarshal(body, &tagList) + if err != nil { + return nil, errcode.TogRPCError(errcode.ServerError) + } + return &tagList, nil +} + +func GetClientConn(ctx context.Context, target string, opts []grpc.DialOption) (*grpc.ClientConn, error) { + opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) + return grpc.DialContext(ctx, target, opts...) +}