|
|
|
|
@ -18,13 +18,18 @@ import (
|
|
|
|
|
const ( |
|
|
|
|
PingInterval = 5 * time.Second |
|
|
|
|
PingWait = 10 * time.Second |
|
|
|
|
SessionUidKey = "uid" |
|
|
|
|
SessionGwsConnKey = "gws" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
type soRequest struct { |
|
|
|
|
conn *gwsConn |
|
|
|
|
payload *protocol.Payload |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type GwsHandler struct { |
|
|
|
|
grpcFactory *generic.GrpcGenericClientFactory |
|
|
|
|
sessionStore session.Store // <string, *session.NetSubject> 当前连接用户,内存缓存
|
|
|
|
|
requests chan *soRequest |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func NewGwsHandler( |
|
|
|
|
@ -37,68 +42,26 @@ func NewGwsHandler(
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *GwsHandler) OnOpen(socket *gws.Conn) { |
|
|
|
|
_ = socket.SetDeadline(time.Time{}) // time.Now().Add(PingInterval + PingWait)
|
|
|
|
|
socket.Session().Store(SessionGwsConnKey, newGwsConn(socket)) |
|
|
|
|
} |
|
|
|
|
func (c *GwsHandler) Init(ctx context.Context) { |
|
|
|
|
c.requests = make(chan *soRequest, 1024*16) |
|
|
|
|
|
|
|
|
|
func (c *GwsHandler) OnClose(socket *gws.Conn, err error) { |
|
|
|
|
if err != nil { |
|
|
|
|
logger.Error("gws conn close error: ", err) |
|
|
|
|
} |
|
|
|
|
val, ok := socket.Session().Load(SessionUidKey) |
|
|
|
|
if !ok { |
|
|
|
|
return |
|
|
|
|
// todo 针对不同服务的协程池
|
|
|
|
|
for i := 0; i < 32; i++ { |
|
|
|
|
go c.dispatchRequest(ctx) |
|
|
|
|
} |
|
|
|
|
uid := val.(string) |
|
|
|
|
c.sessionStore.Delete(uid) |
|
|
|
|
logger.Info("subject offline: ", uid) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *GwsHandler) OnPing(socket *gws.Conn, payload []byte) { |
|
|
|
|
_ = socket.SetDeadline(time.Now().Add(PingInterval + PingWait)) |
|
|
|
|
_ = socket.WritePong(nil) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *GwsHandler) OnPong(socket *gws.Conn, payload []byte) {} |
|
|
|
|
|
|
|
|
|
func (c *GwsHandler) OnMessage(socket *gws.Conn, message *gws.Message) { |
|
|
|
|
defer func() { |
|
|
|
|
err := message.Close() |
|
|
|
|
if err != nil { |
|
|
|
|
logger.Error("gws message close error: ", err) |
|
|
|
|
} |
|
|
|
|
}() |
|
|
|
|
if message.Opcode != gws.OpcodeBinary { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
val, ok := socket.Session().Load(SessionGwsConnKey) |
|
|
|
|
if !ok { |
|
|
|
|
logger.Error("gws socket session error: conn not exists") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
conn := val.(*gwsConn) |
|
|
|
|
|
|
|
|
|
val, authorized := socket.Session().Load(SessionUidKey) |
|
|
|
|
var sessionUid string |
|
|
|
|
if authorized { |
|
|
|
|
sessionUid = val.(string) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
messageBytes := message.Bytes() |
|
|
|
|
payload, err := protocol.DecodeSo(messageBytes) |
|
|
|
|
if err != nil { |
|
|
|
|
logger.Errorf("decode message error: len=%d", len(messageBytes), err) |
|
|
|
|
// dispatchRequest 多个 goroutine 进行请求 dispatch
|
|
|
|
|
func (c *GwsHandler) dispatchRequest(ctx context.Context) { |
|
|
|
|
for { |
|
|
|
|
select { |
|
|
|
|
case <-ctx.Done(): |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case request := <-c.requests: |
|
|
|
|
func() { |
|
|
|
|
conn, payload := request.conn, request.payload |
|
|
|
|
header := payload.Header |
|
|
|
|
service, method := header.Svc, header.Target |
|
|
|
|
if !authorized && !(service == "Auth" && method == "Verify") { |
|
|
|
|
writeError(conn, header.SeqId, session.UnauthorizedRequestError.Error()) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// grpc generic call
|
|
|
|
|
ctx := context.Background() |
|
|
|
|
@ -110,11 +73,11 @@ func (c *GwsHandler) OnMessage(socket *gws.Conn, message *gws.Message) {
|
|
|
|
|
writeError(conn, header.SeqId, fmt.Sprintf("service %s not avaliable: %s", header.Svc, err.Error())) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
// put session
|
|
|
|
|
if authorized { |
|
|
|
|
ctx = session.PutSubject(ctx, session.NewRpcSubject(sessionUid)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// put grpc request session
|
|
|
|
|
if conn.uid != "" { |
|
|
|
|
ctx = session.PutSubject(ctx, session.NewRpcSubject(conn.uid)) |
|
|
|
|
} |
|
|
|
|
ctx3, cancel3 := context.WithTimeout(ctx, time.Second*10) |
|
|
|
|
defer cancel3() |
|
|
|
|
resp, err := grpcClient.InvokeUnary(ctx3, header.Target, payload.Body) |
|
|
|
|
@ -140,14 +103,13 @@ func (c *GwsHandler) OnMessage(socket *gws.Conn, message *gws.Message) {
|
|
|
|
|
// auth verify success
|
|
|
|
|
if service == "Auth" && method == "Verify" { |
|
|
|
|
var channel *session.Channel |
|
|
|
|
sessionUid, channel, err = c.extractAuthVerify(conn, payload.Body) |
|
|
|
|
conn.uid, channel, err = c.extractAuthVerify(conn, payload.Body) |
|
|
|
|
if err != nil { |
|
|
|
|
logger.Error("extractAuthVerify error: ", err) |
|
|
|
|
writeError(conn, header.SeqId, "server error") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
socket.Session().Store(SessionUidKey, sessionUid) |
|
|
|
|
// channel
|
|
|
|
|
// channel todo dispatch on conn open
|
|
|
|
|
go c.dispatch(channel) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -162,6 +124,79 @@ func (c *GwsHandler) OnMessage(socket *gws.Conn, message *gws.Message) {
|
|
|
|
|
logger.Error("gws write response error: ", err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *GwsHandler) OnOpen(socket *gws.Conn) { |
|
|
|
|
_ = socket.SetDeadline(time.Time{}) // time.Now().Add(PingInterval + PingWait)
|
|
|
|
|
socket.Session().Store(SessionGwsConnKey, newGwsConn(socket)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *GwsHandler) OnClose(socket *gws.Conn, err error) { |
|
|
|
|
if err != nil { |
|
|
|
|
logger.Error("gws conn close error: ", err) |
|
|
|
|
} |
|
|
|
|
val, ok := socket.Session().Load(SessionGwsConnKey) |
|
|
|
|
if !ok { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
conn := val.(*gwsConn) |
|
|
|
|
if conn.uid != "" { |
|
|
|
|
c.sessionStore.Delete(conn.uid) |
|
|
|
|
logger.Info("subject offline: ", conn.uid) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *GwsHandler) OnPing(socket *gws.Conn, payload []byte) { |
|
|
|
|
_ = socket.SetDeadline(time.Now().Add(PingInterval + PingWait)) |
|
|
|
|
_ = socket.WritePong(nil) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *GwsHandler) OnPong(socket *gws.Conn, payload []byte) {} |
|
|
|
|
|
|
|
|
|
func (c *GwsHandler) OnMessage(socket *gws.Conn, message *gws.Message) { |
|
|
|
|
defer func() { |
|
|
|
|
err := message.Close() |
|
|
|
|
if err != nil { |
|
|
|
|
logger.Error("gws message close error: ", err) |
|
|
|
|
} |
|
|
|
|
}() |
|
|
|
|
if message.Opcode != gws.OpcodeBinary { |
|
|
|
|
logger.Info("receive websocket message type: ", message.Opcode) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
val, ok := socket.Session().Load(SessionGwsConnKey) |
|
|
|
|
if !ok { |
|
|
|
|
logger.Error("gws socket session error: conn not exists") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
conn := val.(*gwsConn) |
|
|
|
|
authorized := conn.uid != "" |
|
|
|
|
|
|
|
|
|
messageBytes := message.Bytes() |
|
|
|
|
payload, err := protocol.DecodeSo(messageBytes) |
|
|
|
|
if err != nil { |
|
|
|
|
logger.Errorf("decode message error: len=%d", len(messageBytes), err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
header := payload.Header |
|
|
|
|
service, method := header.Svc, header.Target |
|
|
|
|
if !authorized && !(service == "Auth" && method == "Verify") { |
|
|
|
|
writeError(conn, header.SeqId, session.UnauthorizedRequestError.Error()) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// payload -> processing channel
|
|
|
|
|
request := &soRequest{conn: conn, payload: payload} |
|
|
|
|
select { |
|
|
|
|
case c.requests <- request: |
|
|
|
|
default: |
|
|
|
|
writeError(conn, header.SeqId, "server busy") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func encodeDeliverMessage(msg *postal.Message) (bytes []byte, err error) { |
|
|
|
|
|