|
|
@ -31,68 +31,271 @@ |
|
|
|
* |
|
|
|
* |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <map> |
|
|
|
|
|
|
|
#include <vector> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <grpc/grpc.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <node.h> |
|
|
|
#include <node.h> |
|
|
|
#include <nan.h> |
|
|
|
#include <nan.h> |
|
|
|
#include "tag.h" |
|
|
|
#include "tag.h" |
|
|
|
|
|
|
|
#include "call.h" |
|
|
|
|
|
|
|
|
|
|
|
namespace grpc { |
|
|
|
namespace grpc { |
|
|
|
namespace node { |
|
|
|
namespace node { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using v8::Boolean; |
|
|
|
|
|
|
|
using v8::Function; |
|
|
|
using v8::Handle; |
|
|
|
using v8::Handle; |
|
|
|
using v8::HandleScope; |
|
|
|
using v8::HandleScope; |
|
|
|
using v8::Persistent; |
|
|
|
using v8::Persistent; |
|
|
|
using v8::Value; |
|
|
|
using v8::Value; |
|
|
|
|
|
|
|
|
|
|
|
struct tag { |
|
|
|
Handle<Value> ParseMetadata(grpc_metadata_array *metadata_array) { |
|
|
|
tag(Persistent<Value> *tag, Persistent<Value> *call) |
|
|
|
NanEscapableScope(); |
|
|
|
: persist_tag(tag), persist_call(call) {} |
|
|
|
grpc_metadata *metadata_elements = metadata_array->metadata; |
|
|
|
|
|
|
|
size_t length = metadata_array->count; |
|
|
|
|
|
|
|
std::map<char*, size_t> size_map; |
|
|
|
|
|
|
|
std::map<char*, size_t> index_map; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < length; i++) { |
|
|
|
|
|
|
|
char *key = metadata_elements[i].key; |
|
|
|
|
|
|
|
if (size_map.count(key)) { |
|
|
|
|
|
|
|
size_map[key] += 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
index_map[key] = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Handle<Object> metadata_object = NanNew<Object>(); |
|
|
|
|
|
|
|
for (unsigned int i = 0; i < length; i++) { |
|
|
|
|
|
|
|
grpc_metadata* elem = &metadata_elements[i]; |
|
|
|
|
|
|
|
Handle<String> key_string = String::New(elem->key); |
|
|
|
|
|
|
|
Handle<Array> array; |
|
|
|
|
|
|
|
if (metadata_object->Has(key_string)) { |
|
|
|
|
|
|
|
array = Handle<Array>::Cast(metadata_object->Get(key_string)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
array = NanNew<Array>(size_map[elem->key]); |
|
|
|
|
|
|
|
metadata_object->Set(key_string, array); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
array->Set(index_map[elem->key], |
|
|
|
|
|
|
|
MakeFastBuffer( |
|
|
|
|
|
|
|
NanNewBufferHandle(elem->value, elem->value_length))); |
|
|
|
|
|
|
|
index_map[elem->key] += 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return NanEscapeScope(metadata_object); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OpResponse { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
explicit OpResponse(char *name): name(name) { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
virtual Handle<Value> GetNodeValue() const = 0; |
|
|
|
|
|
|
|
Handle<Value> GetOpType() const { |
|
|
|
|
|
|
|
NanEscapableScope(); |
|
|
|
|
|
|
|
return NanEscapeScope(NanNew(name)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
char *name; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SendResponse : public OpResponse { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
explicit SendResponse(char *name): OpResponse(name) { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> GetNodeValue() { |
|
|
|
|
|
|
|
NanEscapableScope(); |
|
|
|
|
|
|
|
return NanEscapeScope(NanTrue()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MetadataResponse : public OpResponse { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
explicit MetadataResponse(grpc_metadata_array *recv_metadata): |
|
|
|
|
|
|
|
recv_metadata(recv_metadata), OpResponse("metadata") { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> GetNodeValue() const { |
|
|
|
|
|
|
|
NanEscapableScope(); |
|
|
|
|
|
|
|
return NanEscapeScope(ParseMetadata(recv_metadata)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
grpc_metadata_array *recv_metadata; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MessageResponse : public OpResponse { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
explicit MessageResponse(grpc_byte_buffer **recv_message): |
|
|
|
|
|
|
|
recv_message(recv_message), OpResponse("read") { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> GetNodeValue() const { |
|
|
|
|
|
|
|
NanEscapableScope(); |
|
|
|
|
|
|
|
return NanEscapeScope(ByteBufferToBuffer(*recv_message)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
grpc_byte_buffer **recv_message |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ClientStatusResponse : public OpResponse { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
explicit ClientStatusResponse(grpc_metadata_array *metadata_array, |
|
|
|
|
|
|
|
grpc_status_code *status, |
|
|
|
|
|
|
|
char **status_details): |
|
|
|
|
|
|
|
metadata_array(metadata_array), status(status), |
|
|
|
|
|
|
|
status_details(status_details), OpResponse("status") { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> GetNodeValue() const { |
|
|
|
|
|
|
|
NanEscapableScope(); |
|
|
|
|
|
|
|
Handle<Object> status_obj = NanNew<Object>(); |
|
|
|
|
|
|
|
status_obj->Set(NanNew("code"), NanNew<Number>(*status)); |
|
|
|
|
|
|
|
if (event->data.finished.details != NULL) { |
|
|
|
|
|
|
|
status_obj->Set(NanNew("details"), String::New(*status_details)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
status_obj->Set(NanNew("metadata"), ParseMetadata(metadata_array)); |
|
|
|
|
|
|
|
return NanEscapeScope(status_obj); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
grpc_metadata_array *metadata_array; |
|
|
|
|
|
|
|
grpc_status_code *status; |
|
|
|
|
|
|
|
char **status_details; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ServerCloseResponse : public OpResponse { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
explicit ServerCloseResponse(int *cancelled): cancelled(cancelled), |
|
|
|
|
|
|
|
OpResponse("cancelled") { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> GetNodeValue() const { |
|
|
|
|
|
|
|
NanEscapableScope(); |
|
|
|
|
|
|
|
NanEscapeScope(NanNew<Boolean>(*cancelled)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
int *cancelled; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NewCallResponse : public OpResponse { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
explicit NewCallResponse(grpc_call **call, grpc_call_details *details, |
|
|
|
|
|
|
|
grpc_metadata_array *request_metadata) : |
|
|
|
|
|
|
|
call(call), details(details), request_metadata(request_metadata), |
|
|
|
|
|
|
|
OpResponse("call"){ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> GetNodeValue() const { |
|
|
|
|
|
|
|
NanEscapableScope(); |
|
|
|
|
|
|
|
if (*call == NULL) { |
|
|
|
|
|
|
|
return NanEscapeScope(NanNull()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Handle<Object> obj = NanNew<Object>(); |
|
|
|
|
|
|
|
obj->Set(NanNew("call"), Call::WrapStruct(*call)); |
|
|
|
|
|
|
|
obj->Set(NanNew("method"), NanNew(details->method)); |
|
|
|
|
|
|
|
obj->Set(NanNew("host"), NanNew(details->host)); |
|
|
|
|
|
|
|
obj->Set(NanNew("deadline"), |
|
|
|
|
|
|
|
NanNew<Date>(TimespecToMilliseconds(details->deadline))); |
|
|
|
|
|
|
|
obj->Set(NanNew("metadata"), ParseMetadata(request_metadata)); |
|
|
|
|
|
|
|
return NanEscapeScope(obj); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
grpc_call **call; |
|
|
|
|
|
|
|
grpc_call_details *details; |
|
|
|
|
|
|
|
grpc_metadata_array *request_metadata; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct tag { |
|
|
|
|
|
|
|
tag(NanCallback *callback, std::vector<OpResponse*> *responses) : |
|
|
|
|
|
|
|
callback(callback), repsonses(responses) { |
|
|
|
|
|
|
|
} |
|
|
|
~tag() { |
|
|
|
~tag() { |
|
|
|
persist_tag->Dispose(); |
|
|
|
for (std::vector<OpResponse *>::iterator it = responses->begin(); |
|
|
|
if (persist_call != NULL) { |
|
|
|
it != responses->end(); ++it) { |
|
|
|
persist_call->Dispose(); |
|
|
|
delete *it; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
delete callback; |
|
|
|
|
|
|
|
delete responses; |
|
|
|
} |
|
|
|
} |
|
|
|
Persistent<Value> *persist_tag; |
|
|
|
NanCallback *callback; |
|
|
|
Persistent<Value> *persist_call; |
|
|
|
std::vector<OpResponse*> *responses; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
void *CreateTag(Handle<Value> tag, Handle<Value> call) { |
|
|
|
void *CreateTag(Handle<Function> callback, grpc_op *ops, size_t nops) { |
|
|
|
NanScope(); |
|
|
|
NanScope(); |
|
|
|
Persistent<Value> *persist_tag = new Persistent<Value>(); |
|
|
|
NanCallback *cb = new NanCallback(callback); |
|
|
|
NanAssignPersistent(*persist_tag, tag); |
|
|
|
vector<OpResponse*> *responses = new vector<OpResponse*>(); |
|
|
|
Persistent<Value> *persist_call; |
|
|
|
for (size_t i = 0; i < nops; i++) { |
|
|
|
if (call->IsNull() || call->IsUndefined()) { |
|
|
|
grpc_op *op = &ops[i]; |
|
|
|
persist_call = NULL; |
|
|
|
OpResponse *resp; |
|
|
|
} else { |
|
|
|
// Switching on the TYPE of the op
|
|
|
|
persist_call = new Persistent<Value>(); |
|
|
|
switch (op->op) { |
|
|
|
NanAssignPersistent(*persist_call, call); |
|
|
|
case GRPC_OP_SEND_INITIAL_METADATA: |
|
|
|
} |
|
|
|
resp = new SendResponse("send metadata"); |
|
|
|
struct tag *tag_struct = new struct tag(persist_tag, persist_call); |
|
|
|
break; |
|
|
|
|
|
|
|
case GRPC_OP_SEND_MESSAGE: |
|
|
|
|
|
|
|
resp = new SendResponse("write"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case GRPC_OP_SEND_CLOSE_FROM_CLIENT: |
|
|
|
|
|
|
|
resp = new SendResponse("client close"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case GRPC_OP_SEND_STATUS_FROM_SERVER: |
|
|
|
|
|
|
|
resp = new SendResponse("server close"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case GRPC_OP_RECV_INITIAL_METADATA: |
|
|
|
|
|
|
|
resp = new MetadataResponse(op->data.recv_initial_metadata); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case GRPC_OP_RECV_MESSAGE: |
|
|
|
|
|
|
|
resp = new MessageResponse(op->data.recv_message); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case GRPC_OP_RECV_STATUS_ON_CLIENT: |
|
|
|
|
|
|
|
resp = new ClientStatusResponse( |
|
|
|
|
|
|
|
op->data.recv_status_on_client.trailing_metadata, |
|
|
|
|
|
|
|
op->data.recv_status_on_client.status, |
|
|
|
|
|
|
|
op->data.recv_status_on_client.status_details); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case GRPC_RECV_CLOSE_ON_SERVER: |
|
|
|
|
|
|
|
resp = new ServerCloseResponse(op->data.recv_close_on_server.cancelled); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
responses->push_back(resp); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
struct tag *tag_struct = new struct tag(cb, responses); |
|
|
|
return reinterpret_cast<void *>(tag_struct); |
|
|
|
return reinterpret_cast<void *>(tag_struct); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> GetTagHandle(void *tag) { |
|
|
|
void *CreateTag(Handle<Function> callback, grpc_call **call, |
|
|
|
|
|
|
|
grpc_call_details *details, |
|
|
|
|
|
|
|
grpc_metadata_array *request_metadata) { |
|
|
|
NanEscapableScope(); |
|
|
|
NanEscapableScope(); |
|
|
|
struct tag *tag_struct = reinterpret_cast<struct tag *>(tag); |
|
|
|
NanCallback *cb = new NanCallback(callback); |
|
|
|
Handle<Value> tag_value = NanNew<Value>(*tag_struct->persist_tag); |
|
|
|
vector<OpResponse*> *responses = new vector<OpResponse*>(); |
|
|
|
return NanEscapeScope(tag_value); |
|
|
|
OpResponse *resp = new NewCallResponse(call, details, request_metadata); |
|
|
|
|
|
|
|
responses->push_back(resp); |
|
|
|
|
|
|
|
struct tag *tag_struct = new struct tag(cb, responses); |
|
|
|
|
|
|
|
return reinterpret_cast<void *>(tag_struct); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool TagHasCall(void *tag) { |
|
|
|
NanCallback GetCallback(void *tag) { |
|
|
|
|
|
|
|
NanEscapableScope(); |
|
|
|
struct tag *tag_struct = reinterpret_cast<struct tag *>(tag); |
|
|
|
struct tag *tag_struct = reinterpret_cast<struct tag *>(tag); |
|
|
|
return tag_struct->persist_call != NULL; |
|
|
|
return NanEscapeScope(*tag_struct->callback); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> TagGetCall(void *tag) { |
|
|
|
Handle<Value> GetNodeValue(void *tag) { |
|
|
|
NanEscapableScope(); |
|
|
|
NanEscapableScope(); |
|
|
|
struct tag *tag_struct = reinterpret_cast<struct tag *>(tag); |
|
|
|
struct tag *tag_struct = reinterpret_cast<struct tag *>(tag); |
|
|
|
if (tag_struct->persist_call == NULL) { |
|
|
|
Handle<Object> obj = NanNew<Object>(); |
|
|
|
return NanEscapeScope(NanNull()); |
|
|
|
for (std::vector<OpResponse *>::iterator it = tag_struct->responses->begin(); |
|
|
|
|
|
|
|
it != tag_struct->responses->end(); ++it) { |
|
|
|
|
|
|
|
OpResponse *resp = *it; |
|
|
|
|
|
|
|
obj->Set(resp->GetOpType(), resp->GetNodeValue()); |
|
|
|
} |
|
|
|
} |
|
|
|
Handle<Value> call_value = NanNew<Value>(*tag_struct->persist_call); |
|
|
|
return NanEscapeScope(obj); |
|
|
|
return NanEscapeScope(call_value); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void DestroyTag(void *tag) { delete reinterpret_cast<struct tag *>(tag); } |
|
|
|
void DestroyTag(void *tag) { delete reinterpret_cast<struct tag *>(tag); } |
|
|
|