func chainStopped(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	if mixin.Stopped != nil {
		svcHook := service.Stopped
		mixinHook := mixin.Stopped
		service.Stopped = func(ctx moleculer.BrokerContext, svc moleculer.ServiceSchema) {
			mixinHook(ctx, svc)
			if svcHook != nil {
				svcHook(ctx, svc)
			}
		}
	}
	return service
}
chainStopped chain the Stope hook of services and mixins
the service.Stopped handler is called after all of the mixins Stopped
handlers are called. so all clean up is done by plugins before calling
your service Stopped function.
package service
import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"github.com/moleculer-go/moleculer"
	"github.com/moleculer-go/moleculer/payload"
	log "github.com/sirupsen/logrus"
)
type Action struct {
	name     string
	fullname string
	handler  moleculer.ActionHandler
	params   moleculer.ActionSchema
}
type Event struct {
	name        string
	serviceName string
	group       string
	handler     moleculer.EventHandler
}
func (event *Event) Handler() moleculer.EventHandler {
	return event.handler
}
func (event *Event) Name() string {
	return event.name
}
func (event *Event) ServiceName() string {
	return event.serviceName
}
func (event *Event) Group() string {
	return event.group
}
type HasName interface {
	Name() string
}
type HasVersion interface {
	Version() string
}
type HasDependencies interface {
	Dependencies() []string
}
type HasSettings interface {
	Settings() map[string]interface{}
}
type HasMetadata interface {
	Metadata() map[string]interface{}
}
type HasMixins interface {
	Mixins() []moleculer.Mixin
}
type HasEvents interface {
	Events() []moleculer.Event
}
func ParseVersion(iver interface{}) string {
	v, ok := iver.(string)
	if ok {
		return v
	}
	f, ok := iver.(float64)
	if ok {
		return fmt.Sprintf("%g", f)
	}
	i, ok := iver.(int64)
	if ok {
		return fmt.Sprintf("%d", i)
	}
	return fmt.Sprintf("%v", iver)
}
type Service struct {
	nodeID       string
	fullname     string
	name         string
	version      string
	dependencies []string
	settings     map[string]interface{}
	metadata     map[string]interface{}
	actions      []Action
	events       []Event
	created      moleculer.CreatedFunc
	started      moleculer.LifecycleFunc
	stopped      moleculer.LifecycleFunc
	schema       *moleculer.ServiceSchema
	logger       *log.Entry
}
func (service *Service) Schema() *moleculer.ServiceSchema {
	return service.schema
}
func (service *Service) NodeID() string {
	return service.nodeID
}
func (service *Service) Settings() map[string]interface{} {
	return service.settings
}
func (service *Service) SetNodeID(nodeID string) {
	service.nodeID = nodeID
}
func (service *Service) Dependencies() []string {
	return service.dependencies
}
func (serviceAction *Action) Handler() moleculer.ActionHandler {
	return serviceAction.handler
}
func (serviceAction *Action) Name() string {
	return serviceAction.name
}
func (serviceAction *Action) FullName() string {
	return serviceAction.fullname
}
func (service *Service) Name() string {
	return service.name
}
func (service *Service) FullName() string {
	return service.fullname
}
func (service *Service) Version() string {
	return service.version
}
func (service *Service) Actions() []Action {
	return service.actions
}
func (service *Service) Summary() map[string]string {
	return map[string]string{
		"name":    service.name,
		"version": service.version,
		"nodeID":  service.nodeID,
	}
}
func (service *Service) Events() []Event {
	return service.events
}
func findAction(name string, actions []moleculer.Action) bool {
	for _, a := range actions {
		if a.Name == name {
			return true
		}
	}
	return false
}
func extendActions(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	for _, ma := range mixin.Actions {
		if !findAction(ma.Name, service.Actions) {
			service.Actions = append(service.Actions, ma)
		}
	}
	return service
}
func mergeDependencies(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	list := []string{}
	for _, item := range mixin.Dependencies {
		list = append(list, item)
	}
	for _, item := range service.Dependencies {
		list = append(list, item)
	}
	service.Dependencies = list
	return service
}
func concatenateEvents(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	for _, mixinEvent := range mixin.Events {
		for _, serviceEvent := range service.Events {
			if serviceEvent.Name != mixinEvent.Name {
				service.Events = append(service.Events, mixinEvent)
			}
		}
	}
	return service
}
func MergeSettings(settings ...map[string]interface{}) map[string]interface{} {
	result := map[string]interface{}{}
	for _, set := range settings {
		if set != nil {
			for key, value := range set {
				result[key] = value
			}
		}
	}
	return result
}
func extendSettings(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	service.Settings = MergeSettings(mixin.Settings, service.Settings)
	return service
}
func extendMetadata(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	service.Metadata = MergeSettings(mixin.Metadata, service.Metadata)
	return service
}
func extendHooks(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	service.Hooks = MergeSettings(mixin.Hooks, service.Hooks)
	return service
}
func chainCreated(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	if mixin.Created != nil {
		svcHook := service.Created
		mixinHook := mixin.Created
		service.Created = func(svc moleculer.ServiceSchema, log *log.Entry) {
			mixinHook(svc, log)
			if svcHook != nil {
				svcHook(svc, log)
			}
		}
	}
	return service
}
func chainStarted(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	if mixin.Started != nil {
		svcHook := service.Started
		mixinHook := mixin.Started
		service.Started = func(ctx moleculer.BrokerContext, svc moleculer.ServiceSchema) {
			mixinHook(ctx, svc)
			if svcHook != nil {
				svcHook(ctx, svc)
			}
		}
	}
	return service
}