Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Pages: [1]
Print
Author Topic: handlePipeMessage function  (Read 19577 times)
saad
Sr. Member
****
Posts: 65


View Profile Email
« on: October 28, 2014, 03:06:32 »

In a case when any module is connected to several other modules, and there's communication back and forth.

module A will receive a message from Shell.

then module A will send a request to module B and will get it's response within same handlePipeMessage.

from there, module A will then send some request to module C, and will get it's response within the same handlePipeMessage.

module B is connected to several modules and outputting on it's STDOUT, and I'm filtering based on the requester (module) name.

so handlePipeMessage of moduleA is getting complex.

What's the best workflow would you suggest in the above scenario, have separate Message types or have information like sender/receiver inside the header etc.
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #1 on: November 06, 2014, 10:13:37 »

Hi Saad,

It's difficult with these abstract designations to know what a better module plumbing architecture would be. Just like when we create a set of classes to solve a problem, so with modules, we need to understand and clearly define the roles, responsibilities, and collaboration patterns of the modules in question.

Perhaps you could provide a simple overview of the problem being solved by this set of modules, and what roles you've assigned to the modules themselves?

Cheers,
-=Cliff>
Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #2 on: November 12, 2014, 10:25:07 »

Hi Cliff,

Basically I had too much going on inside handlePipeMessage and wanted to get it under control, I looked at several example code especially sea of arrows and had following conclusion from there, basically this particular module was receiving several messages from different modules and for different execution paths (commands or sometimes delegating to other modules and expecting an answer back/Authentication) and I noticed the handlePipeMessage was checking for message types there, based on that I defined a Message type class for each module involved in the interaction, and then checked for it's type in handlePipeMessage to determine the execution path.

Also after branching message types if a message type can trigger more than one operation, declare a property action and and then use switch statement to trigger associated commands within handlePipeMessage, that managed things very well.

Since it was a server side code (Nodejs) and I had to keep track of who requested it, so I also passed the request and response objects with the notification/message and view tier would simply use the passed response object to output the data (like sender property)

another question, since we can define several named output pipes for a module and module would send message down to any of these pipes to the listeners on the other end, but for the input it's usually one (STDIN) with an associated handlePipeMessage as a listener, so I was thinking what kind of situation would that be if we have to define more than one input pipe with their own listener handlePipeMessage function for each.
« Last Edit: November 13, 2014, 02:59:29 by saad » Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #3 on: November 13, 2014, 02:40:10 »

Some code example (Javascript/Nodejs) in context of the above reply, as you can see my JunctionMediator got busy, it got managed fine but won't be if there's a lot more than this, please advise.

:
handlePipeMessage: function(message) { //EntitlementModule implements a 3rd party authentication system defined in its own core, serves to other cores plus handles direct requests from other client app
    if(message instanceof common.ShellMessage) { //message from Shell
        if(message.body.request.query.authToken) { //if authToken was passed -> MyAgenda (personalized) else General Agenda             
            message.body.sender = modules.AgendaModule.NAME; //set sender as there are other modules listening on stdout of EntitlementModule for authentication response
            this.getJunction().sendMessage(modules.EntitlementModule.NAME, new common.EntitlementMessage({body:message.body})); //get authenticated, response handled below.
        } else { //general public agenda/sessions
            if(message.body.request.route.path == "/sessions/:id") {
                this.sendNotification(modules.agenda.ApplicationFacade.SESSION, message.body);
            } else {
                this.sendNotification(modules.agenda.ApplicationFacade.GENERAL_AGENDA, message.body);
            }
        }
    } else if(message instanceof common.EntitlementMessage && message.body.sender == modules.AgendaModule.NAME) { //reply from EntitlementModule in response to above auth request
        if(message.body.data) { //if authentication successful
            this.sendNotification(modules.agenda.ApplicationFacade.MY_AGENDA, message.body);
        } else { //if authentication failed
            message.body.info.statusCode = 401;
            message.body.info.message = "Unauthorized";
            this.sendNotification(modules.agenda.ApplicationFacade.AGENDA_FAIL, message.body);
        }
    }
},

Another excerpt for the handlePipeMessage

:
handlePipeMessage: function(message) {
    if(message instanceof common.ChatMessage) {
           
        message.getBody().request = {id:message.getBody().socket.id, query:{authToken:message.getBody().socket.handshake.query.authToken}}; //if authToken was passed
           
        switch(message.action) {
            case "connection": //get authenticated first
                message.body.sender = modules.ChatModule.NAME //specify sender as this module is listening to stdout
                this.getJunction().sendMessage(modules.EntitlementModule.NAME, new common.EntitlementMessage({body:message.getBody()}));
                break;
                   
            case "chat": //send a message to the other socket
                this.sendNotification(modules.chat.ApplicationFacade.CHAT, message.getBody());
                break;
                   
            case "disconnect":
                this.sendNotification(modules.chat.ApplicationFacade.DISCONNECT, message.getBody());
                break;
        }
           
    } else if(message instanceof common.EntitlementMessage && message.body.sender == modules.ChatModule.NAME) { //response as a result of above authToken
           
        if(message.body.data) { //user is valid, create a connection
            this.sendNotification(modules.chat.ApplicationFacade.CONNECTION, message.body);
        } else if(message.body.info) { //authentication failed
            this.sendNotification(modules.chat.ApplicationFacade.CHAT_FAIL, {info:{statusCode:401, message:{errorCode:message.body.info.errorCode}}, request:message.body.request, response:message.body.response});
        }
    }
}
« Last Edit: November 13, 2014, 03:34:06 by saad » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #4 on: November 13, 2014, 05:31:05 »

I try not to have a lot of logic in the handlePipeMessage. All we want to do is transform a message into a notification.

To reduce what goes on there, you can use what we used to call a jump table in assembly.

In the JunctionMediator, set up a dictionary of message names and corresponding notification names. Then in the handlePipeMessage() method, just forward the message in the body of the appropriate notification. Let other internal actors consume the message.

If it's a display object or displayable data, one or more Mediators might handle.

If its something that requires logic like inspecting auth tokens, then commands would respond.

Do that and you don't need if/else or switch/case. You just lookup the note name, and fire off the message in the body of that note. QED.
Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #5 on: November 13, 2014, 09:48:33 »

jump table/dictionary does simplifies things up, but there's still more to the equation.

What if this core needs to redirect the request first to the Authentication Core (designed to have it's own core because of the complexity involved). Now two pieces.

1. Check if the incoming request needed Authentication (it handles both kinds of requests, i.e. General/Personalized) and then redirect to Authentication core.
2. Authentication core would respond back with true/false and same handlePipeMessage would be called.

So I was forced to have a little bit logic there to check for redirection needs, and then again a little bit of logic to check if response from the authentication core was true or false, that made the handlePipeMessage busy and I feel no way out.

If I let Message that requires authentication get into a core and then have a command checked and send it back to JunctionMediator for redirection to AuthenticationModule, (seems like a loop to me) and instead just redirect from the handlePipeMessage seems intuitive, although it's going against the rule, that JunctionMediator's responsibility is just to translate messages into notifications.

For regular requests, yes jump table using message name diminishes the switch, if else needs but for the above scenario I'm not finding a way out.
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #6 on: November 14, 2014, 12:44:01 »

Why not run the message through the authentication core first? then if its checks are good, it writes to an output pipe that goes to the module that consumes it. Or to a tee if multiple modules can consume.
Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #7 on: November 14, 2014, 02:39:45 »

because not all cores or even this core requires authentication all the time and shell core can't send all messages via authentication, authentication is a complicated time consuming async process via a 3rd party.

There are apps that uses authentication core directly (response gets output in the browser) so authentication core is getting reused both for the direct as well as requests from other cores.

Here's some more context for this server based app that follows REST.

Shell core forwards the request to the agenda core via named pipe if route is /agendas, (/chat to chat core etc.)

Agenda core serves two kinds of requests

1. General Agenda (all sessions belonging to this event)
2. Personalized Agenda (selected session list of this user identified via authToken)

Agenda core checks if authToken is present in http headers, "only" then it redirects to authentication core (sets the sender property) otherwise simply considers this as a general agenda request and let the request enter the core.

Agenda core followed by redirection is also listening to response from authentication core on STDOUT and compares the message with it's AgendaModule.NAME with sender property before serving personalized agenda.

Chat core on the other hand at STDOUT doesn't do anything since ChatModule.NAME didn't match the sender property.

The authentication core sent the output to STDOUT and not to the browser because sender property was present, meaning some core requested the authentication and wasn't a direct request.

Basically I think it's the reusability aspect of the cores (agenda/chat/authentication) and the 3rd party app is forcing to have some logic and guards at JunctionMediator unless there's a way out.

In this case considering at least two cores (agenda + auth OR chat + auth) were involved in any request, message type checking (every core has it's own Message class) and jump table reduced the complexity to some extent,

but what if this scales up, if a core puts more cores to work with several back and forth messages/communication, the handlePipeMessage is going to get busy.

I think that's where my other question comes in for having multiple input pipes if that's the solution, to manage "Inter-core" communication for several cores for a really large project.

« Last Edit: November 15, 2014, 10:27:24 by saad » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #8 on: November 17, 2014, 02:43:28 »

You can still take the logic out of the JunctionMediator and place it in a Command. Route the message to a command, where you determine if it needs to be bounced through the auth core, and if so, then send the message off to the auth core.
Logged
saad
Sr. Member
****
Posts: 65


View Profile Email
« Reply #9 on: November 18, 2014, 10:11:46 »

great, so I'd let it enter the core instead of redirecting from there (I believe the shortcut-redirection in JunctionMediator was leading to this problem), and let the core decide in a command to send it to the auth core. Thanks.
« Last Edit: November 18, 2014, 10:29:22 by saad » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #10 on: November 19, 2014, 08:38:22 »

Good luck. I think you're on the right track now.
Logged
Pages: [1]
Print