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

128 lines
2.6 KiB
Go

package notify
import (
"fmt"
"net"
"sync"
)
const defaultInboundDispatchSource = "_notify.default_inbound_source"
type inboundDispatcher struct {
mu sync.Mutex
closed bool
workers map[string]*inboundDispatchWorker
wg sync.WaitGroup
}
type inboundDispatchWorker struct {
queue []func()
running bool
}
func newInboundDispatcher() *inboundDispatcher {
return &inboundDispatcher{
workers: make(map[string]*inboundDispatchWorker),
}
}
func (d *inboundDispatcher) Dispatch(source string, fn func()) bool {
if d == nil || fn == nil {
return false
}
if source == "" {
source = defaultInboundDispatchSource
}
d.mu.Lock()
if d.closed {
d.mu.Unlock()
return false
}
worker := d.workers[source]
if worker == nil {
worker = &inboundDispatchWorker{}
d.workers[source] = worker
}
worker.queue = append(worker.queue, fn)
if worker.running {
d.mu.Unlock()
return true
}
worker.running = true
d.wg.Add(1)
d.mu.Unlock()
go d.run(source, worker)
return true
}
func (d *inboundDispatcher) run(source string, worker *inboundDispatchWorker) {
defer d.wg.Done()
for {
d.mu.Lock()
if len(worker.queue) == 0 {
worker.running = false
if current := d.workers[source]; current == worker {
delete(d.workers, source)
}
d.mu.Unlock()
return
}
fn := worker.queue[0]
worker.queue[0] = nil
worker.queue = worker.queue[1:]
d.mu.Unlock()
fn()
}
}
func (d *inboundDispatcher) CloseAndWait() {
if d == nil {
return
}
d.mu.Lock()
d.closed = true
d.mu.Unlock()
d.wg.Wait()
}
func clientInboundDispatchSource() string {
return "client"
}
func serverInboundDispatchSource(source interface{}) string {
switch data := source.(type) {
case serverInboundSource:
return serverInboundDispatchSourceKey(data)
case *serverInboundSource:
if data == nil {
return defaultInboundDispatchSource
}
return serverInboundDispatchSourceKey(*data)
case net.Conn:
return fmt.Sprintf("conn:%p", data)
case string:
if data == "" {
return defaultInboundDispatchSource
}
return "peer:" + data
default:
return defaultInboundDispatchSource
}
}
func serverInboundDispatchSourceKey(source serverInboundSource) string {
if source.Conn != nil {
return fmt.Sprintf("conn:%p:%d", source.Conn, source.TransportGeneration)
}
if source.Logical != nil {
return fmt.Sprintf("logical:%s:%d", source.Logical.ID(), source.TransportGeneration)
}
if source.Source != "" {
return fmt.Sprintf("peer:%s:%d", source.Source, source.TransportGeneration)
}
if source.RemoteAddr != nil {
return fmt.Sprintf("addr:%s:%d", source.RemoteAddr.String(), source.TransportGeneration)
}
return defaultInboundDispatchSource
}