#include <xs/export.h>
#include <xs/unievent/Resolver.h>
using namespace xs;
using namespace panda::unievent;
using panda::net::SockAddr;
MODULE = UniEvent::Resolver PACKAGE = UniEvent::Resolver
PROTOTYPES: DISABLE
BOOT {
Stash s(__PACKAGE__);
xs::exp::create_constants(s, {
{"NUMERICSERV", AddrInfoHints::NUMERICSERV},
{"CANONAME", AddrInfoHints::CANONNAME }
});
}
Resolver* Resolver::new (Loop* loop = Loop::default_loop(), Hash hcfg = Hash()) {
Resolver::Config cfg;
if (hcfg.size()) {
Scalar val;
if ((val = hcfg.fetch("cache_expiration_time"))) cfg.cache_expiration_time = val.number();
if ((val = hcfg.fetch("cache_limit"))) cfg.cache_limit = val.number();
if ((val = hcfg.fetch("query_timeout"))) cfg.query_timeout = val.as_number<double>() * 1000;
if ((val = hcfg.fetch("workers"))) cfg.workers = val.number();
}
RETVAL = make_backref<Resolver>(loop, cfg);
}
#// resolve($node, $callback, [$timeout])
#// resolve({node => ..., callback => ..., timeout => ..., service => ..., use_cache => ..., hints => ...})
Resolver::RequestSP Resolver::resolve (Scalar node_or_params, SV* callback = NULL, double timeout = Resolver::DEFAULT_RESOLVE_TIMEOUT / 1000) {
Resolver::RequestSP req = make_backref<Resolver::Request>();
Sub cb;
if (node_or_params.is_hash_ref()) {
const Hash h = node_or_params;
for (const auto& row : h) {
auto key = row.key();
if (!key.length()) continue;
auto sv = row.value();
switch (key[0]) {
case 'n': if (key == "node") req->node (sv.as_string()); break;
case 't': if (key == "timeout") req->timeout(xs::in<double>(sv) * 1000); break;
case 's': if (key == "service") req->service(sv.as_string()); break;
case 'p': if (key == "port") req->port(sv.number()); break;
case 'h': if (key == "hints") req->hints (xs::in<AddrInfoHints>(sv)); break;
case 'u': if (key == "use_cache") req->use_cache(sv.is_true()); break;
case 'o': if (key == "on_resolve") cb = sv; break;
}
}
} else {
req->node(node_or_params.as_string());
cb = callback;
req->timeout(timeout * 1000);
}
if (cb) req->on_resolve([cb](const AddrInfo& addr, const std::error_code& err, const Resolver::RequestSP& req) {
auto salistref = Scalar::undef;
if (!err) {
auto salist = Array::create();
for (auto ai = addr; ai; ai = ai.next()) {
salist.push(xs::out(ai.addr()));
}
salistref = Ref::create(salist);
}
cb.call<void>(salistref, xs::out(err), xs::out(req));
});
THIS->resolve(req);
RETVAL = req;
}
uint32_t Resolver::cache_expiration_time (Scalar newval = Scalar()) {
if (newval) {
THIS->cache_expiration_time(newval.number());
XSRETURN_UNDEF;
}
RETVAL = THIS->cache_expiration_time();
}
size_t Resolver::cache_limit (Scalar newval = Scalar()) {
if (newval) {
THIS->cache_limit(newval.number());
XSRETURN_UNDEF;
}
RETVAL = THIS->cache_limit();
}
size_t Resolver::cache_size () {
RETVAL = THIS->cache().size();
}
size_t Resolver::queue_size ()
void Resolver::clear_cache () {
THIS->cache().clear();
}
void Resolver::reset ()
AddrInfoHints hints (int family, int socktype, int protocol = 0, int flags = 0) {
RETVAL = AddrInfoHints(family, socktype, protocol, flags);
}
MODULE = UniEvent::Resolver PACKAGE = UniEvent::Resolver::Request
PROTOTYPES: DISABLE
void Resolver::Request::cancel ()