electron usare ipcRenderer anche con contextIsolation = true

AGIORNAMENTO : il codice  sembra funzionare correttamente :

ipcRenderer.on() esiste ma non riceve gli eventi credo che il problema sia in :

let new_ipcRenderer = {};
for(let pro in ipcRenderer){
         new_ipcRenderer[pro] =ipcRenderer[pro];
}

devo far in modo che le proprietà vengano copiate ricorsivamente sospeto in qualche prototipo di prototipo che non venga ricopiato come si deve .

nel frattempo segnalo che il seguente codice risolve il probleam anche se è una soluzione che non mi piace affatto :

contextBridge.exposeInMainWorld(
       "electron",
             {
                 ipcRenderer: {
                         ...ipcRenderer,
                          on: (channel, func) =>ipcRenderer.on(channel, (event, args)      =>func(null,args))
                                         }
              }
);
———————————————————–
Articolo originale:

Muovendo i primi passi con nel programmare in JavaScript usando Electron mi sono imbatturo in un problema che mi ha richiesto un bel pò di gratacapi per essere risolto .

in pratica per comunicare fra il main process ed il rendering process ci sono le ottime libreire di electronjs cioè ipcRenderer e ipcMain il problema sorge lato cliente con contextIsolation = true e tutte le variabili di ambiente settate di default in electronjs .

la soluzione sarebbe passare tutto ipcRenderer usando il preload attraverso contextBridge di electronjs che permette di far passare un ogetto da un ambiente all’altro in fase di precaricamento in questo modo :

const {ipcRenderer, contextBridge } = require('electron');

contextBridge.exposeInMainWorld(
      "electron",
             {
                      ipcRenderer: ipcRenderer
              }
         );


Però se faccio così mi trovo a poter utilizzare la funzione ipcRenderer.send()che mi permette di inviare messaggi a ipcMain

ma invece ipcRenderer.on() non ne vuole sapere di funzionare .
indagando scopro che la funzione on() a differenza di Send() è una funzione di Prototipo e pertando non viene passata correttamente in quanto applica la clonazione strutturata , il limite di questo metodo appunto è che non copia le funzioni prototipo prototype, e quindi come si fa ?
in pratica dovedo trovare il modo di clonare “male” un ogetto e facendo in modo che le sue funzioni prototipo fossero passate non come tali ma come funzioni normali .
il frammento di codice che mi ha permesso di risolvere utto è stato il seguente :
//questo codice fa in modo che tutte le funzioni prototipo vengano copiate come se fossero funzioni normali
let new_ipcRenderer = {};
for(let pro in ipcRenderer){
         new_ipcRenderer[pro] =ipcRenderer[pro];
}
contextBridge.exposeInMainWorld(
     "electron",
          {
                   ipcRenderer: new_ipcRenderer
          }
);
nota : le best practices di Electron suggeriscono altro come vedi questa guida :
ma ritengo che ci siano casi in cui il contextIsolation = true non sia necessario ma che sia comunque un peccato non usarlo per poi usare una sola libreira che mi serve, ritengo che in questo contesto la mi ascelta sia un ottoimo compromesso fra semplicità e sicurezza .
segue codice completo :
File index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <!-- questo tag qui sotto abilita il Content-Security-Policy in breve csp se vi sono problemi nell'acceso alle risorse valutare di rimuoverlo -->
    <meta http-equiv="Content-Security-Policy" content="script-src 'self';"> 
    <title>Document</title>
</head>
<body>
    <button id="ipc_asincrono">ipc asincrono</button>
    <button id="ipc_sincrono">ipc sincrono</button>
    <div id="messaggio_ipc">per ora nessun messaggio </div>

    <script defer src="./js/web_renderer.js"></script>
</body>
</html>
file: main.js
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');

const createWindow = () => {
    const win = new BrowserWindow({
      width: 800,
      height: 600,
      webPreferences: {
        preload: path.join(__dirname, 'preload.js'),
        nodeIntegration: false,
        nodeIntegrationInWorker: false,
        contextIsolation: true,
        enableRemoteModule: false, 
        sandbox: true,
        webSecurity: true
      }
    })
  
    win.loadFile('index.html');
    win.webContents.openDevTools();// apre la console di debug di chroome
  }


  app.whenReady().then(() => {
    createWindow()
  })

 
  app.on('window-all-closed', () => {
    if (process.platform !== 'darwin'){
      app.quit()
    }
  })


  //END FASE DI AVVIO E CREAZIONE DELLE FINESTRA

  // START gestione mssaggio IPC

  
  ipcMain.on('messaggio_asincrono', (event, args) => {
    console.log(args);
    event.sender.send('ris_messaggio_asincrono', 'riposta asincrona a messagio asincrono');
  });

  // ricevuto messagio sincrono
  ipcMain.on('messaggio_sincrono', (event, args) => {
    console.log(args);
    event.returnValue = 'risposta sincrona a mesagio sincrono';
  });

  // END gestione mssaggio IPC

 

file preload.js
const {ipcRenderer, contextBridge } = require('electron');

let new_ipcRenderer = {};
console.log(new_ipcRenderer);
for(let pro in ipcRenderer){
  new_ipcRenderer[pro] = ipcRenderer[pro];
}

contextBridge.exposeInMainWorld(
  "electron",
  {
      ipcRenderer: new_ipcRenderer
  }
);

 

file web_renderer.js
window.addEventListener('load', (event) => {
    console.log('page is fully loaded');
    console.log(window.electron.ipcRenderer);

    const ipc_asincrono = document.querySelector("#ipc_asincrono");
    const ipc_sincrono = document.querySelector("#ipc_sincrono");
    const messaggio_ipc = document.querySelector('#messaggio_ipc');

    ipc_asincrono.addEventListener('click', (event) => {        
        window.electron.ipcRenderer.send('messaggio_asincrono', "ecco a te un messaggio asincrono")
    });

    // mi metto in ascolta di un eventuale risposta asincrona 
    window.electron.ipcRenderer.on('ris_messaggio_asincrono', (event, args) => {
        messaggio_ipc.innerHTML = args;
    });

    ipc_sincrono.addEventListener('click', (event) => { 
        let risposta = window.electron.ipcRenderer.sendSync('messaggio_sincrono', "ecco a te un messagio sincrono");
        messaggio_ipc.innerHTML = risposta;
    });
    
});

 

installare Filmora 9 su Ubuntu Mate 19.10 con Wine

dopo il successo della prima guida mi accingo a ripetere il tutto , con la versione aggiornata sia di ubuntu-mate che di filmora , scoprendo con piacere che le cose si sono semplificate di parecchio .

Nota : il mio computer è sempre un DELL Ispiron 7720 con scheda grafica Nvidia , visto che la situazione dei driver grafici in linux, è si molto migliorata ma rimane fondamentalmente incerta, specifico questa parte va testa sui vari hardware.

Comunque sia Filmora funziona anche senza accellerazione Hardware. Questo devo dire che è una gran cosa .

Capitolo a parte Merita il supporto all’accellerazione 3d su cui Filmora si basa , per prima cosa faremoun istallazione generica senza accellerazione 3d filmora funzionera lo stesso anche se sara più lento . Ed in secondo luogo vedremo cosa fare per risolvere anche questo problema 🙂

allora iniziamo con l’installazione generica.

Per prima cosa dovremo installare la versione stagin di wine che è si quella più in fase di sviluppo ma è anche quella che offre maggiori informazioni. Allora come indica sul sito:

https://wiki.winehq.org/Ubuntu

allora apriamo il nostro teminale e:

aggiungiamo le chiavi di wine

wget -nc https://dl.winehq.org/wine-builds/winehq.key
sudo apt-key add winehq.key

aggiungiamo i reposity

sudo apt-add-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ eoan main'

aggiorniamo l’elenco dei pacchetti :
sudo apt update

e settiamo come versione di wine appunto la stagin ed installiamola con il seguente comando.


sudo apt install --install-recommends winehq-staging

ed eco se tutto è andato come dovrebbe abbiamo la nostra copia di wine bella e funzionante .

Poi creiamo il nostro wineprefix che altro non è che una cartella che considereremo come un installazione separata di windows con tuttw i suoi settaggi custom . Per comodità useremo la sottocartella di playoninux in modo da mettere tutto in una sola parte .

/home/tuo_nome_utente/.PlayOnLinux/wineprefix/filmora

creata la cartella inizia a creare la nostra installazione custom con il seguente comando da terminale

WINEPREFIX="/home/tuo_nome_utente/.PlayOnLinux/wineprefix/filmora" winecfg

a questo punto se ci viene chiesto di installare wine mono e wine geco faciamolo senza problemi .

adesso nel tab librerie dobbiamo aggiungere le seguenti librerie :

dxgi ,opencl,msvcr120,crypt32

le prime tre essenziali di sicuro la 4° non so, le altre ancora credo non siano essenziali ma le ho aggiunte per sicurezza.

 

poi spostiamoci nel tab grafica e diamo le dimensioni dell finestra che deve occupare filmora ,
se non lo settiamo l’applicazione andrà a tutto schermo ma per comodità mi piace lasciare i bordiper interagire anche con le altre applicazioni ( io ho settato diciamo 1400 X 900 )

poi passiamo al Tab stagin e possiamo abilitare le seguenti voci per un accellerazione maggiore (non credo sia una cosa essenziale ) .

a questo punto passiamo all’installazione di filmora vera e propria .

Attenzione:
L’installer che si scarica dal sito di filmora (di circa 1 mb ) va in errore,
o lo si fa andare in errore tante volte finche non vi rimanda ad un link che vi fa scaricare l’installer completo . Oppure si scarica l’installer completo da qualche sito secondario basta googlare un po’ . ad ogni modo l’installer che ho usato io ha questo nome filmora_64bit_full1085.exe

Comunque una volta fatto questo abbiamo sia il nostro wineprefix che il nostro istaller non dobbiamo far altro che avviare l’instllazione dal nostro wineprefix :

WINEPREFIX="/home/tuo_nome_utente/.PlayOnLinux/wineprefix/filmora" wine filmora_64bit_full1085.exe

diamo avanti e vediamo che l’installazione proceder bella e liscia .

Finito l’installazione avviamo il nostro filmora , se tutto andrà bene vedremo un messaggio di errore relativo ha driver grafici , diciamo di continuare e ci potremo godere il nostro filmora :

Approfondimento driver grafici 3D:

sull’argomento accellerazzione 3D abbiamo 3 possibilità :

1) non sfruttare l’accellerazione Hardwere , filmora sarà più lento sopratutto in fase di rendering ma per quello che ho testato io non è nulla di drammatico .

2) sfruttare il progetto dxvk e per le directX 9 specificatamente il d9vk in pratica si convertono le istruzioni directx in opengl elaborate con le libreria Vulcan . In questo caso saremo obbligati ad usare i driver proprietari aggiornati per ottenere maggiori performance . Ho provato ad abilitare questa soluzione più volte senza però mai riuscirci .

(aggiornamento ci sono riuscito anche se non ho capito bene come 🙂

penso sia bastato questo comando : winetricks vulkansdk dxvk )

qui invece il link ufficiale per vulkan on linux

3) Sfruttare il progetto Gallium Nine per Wine questo progetto ha un approccio radicalmente diverso , non fa laboriose conversioni ma fa eseguire le istruzioni DirectX direttamente all’ardwere della scheda grafica richiede una scheda compatibile con le librerie opensource MESA , quindi in questo caso dovremo usare driver opensource , nel mio caso Nouveau per Nvidia , questo approccio è fantastico , oltre a rispettare apieno la filosofia opensource è anche molto veloce , alcuni test su videogiochi mostrano addirittura prestazioni migliori rispetto a lo stesso gioco che gira però su piattaforma windows . Ed il bello che questa soluzione l’ho testa e funziona ! Perlomeno sulla mia configurazione Hardwere .

nel mio caso mi sono trovato bene con l’opzione numero 3 (Gallium Nine),come dicevo per poterla utilizzare bisogna attivare i driver opensource.

e poi installare Galliumnone attraverso winetricks semplicemente con questo comando :

WINEPREFIX="/home/tuo_nome_utente/.PlayOnLinux/wineprefix/filmora" winetricks galliumnine

 

fatto questo potremo finalmente avviare il nostro filmora senza l’errore sui driver :

ecco a voi invece un video in cui mostro il processo d’installazione, nel video però manca la parte relativa all’ installazione del driver grafico .

https://www.youtube.com/watch?v=7TvIrtGI2tM&feature=youtu.be