0722486013be8ff695612a47d218b52135357d1a hiram Mon Feb 11 14:38:12 2019 -0800 now with dowload date stamps refs #18869 diff --git src/hg/hubApi/hubApi.c src/hg/hubApi/hubApi.c index d9b8178..d67abcf 100644 --- src/hg/hubApi/hubApi.c +++ src/hg/hubApi/hubApi.c @@ -64,69 +64,57 @@ static struct hash *trackCounter = NULL; static long totalTracks = 0; static boolean measureTiming = FALSE; /* set by CGI parameters */ static boolean allTrackSettings = FALSE; /* checkbox setting */ static char **shortLabels = NULL; /* public hub short labels in array */ struct hubPublic *publicHubList = NULL; static int publicHubCount = 0; static char *defaultHub = "Plants"; static char *defaultDb = "ce11"; static long enteredMainTime = 0; /* will become = clock1000() on entry */ /* to allow calculation of when to bail out, taking too long */ static long timeOutSeconds = 100; static boolean timedOut = FALSE; /* ######################################################################### */ - -static void jsonStringPrint(FILE *f, char *value) -/* escape string for output */ -{ -char *a = jsonStringEscape(value); -if (isEmpty(a)) - fprintf(f, "%s", "null"); -else - fprintf(f, "\"%s\"", a); -freeMem(a); -} - -static void jsonTagValue(FILE *f, char *tag, char *value) -/* output one json string: "tag":"value" appropriately quoted and encoded */ -{ -fprintf(f,"\"%s\":",tag); -jsonStringPrint(f, value); -} - static struct jsonWrite *jsonStartOutput() /* begin json output */ { +time_t timeNow = time(NULL); +// struct tm tm; +// gmtime_r(&timeNow, &tm); struct jsonWrite *jw = jsonWriteNew(); jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "apiVersion", "0.1"); jsonWriteString(jw, "source", "UCSantaCruz"); +jsonWriteDateFromUnix(jw, "downloadTime", (long long) timeNow); +jsonWriteNumber(jw, "downloadTimeStamp", (long long) timeNow); return jw; } static void jsonErrAbort(char *format, ...) /* Issue an error message in json format. */ { char errMsg[2048]; va_list args; va_start(args, format); vsnprintf(errMsg, sizeof(errMsg), format, args); -fputc('{',stdout); -jsonTagValue(stdout, "error", errMsg); -fputc('}',stdout); +struct jsonWrite *jw = jsonStartOutput(); +jsonWriteString(jw, "error", errMsg); +jsonWriteObjectEnd(jw); +fputs(jw->dy->string,stdout); +exit(0); } static void hubPublicJsonData(struct jsonWrite *jw, struct hubPublic *el) /* Print array data for one row from hubPublic table, order here * must be same as was stated in the columnName header element * TODO: need to figure out how to use the order of the columns as * they are in the 'desc' request */ { jsonWriteListStart(jw, NULL); jsonWriteString(jw, NULL, el->hubUrl); jsonWriteString(jw, NULL, el->shortLabel); jsonWriteString(jw, NULL, el->longLabel); jsonWriteString(jw, NULL, el->registrationTime); jsonWriteNumber(jw, NULL, (long long)el->dbCount); @@ -534,53 +522,55 @@ static boolean tableColumns(struct jsonWrite *jw, char *table) /* output the column names for the given table * return: TRUE on error, FALSE on success */ { jsonWriteListStart(jw, "columnNames"); char query[1024]; struct sqlConnection *conn = hConnectCentral(); sqlSafef(query, sizeof(query), "desc %s", table); struct sqlResult *sr = sqlGetResult(conn, query); char **row; row = sqlNextRow(sr); if (NULL == row) { - jsonErrAbort("ERROR: can not 'desc' table '%s'\n", table); + jsonErrAbort("ERROR: can not 'desc' table '%s'", table); return TRUE; } while ((row = sqlNextRow(sr)) != NULL) jsonWriteString(jw, NULL, row[0]); sqlFreeResult(&sr); hDisconnectCentral(&conn); jsonWriteListEnd(jw); return FALSE; } static void jsonPublicHubs() /* output the hubPublic SQL table */ { struct sqlConnection *conn = hConnectCentral(); char *dataTime = sqlTableUpdate(conn, hubPublicTableName()); hDisconnectCentral(&conn); time_t dataTimeStamp = sqlDateToUnixTime(dataTime); +replaceChar(dataTime, ' ', 'T'); struct hubPublic *el = publicHubList; struct jsonWrite *jw = jsonStartOutput(); jsonWriteString(jw, "dataTime", dataTime); jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp); freeMem(dataTime); +jsonWriteString(jw, "tableName", hubPublicTableName()); tableColumns(jw, hubPublicTableName()); jsonWriteListStart(jw, "publicHubData"); for ( ; el != NULL; el = el->next ) { hubPublicJsonData(jw, el); } jsonWriteListEnd(jw); jsonWriteObjectEnd(jw); fputs(jw->dy->string,stdout); } static int dbDbCmpName(const void *va, const void *vb) /* Compare two dbDb elements: name, ignore case. */ { const struct dbDb *a = *((struct dbDb **)va); @@ -603,63 +593,66 @@ slAddHead(&dbList, el); } sqlFreeResult(&sr); hDisconnectCentral(&conn); slSort(&dbList, dbDbCmpName); return dbList; } static void jsonDbDb() /* output the dbDb SQL table */ { struct sqlConnection *conn = hConnectCentral(); char *dataTime = sqlTableUpdate(conn, "dbDb"); hDisconnectCentral(&conn); time_t dataTimeStamp = sqlDateToUnixTime(dataTime); +replaceChar(dataTime, ' ', 'T'); struct dbDb *dbList = ucscDbDb(); struct dbDb *el; struct jsonWrite *jw = jsonStartOutput(); jsonWriteString(jw, "dataTime", dataTime); jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp); freeMem(dataTime); +jsonWriteString(jw, "tableName", "dbDb"); tableColumns(jw, "dbDb"); jsonWriteListStart(jw, "ucscGenomes"); for ( el=dbList; el != NULL; el = el->next ) { dbDbJsonData(jw, el); } jsonWriteListEnd(jw); jsonWriteObjectEnd(jw); fputs(jw->dy->string,stdout); } static void chromInfoJsonOutput(FILE *f, char *db) /* for given db, if there is a track, list the chromosomes in that track, * for no track, simply list the chromosomes in the sequence */ { char *table = cgiOptionalString("track"); struct sqlConnection *conn = hAllocConn(db); /* in trackDb language: track == table */ if (table) { if (! sqlTableExists(conn, table)) jsonErrAbort("ERROR: endpoint: /list/chromosomes?db=%&table=%s ERROR table does not exist", db, table); if (sqlColumnExists(conn, table, "chrom")) { char *dataTime = sqlTableUpdate(conn, table); time_t dataTimeStamp = sqlDateToUnixTime(dataTime); + replaceChar(dataTime, ' ', 'T'); struct jsonWrite *jw = jsonStartOutput(); jsonWriteString(jw, "genome", db); jsonWriteString(jw, "track", table); jsonWriteString(jw, "dataTime", dataTime); jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp); freeMem(dataTime); struct slPair *list = NULL; char query[2048]; sqlSafef(query, sizeof(query), "select distinct chrom from %s", table); struct sqlResult *sr = sqlGetResult(conn, query); char **row; while ((row = sqlNextRow(sr)) != NULL) { int size = hChromSize(db, row[0]); slAddHead(&list, slPairNew(row[0], intToPt(size))); @@ -673,88 +666,89 @@ for ( ; el != NULL; el = el->next ) jsonWriteNumber(jw, el->name, (long long)ptToInt(el->val)); jsonWriteObjectEnd(jw); /* chromosomes */ jsonWriteObjectEnd(jw); /* top level */ fputs(jw->dy->string,stdout); } else { jsonErrAbort("ERROR: table '%s' is not a position table, no chromosomes for genome: '%s'", table, db); } } else { char *dataTime = sqlTableUpdate(conn, "chromInfo"); time_t dataTimeStamp = sqlDateToUnixTime(dataTime); + replaceChar(dataTime, ' ', 'T'); struct chromInfo *ciList = createChromInfoList(NULL, db); struct chromInfo *el = ciList; struct jsonWrite *jw = jsonStartOutput(); jsonWriteString(jw, "genome", db); jsonWriteString(jw, "dataTime", dataTime); jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp); freeMem(dataTime); jsonWriteNumber(jw, "chromCount", (long long)slCount(ciList)); jsonWriteObjectStart(jw, "chromosomes"); for ( ; el != NULL; el = el->next ) { jsonWriteNumber(jw, el->chrom, (long long)el->size); } jsonWriteObjectEnd(jw); /* chromosomes */ jsonWriteObjectEnd(jw); /* top level */ fputs(jw->dy->string,stdout); } hFreeConn(&conn); } static void trackDbJsonOutput(char *db, FILE *f) /* return track list from specified UCSC database name */ { struct sqlConnection *conn = hAllocConn(db); char *dataTime = sqlTableUpdate(conn, "trackDb"); time_t dataTimeStamp = sqlDateToUnixTime(dataTime); +replaceChar(dataTime, ' ', 'T'); hFreeConn(&conn); struct trackDb *tdbList = hTrackDb(db); struct trackDb *el; struct jsonWrite *jw = jsonStartOutput(); jsonWriteString(jw, "db", db); jsonWriteString(jw, "dataTime", dataTime); jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp); freeMem(dataTime); jsonWriteListStart(jw, "tracks"); for (el = tdbList; el != NULL; el = el->next ) jsonWriteString(jw, NULL, el->track); jsonWriteListEnd(jw); jsonWriteObjectEnd(jw); fputs(jw->dy->string,stdout); } /* static void trackDbJsonOutput(char *db, FILE *f) */ #define MAX_PATH_INFO 32 static void apiList(char *words[MAX_PATH_INFO]) /* 'list' function words[1] is the subCommand */ { if (sameWord("publicHubs", words[1])) jsonPublicHubs(); else if (sameWord("ucscGenomes", words[1])) jsonDbDb(); else if (sameWord("hubGenomes", words[1])) { char *hubUrl = cgiOptionalString("hubUrl"); if (isEmpty(hubUrl)) - jsonErrAbort("ERROR: must supply hubUrl='http:...' some URL to a hub for /list/genomes\n"); + jsonErrAbort("ERROR: must supply hubUrl='http:...' some URL to a hub for /list/genomes"); struct trackHub *hub = trackHubOpen(hubUrl, ""); -registrationTime if (hub->genomeList) { struct jsonWrite *jw = jsonStartOutput(); jsonWriteString(jw, "hubUrl", hubUrl); jsonWriteListStart(jw, "genomes"); struct slName *theList = genomeList(hub, NULL, NULL); slNameSort(&theList); struct slName *el = theList; for ( ; el ; el = el->next ) { jsonWriteString(jw, NULL, el->name); } jsonWriteListEnd(jw); jsonWriteObjectEnd(jw); fputs(jw->dy->string,stdout); @@ -765,31 +759,31 @@ char *hubUrl = cgiOptionalString("hubUrl"); char *genome = cgiOptionalString("genome"); char *db = cgiOptionalString("db"); if (isEmpty(hubUrl) && isEmpty(db)) jsonErrAbort("ERROR: must supply hubUrl or db name to return track list"); if (isEmpty(hubUrl)) // missing hubUrl implies UCSC database { trackDbJsonOutput(db, stdout); // only need db for this function return; } if (isEmpty(genome) || isEmpty(hubUrl)) { if (isEmpty(genome)) warn("# must supply genome='someName' the name of a genome in a hub for /list/tracks\n"); if (isEmpty(hubUrl)) - jsonErrAbort("ERROR: must supply hubUrl='http:...' some URL to a hub for /list/genomes\n"); + jsonErrAbort("ERROR: must supply hubUrl='http:...' some URL to a hub for /list/genomes"); } struct trackHub *hub = trackHubOpen(hubUrl, ""); if (hub->genomeList) { struct slName *dbTrackList = NULL; (void) genomeList(hub, &dbTrackList, genome); struct jsonWrite *jw = jsonStartOutput(); jsonWriteString(jw, "hubUrl", hubUrl); jsonWriteListStart(jw, "genome"); slNameSort(&dbTrackList); struct slName *el = dbTrackList; for ( ; el != NULL; el = el->next ) { jsonWriteString(jw, NULL, el->name); } @@ -801,62 +795,65 @@ else if (sameWord("chromosomes", words[1])) { char *hubUrl = cgiOptionalString("hubUrl"); // char *genome = cgiOptionalString("genome"); char *db = cgiOptionalString("db"); if (isEmpty(hubUrl) && isEmpty(db)) jsonErrAbort("ERROR: must supply hubUrl or db name to return chromosome list"); if (isEmpty(hubUrl)) // missing hubUrl implies UCSC database { chromInfoJsonOutput(stdout, db); return; } } else - jsonErrAbort("ERROR: do not recognize endpoint '/list/%s' function\n", words[1]); + jsonErrAbort("do not recognize endpoint: '/list/%s' request", words[1]); } static struct hash *apiFunctionHash = NULL; static void setupFunctionHash() /* initialize the apiFunctionHash */ { if (apiFunctionHash) return; apiFunctionHash = hashNew(0); hashAdd(apiFunctionHash, "list", &apiList); } static void apiFunctionSwitch(char *pathInfo) /* given a pathInfo string: /command/subCommand/etc... * parse that and decide on which function to acll */ { hPrintDisable(); /* turn off all normal HTML output, doing JSON output */ /* the leading slash has been removed from the pathInfo, therefore, the * chop will have the first word in words[0] */ char *words[MAX_PATH_INFO];/*expect no more than MAX_PATH_INFO number of words*/ int wordCount = chopByChar(pathInfo, '/', words, ArraySize(words)); if (wordCount < 2) - jsonErrAbort("ERROR: no endpoint commands found ?\n"); + jsonErrAbort("unknown endpoint command: '/%s'", pathInfo); -/* TBD: need to protect this hash find from 'not found' error */ -void (*apiFunction)(char **) = hashMustFindVal(apiFunctionHash, words[0]); +struct hashEl *hel = hashLookup(apiFunctionHash, words[0]); +if (hel == NULL) + jsonErrAbort("no such command: '%s' for endpoint '/%s'", words[0], pathInfo); +void (*apiFunction)(char **) = hel->val; +// void (*apiFunction)(char **) = hashMustFindVal(apiFunctionHash, words[0]); (*apiFunction)(words); } /* static void apiFunctionSwitch(char *pathInfo) */ static void tracksForUcscDb(char * ucscDb) { hPrintf("

Tracks in UCSC genome: '%s'
\n", ucscDb); struct trackDb *tdbList = hTrackDb(ucscDb); struct trackDb *track; hPrintf("