基于WebSocket的项目构建工具实现
目录
一、背景
类似Jenkins的构建工具在项目维护以及部署上为开发人员节约了大量时间,但是构建工具本身也会消耗一部分服务器资源,对于服务器配置较低的小项目或个人项目,往往很难分配出相应资源运载这个"大家伙"。针对这类场景,一套简单的构建系统:能实现基本的构建任务;能实时查看构建进度及构建信息;最好能实现构建的配置化、管理化,其实就完全可以满足需求。
二、技术方案
引入node ssh2模块 实现远程ssh连接服务器并执行相关shell命令
基于WebSocket实现远程shell命令的实时数据传输,查看构建进度
通过建立构建配置表,支持多项目构建的管理
三、实现
1、基于ThinkJs+MongoDB搭建基本后端服务,并根据官方文档配置需要的websocket服务
adapter.js - ThinkJs
/**
* socketio config
* 配置websocket
*/
exports.websocket = {
type: 'socketio',
common: {
// common config
},
socketio: {
handle: socketio,
// allowOrigin: 'https://127.0.0.1', // 默认所有的域名都允许访问
path: '/socket.io', // 默认 '/socket.io'
adapter: null, // 默认无 adapter
messages: {
open: '/websocket/open', // 建立连接时处理对应到 websocket Controller 下的 open Action
close: '/websocket/close', // 关闭连接时处理的 Action
structure: '/websocket/structure', // 构建事件处理的 Action
}
}
}
2、实现一个连接ssh的Service并实现相关Controller对于的业务
service/ssh.js - ThinkJs
var Client = require('ssh2').Client;
module.exports = class extends think.Service {
constructor({ ip, username, password, command }) {//实例化时初始化参数
super();
this.ip = ip;
this.username = username;
this.password = password;
this.command = command;
}
//执行命令并传递回调函数(用于输出shell控制台信息)
connect({
output
}) {
let self = this;
var conn = new Client();
conn.on('ready', function() {
// console.log('Client :: ready');
conn.shell(function(err, stream) {
if (err) throw err;
stream.on('end', function() {
output('Stream :: end');
// console.log('Stream :: end')
conn.end();
}).on('close', function() {
output('Stream :: close');
// console.log('Stream :: close')
conn.end();
}).on('data', function(data) {
// console.log(data.toString());
output(data.toString('utf-8')) //实时输出控制台信息
}).stderr.on('data', function(data) {
output('STDERR: ' + data);
});
stream.end(self.command);//设置执行的命令
});
}).connect({//ssh传递配置
host: self.ip,
port: 22,
username: self.username,
password: self.password,
});
}
}
controller/websocket.js - ThinkJs
module.exports = class extends think.Controller {
constructor(...arg) {
super(...arg);
}
openAction() {
this.emit('opend', 'websocket connect successfully!')
}
closeAction() {
console.log('websocket close!')
}
structureAction() {
let self = this;
var ctx = this.ctx;
var websocketData = ctx.req.websocketData;
const ssh = think.service('ssh', websocketData);//实例化ssh service
ssh.connect({
output: function(data) {
self.emit('ssh-output', data) // websocket提交信息到前端
}
});
}
}
3、页面建立websocket连接并根据返回信息完成数据展示(这里只展示具体构建相关的前端代码)
/frame/utils/structure.vue - Nuxt
//...
// 打开构建面板
startStructure(row) {
let connectSuccess = false;
let self = this;
self.structureActionVisible = true;
self.socket = io(location.origin);
self.socket.on('opend', function(data) {
self.$message.success('websocket连接成功!');
self.connectSuccess = true;
self.structureData = row;
});
self.socket.on('connect', () => {});
//监听服务器返回
self.socket.on('ssh-output', (data) => {
//********信息打印到浏览器之前的一些过滤处理 START
if (data.match(/^\s+$/)) {
return;
}
console.log(data);
if ((data.indexOf('Client') != -1 && data.indexOf('building') != -1) || (data.indexOf('Server') != -1 && data.indexOf('building') != -1) || (data.indexOf('') != -1) || (data.indexOf('[email protected]') != -1)) {
if (data.indexOf('[PM2]') != -1) {} else {
self.console += "|";
}
//********信息打印到浏览器之前的一些过滤处理 END
} else {
self.console += data + '<br>'
}
self.$nextTick(_ => {
$('.console').scrollTop(999999999999999999);
})
});
self.socket.on('disconnect', () => {
self.$message.info('websocket已经断开!');
self.connectSuccess = false;
});
self.socket.on('connect_error', () => {
self.$message.error('websocket连接失败!');
self.connectSuccess = false;
});
},
//进行构建
structureAction() {
let self = this;
let socket = self.socket;
if (!self.connectSuccess) {
self.$message.info('websocket并未连接!');
return;
}
socket.emit('structure', self.structureData)
},
//...
四、效果展示
暂无
五、问题与扩展
1、由于服务器输出流存在16进制转码以及色彩信息,在浏览器页面(控制台无问题)部分内容展示会出现16进制乱码问题
2、扩展实现简单的构建次数或构建历史统计
3、多项目同时构建
Reference
1、ThinkJs WebSocket官方文档
https://thinkjs.org/zh-cn/doc/3.0/websocket.html
2、ssh2 官方文档
上一篇: Java大数据实习随笔14
下一篇: Java压缩字符串