832026164cc5f13b2764e5556bf003864d662938
hiram
  Mon Sep 9 14:19:33 2019 -0700
now allowing hgCustom to play the bottleneck game, and bold highlight the error 429 message refs #23217

diff --git src/hg/hgCustom/hgCustom.c src/hg/hgCustom/hgCustom.c
index d02531e..031f064 100644
--- src/hg/hgCustom/hgCustom.c
+++ src/hg/hgCustom/hgCustom.c
@@ -11,33 +11,37 @@
 #include "web.h"
 #include "htmshell.h"
 #include "hdb.h"
 #include "hui.h"
 #include "hCommon.h"
 #include "customTrack.h"
 #include "customFactory.h"
 #include "portable.h"
 #include "errCatch.h"
 #include "knetUdc.h"
 #include "udc.h"
 #include "net.h"
 #include "jsHelper.h"
 #include <signal.h>
 #include "trackHub.h"
+#include "botDelay.h"
 
 static long loadTime = 0;
-
+static boolean issueBotWarning = FALSE;
+#define delayFraction   0.25	/* same as hgTracks */
+#define warnMs 10000	/* warning at 10 to 20 second delay */
+#define exitMs 20000	/* error 429 Too Many Requests after 20+ second delay */
 
 void usage()
 /* Explain usage and exit. */
 {
 errAbort(
   "hgCustom - Custom track management CGI\n"
   "usage:\n"
   "   hgCustom <CGI settings>\n"
   );
 }
 
 /* DON'T EDIT THIS -- use CGI param "&measureTiming=." */
 static boolean measureTiming = FALSE;
 
 #define TEXT_ENTRY_ROWS 7
@@ -927,63 +931,80 @@
 printf("<INPUT TYPE=\"HIDDEN\" NAME=\"db\" VALUE=\"%s\">\n", database);
 printf("<INPUT TYPE=\"HIDDEN\" NAME=\"hgct_do_add\" VALUE=\"1\">\n");
 puts("</FORM>");
 }
 static void doProgress(char *err)
 /* display progress meter to show loading process */
 {
 cartWebStart(cart, database, "Custom Track loading progress meter");
 progressMeter();
 // addCustomForm(NULL, err);
 helpCustom();
 cartWebEnd(cart);
 }
 #endif
 
+static void webBotWarning()
+/* display the overuse warning message in the javaScript warning text box
+ * html output has already started at this point, just need to add the
+ * warning handler and setup the warning javaScript box, warnings after
+ * this will go to that text box
+ */
+{
+pushWarnHandler(webVaWarn);
+htmlWarnBoxSetup(stdout);
+char *ip = getenv("REMOTE_ADDR");
+botDelayMessage(ip, botDelayMillis);
+}
+
 void doAddCustom(char *err)
 /* display form for adding custom tracks.
  * Include error message, if any */
 {
 cartWebStart(cart, database, "Add Custom Tracks");
 addCustomForm(NULL, err);
 helpCustom();
+if (issueBotWarning)
+    webBotWarning();
 cartWebEnd(cart);
 }
 
 void doUpdateCustom(struct customTrack *ct, char *err)
 /* display form for adding custom tracks.
  * Include error message, if any */
 {
 char *longLabel = htmlEncode(ct->tdb->longLabel);
 cartWebStart(cart, database, "Update Custom Track: %s [%s]",
         longLabel, database);
 freeMem(longLabel);
 cartSetString(cart, hgCtDocText, ct->tdb->html);
 addCustomForm(ct, err);
 helpCustom();
 cartWebEnd(cart);
 }
 
 static void doManageCustom(char *warnMsg)
 /* display form for deleting & updating custom tracks.
  * Include warning message, if any */
 {
 cartWebStart(cart, database, "Manage Custom Tracks");
 jsIncludeFile("jquery.js", NULL);
 manageCustomForm(warnMsg);
 webNewSection("Managing Custom Tracks");
 webIncludeHelpFile("customTrackManage", FALSE);
+if (issueBotWarning)
+    webBotWarning();
 cartWebEnd(cart);
 }
 
 char *fixNewData(struct cart *cart)
 /* append a newline to incoming data, to keep custom preprocessor happy */
 {
 char *customText = cartUsualString(cart, hgCtDataText, "");
 if (isNotEmpty(customText))
     {
     struct dyString *ds = dyStringNew(0);
     dyStringPrintf(ds, "%s\n", customText);
     customText = dyStringCannibalize(&ds);
     cartSetString(cart, hgCtDataText, customText);
     }
 return customText;
@@ -1297,30 +1318,31 @@
             if (ct)
                 {
                 struct errCatch *catch = errCatchNew();
                 if (errCatchStart(catch))
                     {
                     customTrackUpdateFromConfig(ct, database, trackConfig, &browserLines);
                     ctUpdated = TRUE;
                     }
                 errCatchEnd(catch);
                 if (catch->gotError)
                     addWarning(dsWarn, catch->message->string);
                 errCatchFree(&catch);
                 }
             }
         }
+
     addWarning(dsWarn, replacedTracksMsg(replacedCts));
     doBrowserLines(browserLines, &warnMsg);
     addWarning(dsWarn, warnMsg);
     if (err)
 	{
         char *selectedTable = NULL;
         cartSetString(cart, hgCtDataText, savedCustomText);
         cartSetString(cart, hgCtConfigLines, savedConfig);
         if ((selectedTable= cartOptionalString(cart, hgCtUpdatedTable)) != NULL)
             {
             ct = ctFromList(ctList, selectedTable);
             doUpdateCustom(ct, err);
             }
         else
             doAddCustom(err);
@@ -1364,22 +1386,23 @@
 	}
     if (ctList || cartVarExists(cart, hgCtDoDelete))
         doManageCustom(warnMsg);
     else
 	doAddCustom(warnMsg);
     }
 cartRemovePrefix(cart, hgCt);
 cartRemove(cart, CT_CUSTOM_TEXT_VAR);
 }
 
 
 int main(int argc, char *argv[])
 /* Process command line. */
 {
 long enteredMainTime = clock1000();
+issueBotWarning = earlyBotCheck(enteredMainTime, "hgTracks", delayFraction, warnMs, exitMs);
 htmlPushEarlyHandlers();
 oldVars = hashNew(10);
 cgiSpoof(&argc, argv);
 cartEmptyShell(doMiddle, hUserCookie(), excludeVars, oldVars);
 cgiExitTime("hgCustom", enteredMainTime);
 return 0;
 }