mirror of
https://github.com/whyour/qinglong.git
synced 2025-07-29 16:06:07 +08:00
抽取到service层
This commit is contained in:
parent
f9ea960758
commit
74cad45856
|
@ -1,113 +1,29 @@
|
||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import * as pty from 'node-pty';
|
import Container from 'typedi';
|
||||||
import os from 'os';
|
import { Logger } from 'winston';
|
||||||
|
import TerminalService from '../services/terminal';
|
||||||
// Whether to use binary transport.
|
// Whether to use binary transport.
|
||||||
const USE_BINARY = os.platform() !== 'win32';
|
|
||||||
const route = Router();
|
const route = Router();
|
||||||
|
|
||||||
export default (app: Router) => {
|
export default (app: Router) => {
|
||||||
const terminals = {};
|
const logger: Logger = Container.get('logger');
|
||||||
const logs = {};
|
|
||||||
app.use('/', route);
|
app.use('/', route);
|
||||||
route.post('/terminals', (req, res) => {
|
route.post('/terminals', (req, res) => {
|
||||||
const env = Object.assign({}, process.env);
|
const terminalService = Container.get(TerminalService);
|
||||||
env['COLORTERM'] = 'truecolor';
|
const term = terminalService.createTerminal(req);
|
||||||
var cols = parseInt(req.query.cols),
|
|
||||||
rows = parseInt(req.query.rows),
|
|
||||||
term = pty.spawn(process.platform === 'win32' ? 'cmd.exe' : 'bash', [], {
|
|
||||||
name: 'xterm-256color',
|
|
||||||
cols: cols || 80,
|
|
||||||
rows: rows || 24,
|
|
||||||
cwd: process.platform === 'win32' ? undefined : env.PWD,
|
|
||||||
env: env,
|
|
||||||
encoding: USE_BINARY ? null : 'utf8',
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Created terminal with PID: ' + term.pid);
|
|
||||||
terminals[term.pid] = term;
|
|
||||||
logs[term.pid] = '';
|
|
||||||
term.on('data', function (data) {
|
|
||||||
logs[term.pid] += data;
|
|
||||||
});
|
|
||||||
res.send(term.pid.toString());
|
res.send(term.pid.toString());
|
||||||
res.end();
|
res.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
route.post('/terminals/:pid/size', (req, res) => {
|
route.post('/terminals/:pid/size', (req, res) => {
|
||||||
var pid = parseInt(req.params.pid),
|
const terminalService = Container.get(TerminalService);
|
||||||
cols = parseInt(req.query.cols),
|
terminalService.resizeTerminal(req);
|
||||||
rows = parseInt(req.query.rows),
|
|
||||||
term = terminals[pid];
|
|
||||||
|
|
||||||
term.resize(cols, rows);
|
|
||||||
console.log(
|
|
||||||
'Resized terminal ' +
|
|
||||||
pid +
|
|
||||||
' to ' +
|
|
||||||
cols +
|
|
||||||
' cols and ' +
|
|
||||||
rows +
|
|
||||||
' rows.',
|
|
||||||
);
|
|
||||||
res.end();
|
res.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
route.ws('/terminals/:pid', function (ws, req) {
|
route.ws('/terminals/:pid', function (ws, req) {
|
||||||
var term = terminals[parseInt(req.params.pid)];
|
const terminalService = Container.get(TerminalService);
|
||||||
console.log('Connected to terminal ' + term.pid);
|
terminalService.listenTerminal(ws, req);
|
||||||
ws.send(logs[term.pid]);
|
|
||||||
|
|
||||||
// string message buffering
|
|
||||||
function buffer(socket, timeout) {
|
|
||||||
let s = '';
|
|
||||||
let sender = null;
|
|
||||||
return (data) => {
|
|
||||||
s += data;
|
|
||||||
if (!sender) {
|
|
||||||
sender = setTimeout(() => {
|
|
||||||
socket.send(s);
|
|
||||||
s = '';
|
|
||||||
sender = null;
|
|
||||||
}, timeout);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// binary message buffering
|
|
||||||
function bufferUtf8(socket, timeout) {
|
|
||||||
let buffer = [];
|
|
||||||
let sender = null;
|
|
||||||
let length = 0;
|
|
||||||
return (data) => {
|
|
||||||
buffer.push(data);
|
|
||||||
length += data.length;
|
|
||||||
if (!sender) {
|
|
||||||
sender = setTimeout(() => {
|
|
||||||
socket.send(Buffer.concat(buffer, length));
|
|
||||||
buffer = [];
|
|
||||||
sender = null;
|
|
||||||
length = 0;
|
|
||||||
}, timeout);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const send = USE_BINARY ? bufferUtf8(ws, 5) : buffer(ws, 5);
|
|
||||||
|
|
||||||
term.on('data', function (data) {
|
|
||||||
try {
|
|
||||||
send(data);
|
|
||||||
} catch (ex) {
|
|
||||||
// The WebSocket is not open, ignore
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ws.on('message', function (msg) {
|
|
||||||
term.write(msg);
|
|
||||||
});
|
|
||||||
ws.on('close', function () {
|
|
||||||
term.kill();
|
|
||||||
console.log('Closed terminal ' + term.pid);
|
|
||||||
// Clean things up
|
|
||||||
delete terminals[term.pid];
|
|
||||||
delete logs[term.pid];
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
123
back/services/terminal.ts
Normal file
123
back/services/terminal.ts
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import os from 'os';
|
||||||
|
import * as pty from 'node-pty';
|
||||||
|
import winston from 'winston';
|
||||||
|
|
||||||
|
const USE_BINARY = os.platform() !== 'win32';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class TerminalService {
|
||||||
|
private terminals: Record<string, any>;
|
||||||
|
private logs: Record<string, string>;
|
||||||
|
constructor(@Inject('logger') private logger: winston.Logger) {
|
||||||
|
this.terminals = {};
|
||||||
|
this.logs = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
createTerminal(req) {
|
||||||
|
const that = this;
|
||||||
|
const env = Object.assign({}, process.env);
|
||||||
|
env['COLORTERM'] = 'truecolor';
|
||||||
|
const cols = parseInt(req.query.cols);
|
||||||
|
const rows = parseInt(req.query.rows);
|
||||||
|
const term = pty.spawn(
|
||||||
|
process.platform === 'win32' ? 'cmd.exe' : 'bash',
|
||||||
|
[],
|
||||||
|
{
|
||||||
|
name: 'xterm-256color',
|
||||||
|
cols: cols || 80,
|
||||||
|
rows: rows || 24,
|
||||||
|
cwd: process.platform === 'win32' ? undefined : env.PWD,
|
||||||
|
env: env,
|
||||||
|
encoding: USE_BINARY ? null : 'utf8',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
that.logger.silly('Created terminal with PID: ' + term.pid);
|
||||||
|
that.terminals[term.pid] = term;
|
||||||
|
that.logs[term.pid] = '';
|
||||||
|
term.on('data', function (data) {
|
||||||
|
that.logs[term.pid] += data;
|
||||||
|
});
|
||||||
|
return term;
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeTerminal(req) {
|
||||||
|
const that = this;
|
||||||
|
const pid = parseInt(req.params.pid);
|
||||||
|
const cols = parseInt(req.query.cols);
|
||||||
|
const rows = parseInt(req.query.rows);
|
||||||
|
const term = that.terminals[pid];
|
||||||
|
|
||||||
|
term.resize(cols, rows);
|
||||||
|
that.logger.silly(
|
||||||
|
'Resized terminal ' +
|
||||||
|
pid +
|
||||||
|
' to ' +
|
||||||
|
cols +
|
||||||
|
' cols and ' +
|
||||||
|
rows +
|
||||||
|
' rows.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
listenTerminal(ws, req) {
|
||||||
|
const that = this;
|
||||||
|
var term = that.terminals[parseInt(req.params.pid)];
|
||||||
|
that.logger.silly('Connected to terminal ' + term.pid);
|
||||||
|
ws.send(that.logs[term.pid]);
|
||||||
|
|
||||||
|
// string message buffering
|
||||||
|
function buffer(socket, timeout) {
|
||||||
|
let s = '';
|
||||||
|
let sender = null;
|
||||||
|
return (data) => {
|
||||||
|
s += data;
|
||||||
|
if (!sender) {
|
||||||
|
sender = setTimeout(() => {
|
||||||
|
socket.send(s);
|
||||||
|
s = '';
|
||||||
|
sender = null;
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// binary message buffering
|
||||||
|
function bufferUtf8(socket, timeout) {
|
||||||
|
let buffer = [];
|
||||||
|
let sender = null;
|
||||||
|
let length = 0;
|
||||||
|
return (data) => {
|
||||||
|
buffer.push(data);
|
||||||
|
length += data.length;
|
||||||
|
if (!sender) {
|
||||||
|
sender = setTimeout(() => {
|
||||||
|
socket.send(Buffer.concat(buffer, length));
|
||||||
|
buffer = [];
|
||||||
|
sender = null;
|
||||||
|
length = 0;
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const send = USE_BINARY ? bufferUtf8(ws, 5) : buffer(ws, 5);
|
||||||
|
|
||||||
|
term.on('data', function (data) {
|
||||||
|
try {
|
||||||
|
send(data);
|
||||||
|
} catch (ex) {
|
||||||
|
// The WebSocket is not open, ignore
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ws.on('message', function (msg) {
|
||||||
|
term.write(msg);
|
||||||
|
});
|
||||||
|
ws.on('close', function () {
|
||||||
|
term.kill();
|
||||||
|
that.logger.silly('Closed terminal ' + term.pid);
|
||||||
|
// Clean things up
|
||||||
|
delete that.terminals[term.pid];
|
||||||
|
delete that.logs[term.pid];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user