Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. General talk
  3. Brainstorm
  4. identifying signal senders
Forum Updated to NodeBB v4.3 + New Features

identifying signal senders

Scheduled Pinned Locked Moved Solved Brainstorm
17 Posts 6 Posters 3.9k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M mzimmers
    25 Apr 2023, 23:25

    Hi all -

    I could use some ideas on how to implement something. My application has several (about a dozen) data models, all of which will be updated through a single message manager (implemented around a QNetworkAccessManager).

    I envision the data flow to be something like this:

    1. a data model sends a request for an update to the message manager
    2. the message manager issues a network GET
    3. the message manager receives a response
    4. the message manager forwards the response to the requester.

    The problem is, as currently proposed, the messages that are sent to my application don't have identifiers to help me know which model to send as per step 4 above. A possible further complication is that requests may come very quickly, and responses may not be received in the same order as the outgoing messages were sent.

    I know that QNetworkAccessManager::get() returns a reply identifier, so I can keep a hash of these along with something to identify the sender, but...I don't know what to do with this in order to forward the reply back to the correct model.

    Eventually this will have to work with PUT methods as well, but I don't think that adds much to the complexity here.

    I have some ideas, but I don't really like any of them. Anyone have a suggestion on how I might go about this?

    Thanks...

    J Offline
    J Offline
    JonB
    wrote on 26 Apr 2023, 08:11 last edited by JonB
    #4

    @mzimmers said in identifying signal senders:

    I know that QNetworkAccessManager::get() returns a reply identifier, so I can keep a hash of these along with something to identify the sender, but...I don't know what to do with this in order to forward the reply back to the correct model.

    This is the issue? To identify which QNetworkReply belongs to which QNetworkAccessManager::get(const QNetworkRequest &request) at a later date when processing the QNetworkReply? You could subclass the QNetworkRequest to add some identifier, and retrieve that from QNetworkReply::request(). Or QNetworkReply is a QObject so you could add a QObject::setProperty() when it is returned from QNetworkAccessManager::get(). These approaches do not require maintain a hash.

    Whatever you add must be usable to identify which model the request came from. Subclassing QNetworkRequest could allow you add a QAbstractItemModel * to directly identify the data model. Or as you say you could maintain some hash/mapping if necessary.

    Finally, if for whatever reason the manager does not have any access to the models, or the request/reply is tagged with an identifier so opaque to the manager that it cannot identify the model from it but the models themselves can identify whether it pertains to them, you could have the manager emit a signal with the reply on which all the models have a slot. They could then identify whether the reply is for them. Obviously a small overhead here if they all have to listen to every reply in order to see if its for them individually.

    I don't really see the problem?

    M 1 Reply Last reply 26 Apr 2023, 11:20
    0
    • J JonB
      26 Apr 2023, 08:11

      @mzimmers said in identifying signal senders:

      I know that QNetworkAccessManager::get() returns a reply identifier, so I can keep a hash of these along with something to identify the sender, but...I don't know what to do with this in order to forward the reply back to the correct model.

      This is the issue? To identify which QNetworkReply belongs to which QNetworkAccessManager::get(const QNetworkRequest &request) at a later date when processing the QNetworkReply? You could subclass the QNetworkRequest to add some identifier, and retrieve that from QNetworkReply::request(). Or QNetworkReply is a QObject so you could add a QObject::setProperty() when it is returned from QNetworkAccessManager::get(). These approaches do not require maintain a hash.

      Whatever you add must be usable to identify which model the request came from. Subclassing QNetworkRequest could allow you add a QAbstractItemModel * to directly identify the data model. Or as you say you could maintain some hash/mapping if necessary.

      Finally, if for whatever reason the manager does not have any access to the models, or the request/reply is tagged with an identifier so opaque to the manager that it cannot identify the model from it but the models themselves can identify whether it pertains to them, you could have the manager emit a signal with the reply on which all the models have a slot. They could then identify whether the reply is for them. Obviously a small overhead here if they all have to listen to every reply in order to see if its for them individually.

      I don't really see the problem?

      M Offline
      M Offline
      mzimmers
      wrote on 26 Apr 2023, 11:20 last edited by mzimmers
      #5

      @JonB said in identifying signal senders:

      This is the issue? To identify which QNetworkReply belongs to which QNetworkAccessManager::get(const QNetworkRequest &request) at a later date when processing the QNetworkReply?

      Sort of (this issue is tough to explain)...I can easily enough associate the reply with the get, but I'm not sure how to go about knowing to which model the reply should be forwarded.

      Thinking about this a little more, it's probably better to ascertain the source of the request at the point of the request, rather than after the reply comes in. I guess I could add another parameter to my signals to the manager:

      class MessageMgr : public QObject
      {
      public slots:
          void sendGet(QString message); // my current way
          void sendGet(QString message, QString model); // an alternative
      

      When a module emits a send request, it would include a string containing its name. This would be entered into a hash, with the NetworkReply * as the key, and the model name as the value.

      When the reply comes back, the message manager would look up the model in the hash, and add it to the signal that the reply came back. The signal would then go to each model, which would check for a name match before attempting to process.

      This sounds like it would work, but it's hardly elegant. A variant on this theme would be to have separate signals for each model, but that's also really a hack.

      I'm beginning to wonder if perhaps the signal/slot mechanism isn't the best way to approach this (a traditional callback method would actually work better in this case), but I'm not sure what to do.

      I'll think a little about your subclassing ideas.

      J 1 Reply Last reply 26 Apr 2023, 11:45
      0
      • M mzimmers
        26 Apr 2023, 11:20

        @JonB said in identifying signal senders:

        This is the issue? To identify which QNetworkReply belongs to which QNetworkAccessManager::get(const QNetworkRequest &request) at a later date when processing the QNetworkReply?

        Sort of (this issue is tough to explain)...I can easily enough associate the reply with the get, but I'm not sure how to go about knowing to which model the reply should be forwarded.

        Thinking about this a little more, it's probably better to ascertain the source of the request at the point of the request, rather than after the reply comes in. I guess I could add another parameter to my signals to the manager:

        class MessageMgr : public QObject
        {
        public slots:
            void sendGet(QString message); // my current way
            void sendGet(QString message, QString model); // an alternative
        

        When a module emits a send request, it would include a string containing its name. This would be entered into a hash, with the NetworkReply * as the key, and the model name as the value.

        When the reply comes back, the message manager would look up the model in the hash, and add it to the signal that the reply came back. The signal would then go to each model, which would check for a name match before attempting to process.

        This sounds like it would work, but it's hardly elegant. A variant on this theme would be to have separate signals for each model, but that's also really a hack.

        I'm beginning to wonder if perhaps the signal/slot mechanism isn't the best way to approach this (a traditional callback method would actually work better in this case), but I'm not sure what to do.

        I'll think a little about your subclassing ideas.

        J Offline
        J Offline
        JonB
        wrote on 26 Apr 2023, 11:45 last edited by JonB
        #6

        @mzimmers
        I don't understand your complications. If you don't want hashes and strings and lookups I said you could always just store the QAbstractItemModel *, or whatever Model *, to access the model directly. Only you know what is and is not available to you in your code.

        M 1 Reply Last reply 26 Apr 2023, 11:48
        0
        • J JonB
          26 Apr 2023, 11:45

          @mzimmers
          I don't understand your complications. If you don't want hashes and strings and lookups I said you could always just store the QAbstractItemModel *, or whatever Model *, to access the model directly. Only you know what is and is not available to you in your code.

          M Offline
          M Offline
          mzimmers
          wrote on 26 Apr 2023, 11:48 last edited by
          #7

          @JonB I suppose that's an option. Of course, each model would have to have the same handler signature, but that's probably best practices anyway. I suppose I could take it a step further, and pass a pointer to the handler function instead of the entire object?

          J S 2 Replies Last reply 26 Apr 2023, 12:10
          0
          • M mzimmers
            26 Apr 2023, 11:48

            @JonB I suppose that's an option. Of course, each model would have to have the same handler signature, but that's probably best practices anyway. I suppose I could take it a step further, and pass a pointer to the handler function instead of the entire object?

            J Offline
            J Offline
            JonB
            wrote on 26 Apr 2023, 12:10 last edited by
            #8

            @mzimmers Of course, whatever you need to identify it when the response is received.

            1 Reply Last reply
            0
            • M mzimmers
              26 Apr 2023, 11:48

              @JonB I suppose that's an option. Of course, each model would have to have the same handler signature, but that's probably best practices anyway. I suppose I could take it a step further, and pass a pointer to the handler function instead of the entire object?

              S Offline
              S Offline
              SGaist
              Lifetime Qt Champion
              wrote on 26 Apr 2023, 19:12 last edited by
              #9

              @mzimmers hi, QNetworkReply being a QObject, you could set the signal sender as dynamic property on it. You can then retrieve it when processing the result.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              M 1 Reply Last reply 26 Apr 2023, 23:47
              0
              • S SGaist
                26 Apr 2023, 19:12

                @mzimmers hi, QNetworkReply being a QObject, you could set the signal sender as dynamic property on it. You can then retrieve it when processing the result.

                M Offline
                M Offline
                mzimmers
                wrote on 26 Apr 2023, 23:47 last edited by
                #10

                @SGaist right, but it's the same problem -- what do I do with it? How do I go from knowing the sender to invoking a method in the sender class?

                J 1 Reply Last reply 27 Apr 2023, 07:31
                0
                • J Offline
                  J Offline
                  jeremy_k
                  wrote on 27 Apr 2023, 03:12 last edited by
                  #11

                  Return the QNetworkReply from MessageMgr::sendGet(), connect the appropriate model slot to QNetworkReply::finished(), and eliminate the intermediary handling of the reply.

                  Another alternative is QNetworkRequest::setOriginatingObject() and QNetworkReply::originatingObject().

                  Asking a question about code? http://eel.is/iso-c++/testcase/

                  1 Reply Last reply
                  1
                  • M mzimmers
                    26 Apr 2023, 23:47

                    @SGaist right, but it's the same problem -- what do I do with it? How do I go from knowing the sender to invoking a method in the sender class?

                    J Offline
                    J Offline
                    JonB
                    wrote on 27 Apr 2023, 07:31 last edited by JonB
                    #12

                    @mzimmers said in identifying signal senders:

                    @SGaist right, but it's the same problem -- what do I do with it? How do I go from knowing the sender to invoking a method in the sender class?

                    Again, I don't understand. I wrote earlier for this suggestion:

                    Subclassing QNetworkRequest could allow you add a QAbstractItemModel * to directly identify the data model.

                    So you would have a pointer to the model as a QAbstractItemModel *. On which you can call (QAbstractItemModel) methods directly. Or if your models share some other common interface you could derive them from YourModelBase and pass that as parameter to be able to call its methods. Or you could use qobject_cast<SpecificModelType *> to test their type and call specific model methods.

                    Or the approaches @jeremy_k mentions. Using QNetworkRequest::setOriginatingObject(someModel) saves subclassing if you don't want to do that, but it's the same approach. His direct connection of finished signal could be used if you do not actually want/need the manager to see/handle the replies.

                    One way or another you can either have the models send an identifier for themselves to the manager, which then routes replies to the model from that, or you can have the manager return the QNetworkReply * from QNetworkAccessManager::get() to the model and that puts e.g. a slot on QNetworkReply::finished() to its own code.

                    J 1 Reply Last reply 28 Apr 2023, 08:06
                    1
                    • J JonB
                      27 Apr 2023, 07:31

                      @mzimmers said in identifying signal senders:

                      @SGaist right, but it's the same problem -- what do I do with it? How do I go from knowing the sender to invoking a method in the sender class?

                      Again, I don't understand. I wrote earlier for this suggestion:

                      Subclassing QNetworkRequest could allow you add a QAbstractItemModel * to directly identify the data model.

                      So you would have a pointer to the model as a QAbstractItemModel *. On which you can call (QAbstractItemModel) methods directly. Or if your models share some other common interface you could derive them from YourModelBase and pass that as parameter to be able to call its methods. Or you could use qobject_cast<SpecificModelType *> to test their type and call specific model methods.

                      Or the approaches @jeremy_k mentions. Using QNetworkRequest::setOriginatingObject(someModel) saves subclassing if you don't want to do that, but it's the same approach. His direct connection of finished signal could be used if you do not actually want/need the manager to see/handle the replies.

                      One way or another you can either have the models send an identifier for themselves to the manager, which then routes replies to the model from that, or you can have the manager return the QNetworkReply * from QNetworkAccessManager::get() to the model and that puts e.g. a slot on QNetworkReply::finished() to its own code.

                      J Offline
                      J Offline
                      jeremy_k
                      wrote on 28 Apr 2023, 08:06 last edited by
                      #13

                      @JonB said in identifying signal senders:

                      His direct connection of finished signal could be used if you do not actually want/need the manager to see/handle the replies.

                      The struck-out portion is inaccurate. The manager can view the reply status via any of the const methods, or read content via QIODevice::peek() without interfering with later connections to the finished or readyRead signals.

                      Asking a question about code? http://eel.is/iso-c++/testcase/

                      J 1 Reply Last reply 28 Apr 2023, 08:51
                      0
                      • J jeremy_k
                        28 Apr 2023, 08:06

                        @JonB said in identifying signal senders:

                        His direct connection of finished signal could be used if you do not actually want/need the manager to see/handle the replies.

                        The struck-out portion is inaccurate. The manager can view the reply status via any of the const methods, or read content via QIODevice::peek() without interfering with later connections to the finished or readyRead signals.

                        J Offline
                        J Offline
                        JonB
                        wrote on 28 Apr 2023, 08:51 last edited by JonB
                        #14

                        @jeremy_k
                        Yes, but that's not what's meant. It's a question of whether the OP wants the replies routed through the manager, possibly to choose whether to send on to the models or to ignore/not do so, or whether the model receives the finished regardless and acts on it. I said "could" be used if OP does not want manager to see/handle the replies, not that it would preclude the manager seeing the responses as you wrote. As you said, not attaching the finished() signal to the model to "eliminate the intermediary handling of the reply" means that it will be attached and handled by the manager as "intermediary". Depends what the OP wants,

                        J 1 Reply Last reply 28 Apr 2023, 09:04
                        0
                        • J JonB
                          28 Apr 2023, 08:51

                          @jeremy_k
                          Yes, but that's not what's meant. It's a question of whether the OP wants the replies routed through the manager, possibly to choose whether to send on to the models or to ignore/not do so, or whether the model receives the finished regardless and acts on it. I said "could" be used if OP does not want manager to see/handle the replies, not that it would preclude the manager seeing the responses as you wrote. As you said, not attaching the finished() signal to the model to "eliminate the intermediary handling of the reply" means that it will be attached and handled by the manager as "intermediary". Depends what the OP wants,

                          J Offline
                          J Offline
                          jeremy_k
                          wrote on 28 Apr 2023, 09:04 last edited by
                          #15

                          @JonB said in identifying signal senders:

                          @jeremy_k
                          Yes, but that's not what's meant. It's a question of whether the OP wants the replies routed through the manager, possibly to choose whether to send on to the models or to ignore/not do so, or whether the model receives the finished regardless and acts on it. I said "could" be used if OP does not want manager to see/handle the replies, not that it would preclude the manager seeing the responses as you wrote. As you said, not attaching the finished() signal to the model to "eliminate the intermediary handling of the reply" means that it will be handled by the manager as "intermediary".

                          Fair enough. I had interpreted "see/handle" as non-exclusive.
                          To me, a manager that inhibits what the model sees from a successful request is acting as part of the model. HTTP and QNetworkReply has error codes to indicate lack of success.

                          Asking a question about code? http://eel.is/iso-c++/testcase/

                          1 Reply Last reply
                          0
                          • T Offline
                            T Offline
                            TomZ
                            wrote on 4 May 2023, 20:18 last edited by TomZ 5 Apr 2023, 20:21
                            #16

                            Feels like the issue has little to do with the network request.

                            The issue is that the manager doesn't keep state.

                            So, if model X makes a request to the manager which is then forwarded to get an async reply. What you want to do is to ignore the fact on how its implemented and simply do what all async APIs do. Create a new QObject that emits a signal when its got a data update.

                            So what you see, as an example API, networkmanger::get() do, they return an object with a bunch of signals.

                            What you want to do is make you message-manager do the same. This means it needs to keep state. Which means it needs to route messages only back to the object it actually owns. An equivalent to the NetworkReply, maybe called SignalManagerReply...

                            The fact that the message-manager itself uses the network manager privately is a nice parallel you can probably use to mirror the workflows.

                            Edit; oh, and want to add that your initial statement of a 'model' asking he signal-manager something is breaking the model-view-controller design. You need a controller to handle an async API like the signalmanager would have (as a result of it using networkmanager).

                            Such a controller-style class is where the SignalManagerReply is used.

                            M 1 Reply Last reply 4 May 2023, 23:41
                            0
                            • T TomZ
                              4 May 2023, 20:18

                              Feels like the issue has little to do with the network request.

                              The issue is that the manager doesn't keep state.

                              So, if model X makes a request to the manager which is then forwarded to get an async reply. What you want to do is to ignore the fact on how its implemented and simply do what all async APIs do. Create a new QObject that emits a signal when its got a data update.

                              So what you see, as an example API, networkmanger::get() do, they return an object with a bunch of signals.

                              What you want to do is make you message-manager do the same. This means it needs to keep state. Which means it needs to route messages only back to the object it actually owns. An equivalent to the NetworkReply, maybe called SignalManagerReply...

                              The fact that the message-manager itself uses the network manager privately is a nice parallel you can probably use to mirror the workflows.

                              Edit; oh, and want to add that your initial statement of a 'model' asking he signal-manager something is breaking the model-view-controller design. You need a controller to handle an async API like the signalmanager would have (as a result of it using networkmanager).

                              Such a controller-style class is where the SignalManagerReply is used.

                              M Offline
                              M Offline
                              mzimmers
                              wrote on 4 May 2023, 23:41 last edited by
                              #17

                              @TomZ I ended up taking Jeremy's suggestion, and it works beautifully. Keeps the message manager self contained and no need for state awareness.

                              1 Reply Last reply
                              0
                              • M mzimmers has marked this topic as solved on 4 May 2023, 23:41

                              13/17

                              28 Apr 2023, 08:06

                              • Login

                              • Login or register to search.
                              13 out of 17
                              • First post
                                13/17
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • Users
                              • Groups
                              • Search
                              • Get Qt Extensions
                              • Unsolved