Skip to content

Commit

Permalink
kao
Browse files Browse the repository at this point in the history
  • Loading branch information
coderyw committed Sep 4, 2024
1 parent e2fd9c7 commit 55d65fe
Show file tree
Hide file tree
Showing 6 changed files with 404 additions and 103 deletions.
220 changes: 118 additions & 102 deletions gogoproto/gogo.gogo.pb.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions gogoproto/gogo.proto
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ message Router{
optional string router_path = 1;
//插件
repeated string plugins = 3;
// http method
optional string method = 4;
}

extend google.protobuf.MessageOptions {
Expand Down
9 changes: 8 additions & 1 deletion keyreflect/route/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ type Router struct {
// 插件
Plugins map[string]struct{}

Method string

req reflect.Type
resp reflect.Type
}
Expand All @@ -43,7 +45,11 @@ func (r *Router) RespI() (interface{}, error) {
return reflect.New(r.resp).Interface(), nil
}

func Register(serverName, endpoint, path string, plugins []string, req interface{}, resp interface{}) {
func GetAllRouter() map[string]*Router {
return m
}

func Register(serverName, endpoint, path, method string, plugins []string, req interface{}, resp interface{}) {
var reqType reflect.Type
var respType reflect.Type
if req != nil {
Expand Down Expand Up @@ -75,6 +81,7 @@ func Register(serverName, endpoint, path string, plugins []string, req interface
Path: path,
req: reqType,
resp: respType,
Method: method,
Plugins: make(map[string]struct{}),
}
for _, v := range plugins {
Expand Down
96 changes: 96 additions & 0 deletions keyreflect/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,99 @@
// @Date: 2024/9/3 17:29

package keyreflect

import (
"context"
"fmt"
"reflect"
"strings"
)

func RegisterGinRouter(handler interface{}) error {
return rs.register(handler)
}

func GinRouterHandler(ctx context.Context, endpoint string, decode func(interface{}) error) (interface{}, error) {

//m := route.GetAllRouter()
//if m == nil {
// return nil, fmt.Errorf("miss router")
//}
//r,ok:= m[path]
//if !ok{
// return nil, fmt.Errorf("")
//}

serviceName, methodName, err := serviceMethod(endpoint)
if err != nil {
return nil, err
}
rs.mu.Lock()
service := rs.serviceMap[serviceName]
rs.mu.Unlock()
if service == nil {
return nil, fmt.Errorf("unknown router service:%v", serviceName)
}
mtype := service.method[methodName]
if mtype == nil {
return nil, fmt.Errorf("unknown service %s.%s", serviceName, methodName)
}
return processRequest(service, mtype, decode, ctx)
}

func processRequest(service *service, mtype *methodType, decode func(interface{}) error, ctx context.Context) (interface{}, error) {
var argv, replyv reflect.Value
// Decode the argument value.
argIsValue := false // if true, need to indirect before calling.
if mtype.ArgType.Kind() == reflect.Ptr {
argv = reflect.New(mtype.ArgType.Elem())
} else {
argv = reflect.New(mtype.ArgType)
argIsValue = true
}
if err := decode(argv.Interface()); err != nil {
return nil, err
}
if argIsValue {
argv = argv.Elem()
}
replyv = reflect.New(mtype.ReplyType.Elem())

function := mtype.method.Func
var returnValues []reflect.Value

returnValues = function.Call([]reflect.Value{service.rcvr, mtype.prepareContext(ctx), argv, replyv})
if rerr := returnValues[0].Interface(); rerr != nil {
return nil, rerr.(error)
}
return replyv.Interface(), nil
}

func serviceMethod(m string) (string, string, error) {
if len(m) == 0 {
return "", "", fmt.Errorf("malformed method name: %q", m)
}

// grpc method
if m[0] == '/' {
// [ , Foo, Bar]
// [ , package.Foo, Bar]
// [ , a.package.Foo, Bar]
parts := strings.Split(m, "/")
if len(parts) != 3 || len(parts[1]) == 0 || len(parts[2]) == 0 {
return "", "", fmt.Errorf("malformed method name: %q", m)
}
service := strings.Split(parts[1], ".")
return service[len(service)-1], parts[2], nil
}

// non grpc method
parts := strings.Split(m, ".")

// expect [Foo, Bar]
if len(parts) != 2 {
return "", "", fmt.Errorf("malformed method name: %q", m)
}

return parts[0], parts[1], nil
}
164 changes: 164 additions & 0 deletions keyreflect/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,167 @@
// @Date: 2024/9/3 17:19

package keyreflect

import (
"context"
"errors"
"github.com/coderyw/protobuf/log"
"reflect"
"sync"
"unicode"
"unicode/utf8"
)

var (
// Precompute the reflect type for error. Can't use error directly
// because Typeof takes an empty interface value. This is annoying.
typeOfError = reflect.TypeOf((*error)(nil)).Elem()

rs *rServer = &rServer{
mu: sync.Mutex{},
serviceMap: make(map[string]*service),
}
)

type methodType struct {
method reflect.Method
ArgType reflect.Type
ReplyType reflect.Type
ContextType reflect.Type
}

type service struct {
name string // name of service
rcvr reflect.Value // receiver of methods for the service
typ reflect.Type // type of the receiver
method map[string]*methodType // registered methods
}

// server represents an RPC Server.
type rServer struct {
mu sync.Mutex // protects the serviceMap
serviceMap map[string]*service
}

// Is this an exported - upper case - name?
func isExported(name string) bool {
rune, _ := utf8.DecodeRuneInString(name)
return unicode.IsUpper(rune)
}

// Is this type exported or a builtin?
func isExportedOrBuiltinType(t reflect.Type) bool {
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
// PkgPath will be non-empty even for an exported type,
// so we need to check the type name as well.
return isExported(t.Name()) || t.PkgPath() == ""
}

// prepareEndpoint() returns a methodType for the provided method or nil
// in case if the method was unsuitable.
func prepareEndpoint(method reflect.Method) *methodType {
mtype := method.Type
mname := method.Name
var replyType, argType, contextType reflect.Type

// Endpoint() must be exported.
if method.PkgPath != "" {
return nil
}

switch mtype.NumIn() {
case 3:
// assuming streaming
argType = mtype.In(2)
contextType = mtype.In(1)
case 4:
// method that takes a context
argType = mtype.In(2)
replyType = mtype.In(3)
contextType = mtype.In(1)
default:
log.Info("method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn())
return nil
}

// if not stream check the replyType

// First arg need not be a pointer.
if !isExportedOrBuiltinType(argType) {
log.Info("%v argument type not exported: %v", mname, argType)
return nil
}

if replyType.Kind() != reflect.Ptr {
log.Info("method %v reply type not a pointer: %v", mname, replyType)
return nil
}

// Reply type must be exported.
if !isExportedOrBuiltinType(replyType) {
log.Info("method %v reply type not exported: %v", mname, replyType)
return nil
}

// Endpoint() needs one out.
if mtype.NumOut() != 1 {
log.Info("method %v has wrong number of outs: %v", mname, mtype.NumOut())
return nil
}
// The return type of the method must be error.
if returnType := mtype.Out(0); returnType != typeOfError {
log.Info("method %v returns %v not error", mname, returnType.String())
return nil
}
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType}
}

func (server *rServer) register(rcvr interface{}) error {
server.mu.Lock()
defer server.mu.Unlock()
if server.serviceMap == nil {
server.serviceMap = make(map[string]*service)
}
s := new(service)
s.typ = reflect.TypeOf(rcvr)
s.rcvr = reflect.ValueOf(rcvr)
sname := reflect.Indirect(s.rcvr).Type().Name()
if sname == "" {
log.Fatalf("rpc: no service name for type %v", s.typ.String())
}
if !isExported(sname) {
s := "rpc Register: type " + sname + " is not exported"
log.Info(s)
return errors.New(s)
}
if _, present := server.serviceMap[sname]; present {
return errors.New("rpc: service already defined: " + sname)
}
s.name = sname
s.method = make(map[string]*methodType)

// Install the methods
for m := 0; m < s.typ.NumMethod(); m++ {
method := s.typ.Method(m)
if mt := prepareEndpoint(method); mt != nil {
s.method[method.Name] = mt
}
}

if len(s.method) == 0 {
s := "rpc Register: type " + sname + " has no exported methods of suitable type"
log.Info(s)
return errors.New(s)
}
server.serviceMap[s.name] = s
return nil
}

func (m *methodType) prepareContext(ctx context.Context) reflect.Value {
if contextv := reflect.ValueOf(ctx); contextv.IsValid() {
return contextv
}
return reflect.Zero(m.ContextType)
}
16 changes: 16 additions & 0 deletions log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ package log

type Logger interface {
Error(msg string, err error)
Info(msg string, args ...interface{})
Fatalf(msg string, args ...interface{})
}

var logger Logger
Expand All @@ -22,3 +24,17 @@ func Error(msg string, err error) {
}
logger.Error(msg, err)
}

func Info(msg string, args ...interface{}) {
if logger == nil {
return
}
logger.Info(msg, args...)
}

func Fatalf(msg string, args ...interface{}) {
if logger == nil {
return
}
logger.Fatalf(msg, args...)
}

0 comments on commit 55d65fe

Please sign in to comment.