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