我正在使用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。欢迎捐款!

07-24 09:50
查看更多