Author SHA1 Message Date
Kenton Varda 92b821f54f Support "flat" encoding, and "packed-flat" too. 2016-03-27 07:16:05 -07:00
Kenton Varda 62501e2e05 Include Javascript stack when converting to KJ exception. 2016-03-27 05:47:13 -07:00
Drew Fisher 586a0b507a Make the overhead computation look less like it has an integer underflow 2016-02-18 20:05:12 -08:00
Drew Fisher 8731696b87 Compute a tighter upper bound on the buffer needed for packed encoding 2016-02-18 20:05:12 -08:00
Drew Fisher 4c52f07a80 Add tests for packed encoding/decoding. 2016-02-18 20:05:12 -08:00
Drew Fisher ce1fc89df4 Add support for serializing structures to packed Cap'n Proto encoding 2016-02-18 20:05:12 -08:00
Drew Fisher 6b18e62df3 Add support for parsing structures in Cap'n Proto's packed encoding 2016-02-18 20:05:03 -08:00
Kenton Varda 133c15771b Void values are normally represented as 'null', so ignoring 'null' fields is wrong. 2016-02-09 18:34:04 -08:00
Kenton Varda e999e82d46 Turn off the C++ logging and double-down on Javascript. We're closing in now. 2015-12-17 11:21:24 -08:00
Kenton Varda d6a93a7ff4 Yes more debug logging. 2015-12-08 11:22:42 -08:00
Kenton Varda 963dc37a1b More debug logging. 2015-11-21 19:56:46 -08:00
Kenton Varda 6b5faf488c More moar debug logging. 2015-11-13 19:37:12 -08:00
Kenton Varda 30beb85403 Treat closed capability as disconnected.
This seems correct, and works around a bug in Sandstorm where a capability shared between multiple components is sometimes closed by one of them. This isn't the best way to fix the bug, but the real fix will require some refactoring.
2015-11-10 09:54:13 -08:00
Kenton Varda 53914ae5d9 moar logging 2015-11-06 11:18:42 -08:00
Kenton Varda 9911c0e414 Even more verbose debug logging. 2015-11-02 23:59:35 -08:00
Kenton Varda 10900e0bed moar logging 2015-10-28 11:56:33 -07:00
Kenton Varda ed3e786554 Try to track down the damned bug with verbose debug logging. 2015-10-15 23:17:02 -07:00
6 changed files with 290 additions and 26 deletions

No files matched your search

+34
View File
@@ -26,12 +26,21 @@ var Promise = require("es6-promise").Promise;
var spawn = require("child_process").spawn;
var goldenBinary;
var goldenPackedBinary;
var goldenFlatBinary;
var goldenPackedFlatBinary;
try {
// Works in Ekam build.
goldenBinary = fs.readFileSync("node-capnp/testdata/binary");
goldenPackedBinary = fs.readFileSync("node-capnp/testdata/packedbinary");
goldenFlatBinary = fs.readFileSync("node-capnp/testdata/flat");
goldenPackedFlatBinary = fs.readFileSync("node-capnp/testdata/packedflat");
} catch (ex) {
// Works in npm build.
goldenBinary = fs.readFileSync("src/node-capnp/testdata/binary");
goldenPackedBinary = fs.readFileSync("src/node-capnp/testdata/packedbinary");
goldenFlatBinary = fs.readFileSync("src/node-capnp/testdata/flat");
goldenPackedFlatBinary = fs.readFileSync("src/node-capnp/testdata/packedflat");
}
var test = require("./test.capnp");
@@ -54,6 +63,31 @@ assert.equal("foo", test.TestConstants.textConst);
assert.equal("baz", test.TestConstants.structConst.textField);
assert.equal("xyzzy", test.TestConstants.textListConst[1]);
// Test packed serialization/deserialization
var parsedPacked = capnp.parsePacked(test.TestAllTypes, goldenPackedBinary);
var roundTrippedPacked = capnp.serializePacked(test.TestAllTypes, parsedPacked);
assert.equal(goldenPackedBinary.length, roundTrippedPacked.length, "Round trip changed size?");
assert.equal(goldenPackedBinary.toString("base64"), roundTrippedPacked.toString("base64"), "Round trip lost data?");
var parsedFlat = capnp.parse(test.TestAllTypes, goldenFlatBinary, {flat: true});
var roundTrippedFlat = capnp.serialize(test.TestAllTypes, parsedFlat, {flat: true});
assert.equal(goldenFlatBinary.length, roundTrippedFlat.length, "Round trip changed size?");
assert.equal(goldenFlatBinary.toString("base64"), roundTrippedFlat.toString("base64"), "Round trip lost data?");
var parsedPackedFlat = capnp.parse(test.TestAllTypes, goldenPackedFlatBinary, {packed: true, flat: true});
var roundTrippedPackedFlat = capnp.serialize(test.TestAllTypes, parsedPackedFlat, {packed: true, flat: true});
assert.equal(goldenPackedFlatBinary.length, roundTrippedPackedFlat.length, "Round trip changed size?");
assert.equal(goldenPackedFlatBinary.toString("base64"), roundTrippedPackedFlat.toString("base64"), "Round trip lost data?");
// TODO(someday): do a more thorough deep equality comparison of parsed and parsedPacked
var keys = ["voidField", "boolField", "int8Field", "int16Field", "int32Field", "int64Field"];
for (var key in keys) {
assert.equal(parsed[key], parsedPacked[key]);
assert.equal(parsed[key], parsedFlat[key]);
assert.equal(parsed[key], parsedPackedFlat[key]);
}
// =======================================================================================
/*
+219 -18
View File
@@ -34,17 +34,21 @@
#include <uv.h>
#include <kj/async.h>
#include <kj/async-io.h>
#include <kj/io.h>
#include <kj/vector.h>
#include <errno.h>
#include <unistd.h>
#include <capnp/rpc-twoparty.h>
#include <capnp/rpc.capnp.h>
#include <capnp/serialize.h>
#include <capnp/serialize-packed.h>
#include <unordered_map>
#include <inttypes.h>
#include <set>
#include <stdlib.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <typeinfo>
#include <typeindex>
@@ -56,6 +60,8 @@ namespace { // so we get warnings if anything declared in this file is left und
typedef unsigned char byte;
typedef unsigned int uint;
bool verboseDebugLogging = false;
// =======================================================================================
// KJ <-> libuv glue.
@@ -143,6 +149,7 @@ public:
}
void setRunnable(bool runnable) override {
if (verboseDebugLogging) { KJ_LOG(INFO, "setRunnable", runnable, this->runnable, this->scheduled); }
if (runnable != this->runnable) {
this->runnable = runnable;
if (runnable && !scheduled) {
@@ -151,6 +158,10 @@ public:
}
}
void logState() {
KJ_LOG(INFO, "UvEventPort state", runnable, scheduled);
}
private:
uv_loop_t* loop;
UvHandle<uv_timer_t> timer;
@@ -159,11 +170,21 @@ private:
bool scheduled = false;
void schedule() {
if (verboseDebugLogging) { KJ_LOG(INFO, "schedule"); }
UV_CALL(uv_timer_start(timer, &doRun, 0, 0), loop);
if (verboseDebugLogging) { KJ_LOG(INFO, "scheduled"); }
scheduled = true;
}
void run() {
if (verboseDebugLogging) {
KJ_LOG(INFO, "run");
kj::evalLater([]() {
KJ_LOG(INFO, "evalLater() executed");
}).detach([](kj::Exception&& e) {
KJ_LOG(ERROR, e);
});
}
KJ_ASSERT(scheduled);
UV_CALL(uv_timer_stop(timer), loop);
@@ -181,6 +202,8 @@ private:
} else {
scheduled = false;
}
if (verboseDebugLogging) { KJ_LOG(INFO, "run done"); }
}
static void doRun(uv_timer_t* handle, int status) {
@@ -251,11 +274,17 @@ public:
: uvLoop(loop), fd(applyFlags(fd, flags)), flags(flags),
uvPoller(uv_poll_init, uvLoop, fd) {
uvPoller->data = this;
// TODO(soon): This uv_poll_start() is redundant.
UV_CALL(uv_poll_start(uvPoller, 0, &pollCallback), uvLoop);
if (verboseDebugLogging) { KJ_LOG(INFO, "created socket", fd); }
}
~OwnedFileDescriptor() noexcept(false) {
if (verboseDebugLogging) { KJ_LOG(INFO, "destroying socket", fd); }
if (!stopped) {
// TODO(soon): This uv_poll_stop() is redundant so long as we can make sure that uvPoller is
// destroyed before we close the descriptor.
UV_CALL(uv_poll_stop(uvPoller), uvLoop);
}
@@ -279,6 +308,8 @@ public:
int flags = UV_READABLE | (writable == nullptr ? 0 : UV_WRITABLE);
UV_CALL(uv_poll_start(uvPoller, flags, &pollCallback), uvLoop);
if (verboseDebugLogging) { KJ_LOG(INFO, "waiting for readable", this, fd); }
return kj::mv(paf.promise);
}
@@ -293,6 +324,8 @@ public:
int flags = UV_WRITABLE | (readable == nullptr ? 0 : UV_READABLE);
UV_CALL(uv_poll_start(uvPoller, flags, &pollCallback), uvLoop);
if (verboseDebugLogging) { KJ_LOG(INFO, "waiting for writable", this, fd); }
return kj::mv(paf.promise);
}
@@ -300,6 +333,22 @@ protected:
uv_loop_t* const uvLoop;
const int fd;
void logInfo() {
KJ_ASSERT(verboseDebugLogging);
int available;
KJ_SYSCALL(ioctl(fd, FIONREAD, &available));
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fd;
pfd.events = POLLIN | POLLOUT;
int pollResult = poll(&pfd, 1, 0);
KJ_LOG(INFO, "closing socket", fd, available, pollResult, pfd.revents,
uvPoller->io_watcher.events, uvPoller->io_watcher.pevents,
uvPoller->io_watcher.fd, &uvPoller->io_watcher, uvLoop->watchers[fd],
ngx_queue_empty(&uvPoller->io_watcher.watcher_queue));
}
private:
uint flags;
kj::Maybe<kj::Own<kj::PromiseFulfiller<void>>> readable;
@@ -312,6 +361,10 @@ private:
}
void pollDone(int status, int events) {
if (verboseDebugLogging) {
KJ_LOG(INFO, "poll event", this, fd, status, events, readable == nullptr, writable == nullptr);
}
if (status != 0) {
// Error. libuv produces a non-zero status if polling produced POLLERR. The error code
// reported by libuv is always EBADF, even if the file descriptor is perfectly legitimate but
@@ -407,6 +460,10 @@ public:
}
void shutdownWrite() override {
if (verboseDebugLogging) {
logInfo();
}
// There's no legitimate way to get an AsyncStreamFd that isn't a socket through the
// UnixAsyncIoProvider interface.
KJ_SYSCALL(shutdown(fd, SHUT_WR));
@@ -424,6 +481,8 @@ private:
return alreadyRead;
}
if (verboseDebugLogging) { KJ_LOG(INFO, "did read", fd, n); }
if (n < 0) {
// Read would block.
return onReadable().then([=]() {
@@ -480,6 +539,8 @@ private:
return kj::READY_NOW;
}
if (verboseDebugLogging) { KJ_LOG(INFO, "did write", fd, writeResult); }
// A negative result means EAGAIN, which we can treat the same as having written zero bytes.
size_t n = writeResult < 0 ? 0 : writeResult;
@@ -613,6 +674,8 @@ public:
KJ_FAIL_ASSERT("Timers not implemented.");
}
void logState() { return eventPort.logState(); }
private:
UvEventPort eventPort;
kj::WaitScope waitScope;
@@ -741,6 +804,7 @@ v8::Local<v8::Value> toJsException(kj::Exception&& exception) {
kj::Exception fromJsException(v8::Handle<v8::Value> exception) {
kj::Exception::Type type = kj::Exception::Type::FAILED;
kj::String description;
if (exception->IsObject()) {
v8::HandleScope scope;
@@ -756,9 +820,16 @@ kj::Exception fromJsException(v8::Handle<v8::Value> exception) {
type = kj::Exception::Type::UNIMPLEMENTED;
}
}
v8::Handle<v8::Value> stack = obj->Get(v8::String::NewSymbol("stack"));
if (!stack.IsEmpty() && !stack->IsUndefined()) {
description = toKjString(stack);
} else {
description = toKjString(exception);
}
}
return kj::Exception(type, "(javascript)", 0, toKjString(exception));
return kj::Exception(type, "(javascript)", 0, kj::mv(description));
}
EmptyHandle throwTypeError(kj::StringPtr name, const std::type_info& type,
@@ -1112,6 +1183,26 @@ struct StructReader {
: message(data), root(message.getRoot<capnp::DynamicStruct>(schema)) {}
};
struct FlatStructReader {
kj::ArrayPtr<const capnp::word> segments[1];
capnp::SegmentArrayMessageReader message;
capnp::DynamicStruct::Reader root;
FlatStructReader(kj::ArrayPtr<const capnp::word> data, capnp::StructSchema schema)
: segments{data}, message(segments),
root(message.getRoot<capnp::DynamicStruct>(schema)) {}
};
struct PackedStructReader {
kj::ArrayInputStream inputStream;
capnp::PackedMessageReader message;
capnp::DynamicStruct::Reader root;
PackedStructReader(kj::ArrayPtr<const byte> bytes, capnp::StructSchema schema)
: inputStream(bytes), message(inputStream),
root(message.getRoot<capnp::DynamicStruct>(schema)) {}
};
struct ServerRequest {
kj::Own<kj::PromiseFulfiller<void>> fulfiller;
// Fulfill to complete the call. You must null out the pointers below, as well as
@@ -1137,6 +1228,10 @@ kj::Maybe<capnp::DynamicStruct::Reader> unwrapReader(v8::Handle<v8::Value> handl
});
} else KJ_IF_MAYBE(reader, Wrapper::tryUnwrap<StructReader>(handle)) {
return reader->root;
} else KJ_IF_MAYBE(reader, Wrapper::tryUnwrap<PackedStructReader>(handle)) {
return reader->root;
} else KJ_IF_MAYBE(reader, Wrapper::tryUnwrap<FlatStructReader>(handle)) {
return reader->root;
} else KJ_IF_MAYBE(request, Wrapper::tryUnwrap<ServerRequest>(handle)) {
return request->params;
} else KJ_IF_MAYBE(builder, unwrapBuilder(handle)) {
@@ -1393,7 +1488,7 @@ struct FromJsConverter {
bool fieldFromJs(capnp::DynamicStruct::Builder builder, capnp::StructSchema::Field field,
v8::Handle<v8::Value> js) {
if (js->IsNull() || js->IsUndefined()) {
if ((js->IsNull() || js->IsUndefined()) && !field.getType().isVoid()) {
return true;
}
auto proto = field.getProto();
@@ -1695,7 +1790,7 @@ v8::Handle<v8::Value> toJsParams(const v8::Arguments& args) {
// -----------------------------------------------------------------------------
v8::Handle<v8::Value> fromBytes(const v8::Arguments& args) {
// fromBytes(buffer, schema) -> reader
// fromBytes(buffer, schema, options) -> reader
KJV8_UNWRAP(CapnpContext, context, args.Data());
@@ -1708,33 +1803,92 @@ v8::Handle<v8::Value> fromBytes(const v8::Arguments& args) {
return emptyHandle;
}
if (!args[2]->IsObject()) {
KJV8_TYPE_ERROR(obj, v8::Object);
}
return liftKj([&]() -> v8::Handle<v8::Value> {
kj::ArrayPtr<const capnp::word> words;
if (reinterpret_cast<uintptr_t>(buffer.begin()) % sizeof(capnp::word) != 0) {
// Array is not aligned. We have to make a copy. :(
auto array = kj::heapArray<capnp::word>(buffer.size() / sizeof(capnp::word));
memcpy(array.begin(), buffer.begin(), buffer.size());
words = array;
bufferHandle = context.wrapper.wrapCopy(kj::mv(array));
auto options = args[2].As<v8::Object>();
bool packed = options->Get(v8::String::NewSymbol("packed"))->BooleanValue();
bool flat = options->Get(v8::String::NewSymbol("flat"))->BooleanValue();
v8::Local<v8::Object> wrapper;
if (packed) {
if (flat) {
auto bytes = kj::arrayPtr(buffer.begin(), buffer.size());
auto words = kj::heapArray<capnp::word>(capnp::computeUnpackedSizeInWords(bytes));
kj::ArrayInputStream input(bytes);
capnp::_::PackedInputStream unpacker(input);
unpacker.read(words.asBytes().begin(), words.asBytes().size());
wrapper = context.wrapper.wrap(new FlatStructReader(words, schema.asStruct()));
bufferHandle = context.wrapper.wrapCopy(kj::mv(words));
} else {
wrapper = context.wrapper.wrap(new PackedStructReader(
kj::arrayPtr(buffer.begin(), buffer.size()), schema.asStruct()));
}
} else {
// Yay, array is aligned.
words = kj::arrayPtr(reinterpret_cast<const capnp::word*>(buffer.begin()),
buffer.size() / sizeof(capnp::word));
kj::ArrayPtr<const capnp::word> words;
if (reinterpret_cast<uintptr_t>(buffer.begin()) % sizeof(capnp::word) != 0) {
// Array is not aligned. We have to make a copy. :(
auto array = kj::heapArray<capnp::word>(buffer.size() / sizeof(capnp::word));
memcpy(array.begin(), buffer.begin(), buffer.size());
words = array;
bufferHandle = context.wrapper.wrapCopy(kj::mv(array));
} else {
// Yay, array is aligned.
words = kj::arrayPtr(reinterpret_cast<const capnp::word*>(buffer.begin()),
buffer.size() / sizeof(capnp::word));
}
if (flat) {
wrapper = context.wrapper.wrap(new FlatStructReader(words, schema.asStruct()));
} else {
wrapper = context.wrapper.wrap(new StructReader(words, schema.asStruct()));
}
}
auto wrapper = context.wrapper.wrap(new StructReader(words, schema.asStruct()));
wrapper->SetHiddenValue(v8::String::NewSymbol("buffer"), bufferHandle);
return wrapper;
});
}
v8::Handle<v8::Value> toBytes(const v8::Arguments& args) {
// toBytes(builder) -> buffer
// toBytes(builder, options) -> buffer
KJV8_UNWRAP(StructBuilder, builder, args[0]);
if (!args[1]->IsObject()) {
KJV8_TYPE_ERROR(obj, v8::Object);
}
return liftKj([&]() -> v8::Handle<v8::Value> {
return wrapBuffer(capnp::messageToFlatArray(builder.message));
auto options = args[1].As<v8::Object>();
bool packed = options->Get(v8::String::NewSymbol("packed"))->BooleanValue();
bool flat = options->Get(v8::String::NewSymbol("flat"))->BooleanValue();
if (flat) {
// Write whole message to flat array.
auto root = builder.root.asReader();
auto words = kj::heapArray<capnp::word>(root.totalSize().wordCount + 1);
memset(words.asBytes().begin(), 0, words.asBytes().size());
capnp::copyToUnchecked(root, words);
if (packed) {
kj::VectorOutputStream output;
capnp::_::PackedOutputStream packer(output);
packer.write(words.asBytes().begin(), words.asBytes().size());
return wrapBuffer(kj::heapArray(output.getArray()));
} else {
return wrapBuffer(kj::mv(words));
}
} else if (packed) {
kj::VectorOutputStream output;
capnp::writePackedMessage(output, builder.message);
auto packedMessage = heapArray(output.getArray());
return wrapBuffer(kj::mv(packedMessage));
} else {
return wrapBuffer(capnp::messageToFlatArray(builder.message));
}
});
}
@@ -1901,8 +2055,9 @@ v8::Handle<v8::Value> closeCap(const v8::Arguments& args) {
KJV8_UNWRAP(capnp::DynamicCapability::Client, cap, args[0]);
return liftKj([&]() -> v8::Handle<v8::Value> {
// Overwrite with a null cap.
cap = capnp::Capability::Client(capnp::newBrokenCap("Capability has been closed."))
// Overwrite with a disconnected cap.
cap = capnp::Capability::Client(
capnp::newBrokenCap(KJ_EXCEPTION(DISCONNECTED, "Capability has been closed.")))
.castAs<capnp::DynamicCapability>(cap.getSchema());
return v8::Undefined();
@@ -2059,6 +2214,8 @@ v8::Handle<v8::Value> send(const v8::Arguments& args) {
OwnHandle<v8::Function> callback = v8::Handle<v8::Function>(v8::Function::Cast(*args[1]));
OwnHandle<v8::Function> errorCallback = v8::Handle<v8::Function>(v8::Function::Cast(*args[2]));
if (verboseDebugLogging) { KJ_LOG(INFO, "making call"); }
auto promise = KJ_REQUIRE_NONNULL(request.request, "Request already sent.").send();
request.request = nullptr;
@@ -2076,6 +2233,7 @@ v8::Handle<v8::Value> send(const v8::Arguments& args) {
.then(kj::mvCapture(callback,
[&context](OwnHandle<v8::Function>&& callback,
capnp::Response<capnp::DynamicStruct>&& response) {
if (verboseDebugLogging) { KJ_LOG(INFO, "call return"); }
v8::HandleScope scope;
v8::Handle<v8::Value> args[1] = {
context.wrapper.wrapCopy(ClientResponse { kj::mv(response) })
@@ -2091,6 +2249,7 @@ v8::Handle<v8::Value> send(const v8::Arguments& args) {
})).detach(kj::mvCapture(errorCallback,
[&context](OwnHandle<v8::Function>&& errorCallback,
kj::Exception&& exception) {
if (verboseDebugLogging) { KJ_LOG(INFO, "call failed"); }
v8::HandleScope scope;
v8::Handle<v8::Value> args[1] = { toJsException(kj::mv(exception)) };
v8::TryCatch tryCatch;
@@ -2362,6 +2521,45 @@ v8::Handle<v8::Value> throw_(const v8::Arguments& args) {
});
}
v8::Handle<v8::Value> enableVerboseDebugLogging(const v8::Arguments& args) {
// enableVerboseDebugLogging(flag) -> void
//
// If `flag` is true, turn on advanced debug logging.
KJV8_UNWRAP(CapnpContext, context, args.Data());
return liftKj([&]() -> v8::Handle<v8::Value> {
bool enable = args[0]->BooleanValue();
if (enable != verboseDebugLogging) {
verboseDebugLogging = enable;
if (verboseDebugLogging) {
kj::_::Debug::setLogLevel(kj::LogSeverity::INFO);
KJ_LOG(INFO, "node-capnp ulta-verbose debug logging now enabled; hope you track down the bug!");
} else {
KJ_LOG(INFO, "node-capnp ulta-verbose debug logging stopping here");
kj::_::Debug::setLogLevel(kj::LogSeverity::WARNING);
}
}
if (enable) {
context.llaiop.logState();
}
return v8::Undefined();
});
}
v8::Handle<v8::Value> methodName(const v8::Arguments& args) {
// methodName(method) -> string
KJV8_UNWRAP(CapnpContext, context, args.Data());
KJV8_UNWRAP(capnp::InterfaceSchema::Method, method, args[0]);
return liftKj([&]() -> v8::Handle<v8::Value> {
return v8::String::NewSymbol(method.getProto().getName().cStr());
});
}
// -----------------------------------------------------------------------------
void init(v8::Handle<v8::Object> exports) {
@@ -2407,6 +2605,9 @@ void init(v8::Handle<v8::Object> exports) {
mapFunction("return_", return_);
mapFunction("throw_", throw_);
mapFunction("enableVerboseDebugLogging", enableVerboseDebugLogging);
mapFunction("methodName", methodName);
return emptyHandle;
});
}
+37 -8
View File
@@ -153,14 +153,27 @@ function makeMethod(cap, method) {
v8capnp.fromJs(req, Array.prototype.slice.call(arguments, 0), LocalCapWrapper);
var pipeline;
var promise = new Promise(function (resolve, reject) {
pipeline = v8capnp.send(req, resolve, reject, Capability);
pipeline = v8capnp.send(req, function (x) {
if (verboseDebugLogging) console.log("capnp.js: returned to JS 1", v8capnp.methodName(method));
resolve(x);
}, function (x) {
if (verboseDebugLogging) console.log("capnp.js: threw to JS 1", v8capnp.methodName(method), x);
reject(x);
}, Capability);
}).then(function (response) {
if (verboseDebugLogging) console.log("capnp.js: returned to JS 2", v8capnp.methodName(method));
var result = v8capnp.toJs(response, Capability);
v8capnp.release(response);
settleCaps(pipeline, result);
if (verboseDebugLogging) console.log("capnp.js: returned to JS 3", v8capnp.methodName(method));
return result;
}, function (err) {
if (verboseDebugLogging) console.log("capnp.js: threw to JS 2", v8capnp.methodName(method));
throw err;
});
if (verboseDebugLogging) console.log("capnp.js: before makeRemotePromise:", v8capnp.methodName(method), promise);
makeRemotePromise(promise, pipeline);
if (verboseDebugLogging) console.log("capnp.js: after makeRemotePromise:", v8capnp.methodName(method), promise);
return promise;
}
}
@@ -256,23 +269,39 @@ exports.connect = function (addr, bootstrapCap) {
return new Connection(v8capnp.connect(addr, bootstrapCap));
}
exports.parse = function (schema, buffer) {
var reader = v8capnp.fromBytes(buffer, schema);
exports.parse = function (schema, buffer, options) {
var reader = v8capnp.fromBytes(buffer, schema, options || {});
return v8capnp.toJs(reader, Capability);
}
exports.serialize = function (schema, value) {
exports.parsePacked = function (schema, buffer) {
// TODO(cleanup): Remove in favor of options.
return exports.parse(schema, buffer, {packed: true});
}
exports.serialize = function (schema, value, options) {
var builder = v8capnp.newBuilder(schema);
v8capnp.fromJs(builder, value, LocalCapWrapper);
return v8capnp.toBytes(builder);
return v8capnp.toBytes(builder, options || {});
}
exports.serializePacked = function (schema, value) {
// TODO(cleanup): Remove in favor of options.
return exports.serialize(schema, value, {packed: true});
}
exports.Capability = Capability;
exports.bytesToPreorder = function(schema, buf) {
exports.bytesToPreorder = function(schema, buf, options) {
// Parse, copy, serialize, to get a preorder traversal.
var reader = v8capnp.fromBytes(buf, schema);
var reader = v8capnp.fromBytes(buf, schema, options || {});
var builder = v8capnp.copyBuilder(reader);
return v8capnp.toBytes(builder);
return v8capnp.toBytes(builder, options || {});
}
var verboseDebugLogging = false;
exports.enableVerboseDebugLogging = function (flag) {
verboseDebugLogging = flag;
// Turns out the problem isn't even in C++, so don't bother enabling its verbose debug logging.
//v8capnp.enableVerboseDebugLogging(flag);
}
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.