Skip to content

Commit

Permalink
Initial take on runtime services, see #507
Browse files Browse the repository at this point in the history
  • Loading branch information
dcodeIO committed Nov 30, 2016
1 parent 6a06e95 commit d3ae961
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 7 deletions.
51 changes: 50 additions & 1 deletion dist/protobuf.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/protobuf.js.map

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/protobuf.min.js

Large diffs are not rendered by default.

Binary file modified dist/protobuf.min.js.gz
Binary file not shown.
2 changes: 1 addition & 1 deletion dist/protobuf.min.js.map

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions src/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,52 @@ ServicePrototype.remove = function remove(object) {
}
return NamespacePrototype.remove.call(this, object);
};

/**
* RPC implementation passed to {@link Service#create} performing a service request on network level, i.e. by utilizing http requests or websockets.
* @typedef RPCImpl
* @function
* @param {Method} method Reflected method being called
* @param {Uint8Array} requestData Request data
* @param {function(?Error, Uint8Array=)} callback Node-style callback called with the error, if any, and the response data
* @returns {undefined}
*/

/**
* Creates a runtime service using the specified rpc implementation.
* @param {RPCImpl} rpc RPC implementation
* @param {boolean} [requestDelimited=false] Whether request data is length delimited
* @param {boolean} [responseDelimited=false] Whether response data is length delimited
* @returns {Object} Runtime service
*/
ServicePrototype.create = function create(rpc, requestDelimited, responseDelimited) {
var rpcService = {};
this.getMethodsArray().forEach(function(method) {
rpcService[method.resolve().name] = function(request, callback) {
var requestData;
try {
requestData = (requestDelimited && method.resolvedRequestType.encodeDelimited(request) || method.resolvedRequestType.encode(request)).finish();
} catch (err) {
(typeof setImmediate === 'function' && setImmediate || setTimeout)(function() { callback(err); });
return;
}
// Calls the custom RPC implementation with the reflected method and binary request data
// and expects the rpc implementation to call its callback with the binary response data.
rpc(method, requestData, function(err, responseData) {
if (err) {
callback(err);
return;
}
var response;
try {
response = responseDelimited && method.resolvedResponseType.decodeDelimited(responseData) || method.resolvedResponseType.decode(responseData);
} catch (err2) {
callback(err2);
return;
}
callback(null, response);
});
};
});
return rpcService;
};
13 changes: 13 additions & 0 deletions tests/data/rpc.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
syntax = "proto3";

service MyService {
rpc MyMethod (MyRequest) returns (MyResponse);
}

message MyRequest {
string path = 1;
}

message MyResponse {
int32 status = 2;
}
57 changes: 57 additions & 0 deletions tests/rpc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
var tape = require("tape");

var protobuf = require("..");

tape.test("RPC", function(test) {

protobuf.load("tests/data/rpc.proto", function(err, root) {
if (err)
return test.fail(err.message);

var MyService = root.lookup("MyService"),
MyMethod = MyService.get("MyMethod").resolve(),
MyRequest = MyMethod.resolvedRequestType,
MyResponse = MyMethod.resolvedResponseType;

function rpc(method, requestData, callback) {

test.test("should call the rpc impl with", function(test) {
test.equal(method, MyMethod, "the reflected method");
test.ok(requestData.length, "a buffer");
test.ok(typeof callback === 'function', "a callback function");
test.end();
});
test.test("should call with a buffer that contains", function(test) {
test.equal(requestData[0], 3, "ldelim 3");
test.equal(requestData[1], 10, "id 1, wireType 2");
test.equal(requestData[2], 1, "length 1");
test.equal(requestData[3], 0x2f, "the original string");
test.end();
});

setTimeout(function() {
callback(null, MyResponse.encode({
status: 200
}).finish());
});
}

var MyService = root.lookup("MyService");
var service = MyService.create(rpc, true, false);

test.deepEqual(Object.keys(service), [ "MyMethod" ], "should create a service with exactly one method");

service.MyMethod(MyRequest.create({
path: "/"
}), function(err, response) {
if (err)
return test.fail(err.message);
test.ok(response instanceof MyResponse.ctor, "should return an instance of MyResponse");
test.deepEqual(response, {
status: 200
}, "should return status 200");
test.end();
});
});

});
22 changes: 21 additions & 1 deletion types/protobuf.js.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

/*
* protobuf.js v6.0.1 TypeScript definitions
* Generated Wed, 30 Nov 2016 13:45:03 UTC
* Generated Wed, 30 Nov 2016 22:05:17 UTC
*/
declare module protobuf {

Expand Down Expand Up @@ -1259,8 +1259,28 @@ declare module protobuf {
*/
static fromJSON(name: string, json: Object): Service;

/**
* Creates a runtime service using the specified rpc implementation.
* @param {RPCImpl} rpc RPC implementation
* @param {boolean} [requestDelimited=false] Whether request data is length delimited
* @param {boolean} [responseDelimited=false] Whether response data is length delimited
* @returns {Object} Runtime service
*/
create(rpc: RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean): Object;

}

/**
* RPC implementation passed to {@link Service#create} performing a service request on network level, i.e. by utilizing http requests or websockets.
* @typedef RPCImpl
* @function
* @param {Method} method Reflected method being called
* @param {Uint8Array} requestData Request data
* @param {function(?Error, Uint8Array=)} callback Node-style callback called with the error, if any, and the response data
* @returns {undefined}
*/
function RPCImpl(method: Method, requestData: Uint8Array, callback: (() => any)): undefined;

/**
* Handle object returned from {@link tokenize}.
* @typedef {Object} TokenizerHandle
Expand Down

0 comments on commit d3ae961

Please sign in to comment.