Aaronius / penpal

A promise-based library for securely communicating with iframes via postMessage.
MIT License
381 stars 56 forks source link

How to detect if connection with child was lost? #58

Open mariovde opened 3 years ago

mariovde commented 3 years ago

Hi

I am currently using penpal in a setup at a client but we stumbled upon the following "issue":

When the original page in the iframe - that has the penpal library - is replaced by a page that does not have the library and we want to do a call to the child, we get this:

[Penpal] Parent: Sending getState() call

So Child has a function getState. Parent asks the child to do the getState function. This all works when the child has the library running, but we don't get anything when that initial page is changed to another page. It just "hangs" on the "Sending call"... No error, no disconnect, nothing.

The code we use is this from the parent to the child. We don't see any Error from the catch. connection.current.promise .then((child) => { console.log(" Child doGetSTate ", child); return child .getState() .then((state) => console.log("save state to local storage ")) .catch((error) => console.log("an error occured in getState", error)); }) .catch((error) => console.log(" error occured in doGetState() ", error));

What are we doing wrong? TL;DR: we need to know how to intercept or detect when the connection with the child page is lost, so that we cannot do a call anymore to the child, because it just "hangs": [Penpal] Parent: Sending getState() call

Thanks!

Mario

Aaronius commented 3 years ago

Hey Mario. The problem here is that the parent is assuming that the child is still working on preparing a response. By default, it waits indefinitely, but you can configure a timeout when the connectToChild is called (see https://github.com/Aaronius/penpal#options). Once you configure a timeout, if the parent doesn't hear a response from the child after the timeout passes, your .catch should be hit.

There may be a better way to handle this in Penpal so that you don't have to wait for the timeout to pass in this particular case. Maybe Penpal could detect when the iframe is navigated from one page to another and if there's no attempt from the child to reconnect it could immediately fail method calls from the parent. Something like that. I need to think about this some more.

Aaronius commented 3 years ago

Sorry, I misspoke. The timeout configuration option only applies to waiting for the initial connection to be established, so it won't work for your specific situation.

@mariovde, would your ideal solution be that Penpal provides an event that notifies you when there's a disconnection and then a separate event that notifies you when there's a re-connection?

mariovde commented 3 years ago

@Aaronius Well, okay, that's why we were waiting so long to see the timeout kick in :)... it never came. Yes, I think it would be good for everyone to know when the connection was lost and when it would reconnect. That would be awesome for sure!

Aaronius commented 3 years ago

Okay, thank you. Providing an event for reconnection will be probably simple enough. Providing an event for "disconnection" might be trickier, but I'll play around with some ideas. Thanks for bringing this up.

Aaronius commented 3 years ago

@mariovde I'm curious to know what you'd like this API to look like. I've got some ideas, but I don't really love them.

mariovde commented 3 years ago

@Aaronius how about adding another config option onConnectionLost : function() ?

const connection = connectToChild({ // The iframe to which a connection should be made iframe, // Methods the parent is exposing to the child methods: { add(num1, num2) { return num1 + num2; }, }, onConnectionLost: function(params); onConnection: function(params); });

something like that?

Aaronius commented 3 years ago

That's where I was headed. It prompts a few questions:

I'm thinking it might be more appropriate to have onDisconnect (assuming this functionality is feasible) and onReconnect, where onReconnect only gets called on subsequent connections. On a reconnect, a new child object would get passed to the onReconnect callback and the child object provided through connection.promise would stop functioning (an error would be thrown if the parent attempts to call its methods).

I'm not in love with it though.

yowainwright commented 3 years ago

Love PenPal! 🔥

I haven't dug in enough to respond completely coherently so excuse misunderstanding.


I like the idea of isStillConnectedToChild.

Rather than PenPal providing a loss of connection to the child, and then a reconnection to the child, it only confirms it "is Still Connected" connected to the child.


Idea

isStillConnectedToChild() // => boolean
// is still connected to the child (?)
// then do stuff
Aaronius commented 3 years ago

Thanks for the feedback @yowainwright!

mathpaquette commented 9 months ago

just thinking out loud, would it make sense to have a heartbeat between parent and child ? If not received, we can assume they are disconnected. still thinking for better solutions.

ornakash commented 3 months ago

We really like penpal. We'd appreciate a "connection lost" feature. I think what @mariovde suggested is good, but maybe you can add the same thing to the connectToParent.

const connection = connectToChild({
// The iframe to which a connection should be made
iframe,
// Methods the parent is exposing to the child
methods: {
add(num1, num2) {
return num1 + num2;
},
},
onConnectionLost: function(params);
onConnection: function(params);
});
const connection = connectToParent({
methods: {
add(num1, num2) {
return num1 + num2;
},
},
onConnectionLost: function(params);
onConnection: function(params);
});