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

184 lines
4.5 KiB

package gnet_server
import (
"context"
"flag"
"fmt"
"github.com/gobwas/ws"
"log"
"sonet/pkg/protocol"
"sonet/pkg/protocol/session"
"sonet/pkg/utils/logger"
"sync/atomic"
"time"
"github.com/panjf2000/gnet/v2"
"github.com/panjf2000/gnet/v2/pkg/logging"
)
type GnetWsServer struct {
gnet.BuiltinEventEngine
addr string
multicore bool
eng gnet.Engine
connected int64
requests chan *protocol.Payload
}
func NewGnetWsServer() *GnetWsServer {
return &GnetWsServer{
requests: make(chan *protocol.Payload, 1024*16),
}
}
func (wss *GnetWsServer) Init() {
}
// dispatch 多个 goroutine 进行请求 dispatch
func (wss *GnetWsServer) dispatch(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
case payload := <-wss.requests:
fmt.Println(payload.Header)
}
}
}
func (wss *GnetWsServer) OnBoot(eng gnet.Engine) gnet.Action {
wss.eng = eng
logging.Infof("echo server with multi-core=%t is listening on %s", wss.multicore, wss.addr)
return gnet.None
}
func (wss *GnetWsServer) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
// wsCodec, uid, gnetConn
conn := newGnetConn(c)
conn.wsCodec = new(wsCodec)
c.SetContext(conn)
// c.SetContext(new(wsCodec))
atomic.AddInt64(&wss.connected, 1)
return nil, gnet.None
}
func (wss *GnetWsServer) OnClose(c gnet.Conn, err error) (action gnet.Action) {
if err != nil {
logging.Warnf("error occurred on connection=%s, %v\n", c.RemoteAddr().String(), err)
}
atomic.AddInt64(&wss.connected, -1)
logging.Infof("conn[%v] disconnected", c.RemoteAddr().String())
return gnet.None
}
func (wss *GnetWsServer) OnTraffic(c gnet.Conn) (action gnet.Action) {
conn := c.Context().(*gnetConn)
if conn.wsCodec.readBufferBytes(c) == gnet.Close {
return gnet.Close
}
ok, action := conn.wsCodec.upgrade(c)
if !ok {
return
}
if conn.wsCodec.buf.Len() <= 0 {
return gnet.None
}
messages, err := conn.wsCodec.Decode(c)
if err != nil {
return gnet.Close
}
if messages == nil {
return
}
authorized := conn.uid != ""
for _, message := range messages {
if message.OpCode != ws.OpBinary {
logger.Info("receive message type: ", message.OpCode)
continue
}
// decode payload
payload, err := protocol.DecodeSo(message.Payload)
if err != nil {
logger.Errorf("decode message error: len=%d", len(message.Payload), err)
return gnet.Close
}
header := payload.Header
service, method := header.Svc, header.Target
// authorization
if !authorized {
if !(service == "Auth" && method == "Verify") {
writeError(conn, header.SeqId, session.UnauthorizedRequestError.Error())
return gnet.Close
}
}
// payload -> processing channel
select {
case wss.requests <- payload:
default:
writeError(conn, header.SeqId, "server busy")
}
//msgLen := len(message.Payload)
//if msgLen > 128 {
// logging.Infof("conn[%v] receive [op=%v] [msg=%v..., len=%d]", c.RemoteAddr().String(), message.OpCode, string(message.Payload[:128]), len(message.Payload))
//} else {
// logging.Infof("conn[%v] receive [op=%v] [msg=%v, len=%d]", c.RemoteAddr().String(), message.OpCode, string(message.Payload), len(message.Payload))
//}
//// This is the echo server
//err = wsutil.WriteServerMessage(c, message.OpCode, message.Payload)
//if err != nil {
// logging.Infof("conn[%v] [err=%v]", c.RemoteAddr().String(), err.Error())
// return gnet.Close
//}
}
return gnet.None
}
func (wss *GnetWsServer) OnTick() (delay time.Duration, action gnet.Action) {
logging.Infof("[connected-count=%v]", atomic.LoadInt64(&wss.connected))
return 10 * time.Second, gnet.None
}
func writeError(conn session.NetConn, seqId int32, errMsg string) {
header := &protocol.Header{}
payload := &protocol.Payload{Header: header}
header.Magic = protocol.Magic
header.Type = protocol.TypeError
header.Status = 50
header.SeqId = seqId
payload.Body = []byte(errMsg)
message, err := protocol.EncodeSo(payload)
if err != nil {
logger.Error("NetClient writeError encode error: ", err)
return
}
err = conn.Write(message)
if err != nil {
logger.Error("net conn write error msg fail: ", err)
return
}
return
}
func main() {
var port int
var multicore bool
// Example command: go run main.go --port 8080 --multicore=true
flag.IntVar(&port, "port", 9080, "server port")
flag.BoolVar(&multicore, "multicore", true, "multicore")
flag.Parse()
wss := &GnetWsServer{addr: fmt.Sprintf("tcp://127.0.0.1:%d", port), multicore: multicore}
// Start serving!
log.Println("server exits:", gnet.Run(wss, wss.addr, gnet.WithMulticore(multicore), gnet.WithReusePort(true), gnet.WithTicker(true)))
}