AnyEvent-YACurl
view release on metacpan or search on metacpan
#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;
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,
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
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);
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 )