feat: 实现消息分发推送确认撤回与启动恢复
This commit is contained in:
+61
-50
@@ -1,7 +1,7 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.asio.asia/nixevol/NixMsg/internal/app/port"
|
||||
@@ -18,11 +18,6 @@ const (
|
||||
StateCompleted = "completed"
|
||||
)
|
||||
|
||||
// 投递状态。
|
||||
const (
|
||||
DeliveryPending = "pending"
|
||||
)
|
||||
|
||||
// talk_grants.kind。
|
||||
const (
|
||||
GrantKindPassword = "password"
|
||||
@@ -32,7 +27,7 @@ const (
|
||||
// 请求频率桶默认突发容量(DEVELOPMENT 6.10;配置无单独字段)。
|
||||
const defaultRequestBurst = 100
|
||||
|
||||
// Limits 是提交所需的配置上限(来自 config.LimitsConfig)。
|
||||
// Limits 是消息子系统所需配置上限。
|
||||
type Limits struct {
|
||||
MaxBodyBytes int
|
||||
MaxMetaBytes int
|
||||
@@ -44,11 +39,16 @@ type Limits struct {
|
||||
MaxPendingPerSender int
|
||||
MaxPendingPerReceiver int
|
||||
GraceSeconds int64
|
||||
AckTimeoutSeconds int64
|
||||
DeliveryWindow int
|
||||
ReceiptWindow int
|
||||
RecordRetentionDays int
|
||||
ReceiptRetentionDays int
|
||||
IdempotencyHours int
|
||||
}
|
||||
|
||||
// LimitsFromConfig 从平台配置构造 Limits。
|
||||
func LimitsFromConfig(c config.LimitsConfig) Limits {
|
||||
burst := defaultRequestBurst
|
||||
return Limits{
|
||||
MaxBodyBytes: c.MaxBodyBytes,
|
||||
MaxMetaBytes: c.MaxMetaBytes,
|
||||
@@ -56,14 +56,26 @@ func LimitsFromConfig(c config.LimitsConfig) Limits {
|
||||
MaxTTLSeconds: int64(c.MaxTTLSeconds),
|
||||
MaxScheduleSeconds: int64(c.MaxScheduleSeconds),
|
||||
RequestsPerSecond: float64(c.RequestsPerSecond),
|
||||
RequestBurst: burst,
|
||||
RequestBurst: defaultRequestBurst,
|
||||
MaxPendingPerSender: c.MaxPendingPerSender,
|
||||
MaxPendingPerReceiver: c.MaxPendingPerReceiver,
|
||||
GraceSeconds: int64(c.GraceSeconds),
|
||||
AckTimeoutSeconds: int64(c.AckTimeoutSeconds),
|
||||
DeliveryWindow: c.DeliveryWindow,
|
||||
ReceiptWindow: c.ReceiptWindow,
|
||||
}
|
||||
}
|
||||
|
||||
// App 实现 Service 的提交路径(M1);其余方法暂返回未实现或空操作。
|
||||
// LimitsFromFullConfig 附带保留天数等顶层配置。
|
||||
func LimitsFromFullConfig(cfg config.Config) Limits {
|
||||
lim := LimitsFromConfig(cfg.Limits)
|
||||
lim.RecordRetentionDays = cfg.RecordRetentionDays
|
||||
lim.ReceiptRetentionDays = cfg.ReceiptRetentionDays
|
||||
lim.IdempotencyHours = cfg.IdempotencyHours
|
||||
return lim
|
||||
}
|
||||
|
||||
// App 实现 Service:提交、分发、推送、确认、撤回、回执、清理与启动恢复。
|
||||
type App struct {
|
||||
db *store.DB
|
||||
lim Limits
|
||||
@@ -71,6 +83,15 @@ type App struct {
|
||||
locks auth.LoginLocks
|
||||
nowFn func() time.Time
|
||||
rates *rateLimiter
|
||||
|
||||
down port.Downlink
|
||||
conns ConnRegistry
|
||||
|
||||
mu sync.Mutex
|
||||
largeSem chan struct{}
|
||||
largeHeld map[string]bool
|
||||
pendingRevoke []revokeJob
|
||||
repushTimers map[string]*time.Timer
|
||||
}
|
||||
|
||||
// Option 配置 App。
|
||||
@@ -86,17 +107,41 @@ func WithLocks(locks auth.LoginLocks) Option {
|
||||
return func(a *App) { a.locks = locks }
|
||||
}
|
||||
|
||||
// New 创建消息服务实现。hash 用于校验对话密码;locks 可为 nil。
|
||||
// WithDownlink 注入下行发布器(未接线时测试用 RecordingDownlink)。
|
||||
func WithDownlink(d port.Downlink) Option {
|
||||
return func(a *App) { a.down = d }
|
||||
}
|
||||
|
||||
// WithConnRegistry 注入连接查询。
|
||||
func WithConnRegistry(c ConnRegistry) Option {
|
||||
return func(a *App) { a.conns = c }
|
||||
}
|
||||
|
||||
// New 创建消息服务实现。
|
||||
func New(db *store.DB, lim Limits, hash auth.HashPool, opts ...Option) *App {
|
||||
if lim.RequestBurst <= 0 {
|
||||
lim.RequestBurst = defaultRequestBurst
|
||||
}
|
||||
if lim.DeliveryWindow <= 0 {
|
||||
lim.DeliveryWindow = defaultDeliveryWindow
|
||||
}
|
||||
if lim.ReceiptWindow <= 0 {
|
||||
lim.ReceiptWindow = defaultReceiptWindow
|
||||
}
|
||||
if lim.AckTimeoutSeconds <= 0 {
|
||||
lim.AckTimeoutSeconds = 300
|
||||
}
|
||||
if lim.GraceSeconds < 0 {
|
||||
lim.GraceSeconds = 60
|
||||
}
|
||||
a := &App{
|
||||
db: db,
|
||||
lim: lim,
|
||||
hash: hash,
|
||||
nowFn: time.Now,
|
||||
rates: newRateLimiter(lim.RequestsPerSecond, lim.RequestBurst),
|
||||
db: db,
|
||||
lim: lim,
|
||||
hash: hash,
|
||||
nowFn: time.Now,
|
||||
rates: newRateLimiter(lim.RequestsPerSecond, lim.RequestBurst),
|
||||
largeSem: make(chan struct{}, maxLargeInflight),
|
||||
largeHeld: make(map[string]bool),
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(a)
|
||||
@@ -116,38 +161,4 @@ func (a *App) protocolLimits() protocol.Limits {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) Ack(context.Context, string, *protocol.Ack) (AckResult, error) {
|
||||
return AckResult{}, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (a *App) Recall(context.Context, string, *protocol.Recall) (protocol.RecallData, error) {
|
||||
return protocol.RecallData{}, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (a *App) Status(context.Context, string, *protocol.Status) (any, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (a *App) ReceiptAck(context.Context, string, *protocol.ReceiptAck) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (a *App) DispatchDue(context.Context, int64, int) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (a *App) PushPending(context.Context, string, port.ConnID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) OnPublishDropped(context.Context, string, port.ConnID, []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) CleanupOnce(context.Context, int64) error { return nil }
|
||||
|
||||
func (a *App) RecoverOnStart(context.Context) error { return nil }
|
||||
|
||||
func (a *App) WakePush(string) {}
|
||||
|
||||
var _ Service = (*App)(nil)
|
||||
|
||||
Reference in New Issue
Block a user