Sfoglia il codice sorgente

additional rate throttling behavior

gravydevsupreme 7 anni fa
parent
commit
94336588da

+ 32 - 21
src/XUnity.AutoTranslator.Plugin.Core/AutoTranslationPlugin.cs

@@ -77,12 +77,11 @@ namespace XUnity.AutoTranslator.Plugin.Core
       /// </summary>
       private Func<string, bool> _symbolCheck;
 
-      private int[] _currentTranslationsQueuedPerSecond = new int[ Settings.TranslationQueueWatchWindow ];
+      private int[] _currentTranslationsQueuedPerSecondRollingWindow = new int[ Settings.TranslationQueueWatchWindow ];
       private float? _timeExceededThreshold;
 
       private bool _isInTranslatedMode = true;
       private bool _hooksEnabled = true;
-      private bool _forceShutdown = false;
 
       public void Initialize()
       {
@@ -235,35 +234,35 @@ namespace XUnity.AutoTranslator.Plugin.Core
          job = new TranslationJob( key );
          _unstartedJobs.Add( key.ForcedRelevantKey, job );
 
-         AddToThresholdTimeAndCheck();
+         CheckThresholds();
 
          return job;
       }
 
-      private void AddToThresholdTimeAndCheck()
+      private void CheckThresholds()
       {
          var previousIdx = ( (int)( Time.time - Time.deltaTime ) ) % Settings.TranslationQueueWatchWindow;
          var newIdx = ( (int)Time.time ) % Settings.TranslationQueueWatchWindow;
          if( previousIdx != newIdx )
          {
-            _currentTranslationsQueuedPerSecond[ newIdx ] = 0;
+            _currentTranslationsQueuedPerSecondRollingWindow[ newIdx ] = 0;
          }
-         _currentTranslationsQueuedPerSecond[ newIdx ]++;
+         _currentTranslationsQueuedPerSecondRollingWindow[ newIdx ]++;
 
-         var translationsInWindow = _currentTranslationsQueuedPerSecond.Sum();
+         var translationsInWindow = _currentTranslationsQueuedPerSecondRollingWindow.Sum();
          var translationsPerSecond = (float)translationsInWindow / Settings.TranslationQueueWatchWindow;
          if( translationsPerSecond > Settings.MaxTranslationsQueuedPerSecond )
          {
-            // ABOVE THRESHOLD, remember time
             if( !_timeExceededThreshold.HasValue )
             {
                _timeExceededThreshold = Time.time;
             }
 
-            if( Time.time - _timeExceededThreshold.Value > Settings.MaxSecondsAboveTranslationThreshold )
+            if( Time.time - _timeExceededThreshold.Value > Settings.MaxSecondsAboveTranslationThreshold || _unstartedJobs.Count > Settings.MaxUnstartedJobs )
             {
                _unstartedJobs.Clear();
-               _forceShutdown = true;
+               _completedJobs.Clear();
+               Settings.IsShutdown = true;
 
                Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: Shutting down... spam detected." );
             }
@@ -280,10 +279,10 @@ namespace XUnity.AutoTranslator.Plugin.Core
          var newIdx = ( (int)Time.time ) % Settings.TranslationQueueWatchWindow;
          if( previousIdx != newIdx )
          {
-            _currentTranslationsQueuedPerSecond[ newIdx ] = 0;
+            _currentTranslationsQueuedPerSecondRollingWindow[ newIdx ] = 0;
          }
 
-         var translationsInWindow = _currentTranslationsQueuedPerSecond.Sum();
+         var translationsInWindow = _currentTranslationsQueuedPerSecondRollingWindow.Sum();
          var translationsPerSecond = (float)translationsInWindow / Settings.TranslationQueueWatchWindow;
 
          if( translationsPerSecond <= Settings.MaxTranslationsQueuedPerSecond )
@@ -337,7 +336,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
       private string Override_TextChanged( object ui, string text )
       {
-         if( _hooksEnabled && !_forceShutdown )
+         if( _hooksEnabled && !Settings.IsShutdown )
          {
             return TranslateOrQueueWebJob( ui, text, true );
          }
@@ -346,7 +345,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
       public void Hook_TextChanged( object ui )
       {
-         if( _hooksEnabled && !_forceShutdown )
+         if( _hooksEnabled && !Settings.IsShutdown )
          {
             TranslateOrQueueWebJob( ui, null, false );
          }
@@ -354,7 +353,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
       public void Hook_TextInitialized( object ui )
       {
-         if( _hooksEnabled && !_forceShutdown )
+         if( _hooksEnabled && !Settings.IsShutdown )
          {
             TranslateOrQueueWebJob( ui, null, true );
          }
@@ -559,10 +558,13 @@ namespace XUnity.AutoTranslator.Plugin.Core
                                  else
                                  {
                                     // Lets try not to spam a service that might not be there...
-                                    if( AutoTranslateClient.IsConfigured && _consecutiveErrors < Settings.MaxErrors )
+                                    if( AutoTranslateClient.IsConfigured )
                                     {
-                                       var job = GetOrCreateTranslationJobFor( stabilizedTextKey );
-                                       job.Components.Add( ui );
+                                       if( _consecutiveErrors < Settings.MaxErrors )
+                                       {
+                                          var job = GetOrCreateTranslationJobFor( stabilizedTextKey );
+                                          job.Components.Add( ui );
+                                       }
                                     }
                                     else
                                     {
@@ -587,9 +589,12 @@ namespace XUnity.AutoTranslator.Plugin.Core
                      QueueNewUntranslatedForClipboard( textKey );
 
                      // Lets try not to spam a service that might not be there...
-                     if( AutoTranslateClient.IsConfigured && _consecutiveErrors < Settings.MaxErrors )
+                     if( AutoTranslateClient.IsConfigured )
                      {
-                        GetOrCreateTranslationJobFor( textKey );
+                        if( _consecutiveErrors < Settings.MaxErrors )
+                        {
+                           GetOrCreateTranslationJobFor( textKey );
+                        }
                      }
                      else
                      {
@@ -645,7 +650,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
       public void Update()
       {
-         if( _forceShutdown ) return;
+         if( Settings.IsShutdown ) return;
 
          try
          {
@@ -719,6 +724,12 @@ namespace XUnity.AutoTranslator.Plugin.Core
             () =>
             {
                _consecutiveErrors++;
+
+               if( _consecutiveErrors > Settings.MaxErrors && !Settings.IsShutdown )
+               {
+                  Settings.IsShutdown = true;
+                  Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: More than 5 consecutive errors occurred. Shutting down plugin..." );
+               }
             } ) );
          }
 

+ 11 - 6
src/XUnity.AutoTranslator.Plugin.Core/Configuration/Settings.cs

@@ -11,13 +11,18 @@ namespace XUnity.AutoTranslator.Plugin.Core.Configuration
    {
       // cannot be changed
       public static readonly int MaxErrors = 5;
-      public static readonly int MaxConcurrentTranslations = 3;
-      public static readonly TimeSpan WebClientLifetime = TimeSpan.FromSeconds( 20 );
       public static readonly float ClipboardDebounceTime = 1f;
+      public static readonly int MaxTranslationsBeforeSlowdown = 1000;
+      public static readonly int MaxTranslationsBeforeShutdown = 6000;
+      public static readonly int MaxUnstartedJobs = 3500;
 
-      public static readonly float MaxTranslationsQueuedPerSecond = 6;
-      public static readonly int MaxSecondsAboveTranslationThreshold = 10;
-      public static readonly int TranslationQueueWatchWindow = 5;
+      public static int DefaultMaxConcurrentTranslations = 2;
+      public static int MaxConcurrentTranslations = DefaultMaxConcurrentTranslations;
+      public static bool IsShutdown = false;
+
+      public static readonly float MaxTranslationsQueuedPerSecond = 5;
+      public static readonly int MaxSecondsAboveTranslationThreshold = 30;
+      public static readonly int TranslationQueueWatchWindow = 10;
       
       // can be changed
       public static string ServiceEndpoint;
@@ -41,7 +46,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Configuration
       public static string BaiduAppSecret;
       public static int ForceSplitTextAfterCharacters;
 
-      public static bool CopyToClipboard = false;
+      public static bool CopyToClipboard;
       public static int MaxClipboardCopyCharacters;
 
       public static void Configure()

+ 1 - 1
src/XUnity.AutoTranslator.Plugin.Core/Constants/PluginInfo.cs

@@ -12,6 +12,6 @@ namespace XUnity.AutoTranslator.Plugin.Core.Constants
 
       public const string Name = "XUnity Auto Translator";
 
-      public const string Version = "2.4.0";
+      public const string Version = "2.5.0";
    }
 }

+ 0 - 75
src/XUnity.AutoTranslator.Plugin.Core/Translatiton/TranslationContext.cs

@@ -1,75 +0,0 @@
-//using System;
-//using System.Collections.Generic;
-//using System.IO;
-//using System.Linq;
-//using System.Text;
-
-//namespace XUnity.AutoTranslator.Plugin.Core.Translatiton
-//{
-//   public class TranslationContext
-//   {
-//      private Dictionary<string, string> _staticTranslations;
-//      private Dictionary<string, string> _dynamicTranslations;
-//      private Dictionary<string, HashSet<string>> _variables;
-
-//      public TranslationContext()
-//      {
-//         _staticTranslations = new Dictionary<string, string>();
-//         _dynamicTranslations = new Dictionary<string, string>();
-//         _variables = new Dictionary<string, HashSet<string>>();
-//      }
-
-//      public void AddVariable( string name, string value )
-//      {
-//         if( !_variables.TryGetValue( name, out var values ) )
-//         {
-//            values = new HashSet<string>();
-//         }
-
-//         values.Add( value );
-//      }
-//   }
-
-//   public class Translation
-//   {
-//      public string Key { get; set; }
-
-//      public string Expression { get; set; }
-//   }
-
-//   public enum DirectiveType
-//   {
-//      SetVariable,
-//      UnsetVariable
-//   }
-
-//   public class TranslationDirective
-//   {
-//      public TranslationDirective( string directive )
-//      {
-
-//      }
-//   }
-
-//   public class RangeValue
-//   {
-
-//   }
-//   public class TranslationReader : IDisposable
-//   {
-//      private readonly TextReader _reader;
-
-//      private string _activeLine;
-//      private List<TranslationDirective> _activeDirectives;
-
-//      public TranslationReader( TextReader reader )
-//      {
-//         _reader = reader;
-//      }
-
-//      public Translation Read()
-//      {
-
-//      }
-//   }
-//}

+ 21 - 125
src/XUnity.AutoTranslator.Plugin.Core/Web/AutoTranslateClient.cs

@@ -14,12 +14,9 @@ namespace XUnity.AutoTranslator.Plugin.Core.Web
 {
    public static class AutoTranslateClient
    {
-      //private static readonly object Sync = new object();
-      //private static readonly HashSet<WebClientReference> AvailableClients = new HashSet<WebClientReference>();
-      //private static readonly HashSet<WebClientReference> WorkingClients = new HashSet<WebClientReference>();
-
       private static KnownEndpoint _endpoint;
       private static int _runningTranslations = 0;
+      private static int _translationCount;
 
       public static void Configure()
       {
@@ -39,8 +36,6 @@ namespace XUnity.AutoTranslator.Plugin.Core.Web
          }
       }
 
-      //private static int CurrentClientCount => AvailableClients.Count + WorkingClients.Count;
-
       public static bool HasAvailableClients => _runningTranslations < Settings.MaxConcurrentTranslations;
 
       public static IEnumerator TranslateByWWW( string untranslated, string from, string to, Action<string> success, Action failure )
@@ -55,6 +50,26 @@ namespace XUnity.AutoTranslator.Plugin.Core.Web
             yield return www;
             _runningTranslations--;
 
+            if( Settings.MaxConcurrentTranslations == Settings.DefaultMaxConcurrentTranslations )
+            {
+               _translationCount++;
+               if( _translationCount > Settings.MaxTranslationsBeforeSlowdown )
+               {
+                  Settings.MaxConcurrentTranslations = 1;
+                  Console.WriteLine( "[XUnity.AutoTranslator][WARN]: Maximum translations per session reached. Entering slowdown mode." );
+               }
+
+               if( !Settings.IsShutdown )
+               {
+                  if( _translationCount > Settings.MaxTranslationsBeforeShutdown )
+                  {
+                     Settings.IsShutdown = true;
+                     Console.WriteLine( "[XUnity.AutoTranslator][ERROR]: Maximum translations per session reached. Shutting plugin down." );
+                  }
+               }
+            }
+
+
             string error = null;
             try
             {
@@ -98,124 +113,5 @@ namespace XUnity.AutoTranslator.Plugin.Core.Web
             }
          }
       }
-
-      //public static bool TranslateByWebClient( string untranslated, string from, string to, Action<string> success, Action failure )
-      //{
-      //   var url = _endpoint.GetServiceUrl( untranslated, from, to );
-      //   var reference = GetOrCreateAvailableClient();
-      //   if( reference == null )
-      //   {
-      //      return false;
-      //   }
-      //   var client = reference.Client;
-
-      //   _endpoint.ApplyHeaders( client.Headers );
-      //   client.Encoding = Encoding.UTF8;
-
-      //   Interlocked.Increment( ref _runningTranslations );
-      //   DownloadStringCompletedEventHandler callback = null;
-      //   callback = ( s, e ) =>
-      //   {
-      //      try
-      //      {
-      //         client.DownloadStringCompleted -= callback;
-
-      //         string translatedText = null;
-      //         bool failed = false;
-
-      //         if( e.Error == null )
-      //         {
-      //            if( e.Result != null )
-      //            {
-      //               try
-      //               {
-      //                  translatedText = _endpoint.ExtractTranslated( e.Result ) ?? string.Empty;
-      //               }
-      //               catch { }
-      //            }
-      //         }
-      //         else
-      //         {
-      //            failed = true;
-      //         }
-
-      //         if( failed )
-      //         {
-      //            failure();
-      //         }
-      //         else
-      //         {
-      //            success( translatedText );
-      //         }
-      //      }
-      //      finally
-      //      {
-      //         ReleaseClientAfterUse( reference );
-      //         Interlocked.Decrement( ref _runningTranslations );
-      //      }
-      //   };
-      //   client.DownloadStringCompleted += callback;
-
-      //   client.DownloadStringAsync( new Uri( url ) );
-
-      //   return true;
-      //}
-
-      //public static void ReleaseClientAfterUse( WebClientReference client )
-      //{
-      //   lock( Sync )
-      //   {
-      //      var removed = WorkingClients.Remove( client );
-      //      if( removed )
-      //      {
-      //         client.LastTimestamp = DateTime.UtcNow;
-      //         AvailableClients.Add( client );
-      //      }
-      //   }
-      //}
-
-      //public static WebClientReference GetOrCreateAvailableClient()
-      //{
-      //   lock( Sync )
-      //   {
-      //      if( AvailableClients.Count > 0 )
-      //      {
-      //         // take a already configured client...
-      //         var client = AvailableClients.First();
-      //         AvailableClients.Remove( client );
-      //         WorkingClients.Add( client );
-      //         return client;
-      //      }
-      //      else if( CurrentClientCount < Settings.MaxConcurrentTranslations )
-      //      {
-      //         var client = new WebClient();
-      //         var reference = new WebClientReference( client );
-      //         WorkingClients.Add( reference );
-      //         return reference;
-      //      }
-      //      else
-      //      {
-      //         return null;
-      //      }
-      //   }
-      //}
-
-      //public static void RemoveUnusedClients()
-      //{
-      //   lock( Sync )
-      //   {
-      //      var now = DateTime.UtcNow;
-      //      var references = AvailableClients.ToList();
-      //      foreach( var reference in references )
-      //      {
-      //         var livedFor = now - reference.LastTimestamp;
-      //         if( livedFor > Settings.WebClientLifetime )
-      //         {
-      //            AvailableClients.Remove( reference );
-      //            reference.Client.Dispose();
-      //         }
-      //      }
-      //   }
-      //}
    }
 }