web-dev-qa-db-ja.com

すでに定義された記述子のセットから新しいprotobufを動的に構築する方法は?

私のサーバーでは、自己記述メッセージを受け取ります(定義されているように ここ ...これはc ++に「良い」例がないため、それほど簡単ではありませんでした)。

この時点で、これらの自己記述メッセージからメッセージを作成することに問題はありません。 FileDescriptorSetを取得し、各 FileDescriptorProto を調べて、それぞれをDescriptorPoolに追加します( BuildFile を使用すると、定義されているすべてのFileDescriptorも取得できます)。

ここから、DPでインスタンス化されたDynamicMessageFactoryを使用してFileDescriptorSetで定義されたメッセージを作成し、 GetPrototype を呼び出すことができます(SelfDescribedMessageがメッセージfull_name()を必要とするため、これは非常に簡単です。 DPの FindMessageTypeByName メソッドを呼び出して、適切にエンコードされたメッセージプロトタイプを取得できます。

問題は、定義済みの各記述子またはメッセージを取得して、定義済みのすべてのメッセージをネストされたメッセージとして含む「マスター」メッセージを動的に構築するにはどうすればよいかということです。これは主に、メッセージの現在の状態を保存するために使用されます。現在、サーバー内の各メッセージのタイプをインスタンス化するだけでこれを処理しています(さまざまなプログラム間で中央の状態を維持するため)。しかし、現在の状態を「保存」したい場合は、定義されているようにディスクにストリーミングする必要があります ここ 。一度に1つのメッセージがストリーミングされます(サイズプレフィックス付き)。個別のメッセージの安定したストリームではなく、1つのメッセージ(すべてを支配する1つ)が必要です。これは、一度解決されると他のことに使用できます(最適化された簡単なシリアル化を備えたネットワークベースの共有状態)

すでにクロスリンクされ定義された記述子があるので、それらのすでに定義されたものから「新しい」メッセージを構築する簡単な方法があると思うでしょう。これまでのところ、解決策は私たちをほのめかしています。独自のDescriptorProtoを作成し、定義済みのDescriptorからこのタイプの新しいフィールドを追加しようとしましたが、迷子になりました(まだ深く掘り下げていません)。また、それらを拡張機能として追加する可能性も検討しました(現時点ではその方法は不明です)。独自の DescriptorDatabase を作成する必要がありますか(現時点ではその方法も不明です)?

何か洞察はありますか?


リンク ソースの例 BitBucket上。


この説明がお役に立てば幸いです。

すでに定義されているメッセージのセットからメッセージを動的に作成しようとしています。すでに定義されているメッセージのセットは、公式のc ++ protobufチュートリアルで(簡単に)説明されている「自己記述」メソッドを使用して作成されます(つまり、これらのメッセージはコンパイルされた形式では利用できません)。この新しく定義されたメッセージは、実行時に作成する必要があります。

各メッセージにストレート記述子を使用してみて、FileDescriptorProtoを作成しようとしました。 DatabaseDescriptorメソッドを調べてみました。どちらも運がない。現在、これらの定義済みメッセージを別のメッセージの拡張機能として追加しようとしています(コンパイル時にこれらの定義済みメッセージがあり、それらの「descriptor-set」は拡張機能として分類されていません)。ここからサンプルコードが始まります。

28
g19fanatic

.protoファイルを動的に作成し、それを Importer でロードすることで、この問題を解決することができました。

唯一の要件は、各クライアントがそのプロトファイルを介して送信することです(初期化時にのみ必要です...完全な実行中ではありません)。次に、サーバーは各プロトファイルを一時ディレクトリに保存します。可能であれば、必要なすべてのプロトファイルを保持する中央の場所にサーバーを指定することもできます。

これは、最初にDiskSourceTreeを使用して、実際のパスの場所をプログラム内の仮想の場所にマップすることによって行われました。次に、.protoファイルを作成して、送信されたすべてのprotoファイルをインポートし、「マスターメッセージ」にオプションのフィールドを定義します。

後に master.protoがディスクに保存されました。インポーターでインポートします。 Importers DescriptorPoolとDynamicMessageFactoryを使用して、1つのメッセージの下でメッセージ全体を確実に生成することができます。私が今夜または明日後で説明していることの例を挙げます。

このプロセスを改善する方法や異なる方法について誰かが提案を持っている場合は、そう言ってください。

他の誰かがより良い解決策を持っている場合に備えて、賞金が期限切れになるまで、この質問には答えないままにしておきます。

4
g19fanatic

あなたには必要だ protobuf::DynamicMessageFactory

{
  using namespace google;

  protobuf::DynamicMessageFactory dmf;
  protobuf::Message* actual_msg = dmf.GetPrototype(some_desc)->New();

  const protobuf::Reflection* refl = actual_msg->GetReflection();

  const protobuf::FieldDescriptor* fd = trip_desc->FindFieldByName("someField");
  refl->SetString(actual_msg, fd, "whee");

  ... 

  cout << actual_msg->DebugString() << endl;
}
6
hoppy

すべてのメッセージを文字列にシリアル化し、マスターメッセージを(バイト)文字列のシーケンスにするのはどうですか?

message MessageSet
{
  required FileDescriptorSet proto_files = 1;
  repeated bytes serialized_sub_message = 2;
}
1
Managu