Fizzy Zhang

本文目录

  1. websocket 服务
    1. ws 服务部署说明
    2. node ws client 示例
  2. Electron 应用搭建

基于 Electron 的团队任务提醒工具

日常工作线上化后,很多时候需要自动化给团队的同学推送消息。基本上会采用企微机器人的方式,但公司企微机器人服务因为撑不住,故不给非业务诉求使用了,只能退而求其次,想到使用 node-mail 来发邮件,但腾讯企业邮箱又有发信限制,其他没有发信限制的邮箱又不够安全合规。最终有了用 Electron 做一个桌面工具给团队同学安装使用的想法,后台(软件最小化)获取 websocket 消息推送,借助 Electron 能力,弹出 mac 消息提示。

举例一个实际的场景:系统发版申请,现有一个 web 页面,用来填写发版申请单,填写完成后推送提醒给发版执行人

核心处理:

  1. websocket 服务:使用 Node 提供 websocket 服务,web 系统/ node 服务 完成消息交互测试
  2. Eleectron 应用搭建:
    1. 使用 Electron 加载 web 系统,登录后传入 用户ID 连接 socket
    2. 使用 Electron 中 Node 线程获取 sokcket 消息并弹出提醒

websocket 服务

创建 ws-server 目录,存放 server 相关项目内容;创建 node-server/app.js 用作 ws server。

1
2
npm init -y
pnpm install ws query-string
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// ws-server/app.js
const WebSocket = require('ws')
const qs = require('querystring')
const wss = new WebSocket.Server({ port: 8080 })
wss.on('connection', (ws, req) => {
const params = qs.parse(req.url.split('?')[1])
console.log(`客户端请求建立连接,参数:${JSON.stringify(params)}`)
ws.id = params.id
ws.on('message', message => {
console.log(`服务端收到消息: ${message}`)
console.log(`消息来源: ${ws.id}`)
})
ws.send('建立 ws 连接成功')
})

const http = require('http')
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end('触发广播消息发送')
console.log('触发广播消息发送')
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send('广播消息,你好' + client.id)
}
})
}).listen(8800)

console.log('服务已启动')

创建 index.html 用作 ws client。前端建立 ws 连接参考:https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!-- 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">
<title>Document</title>
</head>

<body>
<section>
WS 连接标识(id):<input id="wsKey" />
<button id="connect">连接</button>
</section>
<section>
<input id="msg" placeholder="消息内容" />
<button id="send">发送消息</button>
</section>

<script>
let socket = null;
document.getElementById('connect').onclick = function() {
if (socket) {
alert('已经建立连接,无需重复连接')
return;
}
const wsKey = document.getElementById('wsKey').value;
if (wsKey !== '') {
socket = new WebSocket(`ws://localhost:8080?id=${wsKey}`);
socket.addEventListener("open", function(event) {
console.log("连接已打开");
});
socket.addEventListener("message", function(event) {
console.log("获取到服务端消息:", event.data);
});
return;
}
alert('请输入连接标识')
}
document.getElementById('send').onclick = function() {
const msg = document.getElementById('msg').value;
if (msg !== '' && socket) {
socket.send(JSON.stringify({
data: {
msg
}
}));
return;
}
alert('请先建立链接并输入消息内容')
}
</script>
</body>

</html>

可扩展的地方还有很多,除了广播也可以单点推送,通过 wss.clients 中 id 标识(实际ID表示可能是 login user token),推送到指定 chient/用户 等等。

ws 服务部署说明

https 页面发起 ws 链接需要使用 wss 协议,否则会报错。如果需要使用 ng 代理,相关配置如下:

1
2
3
4
5
6
7
location  ~* ^/socket/ {
rewrite ^/socket/(.*) /$1 break;
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

如上配置后,可使用 ws://demo.com/socket/ 链接 ws 服务。

node ws client 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// client.js
const WebSocket = require('ws')
const url = 'ws://demo.com/socket/?id=local_node'
const connection = new WebSocket(url)

connection.onopen = () => {
connection.send('Message From Client')
}

connection.onerror = (error) => {
console.log(`WebSocket error: ${error}`)
console.log('error: ', error);
}

connection.onmessage = (e) => {
console.log(e.data)
}

Electron 应用搭建

Electron 应用模板代码,可参考:https://github.sheincorp.cn/zzyxka/electron-demo-app

核心步骤:

  1. 使用 Electron 加载 web 系统,登录后传入 用户ID 连接 socket
  2. 使用 Electron 中 Node 线程获取 sokcket 消息并弹出提醒
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// main.js
function showNotification({ title, body }) {
new Notification({ title, body }).show()
}

const createWindow = () => {
// ...
win.loadFile('index.html')
}

app.whenReady().then(() => {
ipcMain.handle('login', (event, args) => {
const WebSocket = require('ws')
const url = `ws://127.0.0.1:8080/socket/?id=${args.id}`
const connection = new WebSocket(url)
connection.onopen = () => {
connection.send('Message From Client')
}
connection.onmessage = (e) => {
showNotification({
title: 'new msg',
body: e.data
})
}
return { data: 'login success' }
})
createWindow()
})
推送成功