wip: 又加了一些新东西。
parent
dca483dc32
commit
5779bb7989
@ -0,0 +1,20 @@
|
||||
package component
|
||||
|
||||
type CompWithOptions struct {
|
||||
Comp Component
|
||||
Opts []Option
|
||||
}
|
||||
|
||||
type Components struct {
|
||||
comps []CompWithOptions
|
||||
}
|
||||
|
||||
// Register 全局注册组件,必须在服务启动之前初始化
|
||||
func (cs *Components) Register(c Component, options ...Option) {
|
||||
cs.comps = append(cs.comps, CompWithOptions{c, options})
|
||||
}
|
||||
|
||||
// List 获取所有已注册组件
|
||||
func (cs *Components) List() []CompWithOptions {
|
||||
return cs.comps
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
package interfaces
|
||||
|
||||
type IMessage interface {
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Logger interface {
|
||||
Debugf(format string, v ...interface{})
|
||||
Debug(v ...interface{})
|
||||
Info(v ...interface{})
|
||||
Infof(format string, v ...interface{})
|
||||
Error(v ...interface{})
|
||||
Errorf(format string, v ...interface{})
|
||||
Panic(v ...interface{})
|
||||
Panicf(format string, v ...interface{})
|
||||
}
|
||||
|
||||
func init() {
|
||||
SetLogger(newInnerLogger())
|
||||
}
|
||||
|
||||
var (
|
||||
Debugf func(format string, v ...interface{})
|
||||
Debug func(v ...interface{})
|
||||
Info func(v ...interface{})
|
||||
Infof func(format string, v ...interface{})
|
||||
Error func(v ...interface{})
|
||||
Errorf func(format string, v ...interface{})
|
||||
Panic func(v ...interface{})
|
||||
Panicf func(format string, v ...interface{})
|
||||
)
|
||||
|
||||
func SetLogger(logger Logger) {
|
||||
if logger == nil {
|
||||
return
|
||||
}
|
||||
Debugf = logger.Debugf
|
||||
Debug = logger.Debug
|
||||
Info = logger.Info
|
||||
Infof = logger.Infof
|
||||
Error = logger.Error
|
||||
Errorf = logger.Errorf
|
||||
Panic = logger.Panic
|
||||
Panicf = logger.Panicf
|
||||
}
|
||||
|
||||
type innerLogger struct {
|
||||
log *log.Logger
|
||||
}
|
||||
|
||||
func newInnerLogger() Logger {
|
||||
return &innerLogger{
|
||||
log: log.New(os.Stderr, "[N-Net] ", log.LstdFlags|log.Lshortfile),
|
||||
}
|
||||
}
|
||||
|
||||
func (i *innerLogger) Debugf(format string, v ...interface{}) {
|
||||
i.log.Printf(format, v)
|
||||
}
|
||||
|
||||
func (i *innerLogger) Debug(v ...interface{}) {
|
||||
i.log.Println(v)
|
||||
}
|
||||
|
||||
func (i *innerLogger) Info(v ...interface{}) {
|
||||
i.log.Println(v)
|
||||
}
|
||||
|
||||
func (i *innerLogger) Infof(format string, v ...interface{}) {
|
||||
i.log.Printf(format, v)
|
||||
}
|
||||
|
||||
func (i *innerLogger) Error(v ...interface{}) {
|
||||
i.log.Println(v)
|
||||
}
|
||||
|
||||
func (i *innerLogger) Errorf(format string, v ...interface{}) {
|
||||
i.log.Printf(format, v)
|
||||
}
|
||||
|
||||
func (i *innerLogger) Panic(v ...interface{}) {
|
||||
i.log.Panic(v)
|
||||
}
|
||||
|
||||
func (i *innerLogger) Panicf(format string, v ...interface{}) {
|
||||
i.log.Panicf(format, v)
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package message
|
||||
|
||||
type Header struct {
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Type byte // 消息类型
|
||||
ID uint64 // 消息ID
|
||||
Header []byte // 消息头原始数据
|
||||
Payload []byte // 数据
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package net
|
||||
|
||||
type Option func(server *Server)
|
||||
|
||||
func WithXXX() Option {
|
||||
return func(server *Server) {
|
||||
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package interfaces
|
||||
package nface
|
||||
|
||||
// IRouter 路由接口
|
||||
type IRouter interface {
|
@ -1,4 +1,4 @@
|
||||
package interfaces
|
||||
package nface
|
||||
|
||||
// ISessionAttribute Session数据接口
|
||||
type ISessionAttribute interface {
|
@ -0,0 +1,57 @@
|
||||
package nnet
|
||||
|
||||
import (
|
||||
"git.noahlan.cn/northlan/nnet/component"
|
||||
"git.noahlan.cn/northlan/nnet/log"
|
||||
"git.noahlan.cn/northlan/nnet/pipeline"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Option func(options *Options)
|
||||
type WSOption func(opts *WSOptions)
|
||||
|
||||
func WithLogger(logger log.Logger) Option {
|
||||
return func(_ *Options) {
|
||||
log.SetLogger(logger)
|
||||
}
|
||||
}
|
||||
|
||||
func WithPipeline(pipeline pipeline.Pipeline) Option {
|
||||
return func(options *Options) {
|
||||
options.Pipeline = pipeline
|
||||
}
|
||||
}
|
||||
|
||||
func WithComponents(components *component.Components) Option {
|
||||
return func(options *Options) {
|
||||
options.Components = components
|
||||
}
|
||||
}
|
||||
|
||||
func WithHeartbeatInterval(d time.Duration) Option {
|
||||
return func(options *Options) {
|
||||
options.HeartbeatInterval = d
|
||||
}
|
||||
}
|
||||
|
||||
func WithWebsocket(wsOpts ...WSOption) Option {
|
||||
return func(options *Options) {
|
||||
for _, opt := range wsOpts {
|
||||
opt(&options.WS)
|
||||
}
|
||||
options.WS.IsWebsocket = true
|
||||
}
|
||||
}
|
||||
|
||||
func WithWSPath(path string) WSOption {
|
||||
return func(opts *WSOptions) {
|
||||
opts.WebsocketPath = path
|
||||
}
|
||||
}
|
||||
|
||||
func WithWSTLS(certificate, key string) WSOption {
|
||||
return func(opts *WSOptions) {
|
||||
opts.TLSCertificate = certificate
|
||||
opts.TLSKey = key
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package nnet
|
||||
|
||||
import "github.com/panjf2000/ants/v2"
|
||||
|
||||
var pool *Pool
|
||||
|
||||
type Pool struct {
|
||||
connPool *ants.Pool
|
||||
workerPool *ants.Pool
|
||||
}
|
||||
|
||||
func initPool(size int) {
|
||||
p := &Pool{}
|
||||
|
||||
p.connPool, _ = ants.NewPool(size, ants.WithNonblocking(true))
|
||||
p.workerPool, _ = ants.NewPool(size*2, ants.WithNonblocking(true))
|
||||
|
||||
pool = p
|
||||
}
|
||||
|
||||
func (p *Pool) SubmitConn(h func()) error {
|
||||
return p.connPool.Submit(h)
|
||||
}
|
||||
|
||||
func (p *Pool) SubmitWorker(h func()) error {
|
||||
return p.workerPool.Submit(h)
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package nnet
|
||||
|
||||
import (
|
||||
"git.noahlan.cn/northlan/nnet/nface"
|
||||
"git.noahlan.cn/northlan/nnet/pipeline"
|
||||
"git.noahlan.cn/northlan/nnet/session"
|
||||
"github.com/gorilla/websocket"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
session nface.ISession // Session
|
||||
|
||||
conn net.Conn // low-level conn fd
|
||||
status Status // 连接状态
|
||||
lastMid uint64 // 最近一次消息ID
|
||||
lastHeartbeatAt int64 // 最近一次心跳时间
|
||||
|
||||
chDie chan struct{} // 停止通道
|
||||
chSend chan []byte // 消息发送通道
|
||||
|
||||
pipeline pipeline.Pipeline // 消息管道
|
||||
}
|
||||
|
||||
func newRequest(conn net.Conn, pipeline pipeline.Pipeline) *Request {
|
||||
r := &Request{
|
||||
conn: conn,
|
||||
status: StatusStart,
|
||||
|
||||
lastHeartbeatAt: time.Now().Unix(),
|
||||
|
||||
chDie: make(chan struct{}),
|
||||
chSend: make(chan []byte),
|
||||
|
||||
pipeline: pipeline,
|
||||
}
|
||||
|
||||
// binding session
|
||||
r.session = session.New()
|
||||
return r
|
||||
}
|
||||
|
||||
func newRequestWS(conn *websocket.Conn, pipeline pipeline.Pipeline) *Request {
|
||||
c, err := newWSConn(conn)
|
||||
if err != nil {
|
||||
// TODO panic ?
|
||||
panic(err)
|
||||
}
|
||||
return newRequest(c, pipeline)
|
||||
}
|
||||
|
||||
func (r *Request) Status() Status {
|
||||
return r.status
|
||||
}
|
||||
|
||||
func (r *Request) ID() int64 {
|
||||
return r.session.ID()
|
||||
}
|
||||
|
||||
func (r *Request) Session() nface.ISession {
|
||||
return r.session
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package net
|
||||
package nnet
|
||||
|
||||
type Status uint8
|
||||
|
@ -0,0 +1,114 @@
|
||||
package nnet
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// wsConn 封装 websocket.Conn 并实现所有 net.Conn 接口
|
||||
// 兼容所有使用 net.Conn 的方法
|
||||
type wsConn struct {
|
||||
conn *websocket.Conn
|
||||
typ int // message type
|
||||
reader io.Reader
|
||||
}
|
||||
|
||||
// newWSConn 新建wsConn
|
||||
func newWSConn(conn *websocket.Conn) (*wsConn, error) {
|
||||
c := &wsConn{conn: conn}
|
||||
|
||||
t, r, err := conn.NextReader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.typ = t
|
||||
c.reader = r
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Read reads data from the connection.
|
||||
// Read can be made to time out and return an Error with Timeout() == true
|
||||
// after a fixed time limit; see SetDeadline and SetReadDeadline.
|
||||
func (c *wsConn) Read(b []byte) (int, error) {
|
||||
n, err := c.reader.Read(b)
|
||||
if err != nil && err != io.EOF {
|
||||
return n, err
|
||||
} else if err == io.EOF {
|
||||
_, r, err := c.conn.NextReader()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
c.reader = r
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Write writes data to the connection.
|
||||
// Write can be made to time out and return an Error with Timeout() == true
|
||||
// after a fixed time limit; see SetDeadline and SetWriteDeadline.
|
||||
func (c *wsConn) Write(b []byte) (int, error) {
|
||||
err := c.conn.WriteMessage(websocket.BinaryMessage, b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// Close closes the connection.
|
||||
// Any blocked Read or Write operations will be unblocked and return errors.
|
||||
func (c *wsConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
// LocalAddr returns the local network address.
|
||||
func (c *wsConn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote network address.
|
||||
func (c *wsConn) RemoteAddr() net.Addr {
|
||||
return c.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
// SetDeadline sets the read and write deadlines associated
|
||||
// with the connection. It is equivalent to calling both
|
||||
// SetReadDeadline and SetWriteDeadline.
|
||||
//
|
||||
// A deadline is an absolute time after which I/O operations
|
||||
// fail with a timeout (see type Error) instead of
|
||||
// blocking. The deadline applies to all future and pending
|
||||
// I/O, not just the immediately following call to Read or
|
||||
// Write. After a deadline has been exceeded, the connection
|
||||
// can be refreshed by setting a deadline in the future.
|
||||
//
|
||||
// An idle timeout can be implemented by repeatedly extending
|
||||
// the deadline after successful Read or Write calls.
|
||||
//
|
||||
// A zero value for t means I/O operations will not time out.
|
||||
func (c *wsConn) SetDeadline(t time.Time) error {
|
||||
if err := c.conn.SetReadDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for future Read calls
|
||||
// and any currently-blocked Read call.
|
||||
// A zero value for t means Read will not time out.
|
||||
func (c *wsConn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the deadline for future Write calls
|
||||
// and any currently-blocked Write call.
|
||||
// Even if write times out, it may return n > 0, indicating that
|
||||
// some data was successfully written.
|
||||
// A zero value for t means Write will not time out.
|
||||
func (c *wsConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package packet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Type 数据帧类型,如:握手,心跳,数据等
|
||||
type Type byte
|
||||
|
||||
const (
|
||||
// Default 默认,暂无意义
|
||||
Default Type = iota
|
||||
|
||||
// Handshake 握手数据(服务端主动发起)
|
||||
Handshake = 0x01
|
||||
|
||||
// HandshakeAck 握手回复(客户端回复)
|
||||
HandshakeAck = 0x02
|
||||
|
||||
// Heartbeat 心跳(服务端发起)
|
||||
Heartbeat = 0x03
|
||||
|
||||
// Data 数据传输
|
||||
Data = 0x04
|
||||
|
||||
// Kick 服务端主动断开连接
|
||||
Kick = 0x05
|
||||
)
|
||||
|
||||
type Packet struct {
|
||||
Type Type // 数据帧 类型
|
||||
|
||||
HeaderLen uint32 // 数据帧头 长度
|
||||
HeaderRaw []byte // 头原始数据
|
||||
|
||||
DataLen uint32 // 数据长度
|
||||
DataRaw []byte // 原始数据
|
||||
}
|
||||
|
||||
func New() *Packet {
|
||||
return &Packet{
|
||||
Type: Default,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Packet) String() string {
|
||||
return fmt.Sprintf("Type: %d, HeaderLen: %d, DataLen: %d, Header: %s, Data: %s", p.Type, p.HeaderLen, p.DataLen, string(p.HeaderRaw), string(p.DataRaw))
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type (
|
||||
Func func(request *nnet.Request) error
|
||||
|
||||
// Pipeline 消息管道
|
||||
Pipeline interface {
|
||||
Outbound() Channel
|
||||
Inbound() Channel
|
||||
}
|
||||
|
||||
pipeline struct {
|
||||
outbound, inbound *pipelineChannel
|
||||
}
|
||||
|
||||
Channel interface {
|
||||
PushFront(h Func)
|
||||
PushBack(h Func)
|
||||
Process(request *nnet.Request) error
|
||||
}
|
||||
|
||||
pipelineChannel struct {
|
||||
mu sync.RWMutex
|
||||
handlers []Func
|
||||
}
|
||||
)
|
||||
|
||||
func New() Pipeline {
|
||||
return &pipeline{
|
||||
outbound: &pipelineChannel{},
|
||||
inbound: &pipelineChannel{},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pipeline) Outbound() Channel {
|
||||
return p.outbound
|
||||
}
|
||||
|
||||
func (p *pipeline) Inbound() Channel {
|
||||
return p.inbound
|
||||
}
|
||||
|
||||
// PushFront 将func压入slice首位
|
||||
func (p *pipelineChannel) PushFront(h Func) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
handlers := make([]Func, len(p.handlers)+1)
|
||||
handlers[0] = h
|
||||
copy(handlers[1:], p.handlers)
|
||||
|
||||
p.handlers = handlers
|
||||
}
|
||||
|
||||
// PushBack 将func压入slice末位
|
||||
func (p *pipelineChannel) PushBack(h Func) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
p.handlers = append(p.handlers, h)
|
||||
}
|
||||
|
||||
// Process 处理所有的pipeline方法
|
||||
func (p *pipelineChannel) Process(request *nnet.Request) error {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
if len(p.handlers) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, handler := range p.handlers {
|
||||
err := handler(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"git.noahlan.cn/northlan/nnet/nface"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Manager struct {
|
||||
sync.RWMutex
|
||||
sessions map[int64]nface.ISession
|
||||
}
|
||||
|
||||
func NewManager() *Manager {
|
||||
return &Manager{
|
||||
RWMutex: sync.RWMutex{},
|
||||
sessions: make(map[int64]nface.ISession),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) storeSession(s nface.ISession) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
m.sessions[s.ID()] = s
|
||||
}
|
||||
|
||||
func (m *Manager) findSession(sid int64) nface.ISession {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
return m.sessions[sid]
|
||||
}
|
||||
|
||||
func (m *Manager) findOrCreateSession(sid int64) nface.ISession {
|
||||
m.RLock()
|
||||
s, ok := m.sessions[sid]
|
||||
m.RUnlock()
|
||||
|
||||
if !ok {
|
||||
s = New()
|
||||
|
||||
m.Lock()
|
||||
m.sessions[s.ID()] = s
|
||||
m.Unlock()
|
||||
}
|
||||
return s
|
||||
}
|
Loading…
Reference in New Issue