notify/file_event.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

244 lines
6.7 KiB
Go

package notify
import "time"
type FileEvent struct {
NetType NetType
LogicalConn *LogicalConn
// Deprecated: ClientConn aliases LogicalConn for compatibility.
ClientConn *ClientConn
TransportConn *TransportConn
ServerConn Client
Kind EnvelopeKind
Packet FilePacket
Path string
Received int64
Total int64
Percent float64
Done bool
StartedAt time.Time
UpdatedAt time.Time
Duration time.Duration
RateBPS float64
StepDuration time.Duration
InstantRateBPS float64
Err error
Time time.Time
}
func normalizeFileEventTime(now time.Time) time.Time {
if now.IsZero() {
return time.Now()
}
return now
}
func hydrateServerFileEventPeerFields(event FileEvent) FileEvent {
if event.LogicalConn == nil {
event.LogicalConn = logicalConnFromClient(event.ClientConn)
}
if event.ClientConn == nil {
event.ClientConn = event.LogicalConn.compatClientConn()
}
if event.TransportConn == nil && event.LogicalConn != nil {
event.TransportConn = event.LogicalConn.CurrentTransportConn()
}
return event
}
func fileEventLogicalConnSnapshot(event FileEvent) *LogicalConn {
if event.LogicalConn != nil {
return event.LogicalConn
}
return logicalConnFromClient(event.ClientConn)
}
func fileEventTransportConnSnapshot(event FileEvent) *TransportConn {
if event.TransportConn != nil {
return event.TransportConn
}
logical := fileEventLogicalConnSnapshot(event)
if logical == nil {
return nil
}
return logical.CurrentTransportConn()
}
type fileEventTimeline struct {
startedAt time.Time
updatedAt time.Time
previousUpdatedAt time.Time
previousProgress int64
}
func fillFileEventProgress(event *FileEvent) {
if event == nil {
return
}
event.Total = event.Packet.Size
if event.Received < 0 {
event.Received = 0
}
if event.Total > 0 && event.Received > event.Total {
event.Received = event.Total
}
switch event.Kind {
case EnvelopeFileEnd:
event.Done = event.Err == nil
if event.Done && event.Total > 0 {
event.Received = event.Total
}
case EnvelopeFileAbort:
event.Done = false
}
if event.Total <= 0 {
if event.Done {
event.Percent = 100
}
if !event.StartedAt.IsZero() && !event.UpdatedAt.IsZero() && !event.UpdatedAt.Before(event.StartedAt) {
event.Duration = event.UpdatedAt.Sub(event.StartedAt)
}
return
}
event.Percent = float64(event.Received) * 100 / float64(event.Total)
if event.Percent < 0 {
event.Percent = 0
}
if event.Percent > 100 {
event.Percent = 100
}
if !event.StartedAt.IsZero() && !event.UpdatedAt.IsZero() && !event.UpdatedAt.Before(event.StartedAt) {
event.Duration = event.UpdatedAt.Sub(event.StartedAt)
}
if event.Duration > 0 && event.Received > 0 {
event.RateBPS = float64(event.Received) / event.Duration.Seconds()
}
}
func fillFileEventTimeline(event *FileEvent, timeline fileEventTimeline) {
if event == nil {
return
}
event.StartedAt = timeline.startedAt
event.UpdatedAt = timeline.updatedAt
if !timeline.previousUpdatedAt.IsZero() && !timeline.updatedAt.Before(timeline.previousUpdatedAt) {
event.StepDuration = timeline.updatedAt.Sub(timeline.previousUpdatedAt)
}
if delta := event.Received - timeline.previousProgress; delta > 0 && event.StepDuration > 0 {
event.InstantRateBPS = float64(delta) / event.StepDuration.Seconds()
}
}
func fillFileEventTiming(event *FileEvent, session *fileReceiveSession) {
if session == nil {
return
}
fillFileEventTimeline(event, fileEventTimeline{
startedAt: session.startedAt,
updatedAt: session.updatedAt,
previousUpdatedAt: session.previousUpdatedAt,
previousProgress: session.previousReceived,
})
}
func fillFileSendEventTiming(event *FileEvent, session *fileSendSession) {
if session == nil {
return
}
fillFileEventTimeline(event, fileEventTimeline{
startedAt: session.startedAt,
updatedAt: session.updatedAt,
previousUpdatedAt: session.previousUpdatedAt,
previousProgress: session.previousSent,
})
}
func normalizeFileEventCallback(fn func(FileEvent)) func(FileEvent) {
if fn == nil {
return func(FileEvent) {}
}
return fn
}
func (c *ClientCommon) setFileEventObserver(fn func(FileEvent)) {
c.mu.Lock()
c.fileEventObserver = normalizeFileEventCallback(fn)
c.mu.Unlock()
}
func (s *ServerCommon) setFileEventObserver(fn func(FileEvent)) {
s.mu.Lock()
s.fileEventObserver = normalizeFileEventCallback(fn)
s.mu.Unlock()
}
func (c *ClientCommon) observeFileEvent(event FileEvent) {
c.mu.Lock()
observer := c.fileEventObserver
c.mu.Unlock()
normalizeFileEventCallback(observer)(event)
}
func (s *ServerCommon) observeFileEvent(event FileEvent) {
s.mu.RLock()
observer := s.fileEventObserver
s.mu.RUnlock()
normalizeFileEventCallback(observer)(hydrateServerFileEventPeerFields(event))
}
func (c *ClientCommon) publishReceivedFileEvent(event FileEvent) {
c.getFileTransferState().observe(fileTransferDirectionReceive, event)
c.observeFileEvent(event)
c.logFileEvent("client", event)
c.emitFileEvent(event)
}
func (c *ClientCommon) publishReceivedFileEventMonitorOnly(event FileEvent) {
c.getFileTransferState().observeMonitorOnly(fileTransferDirectionReceive, event)
c.observeFileEvent(event)
c.logFileEvent("client", event)
c.emitFileEvent(event)
}
func (s *ServerCommon) publishReceivedFileEvent(event FileEvent) {
event = hydrateServerFileEventPeerFields(event)
s.getFileTransferState().observe(fileTransferDirectionReceive, event)
s.observeFileEvent(event)
s.logFileEvent("server", event)
s.emitFileEvent(event)
}
func (s *ServerCommon) publishReceivedFileEventMonitorOnly(event FileEvent) {
event = hydrateServerFileEventPeerFields(event)
s.getFileTransferState().observeMonitorOnly(fileTransferDirectionReceive, event)
s.observeFileEvent(event)
s.logFileEvent("server", event)
s.emitFileEvent(event)
}
func (c *ClientCommon) publishSendFileEvent(event FileEvent) {
c.getFileTransferState().observe(fileTransferDirectionSend, event)
c.observeFileEvent(event)
c.logFileEvent("client-send", event)
}
func (c *ClientCommon) publishSendFileEventMonitorOnly(event FileEvent) {
c.getFileTransferState().observeMonitorOnly(fileTransferDirectionSend, event)
c.observeFileEvent(event)
c.logFileEvent("client-send", event)
}
func (s *ServerCommon) publishSendFileEvent(event FileEvent) {
event = hydrateServerFileEventPeerFields(event)
s.getFileTransferState().observe(fileTransferDirectionSend, event)
s.observeFileEvent(event)
s.logFileEvent("server-send", event)
}
func (s *ServerCommon) publishSendFileEventMonitorOnly(event FileEvent) {
event = hydrateServerFileEventPeerFields(event)
s.getFileTransferState().observeMonitorOnly(fileTransferDirectionSend, event)
s.observeFileEvent(event)
s.logFileEvent("server-send", event)
}