feat: 关闭主机回调.

This commit is contained in:
lijiahangmax
2024-01-07 01:29:17 +08:00
parent b160c6317e
commit 48156ebb0d
23 changed files with 287 additions and 160 deletions

View File

@@ -2,6 +2,7 @@ import type {
InputPayload,
ITerminalChannel,
ITerminalOutputProcessor,
ITerminalSessionManager,
OutputPayload,
Protocol,
} from '../types/terminal.type';
@@ -9,6 +10,7 @@ import { OutputProtocol } from '../types/terminal.protocol';
import { getHostTerminalAccessToken } from '@/api/asset/host-terminal';
import { Message } from '@arco-design/web-vue';
import { sleep } from '@/utils';
import TerminalOutputProcessor from './terminal-output-processor';
export const wsBase = import.meta.env.VITE_WS_BASE_URL;
@@ -17,10 +19,10 @@ export default class TerminalChannel implements ITerminalChannel {
private client?: WebSocket;
private readonly processor;
private readonly processor: ITerminalOutputProcessor;
constructor(processor: ITerminalOutputProcessor) {
this.processor = processor;
constructor(sessionManager: ITerminalSessionManager) {
this.processor = new TerminalOutputProcessor(sessionManager, this);
}
// 初始化
@@ -68,26 +70,14 @@ export default class TerminalChannel implements ITerminalChannel {
if (!payload) {
return;
}
// 消息调度
switch (payload.type) {
case OutputProtocol.CHECK.type:
// 检查 回调
this.processor.processCheck.call(this.processor, payload);
break;
case OutputProtocol.CONNECT.type:
// 连接 回调
this.processor.processConnect.call(this.processor, payload);
break;
case OutputProtocol.PONG.type:
// pong 回调
this.processor.processPong.call(this.processor, payload);
break;
case OutputProtocol.OUTPUT.type:
// 输出 回调
this.processor.processOutput.call(this.processor, payload);
break;
default:
break;
// 获取消息处理方法
const processMethod = Object.values(OutputProtocol)
.find(protocol => protocol.type === payload.type)
?.processMethod;
// 处理消息
if (processMethod) {
const processMethodFn = this.processor[processMethod as keyof ITerminalOutputProcessor] as Function;
processMethodFn && processMethodFn.call(this.processor, payload);
}
}

View File

@@ -0,0 +1,74 @@
import {
ITerminalChannel,
ITerminalOutputProcessor,
ITerminalSessionManager,
OutputPayload
} from '../types/terminal.type';
import { InputProtocol } from '../types/terminal.protocol';
// 终端输出消息体处理器实现
export default class TerminalOutputProcessor implements ITerminalOutputProcessor {
private readonly sessionManager: ITerminalSessionManager;
private readonly channel: ITerminalChannel;
constructor(sessionManager: ITerminalSessionManager, channel: ITerminalChannel) {
this.sessionManager = sessionManager;
this.channel = channel;
}
// 处理检查消息
processCheck({ sessionId, result, msg }: OutputPayload): void {
const success = !!Number.parseInt(result);
const session = this.sessionManager.getSession(sessionId);
// 未成功展示错误信息
if (!success) {
session.write(`${msg || ''}`);
return;
}
// 发送 connect 命令
this.channel.send(InputProtocol.CONNECT, { sessionId, cols: session.inst.cols, rows: session.inst.rows });
}
// 处理连接消息
processConnect({ sessionId, result, msg }: OutputPayload): void {
const success = !!Number.parseInt(result);
const session = this.sessionManager.getSession(sessionId);
// 未成功展示错误信息
if (!success) {
session.write(`${msg || ''}`);
return;
}
// 设置可写
session.setCanWrite(true);
// 执行连接逻辑
session.connect();
}
// 处理关闭消息
processClose({ sessionId, msg }: OutputPayload): void {
const session = this.sessionManager.getSession(sessionId);
// 关闭 tab 则无需处理
if (session) {
// 提示消息
session.write(`\r\n${msg || ''}`);
// 设置状态
session.connected = false;
// 设置不可写
session.setCanWrite(false);
}
}
// 处理 pong 消息
processPong(payload: OutputPayload): void {
console.log('pong');
}
// 处理输出消息
processOutput({ sessionId, body }: OutputPayload): void {
const session = this.sessionManager.getSession(sessionId);
session && session.write(body);
}
}

View File

@@ -1,20 +1,13 @@
import type {
ITerminalChannel,
ITerminalSession,
ITerminalSessionManager,
ITerminalOutputProcessor,
OutputPayload,
TerminalTabItem
} from '../types/terminal.type';
import type { ITerminalChannel, ITerminalSession, ITerminalSessionManager, TerminalTabItem } from '../types/terminal.type';
import { sleep } from '@/utils';
import { InputProtocol } from '../types/terminal.protocol';
import TerminalSession from './terminal-session';
import { useDebounceFn } from '@vueuse/core';
import TerminalChannel from '@/views/host/terminal/handler/terminal-channel';
import { addEventListen, removeEventListen } from '@/utils/event';
import TerminalSession from './terminal-session';
import TerminalChannel from './terminal-channel';
// 终端会话管理器实现
export default class TerminalSessionManager implements ITerminalSessionManager, ITerminalOutputProcessor {
export default class TerminalSessionManager implements ITerminalSessionManager {
private readonly channel: ITerminalChannel;
@@ -50,11 +43,33 @@ export default class TerminalSessionManager implements ITerminalSessionManager,
this.sessions[sessionId] = session;
// 发送会话初始化请求
this.channel.send(InputProtocol.CHECK, {
session: sessionId,
hostId: hostId
sessionId,
hostId
});
}
// 获取终端会话
getSession(sessionId: string): ITerminalSession {
return this.sessions[sessionId];
}
// 关闭终端会话
closeSession(sessionId: string): void {
// 发送关闭消息
this.channel?.send(InputProtocol.CLOSE, { sessionId });
// 关闭 session
const session = this.sessions[sessionId];
if (session) {
session.close();
}
// 移除 session
this.sessions[sessionId] = undefined as unknown as ITerminalSession;
// session 全部关闭后 关闭 channel
if (Object.values(this.sessions).filter(Boolean).every(s => !s?.connected)) {
this.reset();
}
}
// 初始化 channel
private async initChannel() {
// 检查 channel 是否已经初始化
@@ -71,28 +86,6 @@ export default class TerminalSessionManager implements ITerminalSessionManager,
}, 15000);
}
// 获取终端会话
getSession(sessionId: string): ITerminalSession {
return this.sessions[sessionId];
}
// 关闭终端会话
closeSession(sessionId: string): void {
// 发送关闭消息
this.channel?.send(InputProtocol.CLOSE, { session: sessionId });
// 关闭 session
const session = this.sessions[sessionId];
if (session) {
session.close();
}
// 移除 session
this.sessions[sessionId] = undefined as unknown as ITerminalSession;
// session 全部关闭后 关闭 channel
if (Object.values(this.sessions).filter(Boolean).every(s => !s?.connected)) {
this.reset();
}
}
// 调度重置大小
private dispatchResize() {
// 对所有已连接的会话重置大小
@@ -101,45 +94,6 @@ export default class TerminalSessionManager implements ITerminalSessionManager,
.forEach(h => h.fit());
}
// 处理检查消息
processCheck({ session: sessionId, result, errorMessage }: OutputPayload): void {
const success = !!Number.parseInt(result);
const session = this.sessions[sessionId];
// 未成功展示错误信息
if (!success) {
session.write('' + errorMessage + '');
return;
}
// 发送 connect 命令
this.channel.send(InputProtocol.CONNECT, { session: sessionId, cols: session.inst.cols, rows: session.inst.rows });
}
// 处理连接消息
processConnect({ session: sessionId, result, errorMessage }: OutputPayload): void {
const success = !!Number.parseInt(result);
const session = this.sessions[sessionId];
// 未成功展示错误信息
if (!success) {
session.write('' + errorMessage + '');
return;
}
// 设置可写
session.setCanWrite(true);
// 执行连接逻辑
session.connect();
}
// 处理 pong 消息
processPong(payload: OutputPayload): void {
console.log('pong');
}
// 处理输出消息
processOutput({ session: sessionId, body }: OutputPayload): void {
const session = this.sessions[sessionId];
session && session.write(body);
}
// 重置
reset(): void {
this.sessions = {};

View File

@@ -73,14 +73,14 @@ export default class TerminalSession implements ITerminalSession {
}
// 输入
this.channel.send(InputProtocol.INPUT, {
session: this.sessionId,
sessionId: this.sessionId,
command: s
});
});
// 注册 resize 事件
this.inst.onResize(({ cols, rows }) => {
this.channel.send(InputProtocol.RESIZE, {
session: this.sessionId,
sessionId: this.sessionId,
cols,
rows
});
@@ -90,6 +90,11 @@ export default class TerminalSession implements ITerminalSession {
// 设置是否可写
setCanWrite(canWrite: boolean): void {
this.canWrite = canWrite;
if (canWrite) {
this.inst.options.cursorBlink = useTerminalStore().preference.displaySetting.cursorBlink;
} else {
this.inst.options.cursorBlink = false;
}
}
// 写入数据

View File

@@ -3,17 +3,17 @@ export const InputProtocol = {
// 主机连接检查
CHECK: {
type: 'ck',
template: ['type', 'session', 'hostId']
template: ['type', 'sessionId', 'hostId']
},
// 连接主机
CONNECT: {
type: 'co',
template: ['type', 'session', 'cols', 'rows']
template: ['type', 'sessionId', 'cols', 'rows']
},
// 关闭连接
CLOSE: {
type: 'cl',
template: ['type', 'session']
template: ['type', 'sessionId']
},
// ping
PING: {
@@ -23,17 +23,17 @@ export const InputProtocol = {
// 修改大小
RESIZE: {
type: 'rs',
template: ['type', 'session', 'cols', 'rows']
template: ['type', 'sessionId', 'cols', 'rows']
},
// 执行
EXEC: {
type: 'e',
template: ['type', 'session', 'command']
template: ['type', 'sessionId', 'command']
},
// 输入
INPUT: {
type: 'i',
template: ['type', 'session', 'command']
template: ['type', 'sessionId', 'command']
}
};
@@ -42,21 +42,31 @@ export const OutputProtocol = {
// 主机连接检查
CHECK: {
type: 'ck',
template: ['type', 'session', 'result', 'errorMessage']
template: ['type', 'sessionId', 'result', 'msg'],
processMethod: 'processCheck'
},
// 主机连接
CONNECT: {
type: 'co',
template: ['type', 'session', 'result', 'errorMessage']
template: ['type', 'sessionId', 'result', 'msg'],
processMethod: 'processConnect'
},
// 主机连接关闭
CLOSE: {
type: 'cl',
template: ['type', 'sessionId', 'msg'],
processMethod: 'processClose'
},
// pong
PONG: {
type: 'p',
template: ['type']
template: ['type'],
processMethod: 'processPong'
},
// 输出
OUTPUT: {
type: 'o',
template: ['type', 'session', 'body']
template: ['type', 'sessionId', 'body'],
processMethod: 'processOutput'
},
};

View File

@@ -13,12 +13,14 @@ export interface TerminalTabItem {
export interface Protocol {
type: string;
template: string[];
[key: string]: unknown;
}
// 终端输入消息内容
export interface InputPayload {
type?: string;
session?: string;
sessionId?: string;
[key: string]: unknown;
}
@@ -26,7 +28,7 @@ export interface InputPayload {
// 终端输出消息内容
export interface OutputPayload {
type: string;
session: string;
sessionId: string;
[key: string]: string;
}
@@ -78,6 +80,8 @@ export interface ITerminalOutputProcessor {
processCheck: (payload: OutputPayload) => void;
// 处理连接消息
processConnect: (payload: OutputPayload) => void;
// 处理关闭消息
processClose: (payload: OutputPayload) => void;
// 处理 pong 消息
processPong: (payload: OutputPayload) => void;
// 处理输出消息