mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 09:40:12 +00:00
145 lines
4.1 KiB
Go
145 lines
4.1 KiB
Go
//go:build agentcompat
|
|
|
|
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
type IOStreamQuotaProbeResult struct {
|
|
UserAccepted int
|
|
UserRejected int
|
|
ServerAccepted int
|
|
ServerRejected int
|
|
TrackedStreams int
|
|
WaitForAgentWokeOnClose bool
|
|
UserSlotReused bool
|
|
UserBoundaryError error
|
|
ServerBoundaryError error
|
|
Err error
|
|
}
|
|
|
|
func RunIOStreamQuotaProbe(ctx context.Context) IOStreamQuotaProbeResult {
|
|
if err := ctx.Err(); err != nil {
|
|
return IOStreamQuotaProbeResult{Err: err}
|
|
}
|
|
h := NewNezhaHandler()
|
|
result := IOStreamQuotaProbeResult{}
|
|
defer func() {
|
|
h.ioStreamMutex.RLock()
|
|
streamIDs := make([]string, 0, len(h.ioStreams))
|
|
for streamID := range h.ioStreams {
|
|
streamIDs = append(streamIDs, streamID)
|
|
}
|
|
h.ioStreamMutex.RUnlock()
|
|
for _, streamID := range streamIDs {
|
|
_ = h.CloseStream(streamID)
|
|
}
|
|
}()
|
|
for i := 0; i < maxStreamsPerUser; i++ {
|
|
if err := h.CreateStream(fmt.Sprintf("probe-user-%d", i), 101, uint64(i+1)); err != nil {
|
|
result.Err = fmt.Errorf("create user stream %d: %w", i, err)
|
|
return result
|
|
}
|
|
result.UserAccepted++
|
|
}
|
|
result.UserBoundaryError = h.CreateStream("probe-user-over", 101, 500)
|
|
if !errors.Is(result.UserBoundaryError, ErrTooManyStreamsForUser) {
|
|
result.Err = fmt.Errorf("user boundary returned %v", result.UserBoundaryError)
|
|
return result
|
|
}
|
|
result.UserRejected = 1
|
|
|
|
for i := 0; i < maxStreamsPerServer; i++ {
|
|
if err := h.CreateStream(fmt.Sprintf("probe-server-%d", i), uint64(i+1000), 700); err != nil {
|
|
result.Err = fmt.Errorf("create server stream %d: %w", i, err)
|
|
return result
|
|
}
|
|
result.ServerAccepted++
|
|
}
|
|
result.ServerBoundaryError = h.CreateStream("probe-server-over", 2000, 700)
|
|
if !errors.Is(result.ServerBoundaryError, ErrTooManyStreamsForServer) {
|
|
result.Err = fmt.Errorf("server boundary returned %v", result.ServerBoundaryError)
|
|
return result
|
|
}
|
|
result.ServerRejected = 1
|
|
|
|
if err := h.CloseStream("probe-user-0"); err != nil {
|
|
result.Err = fmt.Errorf("close stale user slot: %w", err)
|
|
return result
|
|
}
|
|
if err := h.CreateStream("probe-user-reused", 101, 501); err != nil {
|
|
result.Err = fmt.Errorf("reuse stale user slot: %w", err)
|
|
return result
|
|
}
|
|
result.UserSlotReused = true
|
|
|
|
if err := h.CreateStream("probe-wait", 0, 502); err != nil {
|
|
result.Err = fmt.Errorf("create cancellation probe stream: %w", err)
|
|
return result
|
|
}
|
|
waitStream, err := h.GetStream("probe-wait")
|
|
if err != nil {
|
|
result.Err = fmt.Errorf("get cancellation probe stream: %w", err)
|
|
return result
|
|
}
|
|
waitResult := make(chan bool, 1)
|
|
go func() {
|
|
_, ok := h.WaitForAgent(ctx, "probe-wait", 30*time.Second)
|
|
waitResult <- ok
|
|
}()
|
|
select {
|
|
case <-waitStream.waitStartedCh:
|
|
case <-ctx.Done():
|
|
result.Err = ctx.Err()
|
|
return result
|
|
}
|
|
if err := h.CloseStream("probe-wait"); err != nil {
|
|
result.Err = fmt.Errorf("close cancellation probe stream: %w", err)
|
|
return result
|
|
}
|
|
select {
|
|
case ok := <-waitResult:
|
|
result.WaitForAgentWokeOnClose = !ok
|
|
case <-ctx.Done():
|
|
result.Err = ctx.Err()
|
|
return result
|
|
}
|
|
if !result.WaitForAgentWokeOnClose {
|
|
result.Err = errors.New("WaitForAgent did not wake after stream close")
|
|
return result
|
|
}
|
|
|
|
for i := 0; i < maxStreamsPerUser; i++ {
|
|
if err := h.CloseStream(fmt.Sprintf("probe-user-%d", i)); err != nil {
|
|
result.Err = fmt.Errorf("close user stream %d: %w", i, err)
|
|
return result
|
|
}
|
|
if err := h.CloseStream(fmt.Sprintf("probe-user-%d", i)); err != nil {
|
|
result.Err = fmt.Errorf("repeat close user stream %d: %w", i, err)
|
|
return result
|
|
}
|
|
}
|
|
if err := h.CloseStream("probe-user-reused"); err != nil {
|
|
result.Err = fmt.Errorf("close reused user slot: %w", err)
|
|
return result
|
|
}
|
|
for i := 0; i < maxStreamsPerServer; i++ {
|
|
if err := h.CloseStream(fmt.Sprintf("probe-server-%d", i)); err != nil {
|
|
result.Err = fmt.Errorf("close server stream %d: %w", i, err)
|
|
return result
|
|
}
|
|
}
|
|
if err := ctx.Err(); err != nil {
|
|
result.Err = err
|
|
return result
|
|
}
|
|
h.ioStreamMutex.RLock()
|
|
result.TrackedStreams = len(h.ioStreams)
|
|
h.ioStreamMutex.RUnlock()
|
|
return result
|
|
}
|