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
|
||||
|
||||
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