<commit_before>#ifndef H_DSCPP_PUSHABLE
#define H_DSCPP_PUSHABLE

#include "api.hh"
#include "rapidjson/document.h"
#include <curl/curl.h>

namespace dsc {

class Pushable : Fetchable {
    private:
    typedef size_t(*CURL_WRITEFUNCTION_PTR)(void*, size_t, size_t, void*);
    
    rapidjson::Document serialize();
    const char* endpoint_name;
    void buildEndpointUri(char* out);
    bool getErrCode(rapidjson::Document* d, ErrorCode* r);
    
    public:
    marshal(char* out);
    // to make thread-safe, call curl_global_init()
    ErrorCode push(Client* c, long* err);
    // to make thread-safe, call curl_global_init()
    ErrorCode delete(Client* c, long* err);
};

void Pushable::marshal(char* out) {
    using namespace rapidjson;
    Document d = serialize();
    StringBuffer buf;
    Writer<StringBuffer> writer(buf);
    d.Accept(writer);
    out = buf.GetString();
};


void Pushable::buildEndpointUri(Client* c, char* out) {
    sprintf(out, "%s/%s/llu", 
            c->sessionEndpointUri, endpoint_name, id);
}

ErrorCode Pushable::getErrCode(rapidjson::Document* d) {
    if(!d["code"].IsInt()) return JSON_PARSE_FAILED;
    return static_cast<ErrorCode>(d["code"].GetInt());
}

ErrorCode Pushable::push(Client* c, long* err, bool mkNew = false) {
    char* uri;
    buildEndpointUri(c, uri);
    CURL* curl = c->getCurl();
    CURLcode res;
    if(!curl) return CURL_INIT_FAILED;
    if(res = curl_easy_setopt(curl, CURLOPT_URL, uri) != CURLE_OK) {
        *err = res;
        return CURL_INIT_FAILED;
    }
    if(mkNew) {
        if(res = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST")) {
            *err = res;
            return CURL_INIT_FAILED;
        }
    } else {
        if(res = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH") != CURLE_OK) {
            *err = res;
            return CURL_INIT_FAILED;
        }
    }
    struct curl_slist* header;
    header = curl_slist_append(header, "Content-Type:application/json");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
    char* payload;
    marshal(payload);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload);
    ErrorCode ret;
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret);
    auto wfunc = [](void* dat, size_t size, size_t nmemb, void* ret) {
        using namespace rapidjson;
        Document d = new Document();
        ParseResult ok = d.Parse(static_cast<char*>(dat));
        if(!ok) {
            *err = ok;
            *ret = JSON_PARSE_FAILED;
        }
        long httpStat;
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpStat);
        if(httpStat < 200 || httpStat > 300) {
            getErrCode(d, ret);
            *err = httpStat;
        } else {
            *ret = NIL;
        } return size * nmemb;
    };
    curl_easy_setopt(curl, CURLOPT_WRITEFUNC, static_cast<CURLOPT_WRITEFUNCTION_PTR>(&wfunc));
    CURLcode res = curl_easy_perform(curl);
    if(cresp != CURLE_OK) return res;
    curl_easy_cleanup(c->getCurl());
    curl_slist_free(header);
    return NIL;
}

ErrorCode Pushable::delete(Client* c, long* err) {
    char* uri;
    buildEndpointUri(c, uri);
    CURL* curl = curl_easy_init();
    if(!curl) return CURL_INIT_FAILED;
    CURLcode res;
    if(res = curl_easy_setopt(curl, CURLOPT_URL, uri) != CURLE_OK) {
        *err = res;
        return CURL_INIT_FAILED;
    }
    if(res = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE")) {
        *err = res;
        return CURL_INIT_FAILED;
    }
    if(res = curl_easy_perform(curl) != CURLE_OK) {
        *err = res;
        return CURL_PERFORM_FAILED;
    }
    long httpStat;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpStat);
    curl_easy_cleanup(c->getCurl());
    if(httpStat < 200 || httpStat > 300) {
        *err = httpStat;<commit_msg>facilitate optional error handling in Pushable<commit_after>#ifndef H_DSCPP_PUSHABLE
#define H_DSCPP_PUSHABLE

#include "api.hh"
#include "rapidjson/document.h"
#include <curl/curl.h>

namespace dsc {

class Pushable : Fetchable {
    private:
    typedef size_t(*CURL_WRITEFUNCTION_PTR)(void*, size_t, size_t, void*);
    
    rapidjson::Document serialize();
    const char* endpoint_name;
    void buildEndpointUri(char* out);
    bool getErrCode(rapidjson::Document* d, ErrorCode* r);
    
    public:
    marshal(char* out);
    // to make thread-safe, call curl_global_init()
    ErrorCode push(Client* c, long* err);
    // to make thread-safe, call curl_global_init()
    ErrorCode delete(Client* c, long* err);
};

void Pushable::marshal(char* out) {
    using namespace rapidjson;
    Document d = serialize();
    StringBuffer buf;
    Writer<StringBuffer> writer(buf);
    d.Accept(writer);
    out = buf.GetString();
};


void Pushable::buildEndpointUri(Client* c, char* out) {
    sprintf(out, "%s/%s/llu", 
            c->sessionEndpointUri, endpoint_name, id);
}

ErrorCode Pushable::getErrCode(rapidjson::Document* d) {
    if(!d["code"].IsInt()) return JSON_PARSE_FAILED;
    return static_cast<ErrorCode>(d["code"].GetInt());
}

ErrorCode Pushable::push(Client* c, long* err = NULL, bool mkNew = false) {
    char* uri;
    buildEndpointUri(c, uri);
    CURL* curl = c->getCurl();
    CURLcode res;
    if(!curl) return CURL_INIT_FAILED;
    if(res = curl_easy_setopt(curl, CURLOPT_URL, uri) != CURLE_OK) {
        if(err) *err = res;
        return CURL_INIT_FAILED;
    }
    if(mkNew) {
        if(res = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST")) {
            if(err) *err = res;
            return CURL_INIT_FAILED;
        }
    } else {
        if(res = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH") != CURLE_OK) {
            if(err) *err = res;
            return CURL_INIT_FAILED;
        }
    }
    struct curl_slist* header;
    header = curl_slist_append(header, "Content-Type:application/json");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
    char* payload;
    marshal(payload);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload);
    ErrorCode ret;
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret);
    auto wfunc = [](void* dat, size_t size, size_t nmemb, void* ret) {
        using namespace rapidjson;
        Document d = new Document();
        ParseResult ok = d.Parse(static_cast<char*>(dat));
        if(!ok) {
            if(err) *err = ok;
            *ret = JSON_PARSE_FAILED;
        }
        long httpStat;
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpStat);
        if(httpStat < 200 || httpStat > 300) {
            getErrCode(d, ret);
            if(err) *err = httpStat;
        } else {
            *ret = NIL;
        } return size * nmemb;
    };
    curl_easy_setopt(curl, CURLOPT_WRITEFUNC, static_cast<CURLOPT_WRITEFUNCTION_PTR>(&wfunc));
    CURLcode res = curl_easy_perform(curl);
    if(cresp != CURLE_OK) return res;
    curl_easy_cleanup(c->getCurl());
    curl_slist_free(header);
    return NIL;
}

ErrorCode Pushable::delete(Client* c, long* err = NULL) {
    char* uri;
    buildEndpointUri(c, uri);
    CURL* curl = curl_easy_init();
    if(!curl) return CURL_INIT_FAILED;
    CURLcode res;
    if(res = curl_easy_setopt(curl, CURLOPT_URL, uri) != CURLE_OK) {
        if(err) *err = res;
        return CURL_INIT_FAILED;
    }
    if(res = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE")) {
        if(err) *err = res;
        return CURL_INIT_FAILED;
    }
    if(res = curl_easy_perform(curl) != CURLE_OK) {
        if(err) *err = res;
        return CURL_PERFORM_FAILED;
    }
    long httpStat;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpStat);
    curl_easy_cleanup(c->getCurl());
    if(httpStat < 200 || httpStat > 300) {
        if(err) *err = httpStat;
{'fraction_non_alphanumeric': 0.1254056860963261, 'fraction_numerical': 0.0031156692197844994, 'mean_word_length': 3.039853172522286, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4391272', 'n_tokens_mistral': 2820, 'n_tokens_neox': 2677, 'n_words': 555}