105 lines
2.8 KiB
Go
105 lines
2.8 KiB
Go
package isphere
|
|
|
|
import "math"
|
|
|
|
const reconciliationMediumTimestampWindowMillis int64 = 3000
|
|
|
|
type MessageReconciliationCandidate struct {
|
|
Source string
|
|
MessageID string
|
|
ConversationID string
|
|
SenderID string
|
|
TimestampUnixMilli int64
|
|
BodyPresent bool
|
|
AttachmentPresent bool
|
|
}
|
|
|
|
type MessageReconciliationSummary struct {
|
|
LeftCount int
|
|
RightCount int
|
|
StrongMatches int
|
|
MediumMatches int
|
|
UnmatchedLeft int
|
|
UnmatchedRight int
|
|
AutoMergeRecommended bool
|
|
}
|
|
|
|
func ReconcileMessageSources(left, right []MessageReconciliationCandidate) MessageReconciliationSummary {
|
|
matchedLeft := make([]bool, len(left))
|
|
matchedRight := make([]bool, len(right))
|
|
summary := MessageReconciliationSummary{LeftCount: len(left), RightCount: len(right)}
|
|
|
|
for leftIndex, leftCandidate := range left {
|
|
if leftCandidate.MessageID == "" {
|
|
continue
|
|
}
|
|
for rightIndex, rightCandidate := range right {
|
|
if matchedRight[rightIndex] || rightCandidate.MessageID == "" {
|
|
continue
|
|
}
|
|
if leftCandidate.MessageID == rightCandidate.MessageID {
|
|
matchedLeft[leftIndex] = true
|
|
matchedRight[rightIndex] = true
|
|
summary.StrongMatches++
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
for leftIndex, leftCandidate := range left {
|
|
if matchedLeft[leftIndex] {
|
|
continue
|
|
}
|
|
for rightIndex, rightCandidate := range right {
|
|
if matchedRight[rightIndex] {
|
|
continue
|
|
}
|
|
if isMediumMessageMatch(leftCandidate, rightCandidate) {
|
|
matchedLeft[leftIndex] = true
|
|
matchedRight[rightIndex] = true
|
|
summary.MediumMatches++
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
summary.UnmatchedLeft = countFalse(matchedLeft)
|
|
summary.UnmatchedRight = countFalse(matchedRight)
|
|
summary.AutoMergeRecommended = shouldRecommendAutoMerge(summary)
|
|
return summary
|
|
}
|
|
|
|
func isMediumMessageMatch(left, right MessageReconciliationCandidate) bool {
|
|
if left.ConversationID == "" || right.ConversationID == "" || left.ConversationID != right.ConversationID {
|
|
return false
|
|
}
|
|
if left.SenderID == "" || right.SenderID == "" || left.SenderID != right.SenderID {
|
|
return false
|
|
}
|
|
if left.TimestampUnixMilli <= 0 || right.TimestampUnixMilli <= 0 {
|
|
return false
|
|
}
|
|
delta := int64(math.Abs(float64(left.TimestampUnixMilli - right.TimestampUnixMilli)))
|
|
return delta <= reconciliationMediumTimestampWindowMillis
|
|
}
|
|
|
|
func countFalse(values []bool) int {
|
|
count := 0
|
|
for _, value := range values {
|
|
if !value {
|
|
count++
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
func shouldRecommendAutoMerge(summary MessageReconciliationSummary) bool {
|
|
if summary.LeftCount == 0 || summary.RightCount == 0 {
|
|
return false
|
|
}
|
|
if summary.UnmatchedLeft != 0 || summary.UnmatchedRight != 0 || summary.MediumMatches != 0 {
|
|
return false
|
|
}
|
|
return summary.StrongMatches == summary.LeftCount && summary.StrongMatches == summary.RightCount
|
|
}
|