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

identifying signal senders

Scheduled Pinned Locked Moved Solved Brainstorm
17 Posts 6 Posters 3.1k Views
  • 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.
  • mzimmersM Offline
    mzimmersM Offline
    mzimmers
    wrote on last edited by
    #1

    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...

    JonBJ 1 Reply Last reply
    0
    • Kent-DorfmanK Offline
      Kent-DorfmanK Offline
      Kent-Dorfman
      wrote on last edited by Kent-Dorfman
      #2

      just as a WAG, without thinking too hard about it:

      assuming you are using IP transport, then the senders IP and source port are available. Not elegant but can help to differentiate between instances as long as sessions are persistent.

      mzimmersM 1 Reply Last reply
      0
      • Kent-DorfmanK Kent-Dorfman

        just as a WAG, without thinking too hard about it:

        assuming you are using IP transport, then the senders IP and source port are available. Not elegant but can help to differentiate between instances as long as sessions are persistent.

        mzimmersM Offline
        mzimmersM Offline
        mzimmers
        wrote on last edited by
        #3

        @Kent-Dorfman interesting idea. The back end has one address and one port. I need a way to distinguish the proper recipient once the message is "in house" (within my app).

        1 Reply Last reply
        0
        • mzimmersM mzimmers

          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...

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on 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?

          mzimmersM 1 Reply Last reply
          0
          • JonBJ JonB

            @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?

            mzimmersM Offline
            mzimmersM Offline
            mzimmers
            wrote on 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.

            JonBJ 1 Reply Last reply
            0
            • mzimmersM mzimmers

              @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.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on 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.

              mzimmersM 1 Reply Last reply
              0
              • JonBJ JonB

                @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.

                mzimmersM Offline
                mzimmersM Offline
                mzimmers
                wrote on 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?

                JonBJ SGaistS 2 Replies Last reply
                0
                • mzimmersM mzimmers

                  @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?

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by
                  #8

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

                  1 Reply Last reply
                  0
                  • mzimmersM mzimmers

                    @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?

                    SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on 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

                    mzimmersM 1 Reply Last reply
                    0
                    • SGaistS SGaist

                      @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.

                      mzimmersM Offline
                      mzimmersM Offline
                      mzimmers
                      wrote on 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?

                      JonBJ 1 Reply Last reply
                      0
                      • jeremy_kJ Online
                        jeremy_kJ Online
                        jeremy_k
                        wrote on 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
                        • mzimmersM mzimmers

                          @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?

                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on 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.

                          jeremy_kJ 1 Reply Last reply
                          1
                          • JonBJ JonB

                            @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.

                            jeremy_kJ Online
                            jeremy_kJ Online
                            jeremy_k
                            wrote on 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/

                            JonBJ 1 Reply Last reply
                            0
                            • jeremy_kJ jeremy_k

                              @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.

                              JonBJ Offline
                              JonBJ Offline
                              JonB
                              wrote on 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,

                              jeremy_kJ 1 Reply Last reply
                              0
                              • JonBJ JonB

                                @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,

                                jeremy_kJ Online
                                jeremy_kJ Online
                                jeremy_k
                                wrote on 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
                                • TomZT Offline
                                  TomZT Offline
                                  TomZ
                                  wrote on last edited by TomZ
                                  #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.

                                  mzimmersM 1 Reply Last reply
                                  0
                                  • TomZT TomZ

                                    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.

                                    mzimmersM Offline
                                    mzimmersM Offline
                                    mzimmers
                                    wrote on 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
                                    • mzimmersM mzimmers has marked this topic as solved on

                                    • Login

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