You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nnet/component/service.go

99 lines
2.6 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package component
import (
"fmt"
"reflect"
)
type (
// Handler 消息处理器,当前仅支持单个自定义参数
Handler struct {
Receiver reflect.Value // 方法接收者
Method reflect.Method // 方法存根
Type reflect.Type // 方法参数类型
IsRawArg bool // 数据是否需要被序列化true代表不需要
}
// Service 服务,绑定消息处理器用以处理发生的消息
Service struct {
Name string // 服务名称
Type reflect.Type // 接收者类型
Receiver reflect.Value // 该服务下所有方法的接收者
Handlers map[string]*Handler // 该服务下属的所有方法
Options options // options
}
)
func NewService(comp Component, opts []Option) *Service {
s := &Service{
Type: reflect.TypeOf(comp),
Receiver: reflect.ValueOf(comp),
}
// apply options
for _, opt := range opts {
opt(&s.Options)
}
if name := s.Options.serviceName; name != "" {
s.Name = name
} else {
s.Name = reflect.Indirect(s.Receiver).Type().Name()
}
return s
}
// suitableHandlerMethods 反射装填指定type-service的所有认定为handlerMethod的方法
func (s *Service) suitableHandlerMethods(typ reflect.Type) map[string]*Handler {
methods := make(map[string]*Handler)
for m := 0; m < typ.NumMethod(); m++ {
method := typ.Method(m)
mt := method.Type
mn := method.Name
if isHandlerMethod(method) {
raw := false
if mt.In(2) == typeOfBytes {
raw = true
}
// rewrite handler name
if s.Options.methodNameFunc != nil {
mn = s.Options.methodNameFunc(mn)
}
methods[mn] = &Handler{Method: method, Type: mt.In(2), IsRawArg: raw}
}
}
return methods
}
// ExtractHandler 反射提取满足以下条件的方法
// - 两个显示入参
// - 第一个是 *net.request
// - 另一个是 []byte 或者 任意指针类型 pointer
func (s *Service) ExtractHandler() error {
typeName := reflect.Indirect(s.Receiver).Type().Name()
if typeName == "" {
return fmt.Errorf("no service name for type %s", s.Type.String())
}
if !isExported(typeName) {
return fmt.Errorf("type %s is not exported", typeName)
}
// suitable handlers
s.Handlers = s.suitableHandlerMethods(s.Type)
if len(s.Handlers) == 0 {
method := s.suitableHandlerMethods(reflect.PtrTo(s.Type))
if len(method) == 0 {
return fmt.Errorf("type %s has no exported methods of suitable type (hint: pass a pointer to value of that type)", s.Name)
} else {
return fmt.Errorf("type %s has no exported methods of suitable type")
}
}
for _, handler := range s.Handlers {
handler.Receiver = s.Receiver
}
return nil
}