mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 17:50:12 +00:00
95 lines
3.0 KiB
Go
95 lines
3.0 KiB
Go
//go:build linux
|
|
|
|
package dashboard
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
func (dashboard *Dashboard) MCPReceiptCursor() MCPReceiptCursor {
|
|
dashboard.eventMu.RLock()
|
|
defer dashboard.eventMu.RUnlock()
|
|
return MCPReceiptCursor{Sequence: dashboard.mcpReceiptSequence}
|
|
}
|
|
|
|
func (dashboard *Dashboard) MCPReceiptEventsAfter(cursor MCPReceiptCursor) []MCPReceiptEvent {
|
|
dashboard.eventMu.RLock()
|
|
defer dashboard.eventMu.RUnlock()
|
|
events := make([]MCPReceiptEvent, 0, len(dashboard.mcpReceiptEvents))
|
|
for _, event := range dashboard.mcpReceiptEvents {
|
|
if event.Sequence > cursor.Sequence {
|
|
events = append(events, event)
|
|
}
|
|
}
|
|
return events
|
|
}
|
|
|
|
func (dashboard *Dashboard) WaitForMCPReceiptPairs(ctx context.Context, cursor MCPReceiptCursor, expectations []MCPReceiptExpectation) ([]MCPReceiptPair, error) {
|
|
if len(expectations) == 0 {
|
|
return nil, errors.New("MCP receipt expectations are empty")
|
|
}
|
|
for {
|
|
dashboard.eventMu.RLock()
|
|
notify, closed := dashboard.eventNotify, dashboard.eventClosed
|
|
events := append([]MCPReceiptEvent(nil), dashboard.mcpReceiptEvents...)
|
|
dashboard.eventMu.RUnlock()
|
|
pairs, complete, err := matchMCPReceiptPairs(events, cursor, expectations)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if complete {
|
|
return pairs, nil
|
|
}
|
|
if closed {
|
|
return nil, ErrReceiptGateClosed
|
|
}
|
|
select {
|
|
case <-notify:
|
|
case <-ctx.Done():
|
|
return nil, ctx.Err()
|
|
}
|
|
}
|
|
}
|
|
|
|
func matchMCPReceiptPairs(events []MCPReceiptEvent, cursor MCPReceiptCursor, expectations []MCPReceiptExpectation) ([]MCPReceiptPair, bool, error) {
|
|
pairs := make([]MCPReceiptPair, len(expectations))
|
|
matched := make(map[uint64]int, len(expectations))
|
|
for _, event := range events {
|
|
if event.Sequence <= cursor.Sequence {
|
|
continue
|
|
}
|
|
index, exists := matched[event.TaskID]
|
|
if !exists {
|
|
if event.Kind != MCPReceiptTask || len(matched) >= len(expectations) {
|
|
return nil, false, fmt.Errorf("unexpected MCP receipt event after cursor: %+v", event)
|
|
}
|
|
index = len(matched)
|
|
expectation := expectations[index]
|
|
if event.ServerID != expectation.ServerID || event.TaskType != expectation.TaskType {
|
|
return nil, false, fmt.Errorf("MCP task receipt mismatch at index %d: %+v", index, event)
|
|
}
|
|
matched[event.TaskID] = index
|
|
pairs[index].Task = event
|
|
continue
|
|
}
|
|
if event.Kind != MCPReceiptResult || pairs[index].Result.TaskID != 0 {
|
|
return nil, false, fmt.Errorf("MCP task ID %d was received more than once", event.TaskID)
|
|
}
|
|
if event.ServerID != pairs[index].Task.ServerID || event.TaskType != pairs[index].Task.TaskType || event.GateGeneration != pairs[index].Task.GateGeneration || event.DashboardGeneration != pairs[index].Task.DashboardGeneration {
|
|
return nil, false, fmt.Errorf("MCP result receipt does not match task: task=%+v result=%+v", pairs[index].Task, event)
|
|
}
|
|
pairs[index].Result = event
|
|
}
|
|
if len(matched) != len(expectations) {
|
|
return nil, false, nil
|
|
}
|
|
for _, pair := range pairs {
|
|
if pair.Result.TaskID == 0 {
|
|
return nil, false, nil
|
|
}
|
|
}
|
|
return pairs, true, nil
|
|
}
|