|
@@ -1,100 +1,9 @@
|
|
#nullable enable
|
|
#nullable enable
|
|
|
|
|
|
-using System.Collections.Concurrent;
|
|
|
|
using System.Runtime.ConstrainedExecution;
|
|
using System.Runtime.ConstrainedExecution;
|
|
|
|
|
|
namespace Terminal.Gui;
|
|
namespace Terminal.Gui;
|
|
|
|
|
|
-public class AnsiRequestScheduler(IAnsiResponseParser parser)
|
|
|
|
-{
|
|
|
|
- public static int sent = 0;
|
|
|
|
- public List<AnsiEscapeSequenceRequest> Requests = new ();
|
|
|
|
-
|
|
|
|
- private ConcurrentDictionary<string, DateTime> _lastSend = new ();
|
|
|
|
-
|
|
|
|
- private TimeSpan _throttle = TimeSpan.FromMilliseconds (100);
|
|
|
|
- private TimeSpan _runScheduleThrottle = TimeSpan.FromMilliseconds (100);
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Sends the <paramref name="request"/> immediately or queues it if there is already
|
|
|
|
- /// an outstanding request for the given <see cref="AnsiEscapeSequenceRequest.Terminator"/>.
|
|
|
|
- /// </summary>
|
|
|
|
- /// <param name="request"></param>
|
|
|
|
- /// <returns><see langword="true"/> if request was sent immediately. <see langword="false"/> if it was queued.</returns>
|
|
|
|
- public bool SendOrSchedule (AnsiEscapeSequenceRequest request )
|
|
|
|
- {
|
|
|
|
- if (CanSend(request))
|
|
|
|
- {
|
|
|
|
- Send (request);
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- Requests.Add (request);
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private DateTime _lastRun = DateTime.Now;
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Identifies and runs any <see cref="Requests"/> that can be sent based on the
|
|
|
|
- /// current outstanding requests of the parser.
|
|
|
|
- /// </summary>
|
|
|
|
- /// <param name="force">Repeated requests to run the schedule over short period of time will be ignored.
|
|
|
|
- /// Pass <see langword="true"/> to override this behaviour and force evaluation of outstanding requests.</param>
|
|
|
|
- /// <returns><see langword="true"/> if a request was found and run. <see langword="false"/>
|
|
|
|
- /// if no outstanding requests or all have existing outstanding requests underway in parser.</returns>
|
|
|
|
- public bool RunSchedule (bool force = false)
|
|
|
|
- {
|
|
|
|
- if (!force && DateTime.Now - _lastRun < _runScheduleThrottle)
|
|
|
|
- {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- var opportunity = Requests.FirstOrDefault (CanSend);
|
|
|
|
-
|
|
|
|
- if (opportunity != null)
|
|
|
|
- {
|
|
|
|
- Requests.Remove (opportunity);
|
|
|
|
- Send (opportunity);
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void Send (AnsiEscapeSequenceRequest r)
|
|
|
|
- {
|
|
|
|
- Interlocked.Increment(ref sent);
|
|
|
|
- _lastSend.AddOrUpdate (r.Terminator,(s)=>DateTime.Now,(s,v)=>DateTime.Now);
|
|
|
|
- parser.ExpectResponse (r.Terminator,r.ResponseReceived);
|
|
|
|
- r.Send ();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public bool CanSend (AnsiEscapeSequenceRequest r)
|
|
|
|
- {
|
|
|
|
- if (ShouldThrottle (r))
|
|
|
|
- {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return !parser.IsExpecting (r.Terminator);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private bool ShouldThrottle (AnsiEscapeSequenceRequest r)
|
|
|
|
- {
|
|
|
|
- if (_lastSend.TryGetValue (r.Terminator, out DateTime value))
|
|
|
|
- {
|
|
|
|
- return DateTime.Now - value < _throttle;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
internal abstract class AnsiResponseParserBase : IAnsiResponseParser
|
|
{
|
|
{
|
|
protected readonly List<(string terminator, Action<string> response)> expectedResponses = new ();
|
|
protected readonly List<(string terminator, Action<string> response)> expectedResponses = new ();
|