Skip to content

Commit

Permalink
feature: override service route
Browse files Browse the repository at this point in the history
  • Loading branch information
lonng committed Sep 29, 2017
1 parent a5266d0 commit 2fc1b8f
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 59 deletions.
17 changes: 11 additions & 6 deletions component.go
Expand Up @@ -25,23 +25,28 @@ import (
)

var (
comps = make([]component.Component, 0)
comps = make([]regComp, 0)
)

type regComp struct {
comp component.Component
opts []component.Option
}

func startupComponents() {
// component initialize hooks
for _, c := range comps {
c.Init()
c.comp.Init()
}

// component after initialize hooks
for _, c := range comps {
c.AfterInit()
c.comp.AfterInit()
}

// register all components
for _, c := range comps {
if err := handler.register(c); err != nil {
if err := handler.register(c.comp, c.opts); err != nil {
logger.Println(err.Error())
}
}
Expand All @@ -53,11 +58,11 @@ func shutdownComponents() {
// reverse call `BeforeShutdown` hooks
length := len(comps)
for i := length - 1; i >= 0; i-- {
comps[i].BeforeShutdown()
comps[i].comp.BeforeShutdown()
}

// reverse call `Shutdown` hooks
for i := length - 1; i >= 0; i-- {
comps[i].Shutdown()
comps[i].comp.Shutdown()
}
}
18 changes: 0 additions & 18 deletions component/method.go
Expand Up @@ -75,21 +75,3 @@ func isHandlerMethod(method reflect.Method) bool {
}
return true
}

// suitableMethods returns suitable methods of typ
func 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
}
methods[mn] = &Handler{Method: method, Type: mt.In(2), IsRawArg: raw}
}
}
return methods
}
26 changes: 26 additions & 0 deletions component/options.go
@@ -0,0 +1,26 @@
package component

type (
options struct {
name string // component name
nameFunc func(string) string // rename handler name
}

// Option used to customize handler
Option func(options *options)
)

// WithName used to rename component name
func WithName(name string) Option {
return func(opt *options) {
opt.name = name
}
}

// WithNameFunc override handler name by specific function
// such as: strings.ToUpper/strings.ToLower
func WithNameFunc(fn func(string) string) Option {
return func(opt *options) {
opt.nameFunc = fn
}
}
89 changes: 68 additions & 21 deletions component/service.go
Expand Up @@ -25,21 +25,67 @@ import (
"reflect"
)

//Handler represents a message.Message's handler's meta information.
type Handler struct {
Receiver reflect.Value // receiver of method
Method reflect.Method // method stub
Type reflect.Type // low-level type of method
IsRawArg bool // whether the data need to serialize
type (
//Handler represents a message.Message's handler's meta information.
//Handler represents a message.Message's handler's meta information.
Handler struct {
Receiver reflect.Value // receiver of method
Method reflect.Method // method stub
Type reflect.Type // low-level type of method
IsRawArg bool // whether the data need to serialize
}

// Service implements a specific service, some of it's methods will be
// called when the correspond events is occurred.
Service struct {
Name string // name of service
Type reflect.Type // type of the receiver
Receiver reflect.Value // receiver of methods for the service
Handlers map[string]*Handler // registered methods
Options options // options
}
)

func NewService(comp Component, opts []Option) *Service {
s := &Service{
Type: reflect.TypeOf(comp),
Receiver: reflect.ValueOf(comp),
}

// apply options
for i := range opts {
opt := opts[i]
opt(&s.Options)
}
if name := s.Options.name; name != "" {
s.Name = name
} else {
s.Name = reflect.Indirect(s.Receiver).Type().Name()
}

return s
}

// Service implements a specific service, some of it's methods will be
// called when the correspond events is occurred.
type Service struct {
Name string // name of service
Receiver reflect.Value // receiver of methods for the service
Type reflect.Type // type of the receiver
Methods map[string]*Handler // registered methods
// suitableMethods returns suitable methods of typ
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.nameFunc != nil {
mn = s.Options.nameFunc(mn)
}
methods[mn] = &Handler{Method: method, Type: mt.In(2), IsRawArg: raw}
}
}
return methods
}

// ExtractHandler extract the set of methods from the
Expand All @@ -49,20 +95,21 @@ type Service struct {
// - the first argument is *session.Session
// - the second argument is []byte or a pointer
func (s *Service) ExtractHandler() error {
if s.Name == "" {
typeName := reflect.Indirect(s.Receiver).Type().Name()
if typeName == "" {
return errors.New("no service name for type " + s.Type.String())
}
if !isExported(s.Name) {
return errors.New("type " + s.Name + " is not exported")
if !isExported(typeName) {
return errors.New("type " + typeName + " is not exported")
}

// Install the methods
s.Methods = suitableHandlerMethods(s.Type)
s.Handlers = s.suitableHandlerMethods(s.Type)

if len(s.Methods) == 0 {
if len(s.Handlers) == 0 {
str := ""
// To help the user, see if a pointer receiver would work.
method := suitableHandlerMethods(reflect.PtrTo(s.Type))
method := s.suitableHandlerMethods(reflect.PtrTo(s.Type))
if len(method) != 0 {
str = "type " + s.Name + " has no exported methods of suitable type (hint: pass a pointer to value of that type)"
} else {
Expand All @@ -71,8 +118,8 @@ func (s *Service) ExtractHandler() error {
return errors.New(str)
}

for i := range s.Methods {
s.Methods[i].Receiver = s.Receiver
for i := range s.Handlers {
s.Handlers[i].Receiver = s.Receiver
}

return nil
Expand Down
10 changes: 9 additions & 1 deletion examples/demo/chat/main.go
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/lonnng/nano/component"
"github.com/lonnng/nano/serialize/json"
"github.com/lonnng/nano/session"
"strings"
)

type (
Expand Down Expand Up @@ -79,8 +80,15 @@ func (r *Room) Message(s *session.Session, msg *UserMessage) error {
}

func main() {
nano.Register(NewRoom())
// override default serializer
nano.SetSerializer(json.NewSerializer())

// rewrite component and handler name
nano.Register(NewRoom(),
component.WithName("room"),
component.WithNameFunc(strings.ToLower),
)

nano.EnableDebug()
log.SetFlags(log.LstdFlags | log.Llongfile)

Expand Down
4 changes: 2 additions & 2 deletions examples/demo/chat/web/index.html
Expand Up @@ -30,7 +30,7 @@
methods: {
sendMessage: function () {
console.log(this.inputMessage);
starx.notify('Room.Message', {name: this.nickname, content: this.inputMessage});
starx.notify('room.message', {name: this.nickname, content: this.inputMessage});
this.inputMessage = '';
}
}
Expand Down Expand Up @@ -62,7 +62,7 @@
console.log("initialized");
starx.on("onNewUser", onNewUser);
starx.on("onMembers", onMembers);
starx.request("Room.Join", {}, join);
starx.request("room.join", {}, join);
})
</script>
</body>
Expand Down
12 changes: 4 additions & 8 deletions handler.go
Expand Up @@ -160,12 +160,8 @@ func (h *handlerService) dispatch() {
}
}

func (h *handlerService) register(c component.Component) error {
s := &component.Service{
Type: reflect.TypeOf(c),
Receiver: reflect.ValueOf(c),
}
s.Name = reflect.Indirect(s.Receiver).Type().Name()
func (h *handlerService) register(comp component.Component, opts []component.Option) error {
s := component.NewService(comp, opts)

if _, ok := h.services[s.Name]; ok {
return fmt.Errorf("handler: service already defined: %s", s.Name)
Expand All @@ -177,8 +173,8 @@ func (h *handlerService) register(c component.Component) error {

// register all handlers
h.services[s.Name] = s
for name, method := range s.Methods {
h.handlers[fmt.Sprintf("%s.%s", s.Name, name)] = method
for name, handler := range s.Handlers {
h.handlers[fmt.Sprintf("%s.%s", s.Name, name)] = handler
}
return nil
}
Expand Down
6 changes: 3 additions & 3 deletions interface.go
Expand Up @@ -42,9 +42,9 @@ func ListenWS(addr string) {
listen(addr, true)
}

// Register register a component
func Register(c component.Component) {
comps = append(comps, c)
// Register register a component with options
func Register(c component.Component, options ...component.Option) {
comps = append(comps, regComp{c, options})
}

// SetHeartbeatInterval set heartbeat time interval
Expand Down

0 comments on commit 2fc1b8f

Please sign in to comment.