EV-YACurl

 view release on metacpan or  search on metacpan

YACurl.xs  view on Meta::CPAN

#endif
    }
}
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif

MODULE = EV::YACurl       PACKAGE = EV::YACurl

PROTOTYPES: DISABLE

BOOT:
{
    MY_CXT_INIT;
    MY_CXT.curlopt = newHV();
    MY_CXT.default_priority = 0;
    MY_CXT.in_data_callback = 0;
    MY_CXT.client_stash = gv_stashpv("EV::YACurl", GV_ADD);
    MY_CXT.response_stash = gv_stashpv("EV::YACurl::Response", GV_ADD);
    fill_hv_with_constants(aTHX_ MY_CXT.curlopt);

    I_EV_API("EV::YACurl");

    curl_global_init(CURL_GLOBAL_ALL);
}

void
CLONE(...)
    CODE:
        MY_CXT_CLONE;
        MY_CXT.curlopt = newHV();
        MY_CXT.in_data_callback = 0;
        MY_CXT.client_stash = gv_stashpv("EV::YACurl", GV_ADD);
        MY_CXT.response_stash = gv_stashpv("EV::YACurl::Response", GV_ADD);
        fill_hv_with_constants(aTHX_ MY_CXT.curlopt);

void
new(class, args)
        SV *class
        HV *args
    PPCODE:
        dMY_CXT;

        EV__YACurl *client;
        struct ev_loop *loop = EV_DEFAULT;

        if (!loop)
            croak("EV has no default loop");

        Newxz(client, 1, EV__YACurl);

        ST(0) = sv_newmortal();
        sv_setref_pv(ST(0), SvPV_nolen(class), (void *)client);

        client->loop = loop;
        client->priority = MY_CXT.default_priority;
        client->timer.client = client;
        ev_timer_init(&client->timer.timer, yacurl_timer_cb, 0., 0.);
        ev_set_priority(&client->timer.timer, client->priority);

        /* Weak, so the client is not kept alive by its own curl callbacks. */
        client->weak_self_ref = newSVsv(ST(0));
        sv_rvweaken(client->weak_self_ref);

        client->multi = curl_multi_init();
        if (!client->multi)
            croak("Failed to instantiate CURLM object");

        curl_multi_setopt(client->multi, CURLMOPT_SOCKETFUNCTION, mcurl_socket_callback);
        curl_multi_setopt(client->multi, CURLMOPT_TIMERFUNCTION, mcurl_timer_callback);
        curl_multi_setopt(client->multi, CURLMOPT_SOCKETDATA, (void *)client);
        curl_multi_setopt(client->multi, CURLMOPT_TIMERDATA, (void *)client);

        apply_multi_options(aTHX_ aMY_CXT_ client, args);

        XSRETURN(1);

void
request(self, callback, options)
        SV *self
        SV *callback
        HV *options
    CODE:
        dMY_CXT;

        EV__YACurl *client;
        EV__YACurl__Response *response_ctx;

        if (MY_CXT.in_data_callback)
            croak("request() cannot be called from a data callback; "
                  "start follow-up requests from the completion callback");

        client = SV_TO_CLIENT(self);
        CURL *easy;
        CURLMcode error;
        HE *iterentry;

        if (!SvROK(callback) || SvTYPE(SvRV(callback)) != SVt_PVCV)
            croak("request() needs a code reference as its callback");

        /* Mortal until curl_multi_add_handle() succeeds, so an intervening
         * croak() still frees everything allocated so far. */
        Newxz(response_ctx, 1, EV__YACurl__Response);
        response_ctx->self_rv = sv_newmortal();
        sv_setref_pv(response_ctx->self_rv, "EV::YACurl::Response", (void *)response_ctx);

        easy = curl_easy_init();
        if (!easy)
            croak("Failed to instantiate CURL object");
        response_ctx->easy = easy;

        if (curl_easy_setopt(easy, CURLOPT_PRIVATE, response_ctx) != CURLE_OK)
            croak("Failed to setup CURL object");
        curl_easy_setopt(easy, CURLOPT_ERRORBUFFER, response_ctx->errbuf);

        response_ctx->held_references = newAV();
        response_ctx->callback = newSVsv(callback);

        /* Pins the client for as long as the request lives. */
        av_push(response_ctx->held_references, newSVsv(self));



( run in 1.078 second using v1.01-cache-2.11-cpan-14f38c9f855 )