反序列化Google Flat缓冲区

ufk*_*ufk 3 javascript node.js angularjs flatbuffers

我有一个使用google flat缓冲区的nodejs应用程序。

饮料模式的fbs文件:

namespace MyAlcoholist;

table Drink {
drink_type_name: string;
drink_company_name: string;
drink_brand_name: string;
drink_flavor_type_name : string;
liquid_color_type_name : string;
liquid_color_is_transparent : bool;
alcohol_vol : float;
calories_for_100g : uint;
global_image_id: uint;
drink_flavor_id: uint;
}

table Drinks { drinks:[Drink]; }

root_type Drinks;
Run Code Online (Sandbox Code Playgroud)

使用进行了编译flatc -s drinks.fbs,它生成了js文件Drinks_genic.js。到目前为止,一切都很好。

我在nodejs服务器中使用以下代码来准备和创建数组之外的平面缓冲区:

flatBuffersUtil.js

var flatbuffers = require('../js/flatbuffers').flatbuffers;
var builder = new flatbuffers.Builder();

var drinks = require('../fbs/drinks_generated').MyAlcoholist; // Generated by `flatc`.

function drinkArrayToBuffer(drinkArray) {
var drinksVectArray = [];
drinkArray.forEach(function (element, index, array) {
    var drinkObj = element;
    var drinkBrandName = builder.createString(drinkObj.drink_brand_name);
    var drinkCompanyName = builder.createString(drinkObj.drink_company_name);
    var drinkflavorTypeName = builder.createString(drinkObj.drink_flavor_type_name);
    var drinkTypeName = builder.createString(drinkObj.drink_type_name);
    var liquidColorTypeName = builder.createString(drinkObj.liquid_color_type_name);
    drinks.Drink.startDrink(builder);
    drinks.Drink.addAlcoholVol(builder, drinkObj.alcohol_vol);
    drinks.Drink.addCaloriesFor100g(builder, drinkObj.calories_for_100g);
    drinks.Drink.addDrinkBrandName(builder, drinkBrandName);
    drinks.Drink.addDrinkCompanyName(builder, drinkCompanyName);
    drinks.Drink.addDrinkFlavorId(builder, drinkObj.drink_flavor_id);
    drinks.Drink.addDrinkFlavorTypeName(builder, drinkflavorTypeName);
    drinks.Drink.addDrinkTypeName(builder, drinkTypeName);
    drinks.Drink.addGlobalImageId(builder, drinkObj.global_image_id);
    drinks.Drink.addLiquidColorIsTransparent(builder, drinkObj.is_transparent);
    drinks.Drink.addLiquidColorTypeName(builder, liquidColorTypeName);
    var drink = drinks.Drink.endDrink(builder);
    drinksVectArray.push(drink);
})
var drinksVect = drinks.Drinks.createDrinksVector(builder, drinksVectArray);
builder.finish(drinksVect);
var buf = builder.dataBuffer();
var drinksArray = drinks.Drinks.getRootAsDrinks(buf);
return buf;
}

module.exports.drinkArrayToBuffer = drinkArrayToBuffer;
Run Code Online (Sandbox Code Playgroud)

flatBuffersUtil.js的用法:

...
var data = flatBuffersUtil.drinkArrayToBuffer(result);
res.send(data);
Run Code Online (Sandbox Code Playgroud)

当我收到缓冲区时,客户端已使用angularjs 1.5.0完成,我尝试使用以下代码从中创建一个对象:

在主索引文件中:

<script type="text/javascript" src="js/flatbuffers.js"></script>
<script type="text/javascript" src="js/fbs/drinks_generated.js"></script>
Run Code Online (Sandbox Code Playgroud)

然后在角度控制器中:

           $http({
                data: data,
                method: 'POST',
                url: 'https://myalcoholist.com:8888/drink/get_list/all_drinks',
            }).then(function successCallback(response) {
                var buffer = response.data;
                var drinks = MyAlcoholist.Drinks.getRootAsDrinks(buffer);
                deferred.resolve(drinks);
                // this callback will be called asynchronously
                // when the response is available
            }, function errorCallback(response) {
                // called asynchronously if an error occurs
                // or server returns response with an error status.
            });
Run Code Online (Sandbox Code Playgroud)

问题是该函数MyAlcoholist.Drinks.getRootAsDrinks(buffer);失败并显示以下错误:

TypeError: bb.position is not a function
at Function.MyAlcoholist.Drinks.getRootAsDrinks (drinks_generated.js:256)
at successCallback (admin-drinks-controller.js:22)
at angular.js:15552
at m.$eval (angular.js:16820)
at m.$digest (angular.js:16636)
at m.$apply (angular.js:16928)
at g (angular.js:11266)
at t (angular.js:11464)
at XMLHttpRequest.u.onload (angular.js:11405)
Run Code Online (Sandbox Code Playgroud)

现在..生成的Drinks_generated.js文件中的函数代码如下:

MyAlcoholist.Drinks.getRootAsDrinks = function(bb, obj) {
return (obj || new MyAlcoholist.Drinks).__init(bb.readInt32(bb.position()) + bb.position(), bb);
};
Run Code Online (Sandbox Code Playgroud)

所以bb应该是带函数position()的字节缓冲区类型,但是我收到的是字节对象。我想我需要首先或以某种方式打字……但这只是一个猜测。

有任何想法吗?

更新

好吧,首先我将我的DrinksArrayToBuffer函数修改为以下代码:

function drinkArrayToBuffer(drinkArray) {
var drinksVectArray = [];
drinkArray.forEach(function (element, index, array) {
    var drinkObj = element;
    var drinkBrandName = builder.createString(drinkObj.drink_brand_name);
    var drinkCompanyName = builder.createString(drinkObj.drink_company_name);
    var drinkflavorTypeName = builder.createString(drinkObj.drink_flavor_type_name);
    var drinkTypeName = builder.createString(drinkObj.drink_type_name);
    var liquidColorTypeName = builder.createString(drinkObj.liquid_color_type_name);
    drinks.Drink.startDrink(builder);
    drinks.Drink.addAlcoholVol(builder, drinkObj.alcohol_vol);
    drinks.Drink.addCaloriesFor100g(builder, drinkObj.calories_for_100g);
    drinks.Drink.addDrinkBrandName(builder, drinkBrandName);
    drinks.Drink.addDrinkCompanyName(builder, drinkCompanyName);
    drinks.Drink.addDrinkFlavorId(builder, drinkObj.drink_flavor_id);
    drinks.Drink.addDrinkFlavorTypeName(builder, drinkflavorTypeName);
    drinks.Drink.addDrinkTypeName(builder, drinkTypeName);
    drinks.Drink.addGlobalImageId(builder, drinkObj.global_image_id);
    drinks.Drink.addLiquidColorIsTransparent(builder, drinkObj.is_transparent);
    drinks.Drink.addLiquidColorTypeName(builder, liquidColorTypeName);
    var drink = drinks.Drink.endDrink(builder);
    drinksVectArray.push(drink);
})
var drinksVect = drinks.Drinks.createDrinksVector(builder, drinksVectArray);
drinks.Drinks.startDrinks(builder);
drinks.Drinks.addDrinks(builder, drinksVect);
var endDrinksOffset = drinks.Drinks.endDrinks(builder);
drinks.Drinks.finishDrinksBuffer(builder, endDrinksOffset);
var buf = builder.dataBuffer();
return buf;
}
Run Code Online (Sandbox Code Playgroud)

现在在服务器端,我能够反序列化缓冲区并正确使用数据。问题在于客户端反序列化。

我发送缓冲区后,客户端会收到以下对象:

Object
 bytes_: Object  
 position_: 7148
 __proto__: Object 
Run Code Online (Sandbox Code Playgroud)

现在..我创建了以下函数以在客户端将缓冲区转换为json对象:

function drinksByteArrayToArray(buffer) {
var res = [];
var byteBuffer =new flatbuffers.ByteBuffer(buffer);
var drinks = MyAlcoholist.Drinks.getRootAsDrinks(byteBuffer);
var drinksLength = drinks.drinksLength();
for (var i=0;i<drinksLength;i++) {
    var drink = drinks.drinks(i);
    var drinkObj = {
        drink_flavor_id: drink.drinkFlavorId(),
        drink_type_name: drink.drinkTypeName(),
        drink_company_name: drink.drinkCompanyName(),
        drink_brand_name: drink.drinkBrandName(),
        drink_flavor_type_name: drink.drinkFlavorTypeName(),
        liquid_color_type_name: drink.liquidColorTypeName(),
        is_transparent: drink.liquidColorIsTransparent(),
        alcohol_vol: drink.alcoholVol(),
        calories_for_100g: drink.caloriesFor100g(),
        global_image_id: drink.globalImageId
    }
    res.push(drinkObj);
}
return res;
}
Run Code Online (Sandbox Code Playgroud)

当我执行此功能时,饮料的长度为零。因此缓冲区似乎为空。

现在我认为问题出在以下代码上:

var byteBuffer =new flatbuffers.ByteBuffer(buffer);
Run Code Online (Sandbox Code Playgroud)

我想我需要以其他方式将数据转换为字节缓冲区。

我了解我需要提供flatbuffers.ByteBuffer一个字节数组,因此我尝试执行以下操作:

var byteBuffer =new flatbuffers.ByteBuffer(buffer.bytes_);
Run Code Online (Sandbox Code Playgroud)

但是结果是一样的。

有任何想法吗?

ufk*_*ufk 5

感谢您的支持。我终于能够找到解决方案。我所缺少的是在设置它的字节后在byteBuffer上使用setPosition。为什么?我不知道!我所知道的是我尝试过,现在可以了。

所以我正在发送整个缓冲区,其中包含用于数据的bytes_和用于...的position_我猜想...长度或某物。因此,在客户端发送缓冲区后,我将执行以下两个命令:

var byteBuffer =new flatbuffers.ByteBuffer(buffer.bytes_);
byteBuffer.setPosition(buffer.position_);
Run Code Online (Sandbox Code Playgroud)

如果有人可以在这里帮助您提供更多有关我为什么需要这样做的信息,那将非常好:)无论如何...它的工作原理!

更新

我在https://github.com/google/flatbuffers/issues/3781上打开了一个问题,得到了答案:)

https://github.com/google/flatbuffers/blob/master/tests/JavaScriptTest.js中有示例。序列化平面缓冲区:

var fbb = new flatbuffers.Builder();
// ... build the flatbuffer ...
var uint8Array = fbb.asUint8Array();
Run Code Online (Sandbox Code Playgroud)

要反序列化flatbuffer:

var bb = new flatbuffers.ByteBuffer(uint8Array);
var drinks = MyAlcoholist.Drinks.getRootAsDrinks(bb);
Run Code Online (Sandbox Code Playgroud)

谢谢!