chrome插件与electron通信

本文介绍了如何通过创建WebSocket服务器,启用chrome插件并与Electron应用通信,实现实时数据共享,以便在桌面应用中关联显示流程图数据。关键步骤包括启动WebSocket服务、使用IPC在Electron中处理请求和响应,以及在chrome插件中连接WebSocket并发送数据。
摘要由CSDN通过智能技术生成

圈选插件有,显示流程图的桌面应用也有,现在就可以把它们的数据关联起来。

实现思路

1、 创建新任务时,使用ipc通信在后台起一个websocket服务
2、启动一个带有元素圈选chrome插件的浏览器,并连接上websocket

实现一个websocket服务

const WebSocket = require('ws');
const http = require('http');
import { globalLogger } from "./logger";
const WS_PORT = 8899


class WsServer {
	server: any;
	connectNum: number // 连接人数
	httpserver: any
	sockets: any
	constructor() {
		this.connectNum = 0
		this.sockets = []
	}
	startWs(onListen, onMessage) {
		const httpserver = http.createServer();
		this.httpserver = httpserver
		this.server = new WebSocket.Server({ noServer: true });

		// this.server = new WebSocket.Server({ port: WS_PORT });
		this.server?.on('connection', (socket) => {
			this.sockets.push(socket)
			console.log('Client connected');
			// 向客户端发送消息
			socket.send('jest_pro');
			this.connectNum = this.connectNum + 1
			// 监听客户端发送的消息
			socket.on('message', (message) => {
				console.log('Received:');
				if (typeof onMessage === 'function') {
					onMessage(socket, message)
				}
			});

			// 监听客户端断开连接
			socket.on('close', () => {
				console.log('Client disconnected');
				globalLogger.info('客户端断开连接.')
				// this.closeServer()
			});
		});

		this.server?.on('error', (err) => {
			console.log('websocket error', err)
			globalLogger.info('ws报错,ws服务关闭.')
			this.closeServer()
		})
		const that = this
		httpserver.on('upgrade', function upgrade(request, socket, head) {
			that.server.handleUpgrade(request, socket, head, function done(ws) {
				that.server.emit('connection', ws, request);
			});
		});


		httpserver.listen(WS_PORT, () => {
			if (typeof onListen === 'function') {
				onListen()
			}
		})
	}
	closeServer() {
		this.connectNum = 0
		this.httpserver && this.httpserver.close()
		this.server && this.server.close()
		this.sockets.forEach(sk => sk && sk.destroy && sk.destroy())
		this.sockets = []
	}
	static getInstance() {
		if (!WsServer.instance) {
			WsServer.instance = new WsServer()
		}
		return WsServer.instance
	}
}
export default WsServer

开启websocket通信

监听:

const handelRunSetting = (win) => {
	ipcMain.handle('start-task-setting', async (event, url) => {
		const wsServer = WsServer.getInstance()
		// console.log('start-task-setting====', url)
		const taslPuppeteer = TaslPuppeteer.getInstance()
		if (wsServer.connectNum !== 0) {
			return [false, wsServer.connectNum]
		};
		return [await startServer(wsServer, taslPuppeteer, url, win), 0]
	})
}

发起:

	const [status, num] = await window.ipcRenderer.invoke('start-task-setting', taskUrl);

启动浏览器

const puppeteer = require('puppeteer');
import path from 'node:path'
class TaslPuppeteer {
	browser: any
	async runPuppeteer(url) {
		// const buildCrx = path.join(__dirname, `${process.env.CHROME_DIST}/chrome_win64/chrome_extension/XPathHelper`)
    const jestProCrx = path.join(__dirname, `${process.env.CHROME_DIST}/chrome_win64/chrome_extension/JestPro`)
		// console.log('buildCrx---', buildCrx)
		const config = {
			headless: false, // 关闭无头模式
			// timeout: 0,
			args: [
				// '--disable-gpu',
				// '--disable-dev-shm-usage',
				// '--disable-setuid-sandbox',
				// '--no-first-run',
				// '--no-sandbox',
				// '--no-zygote',
				// '--single-process', '--no-sandbox','--disable-setuid-sandbox',
				'--start-maximized',
				'--disable-dev-shm-usage',
				'--no-sandbox',
				`--disable-extensions-except=${jestProCrx}`,
				`--load-extension=${jestProCrx}`,
			],
			ignoreHTTPSErrors: false, // 在导航期间忽略 HTTPS 错误
      defaultViewport: null,
			// args: ['--start-maximized', ], // 最大化启动,开启vue-devtools插件
			// defaultViewport: { // 为每个页面设置一个默认视口大小
			// 	width: 1920,
			// 	height: 1080
			// }
		}
		// if (process.platform === 'win32') {
		// 	config['executablePath'] = path.join(__dirname, '../chrome_win64/chrome.exe')
		// }
		const browser = await puppeteer.launch(config);
		this.browser = browser
    browser.on('disconnected', (fn) => {
      console.log('brower disconnected')
      this._disconnected()
    });
		const page = await browser.newPage()
		await page.goto(url, {
			waitUntil: 'domcontentloaded',
		});
	}
	closeBrowser() {
		this.browser && this.browser.close()
	}
  _disconnected() {
   
  }
	static getInstance() {
		if (!TaslPuppeteer.instance) {
			TaslPuppeteer.instance = new TaslPuppeteer()
		}
		return TaslPuppeteer.instance
	}
}

export default TaslPuppeteer

chrome 插件连接websoket

class WsClient {
  constructor() {
    const socket = new WebSocket('ws://localhost:8899');
    this.status = false
    socket.addEventListener('open', () => {
      console.log('Connected to WebSocket server');
    });

    socket.addEventListener('message', (event) => {
      console.log('Received:', event.data);
      if (event.data === 'jest_pro') {
        this.status = true
      }
    });
    socket.addEventListener('close', () => {
      console.log('WebSocket server close');
      this.status = false
    });

    this.socket = socket
  }
  send(value) {
    this.socket && this.socket.send(value)
  }
  getStatus() {
    return this.status
  }
  static getInstance() { 
    if (!WsClient.instance) {
      WsClient.instance = new WsClient()
    }
    return WsClient.instance
  }
}
export default WsClient

当完成参数填写时,发送送定义好的数据给websocket,然后下发到electron的view,渲染节点

// chrome 发送数据到websocket服务
const wsclient = WsClient.getInstance()
		console.log('handleFinish----', wsclient.getStatus())
		if (wsclient.getStatus()) {
			const other = optRef.current
			wsclient.send(getNodeData(optType, xpath, waitTime, optReName, { ...other }))
			typeof onClose === 'function' && onClose();
		} else {
			messageApi.open({
				type: 'error',
				content: '连接不上ws服务',
			});
		}

通过 ipc的通信方式,把chrome插件发送过来的数据,转发到 electron 页面去。


function startServer(wsServer, taslPuppeteer, url, win) {
	return new Promise(resovle => {
		wsServer.startWs(async () => {
			console.log('启动成功')
			globalLogger.info('ws服务启动成功')
			try {
				await taslPuppeteer.runPuppeteer(url)
				globalLogger.info('浏览器启动成功')
        win?.webContents.send('browser-close', false)
        taslPuppeteer._disconnected = () => {
          console.log('browser close')
          win?.webContents.send('browser-close', true)
          globalLogger.info('浏览器已关闭')
          wsServer.closeServer()
        }
				resovle(true)
			} catch (error) {
				globalLogger.info('浏览器启动失败, ws服务关闭')
        win?.webContents.send('browser-close', true)
				wsServer.closeServer()
				resovle(false)
			}
		}, (socket, message) => {
			console.log('socket, message', message.toString())
			win?.webContents.send('task-flow-data', message.toString())
		})
	})
}

最后

完成这一系列的操作,一个通过圈选元素构建流程图的桌面应用就诞生了。到这里还差最后一步,那就执行我们自动化的程序。
有兴趣的可以看看源码(记得给个star)

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天也想MK代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值