Files
2026-07-20 04:46:55 +00:00

185 lines
4.6 KiB
Go

//go:build linux
package dashboard
import (
"context"
"errors"
"fmt"
"strings"
)
func (dashboard *Dashboard) WaitForReceiptAccepted(ctx context.Context) error {
if dashboard.receiptEvents == nil {
return errors.New("receipt gate is disabled")
}
for {
dashboard.eventMu.RLock()
closed, notify := dashboard.eventClosed, dashboard.eventNotify
dashboard.eventMu.RUnlock()
dashboard.receiptMu.RLock()
observed := dashboard.receiptAcceptedCount > 0
dashboard.receiptMu.RUnlock()
if closed {
return ErrReceiptGateClosed
}
if observed {
return nil
}
select {
case <-notify:
case <-ctx.Done():
return ctx.Err()
}
}
}
func (dashboard *Dashboard) WaitForSecondState(ctx context.Context) error {
if dashboard.receiptEvents == nil {
return errors.New("receipt gate is disabled")
}
for {
dashboard.eventMu.RLock()
closed, notify := dashboard.eventClosed, dashboard.eventNotify
dashboard.eventMu.RUnlock()
dashboard.receiptMu.RLock()
observed := dashboard.receiptAcceptedCount >= 2
dashboard.receiptMu.RUnlock()
if closed {
return ErrReceiptGateClosed
}
if observed {
return nil
}
select {
case <-notify:
case <-ctx.Done():
return ctx.Err()
}
}
}
func (dashboard *Dashboard) WaitForState(ctx context.Context, want uint64) error {
return dashboard.waitForState(ctx, 0, "", 0, want)
}
func (dashboard *Dashboard) WaitForStateGeneration(ctx context.Context, serverID uint64, uuid string, generation, want uint64) error {
return dashboard.waitForState(ctx, serverID, uuid, generation, want)
}
func (dashboard *Dashboard) StateGeneration(serverID uint64, uuid string) uint64 {
dashboard.stateMu.Lock()
defer dashboard.stateMu.Unlock()
var generation uint64
for event := range dashboard.stateEvents {
if event.ServerID == serverID && event.UUID == uuid && event.Generation > generation {
generation = event.Generation
}
}
return generation
}
func (dashboard *Dashboard) waitForState(ctx context.Context, serverID uint64, uuid string, generation, want uint64) error {
if dashboard.receiptEvents == nil {
return errors.New("receipt gate is disabled")
}
for {
dashboard.eventMu.RLock()
closed, notify := dashboard.eventClosed, dashboard.eventNotify
dashboard.eventMu.RUnlock()
dashboard.stateMu.Lock()
observed := false
for event := range dashboard.stateEvents {
if (serverID == 0 || event.ServerID == serverID) && (uuid == "" || event.UUID == uuid) && (generation == 0 || event.Generation == generation) && event.Count == want {
observed = true
break
}
}
dashboard.stateMu.Unlock()
if closed {
return ErrReceiptGateClosed
}
if observed {
return nil
}
select {
case <-notify:
case <-ctx.Done():
return ctx.Err()
}
}
}
func (dashboard *Dashboard) WaitForInfo2(ctx context.Context, serverID uint64, uuid string) error {
if dashboard.receiptEvents == nil {
return errors.New("receipt gate is disabled")
}
want := fmt.Sprintf("info2 %d %s\n", serverID, uuid)
for {
dashboard.eventMu.RLock()
closed, notify := dashboard.eventClosed, dashboard.eventNotify
dashboard.eventMu.RUnlock()
dashboard.info2Mu.Lock()
_, observed := dashboard.info2Events[want]
dashboard.info2Mu.Unlock()
if closed {
return ErrReceiptGateClosed
}
if observed {
return nil
}
select {
case <-notify:
case <-ctx.Done():
return ctx.Err()
}
}
}
func (dashboard *Dashboard) WaitForInfo2UUID(ctx context.Context, uuid string) (uint64, error) {
if dashboard.receiptEvents == nil {
return 0, errors.New("receipt gate is disabled")
}
for {
dashboard.eventMu.RLock()
closed, notify := dashboard.eventClosed, dashboard.eventNotify
dashboard.eventMu.RUnlock()
dashboard.info2Mu.Lock()
for event := range dashboard.info2Events {
fields := strings.Fields(event)
if len(fields) == 3 && fields[0] == "info2" && fields[2] == uuid {
var serverID uint64
if _, err := fmt.Sscan(fields[1], &serverID); err == nil && serverID != 0 {
dashboard.info2Mu.Unlock()
return serverID, nil
}
}
}
dashboard.info2Mu.Unlock()
if closed {
return 0, ErrReceiptGateClosed
}
select {
case <-notify:
case <-ctx.Done():
return 0, ctx.Err()
}
}
}
func (dashboard *Dashboard) ReceiptAccepted() bool {
dashboard.receiptMu.RLock()
defer dashboard.receiptMu.RUnlock()
return dashboard.receiptAccepted
}
func (dashboard *Dashboard) ReceiptAcceptedCount() uint64 {
dashboard.receiptMu.RLock()
defer dashboard.receiptMu.RUnlock()
return dashboard.receiptAcceptedCount
}
func (dashboard *Dashboard) ReceiptGeneration() uint64 {
dashboard.receiptMu.RLock()
defer dashboard.receiptMu.RUnlock()
return dashboard.receiptGeneration
}