Comment puis-je charger un worker Web partagé avec un user-script?

je veux charger un worker partagé avec un user-script. Le problème est que le script utilisateur est libre, et n'a pas de modèle d'affaires pour héberger un fichier - ni voudrais-je utiliser un serveur, même un libre, pour héberger un petit fichier. Quoi qu'il en soit, j'ai essayé et j'obtiens (bien sûr) une même erreur de politique d'origine:

Uncaught SecurityError: Failed to construct 'SharedWorker': Script at
'https://cdn.rawgit.com/viziionary/Nacho-Bot/master/webworker.js'
cannot be accessed from origin 'http://stackoverflow.com'.

il y a une autre façon de charger un web worker en convertissant la fonction worker pour une chaîne, puis dans un Blob et le chargement de ce que le travailleur, mais j'ai essayé aussi:

var sharedWorkers = {};
var startSharedWorker = function(workerFunc){
    var funcString = workerFunc.toString();
    var index = funcString.indexOf('{');
    var funcStringClean = funcString.substring(index + 1, funcString.length - 1);
    var blob = new Blob([funcStringClean], { type: "text/javascript" });
    sharedWorkers.google = new SharedWorker(window.URL.createObjectURL(blob));
    sharedWorkers.google.port.start();
};

et ça ne marche pas non plus. Pourquoi? Parce que les travailleurs partagés sont partagé basé sur l'endroit où leur dossier de travailleur est chargé à partir. Depuis createObjectURL génère un nom de fichier unique pour chaque utilisation , les travailleurs n'auront jamais la même URL et ne seront donc jamais partagés.

comment résoudre ce problème?


Note: j'ai essayé de poser des questions sur des solutions spécifiques, mais à ce point je pense le mieux que je puisse faire est de demander d'une manière plus large pour tout solution au problème, car toutes mes tentatives de solutions semblent fondamentalement impossible en raison des mêmes politiques d'origine ou de la manière URL.createObjectURL œuvres de la "caractéristiques techniques des 151960920" , il semble impossible d' modifier L'URL du fichier résultant).

cela dit, si ma question peut être améliorée ou clarifiée, veuillez laisser un commentaire.

32
demandé sur Community 2016-08-07 04:06:27

3 réponses

Vous pouvez utiliser fetch() , response.blob() pour créer un Blob URL de type application/javascript de retour Blob ; set SharedWorker() paramètre Blob URL créé par URL.createObjectURL() ; utiliser window.open() , load l'événement de la nouvellement ouvert window pour définir le même SharedWorker précédemment défini à l'origine window ajouter message de l'événement à l'original SharedWorker nouvellement ouvert window .

javascript a été jugé à console à comment effacer le contenu d'une iFrame à partir d'une autre iFrame , où L'URL de la question actuelle devrait être chargé à nouveau tab avec message de l'ouverture window à worker.port.postMessage() gestionnaire d'événements connecté à console .

Ouverture window devrait également ouvrir une session message événement quand il est affiché à partir nouvellement ouvert window à l'aide worker.postMessage(/* message */) , de la même manière lors de l'ouverture du window

window.worker = void 0, window.so = void 0;

fetch("https://cdn.rawgit.com/viziionary/Nacho-Bot/master/webworker.js")
  .then(response => response.blob())
  .then(script => {
    console.log(script);
    var url = URL.createObjectURL(script);
    window.worker = new SharedWorker(url);
    console.log(worker);
    worker.port.addEventListener("message", (e) => console.log(e.data));
    worker.port.start();

    window.so = window.open("https://stackoverflow.com/questions/" 
                            + "38810002/" 
                            + "how-can-i-load-a-shared-web-worker-" 
                            + "with-a-user-script", "_blank");

    so.addEventListener("load", () => {
      so.worker = worker;
      so.console.log(so.worker);
      so.worker.port.addEventListener("message", (e) => so.console.log(e.data));
      so.worker.port.start();
      so.worker.port.postMessage("hi from " + so.location.href);
    });

    so.addEventListener("load", () => {
      worker.port.postMessage("hello from " + location.href)
    })

  });

À console tab vous pouvez ensuite utiliser, par exemple; à Comment effacer le contenu d'une iFrame à partir d'un autre iFrame worker.postMessage("hello, again") à nouveau window de l'URL actuelle Comment puis-je charger un web partagé travailleur de l'utilisateur, le script? , worker.port.postMessage("hi, again");message événements attachés à chaque window , la communication entre les deux window peut être réalisée en utilisant l'original SharedWorker créé lors de la première URL.

8
répondu guest271314 2017-05-23 12:02:32

condition préalable

  • Comme vous l'avez fait des recherches et comme il a été mentionné dans les commentaires, SharedWorker 'URL est soumis à la Même Politique d'Origine.
  • selon cette question il n'y a pas de support CORS pour L'URL de Worker .
  • selon ce numéro GM_worker est maintenant un WONT_FIX, et semble assez proche de l'impossible à mettre en œuvre en raison de changements dans Firefox. Il y a aussi une note que Sandbox Worker (par opposition à unsafeWindow.Worker ) ne fonctionne pas non plus.

Design

ce que je suppose que vous voulez réaliser est un userscript @include * qui va collecter des statistiques ou créer quelque UI globale ce qui apparaîtra partout. Et donc vous voulez avoir un travailleur pour maintenir certains états ou agrégats statistiques dans l'exécution (qui sera facile d'accès à partir de chaque instance de user-script), et/ou vous voulez faire une routine computation-heavy (parce que sinon il ralentira les sites cibles).

À la manière de toute solution

la solution que je veux proposer est de remplacer SharedWorker design par une alternative.

  • si vous voulez simplement maintenir un État dans le travailleur partagé, utilisez simplement Greasemonkey storage ( GM_setValue et ses amis). Il est partagé entre toutes les instances userscript (SQLite cache les scènes).
  • si vous voulez faire quelque chose de calcul-lourde tâche, à lui dans unsafeWindow.Worker et remettre le résultat dans le stockage Greasemonkey.
  • si vous voulez faire un calcul d'arrière-plan et qu'il ne doit être exécuté que par une seule instance, il existe un certain nombre de bibliothèques de synchronisation" inter-fenêtres "(la plupart utilisent localStorage mais Greasemomkey's a la même API, donc il ne devrait pas être difficile à écrire un adaptateur). Ainsi, vous pouvez acquérir une serrure dans une instance userscript et y exécuter vos routines. Comme, IWC ou ByTheWay ( probablement utilisé ici sur le Stack Exchange; post about it ).

Autre façon

Je ne suis pas sûr, mais il peut y avoir une réponse ingénieuse spoofing, à partir de ServiceWorker à faire SharedWorker travail comme vous le souhaitez. Le point de départ est dans cette réponse édite .

4
répondu saaj 2017-05-23 10:30:43

je suis assez sûr que vous voulez une réponse différente, mais malheureusement c'est ce que cela revient à.

Navigateurs de même origine " politiques pour protéger les utilisateurs d'internet, et même si vos intentions sont pures, pas de pièce de théâtre navigateur vous permet de changer l'origine d'un sharedWorker.

tous les contextes de navigation dans un sharedWorker doivent avoir exactement la même origine

  • hôte
  • protocole
  • port

Vous ne pouvez pas pirater autour de cette question, j'ai essayer en utilisant les iframes, en plus de vos méthodes, mais non fonctionnera.

peut-être que vous pouvez mettre votre fichier javascript sur github et utiliser leur service raw. pour obtenir le fichier, de cette façon vous pouvez le faire fonctionner sans beaucoup d'efforts.

mise à Jour

je lisais les mises à jour chrome et je rappeler vous poser à ce sujet. les travailleurs des services D'origine croisée sont arrivés sur chrome!

pour ce faire, ajouter ce qui suit à l'événement d'installation pour le SW:

self.addEventListener('install', event => {
  event.registerForeignFetch({
    scopes: [self.registration.scope], // or some sub-scope
    origins: ['*'] // or ['https://example.com']
  });
});

D'autres considérations sont nécessaires ainsi, vérifier:

Lien complet: https://developers.google.com/web/updates/2016/09/foreign-fetch?hl=en?utm_campaign=devshow_series_crossoriginserviceworkers_092316&utm_source=gdev&utm_medium=yt-desc

2
répondu Bamieh 2016-09-24 06:41:49