feat(notify): 重构通信内核并补齐 stream/bulk/record/transfer 能力
- 引入 LogicalConn/TransportConn 分层,ClientConn 保留兼容适配层 - 新增 Stream、Bulk、RecordStream 三条数据面能力及对应控制路径 - 完成 transfer/file 传输内核与状态快照、诊断能力 - 补齐 reconnect、inbound dispatcher、modern psk 等基础模块 - 增加大规模回归、并发与基准测试覆盖 - 更新依赖库
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
cryptorand "crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
systemPeerAttachKey = "_notify_peer_attach"
|
||||
peerAttachTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
type peerAttachRequest struct {
|
||||
PeerID string
|
||||
}
|
||||
|
||||
type peerAttachResponse struct {
|
||||
PeerID string
|
||||
Accepted bool
|
||||
Reused bool
|
||||
Error string
|
||||
}
|
||||
|
||||
func newClientPeerIdentity() string {
|
||||
var buf [16]byte
|
||||
if _, err := cryptorand.Read(buf[:]); err == nil {
|
||||
return "peer-" + hex.EncodeToString(buf[:])
|
||||
}
|
||||
return fmt.Sprintf("peer-%d", time.Now().UnixNano())
|
||||
}
|
||||
|
||||
func (c *ClientCommon) ensureClientPeerIdentity() string {
|
||||
if c == nil {
|
||||
return ""
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if strings.TrimSpace(c.peerIdentity) == "" {
|
||||
c.peerIdentity = newClientPeerIdentity()
|
||||
}
|
||||
return c.peerIdentity
|
||||
}
|
||||
|
||||
func (c *ClientCommon) setClientPeerIdentity(peerID string) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
peerID = strings.TrimSpace(peerID)
|
||||
if peerID == "" {
|
||||
return
|
||||
}
|
||||
c.mu.Lock()
|
||||
c.peerIdentity = peerID
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
func decodePeerAttachRequest(decodeFn func([]byte) (interface{}, error), data []byte) (peerAttachRequest, error) {
|
||||
if decodeFn == nil {
|
||||
decodeFn = Decode
|
||||
}
|
||||
value, err := decodeFn(data)
|
||||
if err != nil {
|
||||
return peerAttachRequest{}, err
|
||||
}
|
||||
switch req := value.(type) {
|
||||
case peerAttachRequest:
|
||||
return req, nil
|
||||
case *peerAttachRequest:
|
||||
if req == nil {
|
||||
return peerAttachRequest{}, errors.New("peer attach request is nil")
|
||||
}
|
||||
return *req, nil
|
||||
default:
|
||||
return peerAttachRequest{}, fmt.Errorf("unexpected peer attach request type %T", value)
|
||||
}
|
||||
}
|
||||
|
||||
func decodePeerAttachResponse(decodeFn func([]byte) (interface{}, error), data []byte) (peerAttachResponse, error) {
|
||||
if decodeFn == nil {
|
||||
decodeFn = Decode
|
||||
}
|
||||
value, err := decodeFn(data)
|
||||
if err != nil {
|
||||
return peerAttachResponse{}, err
|
||||
}
|
||||
switch resp := value.(type) {
|
||||
case peerAttachResponse:
|
||||
return resp, nil
|
||||
case *peerAttachResponse:
|
||||
if resp == nil {
|
||||
return peerAttachResponse{}, errors.New("peer attach response is nil")
|
||||
}
|
||||
return *resp, nil
|
||||
default:
|
||||
return peerAttachResponse{}, fmt.Errorf("unexpected peer attach response type %T", value)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ClientCommon) announceClientPeerIdentity() error {
|
||||
if c == nil {
|
||||
return errors.New("client is nil")
|
||||
}
|
||||
peerID := c.ensureClientPeerIdentity()
|
||||
if peerID == "" {
|
||||
return errors.New("peer identity is empty")
|
||||
}
|
||||
encoded, err := c.sequenceEn(peerAttachRequest{PeerID: peerID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reply, err := c.sendWait(TransferMsg{
|
||||
Key: systemPeerAttachKey,
|
||||
Value: encoded,
|
||||
Type: MSG_SYS_WAIT,
|
||||
}, peerAttachTimeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := decodePeerAttachResponse(c.sequenceDe, reply.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.PeerID != "" {
|
||||
c.setClientPeerIdentity(resp.PeerID)
|
||||
}
|
||||
if !resp.Accepted {
|
||||
if strings.TrimSpace(resp.Error) != "" {
|
||||
return errors.New(resp.Error)
|
||||
}
|
||||
return errors.New("peer attach rejected")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServerCommon) bindAcceptedClientIdentity(current *LogicalConn, peerID string) (*LogicalConn, bool, error) {
|
||||
if s == nil {
|
||||
return nil, false, errors.New("server is nil")
|
||||
}
|
||||
if current == nil {
|
||||
return nil, false, errors.New("client is nil")
|
||||
}
|
||||
peerID = strings.TrimSpace(peerID)
|
||||
if peerID == "" {
|
||||
return nil, false, errors.New("peer id is empty")
|
||||
}
|
||||
if current.ID() == peerID {
|
||||
current.markIdentityBound()
|
||||
return current, false, nil
|
||||
}
|
||||
existing := s.GetLogicalConn(peerID)
|
||||
if existing == nil {
|
||||
if err := s.renameAcceptedLogical(current, peerID); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
current.markIdentityBound()
|
||||
return current, false, nil
|
||||
}
|
||||
if existing == current {
|
||||
existing.markIdentityBound()
|
||||
return existing, false, nil
|
||||
}
|
||||
if err := s.handoffAcceptedLogicalTransport(existing, current); err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
existing.markIdentityBound()
|
||||
return existing, true, nil
|
||||
}
|
||||
|
||||
func (s *ServerCommon) replyPeerAttach(client *LogicalConn, message Message, resp peerAttachResponse) error {
|
||||
if s == nil {
|
||||
return errors.New("server is nil")
|
||||
}
|
||||
if client == nil {
|
||||
return errors.New("client is nil")
|
||||
}
|
||||
encoded, err := s.sequenceEn(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reply := TransferMsg{
|
||||
ID: message.ID,
|
||||
Key: systemPeerAttachKey,
|
||||
Value: encoded,
|
||||
Type: MSG_SYS_REPLY,
|
||||
}
|
||||
if message.inboundConn != nil {
|
||||
return s.sendTransferInbound(client, messageTransportConnSnapshot(&message), message.inboundConn, reply)
|
||||
}
|
||||
_, err = s.sendLogical(client, reply)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ServerCommon) handlePeerAttachSystemMessage(message Message) bool {
|
||||
if message.Key != systemPeerAttachKey {
|
||||
return false
|
||||
}
|
||||
message = hydrateServerMessagePeerFields(message)
|
||||
current := messageLogicalConnSnapshot(&message)
|
||||
req, err := decodePeerAttachRequest(s.sequenceDe, message.Value)
|
||||
if err != nil {
|
||||
if current != nil {
|
||||
_ = s.replyPeerAttach(current, message, peerAttachResponse{
|
||||
Accepted: false,
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
bound, reused, err := s.bindAcceptedClientIdentity(current, req.PeerID)
|
||||
if err != nil {
|
||||
if current != nil {
|
||||
_ = s.replyPeerAttach(current, message, peerAttachResponse{
|
||||
PeerID: req.PeerID,
|
||||
Accepted: false,
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
if err := s.replyPeerAttach(bound, message, peerAttachResponse{
|
||||
PeerID: bound.ID(),
|
||||
Accepted: true,
|
||||
Reused: reused,
|
||||
}); err != nil && bound != nil {
|
||||
s.stopLogicalSession(bound, "peer attach reply failed", err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user