在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:protobufjs/protobuf.js开源软件地址:https://github.com/protobufjs/protobuf.js开源编程语言:JavaScript 99.8%开源软件介绍:Protocol Buffers are a language-neutral, platform-neutral, extensible way of serializing structured data for use in communications protocols, data storage, and more, originally designed at Google (see). protobuf.js is a pure JavaScript implementation with TypeScript support for node.js and the browser. It's easy to use, blazingly fast and works out of the box with .proto files! Contents
Installationnode.js
var protobuf = require("protobufjs"); The command line utility lives in the protobufjs-cli package and must be installed separately:
Note that this library's versioning scheme is not semver-compatible for historical reasons. For guaranteed backward compatibility, always depend on BrowsersDevelopment:
Production:
Remember to replace the version tag with the exact release your project depends upon. The library supports CommonJS and AMD loaders and also exports globally as DistributionsWhere bundle size is a factor, there are additional stripped-down versions of the full library (~19kb gzipped) available that exclude certain functionality:
UsageBecause JavaScript is a dynamically typed language, protobuf.js introduces the concept of a valid message in order to provide the best possible performance (and, as a side product, proper typings): Valid message
There are two possible types of valid messages and the encoder is able to work with both of these for convenience:
In a nutshell, the wire format writer understands the following types:
ToolsetWith that in mind and again for performance reasons, each message class provides a distinct set of methods with each method doing just one thing. This avoids unnecessary assertions / redundant operations where performance is a concern but also forces a user to perform verification (of plain JavaScript objects that might just so happen to be a valid message) explicitly where necessary - for example when dealing with user input. Note that
For reference, the following diagram aims to display relationships between the different methods and the concept of a valid message:
ExamplesUsing .proto filesIt is possible to load existing .proto files using the full library, which parses and compiles the definitions to ready to use (reflection-based) message classes: // awesome.proto
package awesomepackage;
syntax = "proto3";
message AwesomeMessage {
string awesome_field = 1; // becomes awesomeField
} protobuf.load("awesome.proto", function(err, root) {
if (err)
throw err;
// Obtain a message type
var AwesomeMessage = root.lookupType("awesomepackage.AwesomeMessage");
// Exemplary payload
var payload = { awesomeField: "AwesomeString" };
// Verify the payload if necessary (i.e. when possibly incomplete or invalid)
var errMsg = AwesomeMessage.verify(payload);
if (errMsg)
throw Error(errMsg);
// Create a new message
var message = AwesomeMessage.create(payload); // or use .fromObject if conversion is necessary
// Encode a message to an Uint8Array (browser) or Buffer (node)
var buffer = AwesomeMessage.encode(message).finish();
// ... do something with buffer
// Decode an Uint8Array (browser) or Buffer (node) to a message
var message = AwesomeMessage.decode(buffer);
// ... do something with message
// If the application uses length-delimited buffers, there is also encodeDelimited and decodeDelimited.
// Maybe convert the message back to a plain object
var object = AwesomeMessage.toObject(message, {
longs: String,
enums: String,
bytes: String,
// see ConversionOptions
});
}); Additionally, promise syntax can be used by omitting the callback, if preferred: protobuf.load("awesome.proto")
.then(function(root) {
...
}); Using JSON descriptorsThe library utilizes JSON descriptors that are equivalent to a .proto definition. For example, the following is identical to the .proto definition seen above: // awesome.json
{
"nested": {
"awesomepackage": {
"nested": {
"AwesomeMessage": {
"fields": {
"awesomeField": {
"type": "string",
"id": 1
}
}
}
}
}
}
} JSON descriptors closely resemble the internal reflection structure:
Exclusively using JSON descriptors instead of .proto files enables the use of just the light library (the parser isn't required in this case). A JSON descriptor can either be loaded the usual way: protobuf.load("awesome.json", function(err, root) {
if (err) throw err;
// Continue at "Obtain a message type" above
}); Or it can be loaded inline: var jsonDescriptor = require("./awesome.json"); // exemplary for node
var root = protobuf.Root.fromJSON(jsonDescriptor);
// Continue at "Obtain a message type" above Using reflection onlyBoth the full and the light library include full reflection support. One could, for example, define the .proto definitions seen in the examples above using just reflection: ...
var Root = protobuf.Root,
Type = protobuf.Type,
Field = protobuf.Field;
var AwesomeMessage = new Type("AwesomeMessage").add(new Field("awesomeField", 1, "string"));
var root = new Root().define("awesomepackage").add(AwesomeMessage);
// Continue at "Create a new message" above
... Detailed information on the reflection structure is available within the API documentation. Using custom classesMessage classes can also be extended with custom functionality and it is also possible to register a custom constructor with a reflected message type: ...
// Define a custom constructor
function AwesomeMessage(properties) {
// custom initialization code
...
}
// Register the custom constructor with its reflected type (*)
root.lookupType("awesomepackage.AwesomeMessage").ctor = AwesomeMessage;
// Define custom functionality
AwesomeMessage.customStaticMethod = function() { ... };
AwesomeMessage.prototype.customInstanceMethod = function() { ... };
// Continue at "Create a new message" above (*) Besides referencing its reflected type through
Afterwards, decoded messages of this type are Alternatively, it is also possible to reuse and extend the internal constructor if custom initialization code is not required: ...
// Reuse the internal constructor
var AwesomeMessage = root.lookupType("awesomepackage.AwesomeMessage").ctor;
// Define custom functionality
AwesomeMessage.customStaticMethod = function() { ... };
AwesomeMessage.prototype.customInstanceMethod = function() { ... };
// Continue at "Create a new message" above Using servicesThe library also supports consuming services but it doesn't make any assumptions about the actual transport channel. Instead, a user must provide a suitable RPC implementation, which is an asynchronous function that takes the reflected service method, the binary request and a node-style callback as its parameters: function rpcImpl(method, requestData, callback) {
// perform the request using an HTTP request or a WebSocket for example
var responseData = ...;
// and call the callback with the binary response afterwards:
callback(null, responseData);
} Below is a working example with a typescript implementation using grpc npm package. const grpc = require('grpc')
const Client = grpc.makeGenericClientConstructor({})
const client = new Client(
grpcServerUrl,
grpc.credentials.createInsecure()
)
const rpcImpl = function(method, requestData, callback) {
client.makeUnaryRequest(
method.name,
arg => arg,
arg => arg,
requestData,
callback
)
} Example: // greeter.proto
syntax = "proto3";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
} ...
var Greeter = root.lookup("Greeter");
var greeter = Greeter.create(/* see above */ rpcImpl, /* request delimited? */ false, /* response delimited? */ false);
greeter.sayHello({ name: 'you' }, function(err, response) {
console.log('Greeting:', response.message);
}); Services also support promises: greeter.sayHello({ name: 'you' })
.then(function(response) {
console.log('Greeting:', response.message);
}); There is also an example for streaming RPC. Note that the service API is meant for clients. Implementing a server-side endpoint pretty much always requires transport channel (i.e. http, websocket, etc.) specific code with the only common denominator being that it decodes and encodes messages. Usage with TypeScriptThe library ships with its own type definitions and modern editors like Visual Studio Code will automatically detect and use them for code completion. The npm package depends on @types/node because of |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论