XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFE.SpaceEngineers.AgentBridge

【SpaceEngineer】AI调试插件

公开
关注 0 Fork 0 Star 0
UTF-8
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using XFE.SeAgent.Plugin.Protocol;

namespace XFE.SeAgent.Plugin.Transport
{
    internal sealed class PendingRequest
    {
        private readonly object gate = new object();
        private readonly long deadline;
        private readonly Func<bool> connectionAlive;
        private readonly Func<bool> serverStopped;
        private readonly TaskCompletionSource<JObject> completion = new TaskCompletionSource<JObject>(TaskCreationOptions.RunContinuationsAsynchronously);
        private RequestState state;

        internal AgentRequest Request { get; }
        internal Task<JObject> Completion => completion.Task;

        internal PendingRequest(AgentRequest request, Func<bool> connectionAlive, Func<bool> serverStopped)
        {
            Request = request;
            this.connectionAlive = connectionAlive;
            this.serverStopped = serverStopped;
            deadline = Stopwatch.GetTimestamp() + (long)Math.Ceiling(request.TimeoutMs * (double)Stopwatch.Frequency / 1000);
        }

        // This is the execution boundary. Cancellation before this claim prevents dispatch;
        // an already executing game operation cannot safely be interrupted by a pipe worker.
        internal bool TryStart()
        {
            lock (gate)
            {
                if (state != RequestState.Waiting) return false;
                if (serverStopped()) return CancelLocked("server_stopped", "Agent server has stopped.");
                if (Stopwatch.GetTimestamp() >= deadline) return CancelLocked("timeout", "Request expired before execution.");
                if (!connectionAlive()) return CancelLocked("disconnected", "Client disconnected before execution.");
                if (serverStopped()) return CancelLocked("server_stopped", "Agent server has stopped.");
                if (Stopwatch.GetTimestamp() >= deadline) return CancelLocked("timeout", "Request expired before execution.");
                state = RequestState.Executing;
                return true;
            }
        }

        internal void Complete(JObject response)
        {
            lock (gate)
            {
                if (state != RequestState.Executing) return;
                state = RequestState.Finished;
                completion.TrySetResult(response);
            }
        }

        internal void Cancel(string code, string message)
        {
            lock (gate)
            {
                if (state == RequestState.Finished || state == RequestState.Canceled) return;
                if (state == RequestState.Executing && code == "timeout")
                    message = "Request timed out after execution began; the operation may have completed. Check state before retrying.";
                CancelLocked(code, message);
            }
        }

        private bool CancelLocked(string code, string message)
        {
            state = RequestState.Canceled;
            completion.TrySetResult(AgentProtocol.Error(Request.Id, code, message));
            return false;
        }

        private enum RequestState { Waiting, Executing, Finished, Canceled }
    }
}