我正在使用Protobuf.js为sails.js编写一个钩子,以便能够通过socket.io发送由协议缓冲区编码的消息。
假设我有一个原始方案Message.proto
:
message Message{
required string message = 1;
optional string user = 2;
optional int32 id = 3;
}
我从数据库中获取一个对象,为
data
:data = {
message: 'Hello',
user: 'johnDoe',
id: 90,
createdAt: '2015-10-16T10:15:39.837Z',
updatedAt: '2015-10-16T10:15:39.837Z'
};
我有一个sails hook的代码:
var ProtoBuf = require("protobufjs"),
Reflect = ProtoBuf.Reflect,
builder = ProtoBuf.newBuilder(),
protoModels;
...
// This method overrides socket.io broadcast call for sails.js models pubSub:
augmentModels: function () {
for (var identity in app.models) {
var protobufSchemeName = app.models[identity].protobufSchemeName;
// protobufSchemeName is the file name of the sheme
if (protobufSchemeName) {
ProtoBuf.loadProtoFile(path.join(app.config.appPath, app.config.protobuf.folder, protobufSchemeName + ".proto"), builder);
app.models[identity].broadcast = function (roomName, eventName, data, socketToOmit) {
var dataToSend = protoModels[protobufSchemeName].encode(???HERE???); //HERE I SHOULD PUT THE MODIFIED DATA WITH THE ONLY NECESSARY FIELDS
app.sockets.broadcast(roomName, eventName, dataToSend.toBuffer(), socketToOmit);
};
}
protoModels = builder.build();
}
}
我不能直接通过
data
这样传递:protoModels[protobufSchemeName].encode(data)
,因为它将导致错误:this+"#"+keyOrObj+" is not a field
,因为数据包含额外的字段;因此,这里出现一个问题:将方案中的字段(
dataToSend
)仅保存到Message.proto
的最简单,正确的方法是什么?附言我知道应该在Reflection中加上一些内容,他们说您可以这样进行:
var TPlayer = builder.lookup("Game.Player"); // instance of ProtoBuf.Reflect.Message
var fields = TPlayer.getChildren(ProtoBuf.Reflect.Message.Field); // instances of ProtoBuf.Reflect.Message.Field
fields.forEach(function(field) {
//Filter it here
});
但是我无法弄清楚如何从
lookup
到达protoModels
方法。也许有办法使用Builder's isMessageField方法来过滤data
中的字段? 最佳答案
我们那里仍然有一个生成器,因此解决方案与example中的完全相同:
...
augmentModels: function () {
for (var identity in app.models) {
var protobufSchemeName = app.models[identity].protobufSchemeName;
if (protobufSchemeName) {
ProtoBuf.loadProtoFile(path.join(app.config.appPath, app.config.protobuf.folder, protobufSchemeName + ".proto"), builder);
app.models[identity].broadcast = function (roomName, eventName, data, socketToOmit) {
var fields = builder.lookup(protobufSchemeName).getChildren(ProtoBuf.Reflect.Message.Field).map(function (f) {
return f.name;
}); //Here are the fieldnames of the scheme as an array
var dataToSend = protoModels[protobufSchemeName].encode(_.pick(data, fields)).toBuffer();
app.sockets.broadcast(roomName, eventName, dataToSend, socketToOmit);
};
}
protoModels = builder.build();
}
}
另一种方法是重写发射/广播方法,就像我在下面的挂钩中所做的那样:
附言如果有人觉得这有用:
我为Sails.js创建了Protobuf Serialization Hook。欢迎捐款!