[英]Protobuf : pass protobuf message from Javascript to C++ WebAssembly module
我想將 Javascript 的 protobuf 消息傳遞給 C++ WebAssembly 模塊。
我確實收到並可以在 C++ 端成功解析更簡單的 protobuf 消息,但是,protobuf 無法解析不太簡單的 protobuf 消息。
這是我正在使用的代碼:
goog.module('protobufMessageGenerator');
goog.require('proto.my_proto.MyMessage');
function generateMyMessage() {
var msg = new proto.my_proto.MyMessage()
var internal = new proto.my_proto.MyMessageInternal()
internal.setAccentColor("#CC1D24")
internal.setLogo("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")
msg.setInternal(internal)
return msg
}
使用 google-closure-compiler,我將此 protobuf 消息生成器編譯為純 Javascript。我使用此代碼將消息傳遞給 C++ WebAssembly 模塊:
function sendMessage() {
Module.self().setMyMessage(module$contents$protobufMessageGenerator_generateMyMessage().serializeBinary())
}
sendMessage()
我使用以下代碼在 C++ 端收到消息:
void JavascriptPublicInterface::setMyMessage(const QString &myMessage)
{
if (_myMessage != myMessage)
{
_myMessage = myMessage;
emit myMessageChanged();
}
}
void JavascriptPublicInterface::setMyMessageEMS(const std::string &myMessage)
{
setMyMessage(QString::fromStdString(myMessage));
}
//...
void startListeningToMyMessage(std::function<void(euf_proto::MyMessage myMessage)> listener)
{
const auto changedListener = [listener]() {
const auto newMyMessageString = JavascriptPublicInterface::self()->myMessage();
my_proto::MyMessage myMessagePb;
if (myMessagePb.ParseFromString(newMyMessageString.toStdString()))
{
qDebug() << "C++ : Successfully parsed new MyMessage: " << newMyMessageString;
}
else
{
qDebug() << "C++ : Failed to parse new MyMessage: " << newMyMessageString;
}
qDebug() << "MyMessage received: " << QString::fromStdString(myMessagePb.DebugString());
listener(myMessagePb);
};
if (!QObject::connect(JavascriptPublicInterface::self(), &JavascriptPublicInterface::myMessageChanged, changedListener))
{
throw std::runtime_error("Failed to connect to JavascriptPublicInterface myMessageChanged");
}
}
在 Javascript 控制台中,我看到:“C++:無法解析新的 MyMessage:...”
我猜這可能與Javascript使用UTF-16和C++使用UTF-8編碼有關(因為UTF-8的消息只能被成功解析),所以我嘗試這樣修復發送和接收:
//For more info see : https://emscripten.org/docs/api_reference/emscripten.h.html?highlight=stringtoutf8
function convertUtf16ToUtf8(input) {
var uint8Arr = input
var jsString = String.fromCharCode.apply(null, uint8Arr)
var lengthBytes = lengthBytesUTF8(jsString)+1
var stringOnWasmHeap = _malloc(lengthBytes)
stringToUTF8(jsString, stringOnWasmHeap, lengthBytes)
return stringOnWasmHeap
}
function sendMessage() {
var myMessage = convertUtf16ToUtf8(module$contents$protobufMessageGenerator_generateMyMessage().serializeBinary())
Module.self().setMyMessage(myMessage)
_free(myMessage)
}
sendMessage()
我像這樣修改了 C++ 端的解析:
void JavascriptPublicInterface::setMyMessageEMS(const int pointer)
{
const char* msg = (char*)pointer;
setMyMessage(QString::fromStdString(msg));
}
但我仍然收到此錯誤:“C++:無法解析新的 MyMessage:...”
我該如何解決這個問題?
(我使用的是 protobuf 3.19.1(Javascript 和 C++ 端的版本相同)。)
更新:如果我修改我的代碼,它傳遞一個簡單的字符串作為標志,那么我可以成功地解析 C++ 端的 protobuf 消息:
internal.setLogo("logo")
所以我想問題出在這個領域。 原始字符串是一個 base64 編碼的圖像。 我應該如何處理這個字符串來修復解析?
我找到了解決方案。
這個 stackoverflow 帖子描述了一個非常相似的問題,它也幫助我修復了我的解析: Protobuf: Serialize/DeSerialize C++ to Js
這是我更新的代碼,效果很好:我必須更新 Javascript 端:
function sendMessage() {
Module.self().setMyMessage(module$contents$protobufMessageGenerator_generateMyMessage().serializeBinary().toString())
}
sendMessage()
和 C++ 端:
namespace
{
QByteArray decryptProtobufMessage(const std::string &str)
{
QStringList strList = QString::fromStdString(str).split(',');
QByteArray bytedata;
foreach (const QString &str, strList)
{
bytedata += (str.toUInt());
}
return bytedata;
}
} // namespace
void JavascriptPublicInterface::setMyMessage(const QByteArray &myMessage)
{
if (_myMessage != myMessage)
{
_myMessage = myMessage;
emit myMessageChanged();
}
}
void JavascriptPublicInterface::setMyMessageEMS(const std::string &myMessage)
{
setMyMessage(decryptProtobufMessage(myMessage));
}
//...
void startListeningToMyMessage(std::function<void(euf_proto::MyMessage myMessage)> listener)
{
const auto changedListener = [listener]() {
const auto newMyMessageByteArray = JavascriptPublicInterface::self()->myMessage();
my_proto::MyMessage myMessagePb;
if (myMessagePb.ParseFromArray(newMyMessageByteArray.data(), newMyMessageByteArray.size()))
{
qDebug() << "C++ : Successfully parsed new MyMessage: " << newMyMessageByteArray;
}
else
{
qDebug() << "C++ : Failed to parse new MyMessage: " << newMyMessageByteArray;
}
qDebug() << "MyMessage received: " << QString::fromStdString(myMessagePb.DebugString());
listener(myMessagePb);
};
if (!QObject::connect(JavascriptPublicInterface::self(), &JavascriptPublicInterface::myMessageChanged, changedListener))
{
throw std::runtime_error("Failed to connect to JavascriptPublicInterface myMessageChanged");
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.