AnyEvent-YACurl

 view release on metacpan or  search on metacpan

YACurl.xs  view on Meta::CPAN

#include "XSUB.h"

#include "ppport.h"
#define MY_CXT_KEY "AnyEvent::YACurl::_guts" XS_VERSION

#include <curl/curl.h>
#include "libcurl-symbols.h"

typedef struct {
    SV *watchset_fn;
    SV *timerset_fn;
    HV *curlopt;
} my_cxt_t;

typedef struct {
    CURLM *multi;
    SV *weak_self_ref;

    int needs_invoke_timeout;
    int needs_read_info;
    int last_running;

YACurl.xs  view on Meta::CPAN

    PUTBACK;

    call_sv(MY_CXT.watchset_fn, G_DISCARD | G_VOID);

    FREETMPS;
    LEAVE;

    return 0;
}

int mcurl_timer_callback(CURLM* multi,
                         long timeout_ms,
                         void *userp)
{
    dTHX;

    if (timeout_ms == 0) {
        /* We short-circuit timeout_ms==0, as we're very likely to call do_post_work shortly
         * after reaching this code path. A timer of 0sec in AnyEvent would almost always turn
         * into a 1ms wait, which is unnecessary and slow. Same goes for AE::postpone. */
        IV tmp = SvIV((SV*)SvRV((SV*)userp));
        AnyEvent__YACurl *client = INT2PTR(AnyEvent__YACurl*, tmp);

        client->needs_invoke_timeout = 1;
        return 0;
    }

    dMY_CXT;
    dSP;

    ENTER;
    SAVETMPS;

    PUSHMARK(SP);
    EXTEND(SP, 2);
    PUSHs((SV*)userp); /* XXX This is a weakened reference, will it ever be undef? */
    PUSHs(sv_2mortal(newSViv(timeout_ms)));
    PUTBACK;

    call_sv(MY_CXT.timerset_fn, G_DISCARD | G_VOID);

    FREETMPS;
    LEAVE;

    return 0;
}

/* write callback: used for WRITEFUNCTION and HEADERFUNCTION */
size_t mcurl_write_callback(char *ptr,
                           size_t size,

YACurl.xs  view on Meta::CPAN

MODULE = AnyEvent::YACurl       PACKAGE = AnyEvent::YACurl

PROTOTYPES: DISABLE

BOOT:
{
    /* XXX: Needs a CLONE */

    MY_CXT_INIT;
    MY_CXT.watchset_fn = NULL;
    MY_CXT.timerset_fn = NULL;
    MY_CXT.curlopt = newHV();
    fill_hv_with_constants(aTHX_ MY_CXT.curlopt);

    curl_global_init(CURL_GLOBAL_ALL);
}

void
new(class, args)
        char *class
        HV *args

YACurl.xs  view on Meta::CPAN

        dMY_CXT;

        (void)class;
        AnyEvent__YACurl *client;

        Newxz(client, 1, AnyEvent__YACurl);

        ST(0) = sv_newmortal();
        sv_setref_pv(ST(0), "AnyEvent::YACurl", (void*)client);

        /* XXX When we destroy the client, do we pass undefs to the timer/watch functions? */
        client->weak_self_ref = newSVsv(ST(0));
        sv_rvweaken(client->weak_self_ref);

        client->multi = curl_multi_init();
        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->weak_self_ref);
        curl_multi_setopt(client->multi, CURLMOPT_TIMERDATA, (void*)client->weak_self_ref);

        {
            hv_iterinit(args);
            HE *iterentry;
            while ((iterentry = hv_iternext(args)) != NULL) {
                long opt;
                int opt_from_str;
                SV *key = HeSVKEY_force(iterentry);

YACurl.xs  view on Meta::CPAN

        SvREFCNT_inc(response_ctx->self_rv);

        update_running(aTHX_ client, client->last_running + 1);
        client->needs_invoke_timeout = 1;

        do_post_work(aTHX_ client);

PROTOTYPES: ENABLE

void
_ae_set_helpers(watchset, timerset)
        SV* watchset
        SV* timerset
    CODE:
        dMY_CXT;

        if (MY_CXT.watchset_fn != NULL)
            croak("watchset already set");
        MY_CXT.watchset_fn = newSVsv(watchset);

        if (MY_CXT.timerset_fn != NULL)
            croak("timerset already set");
        MY_CXT.timerset_fn = newSVsv(timerset);

void
_ae_timer_fired(self)
        SV* self
    CODE:
        AnyEvent__YACurl *client = sv_to_client(aTHX_ self);

        client->needs_invoke_timeout = 1;
        do_post_work(aTHX_ client);

void
_ae_event(self, sock, is_write)
        SV* self

lib/AnyEvent/YACurl.pm  view on Meta::CPAN

                }),
            ];

        } elsif ($what == 0 || $what == 4) { # NONE / REMOVE
            delete $WATCH{$socket};

        } else {
            warn "Don't understand what==$what";
        }
    },
    sub { # timerset
        my ($client, $time_ms)= @_;

        if ($time_ms == -1) {
            delete $TIMER{$$client};
            return;
        }

        AE::now_update;
        $TIMER{$$client}= AE::timer(($time_ms / 1000), 0, sub {
            delete $TIMER{$$client};
            _ae_timer_fired($client);
        });
    }
);

1;

=head1 NAME

AnyEvent::YACurl - Yet Another curl binding for AnyEvent



( run in 0.786 second using v1.01-cache-2.11-cpan-49f99fa48dc )