wip: 初步设计。
parent
e16ec86acd
commit
dca483dc32
@ -0,0 +1,9 @@
|
|||||||
|
package component
|
||||||
|
|
||||||
|
// Component 组件接口
|
||||||
|
type Component interface {
|
||||||
|
// OnInit 初始化组件时调用.
|
||||||
|
OnInit()
|
||||||
|
// OnShutdown 停止组件时调用.
|
||||||
|
OnShutdown()
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package component
|
||||||
|
|
||||||
|
type (
|
||||||
|
options struct {
|
||||||
|
serviceName string // 自定义服务名
|
||||||
|
methodNameFunc func(string) string // 自定义方法名钩子
|
||||||
|
}
|
||||||
|
|
||||||
|
Option func(options *options)
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithServiceName 覆盖默认生成的服务名称
|
||||||
|
func WithServiceName(name string) Option {
|
||||||
|
return func(options *options) {
|
||||||
|
options.serviceName = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMethodNameFunc 覆盖默认生成的方法名
|
||||||
|
// 当前仅支持一些基本策略,如: strings.ToUpper/strings.ToLower
|
||||||
|
// 或自行根据方法名判断后进行重写
|
||||||
|
func WithMethodNameFunc(fn func(string) string) Option {
|
||||||
|
return func(options *options) {
|
||||||
|
options.methodNameFunc = fn
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package component
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.noahlan.cn/northlan/nnet/net"
|
||||||
|
"reflect"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
||||||
|
typeOfBytes = reflect.TypeOf(([]byte)(nil))
|
||||||
|
typeOfRequest = reflect.TypeOf(net.Request{})
|
||||||
|
)
|
||||||
|
|
||||||
|
func isExported(name string) bool {
|
||||||
|
w, _ := utf8.DecodeRuneInString(name)
|
||||||
|
return unicode.IsUpper(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
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() == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHandlerMethod(method reflect.Method) bool {
|
||||||
|
mt := method.Type
|
||||||
|
// 必须是可导出的
|
||||||
|
if isExportedOrBuiltinType(mt) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 必须具有3个入参: receiver, *Request, []byte/pointer
|
||||||
|
// receiver指代 func (*receiver) xxx() 的receiver部分
|
||||||
|
if mt.NumIn() != 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 至少要有一个出参 且是error
|
||||||
|
if mt.NumOut() < 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第一个显式入参必须是*Request
|
||||||
|
if t1 := mt.In(1); t1.Kind() != reflect.Ptr || t1 != typeOfRequest {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第二个显式入参必须是 []byte 或者 任意pointer
|
||||||
|
if t2 := mt.In(2); t2.Kind() != reflect.Ptr || t2 != typeOfBytes {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最后一个出参必须是error
|
||||||
|
if o1 := mt.Out(mt.NumOut() - 1); o1 != typeOfError {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
@ -1,5 +1,9 @@
|
|||||||
module git.noahlan.cn/northlan/nnet
|
module git.noahlan.cn/northlan/nnet
|
||||||
|
|
||||||
go 1.18
|
go 1.19
|
||||||
|
|
||||||
require google.golang.org/protobuf v1.28.1 // indirect
|
require (
|
||||||
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
|
github.com/panjf2000/ants/v2 v2.6.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.28.1 // indirect
|
||||||
|
)
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package interfaces
|
||||||
|
|
||||||
|
// IRouter 路由接口
|
||||||
|
type IRouter interface {
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"git.noahlan.cn/northlan/nnet/component"
|
||||||
|
"github.com/panjf2000/ants/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
allServices map[string]*component.Service // 所有注册的Service
|
||||||
|
allHandlers map[string]*component.Handler // 所有注册的Handler
|
||||||
|
|
||||||
|
workerSize int64 // 业务工作Worker数量
|
||||||
|
taskQueue []chan *Request // 工作协程的消息队列
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler() *Handler {
|
||||||
|
return &Handler{
|
||||||
|
allServices: make(map[string]*component.Service),
|
||||||
|
allHandlers: make(map[string]*component.Handler),
|
||||||
|
// TODO 读取配置
|
||||||
|
workerSize: 10,
|
||||||
|
taskQueue: make([]chan *Request, 10),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) register(comp component.Component, opts []component.Option) error {
|
||||||
|
s := component.NewService(comp, opts)
|
||||||
|
|
||||||
|
p, _ := ants.NewPool()
|
||||||
|
p.Submit(func() {
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
if _, ok := h.allServices[s.Name]; ok {
|
||||||
|
return fmt.Errorf("handler: service already defined: %s", s.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.ExtractHandler(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
h.allServices[s.Name] = s
|
||||||
|
|
||||||
|
// 拷贝一份所有handlers
|
||||||
|
for name, handler := range s.Handlers {
|
||||||
|
handleName := fmt.Sprintf("%s.%s", s.Name, name)
|
||||||
|
// TODO print log
|
||||||
|
h.allHandlers[handleName] = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoWorker 将工作交给worker处理
|
||||||
|
func (h *Handler) DoWorker(request *Request) {
|
||||||
|
// 根据sessionID平均分配worker处理
|
||||||
|
workerId := request.Session.ID() % h.workerSize
|
||||||
|
fmt.Printf("sessionID %d to workerID %d\n", request.Session.ID(), workerId)
|
||||||
|
// 入队
|
||||||
|
h.taskQueue[workerId] <- request
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) handle(request *Request) {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
type Option func(server *Server)
|
||||||
|
|
||||||
|
func WithXXX() Option {
|
||||||
|
return func(server *Server) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.noahlan.cn/northlan/nnet/interfaces"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
session interfaces.ISession // Session
|
||||||
|
|
||||||
|
server *Server // Server reference
|
||||||
|
conn net.Conn // low-level conn fd
|
||||||
|
status Status // 连接状态
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRequest(server *Server, conn net.Conn) *Request {
|
||||||
|
r := &Request{
|
||||||
|
server: server,
|
||||||
|
conn: conn,
|
||||||
|
status: StatusStart,
|
||||||
|
}
|
||||||
|
|
||||||
|
r.session = newSession()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Status() Status {
|
||||||
|
return r.status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) ID() int64 {
|
||||||
|
return r.session.ID()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Session() interfaces.ISession {
|
||||||
|
return r.session
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.noahlan.cn/northlan/nnet/interfaces"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SessionMgr struct {
|
||||||
|
sync.RWMutex
|
||||||
|
sessions map[int64]interfaces.ISession
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SessionMgr) storeSession(s interfaces.ISession) {
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
|
||||||
|
m.sessions[s.ID()] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SessionMgr) findSession(sid int64) interfaces.ISession {
|
||||||
|
m.RLock()
|
||||||
|
defer m.RUnlock()
|
||||||
|
|
||||||
|
return m.sessions[sid]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SessionMgr) findOrCreateSession(sid int64) interfaces.ISession {
|
||||||
|
m.RLock()
|
||||||
|
s, ok := m.sessions[sid]
|
||||||
|
m.RUnlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
s = newSession()
|
||||||
|
|
||||||
|
m.Lock()
|
||||||
|
m.sessions[s.ID()] = s
|
||||||
|
m.Unlock()
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
type Status uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// StatusStart 开始阶段
|
||||||
|
StatusStart Status = iota + 1
|
||||||
|
// StatusPrepare 准备阶段
|
||||||
|
StatusPrepare
|
||||||
|
// StatusWorking 工作阶段
|
||||||
|
StatusWorking
|
||||||
|
// StatusClosed 连接关闭
|
||||||
|
StatusClosed
|
||||||
|
)
|
Loading…
Reference in New Issue