Skip to content

Instantly share code, notes, and snippets.

@kala13x
Created January 26, 2022 13:08
Show Gist options
  • Save kala13x/6e6673b3332a5e8f48924c9c90634ff7 to your computer and use it in GitHub Desktop.
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
/*!
* @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 "&#160;"
#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