2016-02-19 4 views
2

У меня есть приложение nodejs, которое использует плоские буферы Google.deserialise google flat buffers

ФПС файл для схемы напитков:

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; 

скомпилирован с flatc -s drinks.fbs, он сгенерировал JS файл drinks_generated.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; 

использование flatBuffersUtil.js:

... 
var data = flatBuffersUtil.drinkArrayToBuffer(result); 
res.send(data); 

клиент сделан с angularjs 1.5.0 , когда я получаю буфер, я пытаюсь создать объект из него, используя следующий код:

в главном индексном файле:

<script type="text/javascript" src="js/flatbuffers.js"></script> 
<script type="text/javascript" src="js/fbs/drinks_generated.js"></script> 

затем в угловой контроллер:

  $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. 
      }); 

проблема заключается в том, что функция 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) 

Теперь. . Код функции в сгенерированном файле drinks_generated.js выглядит следующим образом:

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

так что 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; 
} 

сейчас в стороне сервера я могу deserialise буфера и использовать данные должным образом. проблема заключается в десериализации на стороне клиента.

после я шлю буфер, на стороне клиента получает следующий объект:

Object 
bytes_: Object 
position_: 7148 
__proto__: Object 

сейчас .. Я создал следующую функцию, чтобы преобразовать буфер объекта 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; 
} 

Когда я выслушиваю эту функцию, длина напитков равна нулю. поэтому буфер кажется пустым.

теперь я думаю, что проблема заключается в следующем коде:

var byteBuffer =new flatbuffers.ByteBuffer(buffer); 

Я думаю, что мне нужно преобразовать данные в ByteBuffer каким-либо другим способом.

я понял, что мне нужно дать flatbuffers.ByteBuffer массив байтов, так что я попытался сделать следующее вещь:

var byteBuffer =new flatbuffers.ByteBuffer(buffer.bytes_); 

, но результат тот же.

любые идеи?

+0

Да, похоже, вам нужно создать 'flatbuffers.ByteBuffer', используя массив байтов – Aardappel

+0

Я согласен с Aardappel. Вероятно, вам нужно обернуть 'var buffer = response.data' в' flatbuffers.ByteBuffer'. (Что-то вроде 'var buffer = flatbuffers.ByteBuffer (response.data)'.) P.S. Кажется, вы вообще не используете 'drinksArray' в фрагменте' flatBuffersUtil.js'. 'var drinksArray = drinks.Drinks.getRootAsDrinks (buf); // unused' – MrHappyAsthma

+0

Вы отправляете весь ByteBuffer. Попробуйте 'res.send (data.bytes())' – Aardappel

ответ

4

Спасибо за вашу поддержку. я смог наконец прийти с решением. , что мне не хватало, это использовать setPosition на byteBuffer после установки его байтов. Зачем? Я не знаю! все, что я знаю, это то, что я пробовал это, и теперь он работает.

поэтому я отправляю весь буфер, который содержит bytes_ для данных и position_ для ... я думаю ... длина или что-то еще. поэтому после того, как я посылаю буфер на стороне клиента я выполнить эти две команды:

var byteBuffer =new flatbuffers.ByteBuffer(buffer.bytes_); 
byteBuffer.setPosition(buffer.position_); 

если кто-нибудь может помочь здесь в предоставлении дополнительной информации о том, почему мне нужно сделать, что бы набухать :) во всяком случае. .. он работает yay!

обновление

Я открыл вопрос о https://github.com/google/flatbuffers/issues/3781, и я получил мой ответ :)

Есть примеры в https://github.com/google/flatbuffers/blob/master/tests/JavaScriptTest.js. Для сериализации flatbuffer:

var fbb = new flatbuffers.Builder(); 
// ... build the flatbuffer ... 
var uint8Array = fbb.asUint8Array(); 

Для десериализации flatbuffer:

var bb = new flatbuffers.ByteBuffer(uint8Array); 
var drinks = MyAlcoholist.Drinks.getRootAsDrinks(bb); 

спасибо!