You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nnet-old/nnet/server.go

231 lines
5.5 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package nnet
import (
"errors"
"fmt"
"git.noahlan.cn/northlan/nnet/component"
"git.noahlan.cn/northlan/nnet/log"
"git.noahlan.cn/northlan/nnet/packet"
"git.noahlan.cn/northlan/nnet/pipeline"
"git.noahlan.cn/northlan/nnet/scheduler"
"git.noahlan.cn/northlan/nnet/serialize"
"git.noahlan.cn/northlan/nnet/session"
"github.com/gorilla/websocket"
"net"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
type (
Options struct {
Name string // 服务端名默认为n-net
Pipeline pipeline.Pipeline // 消息管道
RetryInterval time.Duration // 消息重试间隔时长
Components *component.Components // 组件库
Packer packet.Packer // 封包、拆包器
PacketProcessor packet.Processor // 数据包处理器
Serializer serialize.Serializer // 消息 序列化/反序列化
HeartbeatInterval time.Duration // 心跳间隔0表示不进行心跳
WS WSOptions // websocket
}
WSOptions struct {
IsWebsocket bool // 是否为websocket服务端
WebsocketPath string // ws地址(ws://127.0.0.1/WebsocketPath)
TLSCertificate string // TLS 证书地址 (websocket)
TLSKey string // TLS 证书key地址 (websocket)
CheckOrigin func(*http.Request) bool // check origin
}
)
// Server TCP-Server
type Server struct {
// Options 参数列表
Options
// protocol 协议名
// "tcp", "tcp4", "tcp6", "unix" or "unixpacket"
// 若只想开启IPv4, 使用tcp4即可
protocol string
// address 服务地址
// 地址可直接使用hostname,但强烈不建议这样做,可能会同时监听多个本地IP
// 如果端口号不填或端口号为0例如"127.0.0.1:" 或 ":0",服务端将选择随机可用端口
address string
// DieChan 应用程序退出信号
DieChan chan struct{}
// handler 消息处理器
handler *Handler
// sessionMgr session管理器
sessionMgr *session.Manager
}
func NewServer(protocol, addr string, opts ...Option) *Server {
options := Options{
Components: &component.Components{},
WS: WSOptions{
CheckOrigin: func(_ *http.Request) bool { return true },
},
Packer: packet.NewNNetPacker(),
PacketProcessor: packet.NewNNetProcessor(),
}
s := &Server{
Options: options,
protocol: protocol,
address: addr,
DieChan: make(chan struct{}),
}
for _, opt := range opts {
opt(&s.Options)
}
s.handler = NewHandler(s, s.Options.Pipeline, s.Options.PacketProcessor)
s.sessionMgr = session.NewManager()
initPool(0)
return s
}
func (s *Server) Serve() {
components := s.Components.List()
for _, c := range components {
err := s.handler.register(c.Comp, c.Opts)
if err != nil {
// TODO Log and return
return
}
}
// Initialize components
for _, c := range components {
c.Comp.OnInit()
}
go func() {
if s.WS.IsWebsocket {
if len(s.WS.TLSCertificate) != 0 && len(s.WS.TLSKey) != 0 {
s.listenAndServeWSTLS()
} else {
s.listenAndServeWS()
}
} else {
s.listenAndServe()
}
}()
go scheduler.Schedule()
sg := make(chan os.Signal)
signal.Notify(sg, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM)
select {
case <-s.DieChan:
log.Info("The server will shutdown in a few seconds")
case s := <-sg:
log.Infof("server got signal: %s", s)
}
log.Info("server is stopping...")
s.shutdown()
scheduler.Close()
}
func (s *Server) Close() {
close(s.DieChan)
}
func (s *Server) shutdown() {
components := s.Components.List()
compLen := len(components)
for i := compLen - 1; i >= 0; i-- {
components[i].Comp.OnShutdown()
}
}
func (s *Server) listenAndServe() {
listener, err := net.Listen(s.protocol, s.address)
if err != nil {
panic(err)
}
// 监听成功,服务已启动
log.Info("listening...")
defer func() {
listener.Close()
s.Close()
}()
for {
conn, err := listener.Accept()
if err != nil {
if errors.Is(err, net.ErrClosed) {
log.Errorf("服务器网络错误 %+v", err)
return
}
log.Errorf("监听错误 %v", err)
continue
}
err = pool.SubmitConn(func() {
s.handler.handle(conn)
})
if err != nil {
log.Errorf("submit conn pool err: %s", err.Error())
continue
}
}
}
func (s *Server) listenAndServeWS() {
upgrade := websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: s.WS.CheckOrigin,
}
http.HandleFunc(fmt.Sprintf("/%s/", s.WS.WebsocketPath), func(w http.ResponseWriter, r *http.Request) {
conn, err := upgrade.Upgrade(w, r, nil)
if err != nil {
log.Errorf("Upgrade failure, URI=%s, Error=%s", r.RequestURI, err.Error())
return
}
err = pool.SubmitConn(func() {
s.handler.handleWS(conn)
})
if err != nil {
log.Fatalf("submit conn pool err: %s", err.Error())
}
})
if err := http.ListenAndServe(s.address, nil); err != nil {
log.Fatal(err.Error())
}
}
func (s *Server) listenAndServeWSTLS() {
upgrade := websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: s.WS.CheckOrigin,
}
http.HandleFunc(fmt.Sprintf("/%s/", s.WS.WebsocketPath), func(w http.ResponseWriter, r *http.Request) {
conn, err := upgrade.Upgrade(w, r, nil)
if err != nil {
log.Errorf("Upgrade failure, URI=%s, Error=%s", r.RequestURI, err.Error())
return
}
err = pool.SubmitConn(func() {
s.handler.handleWS(conn)
})
if err != nil {
log.Fatalf("submit conn pool err: %s", err.Error())
}
})
if err := http.ListenAndServeTLS(s.address, s.WS.TLSCertificate, s.WS.TLSKey, nil); err != nil {
log.Fatal(err.Error())
}
}