notify/peer_identity.go
starainrt 09d972c7b7
feat(notify): 重构通信内核并补齐 stream/bulk/record/transfer 能力
- 引入 LogicalConn/TransportConn 分层,ClientConn 保留兼容适配层
  - 新增 Stream、Bulk、RecordStream 三条数据面能力及对应控制路径
  - 完成 transfer/file 传输内核与状态快照、诊断能力
  - 补齐 reconnect、inbound dispatcher、modern psk 等基础模块
  - 增加大规模回归、并发与基准测试覆盖
  - 更新依赖库
2026-04-15 15:24:36 +08:00

233 lines
5.4 KiB
Go

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
}