func (s *Server) SubRoute(pathPrefix string, plugin ...erpc.Plugin) *erpc.SubRouter {
	return s.peer.SubRoute(pathPrefix, plugin...)
}
SubRoute adds handler group.
package micro
import (
	"fmt"
	"net"
	"strconv"
	"time"
	"github.com/henrylee2cn/cfgo"
	"github.com/henrylee2cn/erpc/v6"
	"github.com/henrylee2cn/erpc/v6/plugin/binder"
	"github.com/henrylee2cn/erpc/v6/plugin/heartbeat"
)
type SrvConfig struct {
	Network           string        `yaml:"network"              ini:"network"              comment:"Network; tcp, tcp4, tcp6, unix or unixpacket"`
	ListenAddress     string        `yaml:"listen_address"       ini:"listen_address"       comment:"Listen address; for server role"`
	TlsCertFile       string        `yaml:"tls_cert_file"        ini:"tls_cert_file"        comment:"TLS certificate file path"`
	TlsKeyFile        string        `yaml:"tls_key_file"         ini:"tls_key_file"         comment:"TLS key file path"`
	DefaultSessionAge time.Duration `yaml:"default_session_age"  ini:"default_session_age"  comment:"Default session max age, if less than or equal to 0, no time limit; ns,µs,ms,s,m,h"`
	DefaultContextAge time.Duration `yaml:"default_context_age"  ini:"default_context_age"  comment:"Default CALL or PUSH context max age, if less than or equal to 0, no time limit; ns,µs,ms,s,m,h"`
	SlowCometDuration time.Duration `yaml:"slow_comet_duration"  ini:"slow_comet_duration"  comment:"Slow operation alarm threshold; ns,µs,ms,s ..."`
	DefaultBodyCodec  string        `yaml:"default_body_codec"   ini:"default_body_codec"   comment:"Default body codec type id"`
	PrintDetail       bool          `yaml:"print_detail"         ini:"print_detail"         comment:"Is print body and metadata or not"`
	CountTime         bool          `yaml:"count_time"           ini:"count_time"           comment:"Is count cost time or not"`
	EnableHeartbeat   bool          `yaml:"enable_heartbeat"     ini:"enable_heartbeat"     comment:"enable heartbeat"`
}
func (s *SrvConfig) Reload(bind cfgo.BindFunc) error {
	err := bind()
	if len(s.Network) == 0 {
		s.Network = "tcp"
	}
	if len(s.ListenAddress) == 0 {
		s.ListenAddress = "0.0.0.0:9090"
	}
	return err
}
func (s *SrvConfig) ListenPort() string {
	_, port, err := net.SplitHostPort(s.ListenAddress)
	if err != nil {
		erpc.Fatalf("%v", err)
	}
	return port
}
func (s *SrvConfig) InnerIpPort() string {
	hostPort, err := InnerIpPort(s.ListenPort())
	if err != nil {
		erpc.Fatalf("%v", err)
	}
	return hostPort
}
func (s *SrvConfig) OuterIpPort() string {
	hostPort, err := OuterIpPort(s.ListenPort())
	if err != nil {
		erpc.Fatalf("%v", err)
	}
	return hostPort
}
func (s *SrvConfig) PeerConfig() erpc.PeerConfig {
	host, port, err := net.SplitHostPort(s.ListenAddress)
	if err != nil {
		erpc.Fatalf("%v", err)
	}
	listenPort, _ := strconv.Atoi(port)
	return erpc.PeerConfig{
		DefaultSessionAge: s.DefaultSessionAge,
		DefaultContextAge: s.DefaultContextAge,
		SlowCometDuration: s.SlowCometDuration,
		DefaultBodyCodec:  s.DefaultBodyCodec,
		PrintDetail:       s.PrintDetail,
		CountTime:         s.CountTime,
		Network:           s.Network,
		LocalIP:           host,
		ListenPort:        uint16(listenPort),
	}
}
type Server struct {
	peer   erpc.Peer
	binder *binder.StructArgsBinder
}
func NewServer(cfg SrvConfig, globalLeftPlugin ...erpc.Plugin) *Server {
	doInit()
	if cfg.EnableHeartbeat {
		globalLeftPlugin = append(globalLeftPlugin, heartbeat.NewPong())
	}
	peer := erpc.NewPeer(cfg.PeerConfig(), globalLeftPlugin...)
	binder := binder.NewStructArgsBinder(nil)
	peer.PluginContainer().AppendRight(binder)
	if len(cfg.TlsCertFile) > 0 && len(cfg.TlsKeyFile) > 0 {
		err := peer.SetTLSConfigFromFile(cfg.TlsCertFile, cfg.TlsKeyFile)
		if err != nil {
			erpc.Fatalf("%v", err)
		}
	}
	s := &Server{
		peer:   peer,
		binder: binder,
	}
	s.SetBindErrorFunc(nil)
	return s
}
func (s *Server) Peer() erpc.Peer {
	return s.peer
}
func (s *Server) PluginContainer() *erpc.PluginContainer {
	return s.peer.PluginContainer()
}
func (s *Server) SetBindErrorFunc(fn binder.ErrorFunc) {
	if fn != nil {
		s.binder.SetErrorFunc(fn)
		return
	}
	s.binder.SetErrorFunc(func(handlerName, paramName, reason string) *erpc.Status {
		return RerrInvalidParameter.SetCause(fmt.Sprintf(`{"handler": %q, "param": %q, "reason": %q}`, handlerName, paramName, reason))
	})
}
func (s *Server) Router() *erpc.Router {
	return s.peer.Router()
}