Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8de1b49ad | ||
|
|
4df200effa | ||
|
|
cbb3ab40fb | ||
|
|
1abd120c12 | ||
|
|
ca30a96c1c | ||
|
|
d2f4c72d64 | ||
|
|
202e13c66f | ||
|
|
a3e975d43c | ||
|
|
f1e9306cd6 | ||
|
|
c6fe3c2624 | ||
|
|
7fb9018515 | ||
|
|
742d6b5b79 | ||
|
|
ec1721f298 | ||
|
|
5aeffa328a |
No files matched your search
@@ -22,7 +22,7 @@ messages from complete Javascript objects. This actually makes the library
|
|||||||
somewhat nicer syntactically than it would be otherwise, but it is not fast.
|
somewhat nicer syntactically than it would be otherwise, but it is not fast.
|
||||||
|
|
||||||
A pure-Javascript implementation would likely be much faster. See
|
A pure-Javascript implementation would likely be much faster. See
|
||||||
[capnp-js](https://github.com/capnp-js/serialization) for such an
|
[capnp-js](https://github.com/capnp-js) for such an
|
||||||
implementation. Unfortunately, that implementation is incomplete and does not
|
implementation. Unfortunately, that implementation is incomplete and does not
|
||||||
support [RPC](https://github.com/capnp-js/rpc) just yet. Hence, this hack was
|
support [RPC](https://github.com/capnp-js/rpc) just yet. Hence, this hack was
|
||||||
created for short-term use.
|
created for short-term use.
|
||||||
|
|||||||
+2
-2
@@ -4,12 +4,12 @@
|
|||||||
'target_name': 'capnp',
|
'target_name': 'capnp',
|
||||||
'sources': ['src/node-capnp/capnp.cc'],
|
'sources': ['src/node-capnp/capnp.cc'],
|
||||||
'libraries': ['-lkj', '-lkj-async', '-lcapnp', '-lcapnpc', '-lcapnp-rpc'],
|
'libraries': ['-lkj', '-lkj-async', '-lcapnp', '-lcapnpc', '-lcapnp-rpc'],
|
||||||
'cflags_cc': ['-std=c++11'],
|
'cflags_cc': ['-std=c++14'],
|
||||||
'cflags_cc!': ['-fno-rtti', '-fno-exceptions'],
|
'cflags_cc!': ['-fno-rtti', '-fno-exceptions'],
|
||||||
'conditions': [
|
'conditions': [
|
||||||
[ 'OS=="mac"', {
|
[ 'OS=="mac"', {
|
||||||
'xcode_settings': {
|
'xcode_settings': {
|
||||||
'OTHER_CPLUSPLUSFLAGS' : ['-std=c++11','-stdlib=libc++'],
|
'OTHER_CPLUSPLUSFLAGS' : ['-std=c++14','-stdlib=libc++'],
|
||||||
'OTHER_LDFLAGS': ['-stdlib=libc++'],
|
'OTHER_LDFLAGS': ['-stdlib=libc++'],
|
||||||
'GCC_ENABLE_CPP_RTTI': 'YES',
|
'GCC_ENABLE_CPP_RTTI': 'YES',
|
||||||
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
|
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "capnp",
|
"name": "capnp",
|
||||||
"version": "0.2.0",
|
"version": "0.3.1",
|
||||||
"description": "A wrapper for the C++ Cap'n Proto library",
|
"description": "A wrapper for the C++ Cap'n Proto library",
|
||||||
"keywords": [ "capnproto", "serialization" ],
|
"keywords": [ "capnproto", "serialization" ],
|
||||||
"homepage": "http://capnproto.org",
|
"homepage": "http://capnproto.org",
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"url": "git://github.com/kentonv/node-capnp.git"
|
"url": "git://github.com/kentonv/node-capnp.git"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.12"
|
"node": ">=8.0"
|
||||||
},
|
},
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
@@ -263,31 +263,48 @@ child.stdio[1].once("readable", function() {
|
|||||||
closed: false
|
closed: false
|
||||||
};
|
};
|
||||||
|
|
||||||
var localCap = new capnp.Capability(pow, Calculator.Function);
|
function usePow(pow) {
|
||||||
assert.equal(9, wait(localCap.call([3, 2])).value);
|
var localCap = new capnp.Capability(pow, Calculator.Function);
|
||||||
assert(!pow.closed);
|
assert.equal(9, wait(localCap.call([3, 2])).value);
|
||||||
localCap.close();
|
assert(!pow.closed);
|
||||||
assert(pow.closed);
|
localCap.close();
|
||||||
|
assert(pow.closed);
|
||||||
|
|
||||||
var promise = calc.evaluate(
|
var promise = calc.evaluate(
|
||||||
{call: {"function": subtract, params: [
|
{call: {"function": subtract, params: [
|
||||||
{call: {"function": add, params: [
|
{call: {"function": add, params: [
|
||||||
{literal: 123}, {literal: 456}]}},
|
{literal: 123}, {literal: 456}]}},
|
||||||
{literal: 321}]}});
|
{literal: 321}]}});
|
||||||
|
|
||||||
var value = promise.value;
|
var value = promise.value;
|
||||||
assert.equal(258, wait(value.read()).value);
|
assert.equal(258, wait(value.read()).value);
|
||||||
value.close();
|
value.close();
|
||||||
|
|
||||||
pow.closed = false;
|
pow.closed = false;
|
||||||
value = calc.evaluate(
|
value = calc.evaluate(
|
||||||
{call: {"function": pow, params: [{literal: 2}, {literal: 4}]}}).value;
|
{call: {"function": pow, params: [{literal: 2}, {literal: 4}]}}).value;
|
||||||
assert.equal(16, wait(value.read()).value);
|
assert.equal(16, wait(value.read()).value);
|
||||||
|
|
||||||
// Wait a moment to give the capability a chance to be dropped.
|
// Wait a moment to give the capability a chance to be dropped.
|
||||||
wait(new Promise((resolve, reject) => setTimeout(resolve, 10)));
|
wait(new Promise((resolve, reject) => setTimeout(resolve, 10)));
|
||||||
assert(pow.closed);
|
assert(pow.closed);
|
||||||
value.close();
|
value.close();
|
||||||
|
}
|
||||||
|
usePow(pow);
|
||||||
|
|
||||||
|
// Try using a class.
|
||||||
|
class PowClass {
|
||||||
|
constructor() {
|
||||||
|
this.closed = false
|
||||||
|
}
|
||||||
|
call(params) {
|
||||||
|
return Math.pow(params[0], params[1]);
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
this.closed = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
usePow(new PowClass());
|
||||||
|
|
||||||
// Try wrapping a promise as a capability -- calls are queued until resolution.
|
// Try wrapping a promise as a capability -- calls are queued until resolution.
|
||||||
var resolvePromisedCalc;
|
var resolvePromisedCalc;
|
||||||
|
|||||||
+74
-48
@@ -47,7 +47,6 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
@@ -237,7 +236,7 @@ static int applyFlags(int fd, uint flags) {
|
|||||||
|
|
||||||
static constexpr uint NEW_FD_FLAGS =
|
static constexpr uint NEW_FD_FLAGS =
|
||||||
#if __linux__
|
#if __linux__
|
||||||
kj::LowLevelAsyncIoProvider::ALREADY_CLOEXEC || kj::LowLevelAsyncIoProvider::ALREADY_NONBLOCK ||
|
kj::LowLevelAsyncIoProvider::ALREADY_CLOEXEC | kj::LowLevelAsyncIoProvider::ALREADY_NONBLOCK |
|
||||||
#endif
|
#endif
|
||||||
kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP;
|
kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP;
|
||||||
// We always try to open FDs with CLOEXEC and NONBLOCK already set on Linux, but on other platforms
|
// We always try to open FDs with CLOEXEC and NONBLOCK already set on Linux, but on other platforms
|
||||||
@@ -410,6 +409,13 @@ public:
|
|||||||
KJ_SYSCALL(shutdown(fd, SHUT_WR));
|
KJ_SYSCALL(shutdown(fd, SHUT_WR));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CAPNP_VERSION >= 8000
|
||||||
|
kj::Promise<void> whenWriteDisconnected() override {
|
||||||
|
// TODO(someday): Implement using UV_DISCONNECT?
|
||||||
|
return kj::NEVER_DONE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
kj::Promise<size_t> tryReadInternal(void* buffer, size_t minBytes, size_t maxBytes,
|
kj::Promise<size_t> tryReadInternal(void* buffer, size_t minBytes, size_t maxBytes,
|
||||||
size_t alreadyRead) {
|
size_t alreadyRead) {
|
||||||
@@ -564,7 +570,7 @@ public:
|
|||||||
struct sockaddr_in6 inet6;
|
struct sockaddr_in6 inet6;
|
||||||
} addr;
|
} addr;
|
||||||
addrlen = sizeof(addr);
|
addrlen = sizeof(addr);
|
||||||
KJ_SYSCALL(getsockname(fd, &addr.generic, &addrlen));
|
KJ_SYSCALL(::getsockname(fd, &addr.generic, &addrlen));
|
||||||
switch (addr.generic.sa_family) {
|
switch (addr.generic.sa_family) {
|
||||||
case AF_INET: return ntohs(addr.inet4.sin_port);
|
case AF_INET: return ntohs(addr.inet4.sin_port);
|
||||||
case AF_INET6: return ntohs(addr.inet6.sin6_port);
|
case AF_INET6: return ntohs(addr.inet6.sin6_port);
|
||||||
@@ -866,6 +872,17 @@ class Wrapper {
|
|||||||
handle.SetWeak(this, &deleteCallback, v8::WeakCallbackType::kParameter);
|
handle.SetWeak(this, &deleteCallback, v8::WeakCallbackType::kParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~WrappedObject() {
|
||||||
|
// Since destructors might perform non-trivial operations, including calling back into
|
||||||
|
// JavaScript, delay the destructor until the next turn of the event loop.
|
||||||
|
T* ptrCopy = ptr;
|
||||||
|
kj::evalLater([ptrCopy]() {
|
||||||
|
delete ptrCopy;
|
||||||
|
}).detach([](kj::Exception&& exception) {
|
||||||
|
KJ_LOG(ERROR, exception);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static void deleteCallback(const v8::WeakCallbackInfo<WrappedObject>& data) {
|
static void deleteCallback(const v8::WeakCallbackInfo<WrappedObject>& data) {
|
||||||
delete reinterpret_cast<WrappedObject*>(data.GetParameter());
|
delete reinterpret_cast<WrappedObject*>(data.GetParameter());
|
||||||
}
|
}
|
||||||
@@ -892,11 +909,14 @@ public:
|
|||||||
if (getFunctionTemplate<T>()->HasInstance(obj)) {
|
if (getFunctionTemplate<T>()->HasInstance(obj)) {
|
||||||
return *reinterpret_cast<WrappedObject<T>*>(obj->GetAlignedPointerFromInternalField(0))->ptr;
|
return *reinterpret_cast<WrappedObject<T>*>(obj->GetAlignedPointerFromInternalField(0))->ptr;
|
||||||
} else {
|
} else {
|
||||||
v8::Handle<v8::Value> native = obj->GetHiddenValue(newSymbol("capnp::native"));
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||||
if (native.IsEmpty() || native->IsUndefined()) {
|
v8::Handle<v8::Value> native;
|
||||||
return nullptr;
|
if (obj->GetPrivate(isolate->GetCurrentContext(),
|
||||||
} else {
|
v8::Private::ForApi(isolate, newSymbol("capnp::native"))).ToLocal(&native) &&
|
||||||
|
!native->IsUndefined()) {
|
||||||
return tryUnwrap<T>(native);
|
return tryUnwrap<T>(native);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1013,7 +1033,11 @@ void setNative(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
// passed to fromJs().
|
// passed to fromJs().
|
||||||
|
|
||||||
if (args[0]->IsObject()) {
|
if (args[0]->IsObject()) {
|
||||||
v8::Object::Cast(*args[0])->SetHiddenValue(newSymbol("capnp::native"), args[1]);
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||||
|
v8::Object::Cast(*args[0])->SetPrivate(
|
||||||
|
isolate->GetCurrentContext(),
|
||||||
|
v8::Private::ForApi(isolate, newSymbol("capnp::native")),
|
||||||
|
args[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1876,7 +1900,11 @@ void fromBytes(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapper->SetHiddenValue(newSymbol("buffer"), bufferHandle);
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||||
|
wrapper->SetPrivate(
|
||||||
|
isolate->GetCurrentContext(),
|
||||||
|
v8::Private::ForApi(isolate, newSymbol("capnp::buffer")),
|
||||||
|
bufferHandle);
|
||||||
return wrapper;
|
return wrapper;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2219,11 +2247,18 @@ void pipelineToJs(CapnpContext& context, capnp::DynamicStruct::Pipeline&& pipeli
|
|||||||
v8::Handle<v8::Object> fieldValue;
|
v8::Handle<v8::Object> fieldValue;
|
||||||
|
|
||||||
switch (proto.which()) {
|
switch (proto.which()) {
|
||||||
case capnp::schema::Field::SLOT:
|
case capnp::schema::Field::SLOT: {
|
||||||
switch (proto.getSlot().getType().which()) {
|
auto type = field.getType();
|
||||||
|
switch (type.which()) {
|
||||||
case capnp::schema::Type::STRUCT:
|
case capnp::schema::Type::STRUCT:
|
||||||
fieldValue = pipelineStructFieldToJs(context, pipeline, field, capConstructor);
|
fieldValue = pipelineStructFieldToJs(context, pipeline, field, capConstructor);
|
||||||
break;
|
break;
|
||||||
|
case capnp::schema::Type::ANY_POINTER:
|
||||||
|
if (type.whichAnyPointerKind() !=
|
||||||
|
capnp::schema::Type::AnyPointer::Unconstrained::CAPABILITY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// fallthrough
|
||||||
case capnp::schema::Type::INTERFACE: {
|
case capnp::schema::Type::INTERFACE: {
|
||||||
auto cap = pipeline.get(field).releaseAs<capnp::DynamicCapability>();
|
auto cap = pipeline.get(field).releaseAs<capnp::DynamicCapability>();
|
||||||
capnp::Schema capSchema = cap.getSchema();
|
capnp::Schema capSchema = cap.getSchema();
|
||||||
@@ -2240,6 +2275,7 @@ void pipelineToJs(CapnpContext& context, capnp::DynamicStruct::Pipeline&& pipeli
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case capnp::schema::Field::GROUP:
|
case capnp::schema::Field::GROUP:
|
||||||
fieldValue = pipelineStructFieldToJs(context, pipeline, field, capConstructor);
|
fieldValue = pipelineStructFieldToJs(context, pipeline, field, capConstructor);
|
||||||
@@ -2339,51 +2375,17 @@ void cancel(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Local caps
|
// Local caps
|
||||||
|
|
||||||
struct TypeHash {
|
|
||||||
inline size_t operator()(const capnp::Type& t) const {
|
|
||||||
return t.hashCode();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_map<capnp::Type, uint, TypeHash> localCapTypeCounts;
|
|
||||||
|
|
||||||
void dumpLocalCapTypeCounts(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
||||||
liftKj(args, [&]() -> void {
|
|
||||||
typedef std::pair<capnp::Type, uint> E;
|
|
||||||
kj::Array<E> array = KJ_MAP(e, localCapTypeCounts) { return E(e); };
|
|
||||||
|
|
||||||
std::sort(array.begin(), array.end(),
|
|
||||||
[](const E& a, const E& b) { return a.second > b.second; });
|
|
||||||
|
|
||||||
auto lines = KJ_MAP(e, array) {
|
|
||||||
return kj::str('\n', e.second, " ", e.first.asInterface().getProto().getDisplayName());
|
|
||||||
};
|
|
||||||
|
|
||||||
auto typeStats = kj::strArray(lines, "");
|
|
||||||
KJ_LOG(WARNING, "dumping types of local capabilities", typeStats);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class LocalCap final: public capnp::DynamicCapability::Server {
|
class LocalCap final: public capnp::DynamicCapability::Server {
|
||||||
public:
|
public:
|
||||||
LocalCap(capnp::InterfaceSchema schema, v8::Handle<v8::Object> object,
|
LocalCap(capnp::InterfaceSchema schema, v8::Handle<v8::Object> object,
|
||||||
CapnpContext& capnpContext, v8::Handle<v8::Value> capnpContextHandle)
|
CapnpContext& capnpContext, v8::Handle<v8::Value> capnpContextHandle)
|
||||||
: capnp::DynamicCapability::Server(schema),
|
: capnp::DynamicCapability::Server(schema),
|
||||||
object(object), capnpContext(capnpContext), capnpContextHandle(capnpContextHandle) {
|
object(object), capnpContext(capnpContext), capnpContextHandle(capnpContextHandle) {}
|
||||||
localCapTypeCounts[schema]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
~LocalCap() {
|
~LocalCap() {
|
||||||
// Call the object's close() method if it has one, so that it can react to the handle being
|
// Call the object's close() method if it has one, so that it can react to the handle being
|
||||||
// dropped.
|
// dropped.
|
||||||
|
|
||||||
auto iter = localCapTypeCounts.find(getSchema());
|
|
||||||
if (iter == localCapTypeCounts.end()) {
|
|
||||||
KJ_LOG(ERROR, "inconsistent type counts");
|
|
||||||
} else if (--iter->second == 0) {
|
|
||||||
localCapTypeCounts.erase(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||||
|
|
||||||
auto jsMethod = object->Get(newSymbol("close"));
|
auto jsMethod = object->Get(newSymbol("close"));
|
||||||
@@ -2796,6 +2798,31 @@ void chacha20(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void crashHandler(int signo, siginfo_t* info, void* context) {
|
||||||
|
void* traceSpace[32];
|
||||||
|
|
||||||
|
// ignoreCount = 2 to ignore crashHandler() and signal trampoline.
|
||||||
|
auto trace = kj::getStackTrace(traceSpace, 2);
|
||||||
|
|
||||||
|
auto message = kj::str("*** Received signal #", signo, ": ", strsignal(signo),
|
||||||
|
"\nstack: ", stringifyStackTraceAddresses(trace), '\n');
|
||||||
|
|
||||||
|
kj::FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void catchSegfaults() {
|
||||||
|
struct sigaction action;
|
||||||
|
memset(&action, 0, sizeof(action));
|
||||||
|
action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER | SA_RESETHAND;
|
||||||
|
action.sa_sigaction = &crashHandler;
|
||||||
|
KJ_SYSCALL(sigaction(SIGSEGV, &action, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
#endif // SANDSTORM_BUILD
|
#endif // SANDSTORM_BUILD
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -2848,9 +2875,8 @@ void init(v8::Handle<v8::Object> exports) {
|
|||||||
#ifdef SANDSTORM_BUILD
|
#ifdef SANDSTORM_BUILD
|
||||||
mapFunction("matchPowerboxQuery", matchPowerboxQuery);
|
mapFunction("matchPowerboxQuery", matchPowerboxQuery);
|
||||||
mapFunction("chacha20", chacha20);
|
mapFunction("chacha20", chacha20);
|
||||||
|
catchSegfaults();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mapFunction("dumpLocalCapTypeCounts", dumpLocalCapTypeCounts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
+13
-11
@@ -192,16 +192,20 @@ function wrapLocalMethod(self, method) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function LocalCapWrapper(obj) {
|
function LocalCapWrapper(obj) {
|
||||||
for (var name in obj) {
|
var type = obj;
|
||||||
if (name === "close") {
|
while (type && type !== Object.prototype) {
|
||||||
// Not an RPC method. Called when the capability has no clients.
|
Object.getOwnPropertyNames(type).forEach(name => {
|
||||||
this.close = obj.close.bind(obj);
|
if (name === "close") {
|
||||||
} else {
|
// Not an RPC method. Called when the capability has no clients.
|
||||||
var method = obj[name];
|
this.close = obj.close.bind(obj);
|
||||||
if (typeof method === "function") {
|
} else {
|
||||||
this[name] = wrapLocalMethod(obj, method);
|
var method = obj[name];
|
||||||
|
if (typeof method === "function") {
|
||||||
|
this[name] = wrapLocalMethod(obj, method);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
type = Object.getPrototypeOf(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,5 +302,3 @@ exports.bytesToPreorder = function(schema, buf, options) {
|
|||||||
|
|
||||||
if (v8capnp.matchPowerboxQuery) exports.matchPowerboxQuery = v8capnp.matchPowerboxQuery;
|
if (v8capnp.matchPowerboxQuery) exports.matchPowerboxQuery = v8capnp.matchPowerboxQuery;
|
||||||
if (v8capnp.chacha20) exports.chacha20 = v8capnp.chacha20;
|
if (v8capnp.chacha20) exports.chacha20 = v8capnp.chacha20;
|
||||||
|
|
||||||
exports.dumpLocalCapTypeCounts = v8capnp.dumpLocalCapTypeCounts;
|
|
||||||
Reference in new issue
Block a user