1

My electron app is using the remote isolation approach (mentioned in this article). My remote web app is a Ruby on Rails app. Now, I want to push notifications from a remote web app to the electron app using WebSocket. To send the message to users even if they shut off the app, I got an idea. In the Rails server, I use ActionCable to broadcast the notifications to a channel. In the main process, I subscribe to this channel by using the actioncable package.

import ActionCable from "actioncable";

const websocketUrl = "wss://rt.custom-domain.dev/_/cable";
const cable = ActionCable.createConsumer(websocketUrl);
cable.subscriptions.create(
  { channel: "WallChannel", wall_id: "106" },
  {
    received(data: any): void {},
    disconnect(): void {},
    connected(): void {},
    disconnected(): void {},
    present(): void {},
    absent(): void {},
  }
);

But I got an error:

ReferenceError: window is not defined

Then I dive deep into the source code of the actioncable package and I found that the package using WebSocket API of the browser so that why the error appeared.

I tried to use ws package to subscribe to the websocket instead by following this post. But I couldn't connect to the websocket server. When I call App.ws.sendmessage I got an error:

Error: WebSocket is not open: readyState 0 (CONNECTING)

Has anyone tried to push notifications from the remote web app by using websocket like what I've trying? Did you got the same problem? or If you got a better solution for my case, please share with me your idea. Thanks a lot.

This is my main.ts file of the electron app

import { app, BrowserWindow, ipcMain, Notification } from "electron";
import { createWindow } from "src/main/CreateWindow";
import { showNotification } from "./helpers";
import appConfigs from "src/AppConfigs";

let mainWindow: BrowserWindow;

const createAppWindow = () => {
  mainWindow = createWindow(appConfigs.targetUrl, { interop: true });

  // Open the DevTools.
  if (!app.isPackaged) {
    mainWindow.webContents.openDevTools();
  }
};

// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require("electron-squirrel-startup")) {
  // eslint-disable-line global-require
  app.quit();
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", () => {
  createAppWindow();
});

var App: { ws: any; param: any; connect_server: any; sendmessage: any } = {
  ws: null,
  param: null,
  connect_server: () => {},
  sendmessage: () => {},
};
App.sendmessage = function (send: any) {
  let data = {
    message: send,
    action: "speak",
  };
  let message = {
    command: "message",
    identifier: JSON.stringify(App.param),
    data: JSON.stringify(data),
  };
  App.ws.send(JSON.stringify(message));
};

App.connect_server = function () {
  const WebSocket = require("ws");

  App.ws = new WebSocket("wss://rt.custom-domain.dev/_/cable", [
    "actioncable-v1-json",
    "actioncable-unsupported",
  ]);
  console.log("connect_server", App.ws);
  App.param = { channel: "WallChannel", wall_id: 106 };

  App.ws.on("open", function open() {
    console.log("open channel");
    let data = {
      command: "subscribe",
      identifier: JSON.stringify(App.param),
    };
    App.ws.send(JSON.stringify(data));
    console.log("send JSON");
  });
  App.ws.on("message", function (event: any) {
    console.log("message", event);
  });

  App.ws.on("error", function (err) {
    console.log("Found error: " + err);
  });
};

App.connect_server();

CreateWindow.ts

import { BrowserWindow } from "electron";
import appConfigs from "src/AppConfigs";

declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: any;

interface BrowserWindowOption {
  title?: string;
  height?: string;
  width?: string;
  interop?: boolean;
}

export const createWindow = (
  url: string,
  options: BrowserWindowOption = {}
): BrowserWindow => {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    title: options.title || appConfigs.name,
    height: options.height || appConfigs.height,
    width: options.width || appConfigs.width,
    webPreferences: options.interop
      ? {
          preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
        }
      : {},
  });

  // and load the targetUrl.
  mainWindow.loadURL(url || appConfigs.targetUrl);

  return mainWindow;
};

package.json

{
  "name": "electron-forge-app",
  "productName": "electron-forge-app",
  "version": "1",
  "description": "My Electron application description",
  "main": ".webpack/main",
  "scripts": {
    "start": "electron-forge start",
    "package": "electron-forge package",
    "make": "electron-forge make",
    "publish": "electron-forge publish",
    "lint": "eslint --ext .ts ."
  },
  "keywords": [],
  "author": {
    ...
  },
  "license": "MIT",
  "config": {
    "forge": {
      "packagerConfig": {},
      "makers": [
        {
          "name": "@electron-forge/maker-squirrel",
          "config": {
            "name": "electron_furge"
          }
        },
        {
          "name": "@electron-forge/maker-zip",
          "platforms": [
            "darwin"
          ]
        },
        {
          "name": "@electron-forge/maker-deb",
          "config": {}
        },
        {
          "name": "@electron-forge/maker-rpm",
          "config": {}
        }
      ],
      "plugins": [
        [
          "@electron-forge/plugin-webpack",
          {
            "mainConfig": "./webpack.main.config.js",
            "renderer": {
              "config": "./webpack.renderer.config.js",
              "entryPoints": [
                {
                  "html": "./src/index.html",
                  "js": "./src/renderer.ts",
                  "name": "main_window",
                  "preload": {
                    "js": "./src/interop/preload.ts"
                  }
                }
              ]
            }
          }
        ]
      ]
    }
  },
  "devDependencies": {
    "@electron-forge/cli": "^6.0.0-beta.54",
    "@electron-forge/maker-deb": "^6.0.0-beta.54",
    "@electron-forge/maker-rpm": "^6.0.0-beta.54",
    "@electron-forge/maker-squirrel": "^6.0.0-beta.54",
    "@electron-forge/maker-zip": "^6.0.0-beta.54",
    "@electron-forge/plugin-webpack": "6.0.0-beta.54",
    "@marshallofsound/webpack-asset-relocator-loader": "^0.5.0",
    "@types/actioncable": "^5.2.4",
    "@typescript-eslint/eslint-plugin": "^4.0.1",
    "@typescript-eslint/parser": "^4.0.1",
    "css-loader": "^4.2.1",
    "electron": "12.0.5",
    "eslint": "^7.6.0",
    "eslint-plugin-import": "^2.20.0",
    "fork-ts-checker-webpack-plugin": "^5.0.14",
    "node-loader": "^1.0.1",
    "style-loader": "^1.2.1",
    "ts-loader": "^8.0.2",
    "typescript": "^4.0.2"
  },
  "dependencies": {
    "actioncable": "^5.2.6",
    "electron-squirrel-startup": "^1.0.0",
    "ws": "^7.4.5"
  }
}
Michael
  • 1,806
  • 2
  • 11
  • 20
  • Please [edit] your question to remove the images of code and replace them with the actual code as text. This way we can help you faster because we'll be able to actually test the code. Thanks! – Alexander Leithner May 16 '21 at 16:58

0 Answers0