cec3eb53a47d2c04927c2e2e5303985dc5fefb45
markd
  Mon Apr 12 23:21:46 2021 -0700
added support to status command for dynamic servers

diff --git src/gfServer/gfServer.c src/gfServer/gfServer.c
index a245f2e..5e20e0c 100644
--- src/gfServer/gfServer.c
+++ src/gfServer/gfServer.c
@@ -36,81 +36,88 @@
     {"maxGap", OPTION_INT},
     {"maxNtSize", OPTION_INT},
     {"maxTransHits", OPTION_INT},
     {"minMatch", OPTION_INT},
     {"repMatch", OPTION_INT},
     {"seqLog", OPTION_BOOLEAN},
     {"ipLog", OPTION_BOOLEAN},
     {"debugLog", OPTION_BOOLEAN},
     {"stepSize", OPTION_INT},
     {"tileSize", OPTION_INT},
     {"trans", OPTION_BOOLEAN},
     {"syslog", OPTION_BOOLEAN},
     {"perSeqMax", OPTION_STRING},
     {"noSimpRepMask", OPTION_BOOLEAN},
     {"indexFile", OPTION_STRING},
+    {"genome", OPTION_STRING},
+    {"genomeDataDir", OPTION_STRING},
     {"timeout", OPTION_INT},
     {NULL, 0}
 };
 
 
 int maxNtSize = 40000;
 int maxAaSize = 8000;
 
 int minMatch = gfMinMatch;	/* Can be overridden from command line. */
 int tileSize = gfTileSize;	/* Can be overridden from command line. */
 int stepSize = 0;		/* Can be overridden from command line. */
 boolean doTrans = FALSE;	/* Do translation? */
 boolean allowOneMismatch = FALSE; 
 boolean noSimpRepMask = FALSE;
 int repMatch = 1024;    /* Can be overridden from command line. */
 int maxDnaHits = 100;   /* Can be overridden from command line. */
 int maxTransHits = 200; /* Can be overridden from command line. */
 int maxGap = gfMaxGap;
 boolean seqLog = FALSE;
 boolean ipLog = FALSE;
 boolean doMask = FALSE;
 boolean canStop = FALSE;
 char *indexFile = NULL;
+char *genome = NULL;
+char *genomeDataDir = NULL;
 
 int timeout = 90;  // default timeout in seconds
 
 
 void usage()
 /* Explain usage and exit. */
 {
 errAbort(
   "gfServer v %s - Make a server to quickly find where DNA occurs in genome\n"
   "   To set up a server:\n"
   "      gfServer start host port file(s)\n"
   "      where the files are .2bit or .nib format files specified relative to the current directory\n"
   "   To remove a server:\n"
   "      gfServer stop host port\n"
   "   To query a server with DNA sequence:\n"
   "      gfServer query host port probe.fa\n"
   "   To query a server with protein sequence:\n"
   "      gfServer protQuery host port probe.fa\n"
   "   To query a server with translated DNA sequence:\n"
   "      gfServer transQuery host port probe.fa\n"
   "   To query server with PCR primers:\n"
   "      gfServer pcr host port fPrimer rPrimer maxDistance\n"
   "   To process one probe fa file against a .2bit format genome (not starting server):\n"
   "      gfServer direct probe.fa file(s).2bit\n"
   "   To test PCR without starting server:\n"
   "      gfServer pcrDirect fPrimer rPrimer file(s).2bit\n"
-  "   To figure out usage level:\n"
+  "   To figure out if server is alive, on static instances get usage statics as well:\n"
   "      gfServer status host port\n"
+  "     For dynamic gfServer instances, specify -genome and optionally the -genomeDataDir\n"
+  "     to get information on an untranslated genome index. Include -trans to get about information\n"
+  "     about a translated genome index\n"
   "   To get input file list:\n"
   "      gfServer files host port\n"
   "   To generate a precomputed index:\n"
   "      gfServer index gfidx file(s)\n"
   "     where the files are .2bit or .nib format files.  Separate indexes are\n"
   "     be created for untranslated and translated queries.  These can be used\n"
   "     with a persistent server as with 'start -indexFile or a dynamic server.\n"
   "     They must follow the naming convention for for dynamic servers.\n"
   "   To run a dynamic server (usually called by xinetd):\n"
   "      gfServer dynserver rootdir\n"
   "     Data files for genomes are found relative to the root directory.\n"
   "     Queries are made using the prefix of the file path relative to the root\n"
   "     directory.  The files $genome.2bit, $genome.untrans.gfidx, and\n"
   "     $genome.trans.gfidx are required. Typically the structure will be in\n"
   "     the form:\n"
@@ -776,34 +783,37 @@
     if (!startsWith(gfSignature(), buf))
         {
 	++noSigCount;
 	close(connectionHandle);
 	continue;
 	}
     line = buf + strlen(gfSignature());
     command = nextWord(&line);
     if (sameString("quit", command))
         {
 	if (canStop)
 	    break;
 	else
 	    logError("Ignoring quit message");
 	}
-    else if (sameString("status", command))
+    else if (sameString("status", command) || sameString("transInfo", command)
+             || sameString("untransInfo", command))
         {
 	sprintf(buf, "version %s", gfVersion);
 	errSendString(connectionHandle, buf);
+        errSendString(connectionHandle, "serverType static");
+	errSendString(connectionHandle, buf);
 	sprintf(buf, "type %s", (doTrans ? "translated" : "nucleotide"));
 	errSendString(connectionHandle, buf);
 	sprintf(buf, "host %s", hostName);
 	errSendString(connectionHandle, buf);
 	sprintf(buf, "port %s", portName);
 	errSendString(connectionHandle, buf);
 	sprintf(buf, "tileSize %d", tileSize);
 	errSendString(connectionHandle, buf);
 	sprintf(buf, "stepSize %d", stepSize);
 	errSendString(connectionHandle, buf);
 	sprintf(buf, "minMatch %d", minMatch);
 	errSendString(connectionHandle, buf);
 	sprintf(buf, "pcr requests %ld", pcrCount);
 	errSendString(connectionHandle, buf);
 	sprintf(buf, "blat requests %ld", blatCount);
@@ -965,31 +975,36 @@
 sprintf(buf, "%squit", gfSignature());
 mustWriteFd(sd, buf, strlen(buf));
 close(sd);
 printf("sent stop message to server\n");
 }
 
 int statusServer(char *hostName, char *portName)
 /* Send status message to server arnd report result. */
 {
 char buf[256];
 int sd = 0;
 int ret = 0;
 
 /* Put together command. */
 sd = netMustConnectTo(hostName, portName);
+if (genome == NULL)
     sprintf(buf, "%sstatus", gfSignature());
+else
+    sprintf(buf, "%s%s %s %s", gfSignature(), (doTrans ? "transInfo" : "untransInfo"),
+            genome, genomeDataDir);
+
 mustWriteFd(sd, buf, strlen(buf));
 
 for (;;)
     {
     if (netGetString(sd, buf) == NULL)
 	{
 	warn("Error reading status information from %s:%s",hostName,portName);
 	ret = -1;
         break;
 	}
     if (sameString(buf, "end"))
         break;
     else
         printf("%s\n", buf);
     }
@@ -1247,39 +1262,43 @@
 if (!startsWith(gfSignature(), buf))
     errAbort("query does not start with signature, got '%s'", buf);
 char *cmd = cloneString(buf + strlen(gfSignature()));
 logInfo("dynserver: %s", cmd);
 return cmd;
 }
 
 static const int DYN_CMD_MAX_ARGS = 8;  // more than needed to check for junk
 
 static int dynNextCommand(char* rootDir, struct dynSession *dynSession, char **args)
 /* Read query request from stdin and (re)initialize session to match
  * parameters.  Return number of arguments or zero on EOF
  *
  * Commands are in the format:
  *  signature+command genome genomeDataDir [arg ...]
+ *  signature+status
  */
 {
 char *cmdStr = dynReadCommand(rootDir);
 if (cmdStr == NULL)
     return 0;
 
 int numArgs = chopByWhite(cmdStr, args, DYN_CMD_MAX_ARGS);
 if (numArgs == 0)
     errAbort("empty command");
+if (sameWord(args[0], "status"))
+    return numArgs;  // special case; does not use an index.
+
 if (numArgs < 3)
     errAbort("expected at least 3 arguments for a dynamic server command");
 boolean isTrans = sameString("protQuery", args[0]) || sameString("transQuery", args[0])
     || sameString("transInfo", args[0]);
 
 // initialize session if new or changed
 if ((dynSession->isTrans != isTrans) || (!sameString(dynSession->genome, args[1])))
     dynSessionInit(dynSession, rootDir, args[1], args[2], isTrans);
 return numArgs;
 }
 
 static struct dnaSeq* dynReadQuerySeq(int qSize, boolean isTrans, boolean queryIsProt)
 /* read the DNA sequence from the query, filtering junk  */
 {
 struct dnaSeq *seq;
@@ -1327,84 +1346,106 @@
 if (gfIdx->isTrans)
     {
     if (queryIsProt)
         transQuery(gfIdx->transGf, seq, STDOUT_FILENO);
     else
         transTransQuery(gfIdx->transGf, seq, STDOUT_FILENO);
     }
 else
     {
     dnaQuery(gfIdx->untransGf, seq, STDOUT_FILENO, dynSession->perSeqMaxHash);
     }
 netSendString(STDOUT_FILENO, "end");
 }
 
 static void dynamicServerInfo(struct dynSession *dynSession, int numArgs, char **args)
-/* handle one of the info commands
+/* handle one of the info or status commands commands
  *
- *  signature+command genome genomeDataDir
+ *  signature+untransInfo genome genomeDataDir
+ *  signature+transInfo genome genomeDataDir
  */
 {
 struct genoFindIndex *gfIdx = dynSession->gfIdx;
 if (numArgs != 3)
     errAbort("expected 3 words in %s command, got %d", args[0], numArgs);
 
 char buf[256];
 struct genoFind *gf = gfIdx->isTrans ? gfIdx->transGf[0][0] : gfIdx->untransGf;
 sprintf(buf, "version %s", gfVersion);
 netSendString(STDOUT_FILENO, buf);
+netSendString(STDOUT_FILENO, "serverType dynamic");
 sprintf(buf, "type %s", (gfIdx->isTrans ? "translated" : "nucleotide"));
 netSendString(STDOUT_FILENO, buf);
 sprintf(buf, "tileSize %d", gf->tileSize);
 netSendString(STDOUT_FILENO, buf);
 sprintf(buf, "stepSize %d", gf->stepSize);
 netSendString(STDOUT_FILENO, buf);
 sprintf(buf, "minMatch %d", gf->minMatch);
 netSendString(STDOUT_FILENO, buf);
 netSendString(STDOUT_FILENO, "end");
 }
 
+static void dynamicServerStatus(int numArgs, char **args)
+/* return enough information to indicate server is working without opening
+ * a genome index.
+ *
+ *  signature+status
+ */
+{
+if (numArgs != 1)
+    errAbort("expected 1 word in %s command, got %d", args[0], numArgs);
+char buf[256];
+sprintf(buf, "version %s", gfVersion);
+netSendString(STDOUT_FILENO, buf);
+netSendString(STDOUT_FILENO, "serverType dynamic");
+netSendString(STDOUT_FILENO, "end");
+}
+
 static void dynamicServerPcr(struct dynSession *dynSession, int numArgs, char **args)
 /* Execute a PCR query
  *
  *  signature+command genome genomeDataDir forward reverse maxDistance
  */
 {
 struct genoFindIndex *gfIdx = dynSession->gfIdx;
 if (numArgs != 6)
     errAbort("expected 6 words in %s command, got %d", args[0], numArgs);
 char *fPrimer = args[3];
 char *rPrimer = args[4];
 int maxDistance = atoi(args[5]);
 if (badPcrPrimerSeq(fPrimer) || badPcrPrimerSeq(rPrimer))
     errAbort("Can only handle ACGT in primer sequences.");
 pcrQuery(gfIdx->untransGf, fPrimer, rPrimer, maxDistance, STDOUT_FILENO);
 }
 
 static bool dynamicServerCommand(char* rootDir, struct dynSession* dynSession)
 /* Execute one command from stdin, (re)initializing session as needed */
 {
 time_t startTime = clock1000();
 char *args[DYN_CMD_MAX_ARGS];
 int numArgs = dynNextCommand(rootDir, dynSession, args);
 if (numArgs == 0)
     return FALSE;
 if (sameString("query", args[0]) || sameString("protQuery", args[0])
     || sameString("transQuery", args[0]))
     {
     dynamicServerQuery(dynSession, numArgs, args);
     }
+else if (sameString("status", args[0]))
+    {
+    dynamicServerStatus(numArgs, args);
+    }
 else if (sameString("untransInfo", args[0]) || sameString("transInfo", args[0]))
     {
     dynamicServerInfo(dynSession, numArgs, args);
     }
 else if (sameString("pcr", args[0]))
     {
     dynamicServerPcr(dynSession, numArgs, args);
     }
 else
     errAbort("invalid command '%s'", args[0]);
 
 logInfo("dynserver: %s completed in %4.3f seconds", args[0], 0.001 * (clock1000() - startTime));
 freeMem(args[0]);
 return TRUE;
 }
@@ -1448,30 +1489,36 @@
 if (optionExists("repMatch"))
     repMatch = optionInt("repMatch", 0);
 else
     repMatch = gfDefaultRepMatch(tileSize, stepSize, doTrans);
 minMatch = optionInt("minMatch", minMatch);
 maxDnaHits = optionInt("maxDnaHits", maxDnaHits);
 maxTransHits = optionInt("maxTransHits", maxTransHits);
 maxNtSize = optionInt("maxNtSize", maxNtSize);
 maxAaSize = optionInt("maxAaSize", maxAaSize);
 seqLog = optionExists("seqLog");
 ipLog = optionExists("ipLog");
 doMask = optionExists("mask");
 canStop = optionExists("canStop");
 noSimpRepMask = optionExists("noSimpRepMask");
 indexFile = optionVal("indexFile", NULL);
+genome = optionVal("genome", NULL);
+genomeDataDir = optionVal("genomeDataDir", NULL);
+if ((genomeDataDir != NULL) && (genome == NULL))
+    errAbort("-genomeDataDir requires the -genome option");
+if ((genome != NULL) && (genomeDataDir == NULL))
+    genomeDataDir = ".";
 timeout = optionInt("timeout", timeout);
 if (argc < 2)
     usage();
 if (optionExists("log"))
     logOpenFile(argv[0], optionVal("log", NULL));
 if (optionExists("syslog"))
     logOpenSyslog(argv[0], optionVal("logFacility", NULL));
 if (optionExists("debugLog"))
     logSetMinPriority("debug");
 
 if (sameWord(command, "direct"))
     {
     if (argc < 4)
         usage();
     genoFindDirect(argv[2], argc-3, argv+3);