Is it possible to create a tcp client with electron?
Or can we access the chrome socket api with does that?
https://developer.chrome.com/apps/sockets_tcp
You can use the Node net API in Electron to implement a TCP client.
Try this sample code (don't forget to change IP address) with a little socket server as SocketTest java application for example (HERE).
At the connection, you should see a "World!" string on server side. Try to send this message from server:
{
"nom":"Xplorer",
"prenom":"Yann"
}
And you should see Hello Yann! in your electron console.
'use strict';
const electron = require('electron');
const path = require('path');
const url = require('url');
const net = require('net');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
let mainWindow;
var socketClient
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({width: 800, height: 600,backgroundColor:'#FFFFFF', frame:false})
// and load the index.html of the app.
mainWindow.loadURL(url.format({
pathname: path.join(__dirname+'/html/', 'main.html'),
protocol: 'file:',
slashes: true
}))
// Open the DevTools.
//mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
/* Instance socket on create window */
console.log('Try to connect');
socketClient = net.connect({host:'192.16.122.3', port:9042}, () => {
// 'connect' listener
console.log('connected to server!');
socketClient.write('world!\r\n');
});
socketClient.on('data', (data) => {
console.log(data.toString());
var person = JSON.parse(data);
console.log('Hello '+person.prenom+"!");
});
socketClient.on('end', () => {
console.log('disconnected from server');
});
//mainWindow.openDevTools();
}
app.on('before-quit',function(){
socketClient.end();
})
see you.
You can use the Node net API in Electron to implement a TCP client.
It's easy to just test if the chrome API is present. If not I use the node API. So that I have the same code base for my Chrome App and my Electron App.
The 2 APIs are slightly different so I post here how to do it.
let client = null; // node socket
let socketId; // chrome API socket id
function toBuffer(ab) {
return new Buffer(new Uint8Array(ab));
}
function toArrayBuffer(buf) {
return new Uint8Array(buf).buffer;
}
function initConnToServer (ip, port) {
return new Promise((resolve, reject) => {
if(typeof chrome !== 'undefined') {
chrome.sockets.tcp.create({}, r => {
socketId = r.socketId;
chrome.sockets.tcp.connect(r.socketId, ip, port, code => resolve(code));
});
} else {
client = new net.Socket(); // return a Node socket
client.connect(port, ip);
client.on('connect', () => resolve());
}
});
};
function sendToServer_simple (data) {
return new Promise((resolve, reject) => {
if(typeof chrome !== 'undefined') {
chrome.sockets.tcp.send(socketId, data, r => {});
chrome.sockets.tcp.onReceive.addListener(receiveInfo => resolve(receiveInfo.data));
} else {
client.write(toBuffer(data));
client.on('data', data => resolve(toArrayBuffer(data)));
}
});
};
Related
I'm reading while coding a book(Pro MERN Stack 2nd Edition) and I get the error:
typeerror (0 graphql _1.is definition node) is not a function
in my GitCMD.
Click here to see the error in CMD
I have tried this, from another StackOverflow error but since Im using the apollo-server-express I think is kind of different.
Also tried installing older and newer package versions of the following:
"apollo-server-express": "^3.11.1"
and
"graphql": "^0.13.2",
The code looks like this:
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
let aboutMessage = "Issue Tracker API v1.0";
const typeDefs = `
type Query {
about: String!
}
type Mutation {
setAboutMessage(message: String!): String
}
`;
const resolvers = {
Query: {
about: ()=> aboutMessage,
},
Mutation: {
setAboutMessage,
},
};
function setAboutMessage(_, { message }) {
return aboutMessage = message;
}
const server = new ApolloServer({
typeDefs,
resolvers
});
const app = express();
app.use(express.static('public'));
server.applyMiddleware({ app, path: '/graphql' });
app.listen(3000, function () {
console.log('App started on port 3000');
});
this part alone:
const express = require('express');
const app = express();
app.use(express.static('public'));
app.listen(3000, function () {
console.log('App started on port 3000');
});
worked perfectly fine, but since I added the rest of it, it returns me the error :/
I updated my graphql to "graphql": "^16.6.0" and I got a different error: You must `await server.start()` before calling `server.applyMiddleware() so for that I needed to create an Async function, and inside the function I needed the name for my new server, the typeDefs, resolvers and then the await myserver.start():
and then the
myserver.applyMiddleware({ app, path: '/graphql' }); I dont know if thats well explained but here are the changes I made for the code to work:
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
let aboutMessage = "Issue Tracker API v1.0";
const typeDefs = `
type Query {
about: String!
}
type Mutation {
setAboutMessage(message: String!): String
}
`;
const resolvers = {
Query: {
about: ()=> aboutMessage,
},
Mutation: {
setAboutMessage,
},
};
function setAboutMessage(_, { message }) {
return aboutMessage = message;
}
async function startServer(){
const server = new ApolloServer({
typeDefs,
resolvers,
});
await server.start();
server.applyMiddleware({ app, path: '/graphql' });
}
startServer();
const app = express();
app.use(express.static('public'));
app.listen(3000, function () {
console.log('App started on port 3000');
});
I didnt figured out on my own actually, I saw a post in Qiita about the same issue: Qiita same error URL.
I'm attempting to use playwright to automate an electron js application, but I can't seem to find any relevant information. To automate a simple programme, I used playwright:- https://playwright.dev/docs/api/class-electron and https://www.electronjs.org/docs/latest/tutorial/quick-start. However, I am unable to obtain the elements (buttons, dropdowns, and so on) in the electron application. Any reference or documentation that will deeply guide me to automate desktop application using playwright.
I got mine to work using their intro guide
for me since the installer installs additional components, i had to build and install, then supply the path to the exe
in my package.json i have.
"playwright": "^1.25.0",
"#playwright/test": "^1.25.0",
"eslint-plugin-playwright": "^0.10.0",
I created this class to help me have a cleaner code.
import { _electron as electron, ElectronApplication, Page } from 'playwright';
class ElectronAppController {
static electronApp: ElectronApplication;
static window1: Page;
static window2: Page;
static window3: Page;
static async launchApp() {
ElectronAppController.electronApp = await electron.launch({
executablePath: 'C:\\pathTo\\app.exe',
});
ElectronAppController.electronApp.on('window', async (page) => {
ElectronAppController.assignWindows(page);
});
const mywindows: Page[] =
await ElectronAppController.electronApp.windows();
for (
let index = 0, l = mywindows.length;
index < l;
index += 1
) {
ElectronAppController.assignWindows(
mywindows[index]
);
}
}
private static assignWindows(page: Page) {
const myurl = path.basename(page.url());
if (myurl === 'window1.html') {
ElectronAppController.window1= page;
}
if (myurl === 'window2.html') {
ElectronAppController.window2= page;
}
if (myurl === 'window3.html') {
ElectronAppController.window3= page;
}
return true;
}
}
the test file name should be [name].spec.ts, don't forget to import
test.describe('First Window Tests', async () => {
test.beforeAll(async () => {
await ElectronAppController.launchApp();
});
test('Check if first window opened', didLaunchApp);
test('name of the test', async () => {
// test body
// this will allow you to record a test very useful, but sometimes it has some problems check note bellow
await ElectronAppController.window1.pause;
});
test.afterAll(async () => {
await ElectronAppController.electronApp.close();
});
});
here is a didLaunchApp just as a simple test
const didLaunchApp = async () => {
const isVisible: boolean = await ElectronAppController.electronApp.evaluate(
async ({ BrowserWindow }) => {
const mainWindow = BrowserWindow.getAllWindows()[0];
const getState = () => mainWindow.isVisible();
return new Promise((resolve) => {
if (mainWindow.isVisible()) {
resolve(getState());
} else {
mainWindow.once('ready-to-show', () => {
setTimeout(() => resolve(getState()), 0);
});
}
});
}
);
await expect(isVisible).toBeTruthy();
};
you can record tests but sometimes that might make some problems if you have some popups or other effects on hovering over an element,
you can read more about selectors here
I'm just finishing a series of e2e tests using the same as you, Electron with React. What you don't see? Does it at least load the application?
Share the code of one test and how you launch using .launch method.
On macOs, there's an app event open-file that's triggered when opening a file association with your app. Which allows you to open your file in an existing app window.
On windows when opening a new file it just creates a new app window instead of opening it in the existing one.
How do I get behaviour like in macOs on windows?
my code:
app.on('will-finish-launching', () => {
app.on('open-file', async (event, path) => {
event.preventDefault()
if (!win) {
win = await createWindow()
}
let openFilePath
if (process.platform === 'win32' && process.argv.length >= 2) {
openFilePath = process.argv[1]
}
if (process.platform === 'darwin') {
openFilePath = path
}
win.webContents.send('open-file', openFilePath)
})
})
app.on('ready', async () => {
if (!app.isPackaged && !process.env.IS_TEST) {
// Install Vue Devtools
try {
await installExtension(VUEJS_DEVTOOLS)
} catch (e) {
console.error('Vue Devtools failed to install:', e.toString())
}
}
if (!win) {
win = await createWindow()
}
})
The docs mention that you need to call event.preventDefault() in order to handle it. It also fires before the ready event. Have you tried something like this?
app.on("open-file", (event, path) => {
event.preventDefault();
if (mainWindow === null) {
// create the main window here
// this is usually done on app.on("ready")
// but this event fires before "ready"
}
// if you already had a mainWindow or just finished
// creating it for the first time then handle the file
let file = null;
let openFilePath = null;
if (process.platform == "win32" && process.argv.length >= 2) {
openFilePath = process.argv[1];
}
if (process.platform == "darwin") {
openFilePath = path;
}
file = fs.readFileSync(openFilePath, "utf-8");
// now do stuff with the file such as sending it to the renderer
mainWindow.webContents.send("file-opened", file);
});
I tried to share data between Safari browser and standalone PWA on iPhone12 with iOS 14.3.
The information, that this should work are here: https://firt.dev/ios-14/
I#ve tried this: https://www.netguru.com/codestories/how-to-share-session-cookie-or-state-between-pwa-in-standalone-mode-and-safari-on-ios
Without success.
Are there any suggestions to running this? Or is it not possible ...
This is the code
const CACHE_NAME = "auth";
const TOKEN_KEY = "token";
const FAKE_TOKEN = "sRKWQu6hCJgR25lslcf5s12FFVau0ugi";
// Cache Storage was designed for caching
// network requests with service workers,
// mainly to make PWAs work offline.
// You can give it any value you want in this case.
const FAKE_ENDPOINT = "/fake-endpoint";
const saveToken = async (token: string) => {
try {
const cache = await caches.open(CACHE_NAME);
const responseBody = JSON.stringify({
[TOKEN_KEY]: token
});
const response = new Response(responseBody);
await cache.put(FAKE_ENDPOINT, response);
console.log("Token saved! 🎉");
} catch (error) {
// It's up to you how you resolve the error
console.log("saveToken error:", { error });
}
};
const getToken = async () => {
try {
const cache = await caches.open(CACHE_NAME);
const response = await cache.match(FAKE_ENDPOINT);
if (!response) {
return null;
}
const responseBody = await response.json();
return responseBody[TOKEN_KEY];
} catch (error) {
// Gotta catch 'em all
console.log("getToken error:", { error });
}
};
const displayCachedToken = async () => {
const cachedToken = await getToken();
console.log({ cachedToken });
};
// Uncomment the line below to save the fake token
// saveToken(FAKE_TOKEN);
displayCachedToken();
Without success means no result, i've tried to set data in safari and get them in standalone pwa
I'm working on a JHipster application that I'm trying to get functioning in Electron. I have Golden Layout for window/pane management and cross-pane communication. I am having several problems with the combination of technologies, including:
I can't pop out more than one pane at the same time into their own Electron windows. I instead get an Uncaught Error: Can't create config, layout not yet initialised error in the console.
Two thirds of the panes don't display anything when popped out into Electron windows, and I'm not sure what the reason is. Any ideas or suggestions for this? One example of content is a leaflet map, another is a "PowerPoint preview" that is really just divs that mock the appearance of slides.
I haven't made it this far yet, but I assume that I will have trouble communicating between popped-out Electron windows when I get more than one open. Right now, the panes communicate between each other using Golden Layout's glEventHub emissions. I have an avenue to explore when I cross that bridge, namely Electron ipcRenderer.
Some borrowed code is here (most of it I can't share because it's company confidential):
electron.js:
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const path = require('path');
const isDev = require('electron-is-dev');
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({width: 900, height: 680});
mainWindow.loadURL(isDev ? 'http://localhost:9000' : `file://${path.join(__dirname, '../build/index.html')}`);
if (isDev) {
// Open the DevTools.
//BrowserWindow.addDevToolsExtension('<location to your react chrome extension>');
mainWindow.webContents.openDevTools();
}
mainWindow.on('closed', () => mainWindow = null);
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
goldenLayoutComponent.tsx, a patch for Golden Layout:
import React from "react";
import ReactDOM from "react-dom";
// import "./goldenLayout-dependencies";
import GoldenLayout from "golden-layout";
import "golden-layout/src/css/goldenlayout-base.css";
import "golden-layout/src/css/goldenlayout-dark-theme.css";
import $ from "jquery";
interface IGoldenLayoutProps {
htmlAttrs: {},
config: any,
registerComponents: Function
}
interface IGoldenLayoutState {
renderPanels: Set<any>
}
interface IContainerRef {
current: any
}
export class GoldenLayoutComponent extends React.Component <IGoldenLayoutProps, IGoldenLayoutState> {
goldenLayoutInstance = undefined;
state = {
renderPanels: new Set<any>()
};
containerRef: IContainerRef = React.createRef();
render() {
const panels = Array.from(this.state.renderPanels || []);
return (
<div ref={this.containerRef as any} {...this.props.htmlAttrs}>
{panels.map((panel, index) => {
return ReactDOM.createPortal(
panel._getReactComponent(),
panel._container.getElement()[0]
);
})}
</div>
);
}
componentRender(reactComponentHandler) {
this.setState(state => {
const newRenderPanels = new Set(state.renderPanels);
newRenderPanels.add(reactComponentHandler);
return { renderPanels: newRenderPanels };
});
}
componentDestroy(reactComponentHandler) {
this.setState(state => {
const newRenderPanels = new Set(state.renderPanels);
newRenderPanels.delete(reactComponentHandler);
return { renderPanels: newRenderPanels };
});
}
componentDidMount() {
this.goldenLayoutInstance = new GoldenLayout(
this.props.config || {},
this.containerRef.current
);
if (this.props.registerComponents instanceof Function)
this.props.registerComponents(this.goldenLayoutInstance);
this.goldenLayoutInstance.reactContainer = this;
this.goldenLayoutInstance.init();
}
}
// Patching internal GoldenLayout.__lm.utils.ReactComponentHandler:
const ReactComponentHandler = GoldenLayout["__lm"].utils.ReactComponentHandler;
class ReactComponentHandlerPatched extends ReactComponentHandler {
_container: any;
_reactClass: any;
_render() {
const reactContainer = this._container.layoutManager.reactContainer; // Instance of GoldenLayoutComponent class
if (reactContainer && reactContainer.componentRender)
reactContainer.componentRender(this);
}
_destroy() {
// ReactDOM.unmountComponentAtNode( this._container.getElement()[ 0 ] );
this._container.off("open", this._render, this);
this._container.off("destroy", this._destroy, this);
}
_getReactComponent() {
// the following method is absolute copy of the original, provided to prevent depenency on window.React
const defaultProps = {
glEventHub: this._container.layoutManager.eventHub,
glContainer: this._container
};
const props = $.extend(defaultProps, this._container._config.props);
return React.createElement(this._reactClass, props);
}
}
GoldenLayout["__lm"].utils.ReactComponentHandler = ReactComponentHandlerPatched;
Any help or insight into these issues would be appreciated. Thanks in advance!
If you are still looking for a solutions, 1 and 2 I have solved, if you want to see my solution you could see in this repository.
But it was basically this:
1: The window that popups has a different path than the main window, so I just had to put a try catch in my requires, and you have to set
nativeWindowOpen = true
when creating the Browser window.
2: Solves it's self after 1 I think