- trigger.go: 新增 TriggerKind(TriggerHeartbeat/TriggerEvent) + Trigger.Kind 标记触发来源 - push.go: PushRequest.TriggerKind 分流——event 跳过 gate.Allow/RecordPush(该发就发),heartbeat 仍受 60min≤1/冷却/分类限频;PushResult.Bypassed 标记 + detail=event_bypass 区分 - backthink.go: think() 传 TriggerKind + 过同事件去重门 - event_dedup.go(新): 同事件(Source+Summary)去重防刷,无 60min 节流;不同事件/心跳后重置链 - 测试: event 连续 3 次全推 bypass / heartbeat 第2次 rate_limited / event 不消耗心跳限 / 同事件去重 - build/vet/test 全绿 + windows/darwin 交叉编译通过
32 lines
1.2 KiB
Go
32 lines
1.2 KiB
Go
package backthink
|
|
|
|
// eventRedundant reports whether tr is a duplicate of the immediately preceding
|
|
// event-driven push (same source + summary), so a repeating device/reminder event
|
|
// does not spam the owner (防刷). It is the one guard that still applies to an
|
|
// event-driven push while the PushGate itself is bypassed for events (owner
|
|
// mandate: "该发就发" — a genuine event goes out, only a true duplicate is held).
|
|
//
|
|
// It atomically records tr as the latest event key when the push proceeds, and
|
|
// clears the key on any non-event push (heartbeat) so a later repeat of a prior
|
|
// event is not spuriously suppressed by an intervening reflection.
|
|
//
|
|
// The caller runs it before handing the push to the Pusher; a true duplicate is
|
|
// recorded as suppressed (RouteNone) rather than delivered.
|
|
func (b *Backthink) eventRedundant(tr Trigger) bool {
|
|
if tr.Kind != TriggerEvent {
|
|
// A non-event push (heartbeat) breaks the same-event chain.
|
|
b.eventMu.Lock()
|
|
b.lastEventKey = ""
|
|
b.eventMu.Unlock()
|
|
return false
|
|
}
|
|
key := tr.Source + "\x00" + tr.Summary
|
|
b.eventMu.Lock()
|
|
defer b.eventMu.Unlock()
|
|
if b.lastEventKey == key {
|
|
return true
|
|
}
|
|
b.lastEventKey = key
|
|
return false
|
|
}
|