M
M
MisterN2022-02-16 15:45:50
Angular
MisterN, 2022-02-16 15:45:50

How to conveniently read jspb.Message from grpc in JavaScript?

Can anyone explain the best way to convert the protobuff message to JavaScript?
Let's say I received a message with many different parameters.

export class AnyResponse extends jspb.Message {
  getView(): View | undefined;
  setView(value?: View): OperationResponse;
  hasView(): boolean;
  clearView(): OperationResponse;

  getAnyParam(): string;
  setAnyParam(value: string): OperationResponse;
........

And suppose, somewhere in the depths of this heap of data, there is a value value that must also be obtained.
response.getSome()?.getItems()?.getValue()?.toObject() will give us a value like this
"value": {
            "fieldsMap": [
              [
                "id",
                {
                  "nullValue": 0,
                  "numberValue": 1,
                  "stringValue": "",
                  "boolValue": false
                }
              ],
              [
                "anyNname",
                {
                  "nullValue": 0,
                  "numberValue": 0,
                  "stringValue": "Здесь строка",
                  "boolValue": false
                }
              ],

This is not what I need, it would be much more convenient for me to get a normal object.
If I use response.getSome()?.getItems()?.getValue()?.toJavaScript() I get what I want.
"value": {
            "id": 1,
            "name": "Здесь строка",
            .......
          }

But I need to convert the entire AnyResponse into a normal object with values, which does not have the toJavaScript method, and he and his children down the chain are heirs of jspb.Message and, accordingly, have only toObject. And value is already google_protobuf_struct_pb.Struct and it can be processed via toJavaScript. Actually, there is an array, and .getValue() also needs to be cycled through, for example. I'm trying to simplify the code and omit unnecessary information so that the problem is visually preserved.
The api was designed a long time ago and for json, the values ​​​​are then stored in the store and putting the whole AnyResponse object (jspb.Message) there does not make sense. I really need to get the entire AnyResponse object as a simple JavaScript object with data, for example, via AnyResponse.toObject(), but so that deep in value there is not fieldsMap, but a regular object.
Well, here's how you can do it. Can

const rowResponse = response.toObject();
        const itemsList = response.getSome()?.getItems()?.getValue()?.map(
            value => ({
                ...value.toObject(),
                value: value.getValue()?.toJavaScript(),
            }),
        );
        const items = {
            ...rowResponse.view.items,
            itemsList: itemsList,
        };

        rowResponse.view.items = items;
        
        return rowResponse;

But this is insanity, there must be an easier way. Here I have roughly shown the idea, in fact, the object is larger and the choreography is more complex. Plus, we have to dodge with typing through Omit, because as soon as the item has changed, we can no longer type the response through AnyResponse.AsObject
There must be a simpler and more beautiful way than this.
But only some trash like redefining some protobuff method comes to mind. Indeed, for Items for us, toObject, which returns fieldsMap, is absolutely useless. However, redefining Items.toObject is pointless. However, he is a wall of challenges.
proto.quark.View.Items.toObject = function (includeInstance, msg) {
    var f, obj = {
      anyNameList: jspb.Message.toObjectList(msg.getAnyNameList(),
          proto.quark.Field.toObject, includeInstance),
      anyTwoNameList: jspb.Message.toObjectList(msg.getAnyTwoNameList(),
          ......

    };
    if (includeInstance) {
      obj.$jspbMessageInstance = msg;
    }
    return obj;
  };

Those. note that not anyValueList: msg.getAnyValueList().toObjectList, namely jspb.Message.toObjectList(msg.getAnyNameList(), i.e. there is one common jspb.Message.toObjectList everywhere, you cannot address the method specifically for anyValueList. in principle, there is not much difference between this and what I suggested above. You will still laugh, but I tried. And except that I added operations to the code that jerks 60 times on the page, and it's still a terrible crutch , the code has become much smaller and generally more convenient.
jspb.Message.toObjectList = function (a, b, c) {
    const rowResult = jspbMessageToObjectListProto.call(this, a, b, c);

    // const svgs = a.findIndex(v=>v && v.getType && v.getType() === 'svg');
    const svgIndex = rowResult.findIndex(v=>v.type === 'svg');
    if(svgIndex >= 0) {
        rowResult[svgIndex].value = a[svgIndex].getValue()?.toJavaScript();
    }

    return rowResult;
}

But if you still leave this madhouse, then well, it couldn’t be that there wasn’t a normal standard opportunity to get a normal JavaScript object? What am I doing wrong?
The most obvious option would be to take everything and rewrite it so that we still don’t have such a divine jspb.Message, but besides the fact that it’s just fucking necessary to rewrite, the store seems to be in the way here.
Threat how people are trying to just get json https://github.com/grpc/grpc-web/issues/315
And is this an advanced framework for communicating with the server from Google?

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question