Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92b821f54f | ||
|
|
62501e2e05 | ||
|
|
586a0b507a | ||
|
|
8731696b87 | ||
|
|
4c52f07a80 | ||
|
|
ce1fc89df4 | ||
|
|
6b18e62df3 | ||
|
|
133c15771b | ||
|
|
e999e82d46 | ||
|
|
d6a93a7ff4 | ||
|
|
963dc37a1b | ||
|
|
6b5faf488c | ||
|
|
30beb85403 | ||
|
|
53914ae5d9 | ||
|
|
9911c0e414 | ||
|
|
10900e0bed | ||
|
|
ed3e786554 |
No files matched your search
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Reference in new issue
Block a user