Created
January 26, 2022 13:08
-
-
Save kala13x/6e6673b3332a5e8f48924c9c90634ff7 to your computer and use it in GitHub Desktop.
Parse COVID-19 case statistics from https://stopcov.ge/ and display JSON serialized output
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* @file libxutils/examples/statcov.c | |
* | |
* 2020-2021 Sun Dro ([email protected]) | |
* | |
* @brief Parse and print COVID-19 case | |
* statistics from https://stopcov.ge/ | |
*/ | |
#include <xutils/xstd.h> | |
#include <xutils/xver.h> | |
#include <xutils/sock.h> | |
#include <xutils/http.h> | |
#include <xutils/xstr.h> | |
#include <xutils/xlog.h> | |
#include <xutils/xtype.h> | |
#include <xutils/xjson.h> | |
#define STOPCOV_ADDR "stopcov.ge:443" | |
#define XSPACE_CHAR " " | |
#define XSTART_POS "numver\">" | |
#define XEND_POS "</span>" | |
#define XTAB_SIZE 4 | |
typedef struct { | |
int nQuarantined; | |
int nSupervision; | |
int nConfirmed; | |
int nRecovered; | |
int nDeaths; | |
} covid_cases_t; | |
int COVID_ParseCase(const char *pSource, size_t nLength, const char *pCase) | |
{ | |
int nPosit = xstrnsrc(pSource, nLength, pCase, 0); | |
if (nPosit < 0) return XSTDERR; | |
const char *pOffset = &pSource[nPosit]; | |
XCHAR(sNumber, XSTR_MIN); | |
XCHAR(sToken, XSTR_MIN); | |
size_t i, nLen = xstrncuts(XARG_SIZE(sToken), pOffset, XSTART_POS, XEND_POS); | |
if (!nLen) return XSTDERR; | |
xarray_t *pArr = xstrsplit(sToken, XSPACE_CHAR); | |
if (pArr == NULL) return atoi(sToken); | |
for (i = 0; i < pArr->nUsed; i++) | |
{ | |
const char *pData = (const char*)XArray_GetData(pArr, i); | |
if (pData != NULL) xstrncatf(sNumber, XSTR_AVAIL(sNumber), "%s", pData); | |
} | |
XArray_Destroy(pArr); | |
return atoi(sNumber); | |
} | |
int COVID_GetCases(xsock_t *pSock, xhttp_t *pHttp, covid_cases_t *pCovCases) | |
{ | |
xbyte_buffer_t *pRequest = &pHttp->dataRaw; | |
xlogd("Sending request:\n%s", pRequest->pData); | |
if (XSock_Write(pSock, pRequest->pData, pRequest->nUsed) <= 0) return XSTDERR; | |
XHTTP_Clear(pHttp); | |
if (XHTTP_Receive(pHttp, pSock) != XHTTP_COMPLETE) return XSTDNON; | |
pHttp->dataRaw.pData[pHttp->nHeaderLength - 1] = '\0'; | |
xlogd("Received response:\n%s\n", pHttp->dataRaw.pData); | |
const char *pContent = (const char *)XHTTP_GetBody(pHttp); | |
size_t nBodyLen = XHTTP_GetBodySize(pHttp); | |
xlogd("Parsing HTTP body: %zu bytes", nBodyLen); | |
pCovCases->nConfirmed = COVID_ParseCase(pContent, nBodyLen, "დადასტურებული შემთხვევა"); | |
pCovCases->nRecovered = COVID_ParseCase(pContent, nBodyLen, "მათ შორის გამოჯანმრთელებული"); | |
pCovCases->nQuarantined = COVID_ParseCase(pContent, nBodyLen, "კარანტინის რეჟიმში"); | |
pCovCases->nSupervision = COVID_ParseCase(pContent, nBodyLen, "მეთვალყურეობის ქვეშ"); | |
pCovCases->nDeaths = COVID_ParseCase(pContent, nBodyLen, "მათ შორის გარდაცვლილი"); | |
return pCovCases->nConfirmed; | |
} | |
int COVID_PrintCases(covid_cases_t *pCovCases) | |
{ | |
xlogd("Generating JSON output with tab size: %d", XTAB_SIZE); | |
xjson_obj_t *pRootObject = XJSON_NewObject(NULL, 0); | |
if (pRootObject != NULL) | |
{ | |
XJSON_AddInt(pRootObject, "confirmed", pCovCases->nConfirmed); | |
XJSON_AddInt(pRootObject, "recovered", pCovCases->nRecovered); | |
XJSON_AddInt(pRootObject, "quarantined", pCovCases->nQuarantined); | |
XJSON_AddInt(pRootObject, "supervision", pCovCases->nSupervision); | |
XJSON_AddInt(pRootObject, "deaths", pCovCases->nDeaths); | |
xjson_writer_t linter; | |
XJSON_InitWriter(&linter, NULL, XSTR_MIN); | |
linter.nTabSize = XTAB_SIZE; | |
if (XJSON_WriteObject(pRootObject, &linter)) | |
xlog("%s", linter.pData); | |
XJSON_DestroyWriter(&linter); | |
XJSON_FreeObject(pRootObject); | |
return XSTDOK; | |
} | |
xloge("Failed to allocate memory for JSON obj: %s", strerror(errno)); | |
return XSTDERR; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
xlog_init("statcov", XLOG_DEFAULT, XFALSE); | |
if (argc > 1) xlog_setfl(XLOG_ALL); | |
xsock_t sock; | |
XSock_InitSSL(); | |
xlogd("Connecting to server: %s", STOPCOV_ADDR); | |
if (XSock_Setup(&sock, XSOCK_SSLV2_CLIENT, STOPCOV_ADDR) == XSOCK_INVALID) | |
{ | |
xloge("%s (%s)", XSock_ErrStr(&sock), strerror(errno)); | |
XSock_DeinitSSL(); | |
return 1; | |
} | |
xhttp_t hdr; | |
XHTTP_InitRequest(&hdr, XHTTP_GET, "/", NULL); | |
XHTTP_AddHeader(&hdr, "Host", "%s", STOPCOV_ADDR); | |
XHTTP_AddHeader(&hdr, "User-Agent", "xutils/%s", XUtils_VersionShort()); | |
if (XHTTP_Assemble(&hdr, NULL, 0) == NULL) | |
{ | |
xloge("Can not create HTTP request"); | |
XSock_Close(&sock); | |
XSock_DeinitSSL(); | |
return 1; | |
} | |
covid_cases_t cases; | |
int nStatus = COVID_GetCases(&sock, &hdr, &cases); | |
if (nStatus > 0) COVID_PrintCases(&cases); | |
else xloge("%s", XSock_ErrStr(&sock)); | |
XHTTP_Clear(&hdr); | |
XSock_Close(&sock); | |
XSock_DeinitSSL(); | |
return !nStatus; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment