salsita/chrome-extension-skeleton

Determine TabId of a non-background sender

AleksueiR opened this issue · 6 comments

Is it possible to find out TabId of the sender when invoking cmd, bcast or bg from a non-background context? I can't seem to figure out how to do that.
Thank you.

The problem is that not all the contexts have their respective tabIds. For example the extension popup window context doesn't have one, or we also don't have tabIds from connecting dev-tools scripts automatically and need to figure them out later on.

But if you know that your context will have its tabId (e.g. it is a content script), then we know the tabId in background script when your context connects, which also means we pass it to onConnect background handler (if you provided one).

https://github.com/salsita/chrome-extension-skeleton/blob/master/code/js/modules/msg.js#L179

In this custom handler you can detect that your context just connected (first argument: context name) and you get tabId (as the second argument). When we invoke your custom handler, all the infrastructure for sending messages to the new context (that has just connected) should be in place, so you can send it a message and pass the tabId to the context.

Your context would then remember the tabId value, and when messaging back to background (or any other context for that matter) that needs to know the tabId of the requestor, it can be passed as message parameter.

So I imagine the code to be something like this:

// in background:
var msg = require('msg').init('bg', {
  onConnect: function(ctxName, tabId) {
    if (ctxName === 'ctx') {
      msg.cmd(tabId, ['ctx'], 'rememberTabId', tabId);
    }
  },
  // any other handler you may need ...
  // ...
  doSomething: function(tabId, done) {
    // example of a bg handler that gets tabId from caller
    console.log('tab id:', tabId);
    done();
  }
});

// in context 'ctx'  (please make sure the name of the context matches the background code):
var myTabId = -1;  // we'll set it on connect
var msg = require('msg').init('ctx', {
  rememberTabId: function(id, done) { myTabId = id; done(); },
  // any other handler you may need ...
});
// ...
// later when you need to invoke bg handler that should know tabId:
msg.bg('doSomething', myTabId);

Please verify and let me know if this works for you.

Thank you for such a detailed response. This makes perfect sense; I'll let you know if this works out.

As a workaround, I was piggybacking port object onto handlers inside the msg module.

@AleksueiR: have you had a chance to verify the above proposed solution?, or are you otherwise fine to close this issue?
Thx, -R.

@roman-kaspar, I tried out your suggestion and it works as expected although the context tab has to wait for the rememberTabId command before sending out messages that require its tabId.
Thank you.

Yes, that's right, some synchronization is needed there, you cannot fire messages right after your script is started. However the delay should not be any significant, in a few milliseconds you should get the tabId. Thanks for verifying the solution, I am closing the issue now...

I turned tabId into a promise, which means that you get the synchronisation for free. The promise is only fulfilled when the tab ID is returned from the background.