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 路由接口
 | 
					// IRouter 路由接口
 | 
				
			||||||
type IRouter interface {
 | 
					type IRouter interface {
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
package interfaces
 | 
					package nface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ISessionAttribute Session数据接口
 | 
					// ISessionAttribute Session数据接口
 | 
				
			||||||
type ISessionAttribute interface {
 | 
					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
 | 
					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