refactor: 重构终端连接流程.
This commit is contained in:
@@ -1,96 +0,0 @@
|
||||
import { ITerminalHandler } from '@/store/modules/terminal/types';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { fontFamilySuffix } from '@/views/host/terminal/types/terminal.const';
|
||||
import { ITerminalAddon, Terminal } from 'xterm';
|
||||
import { FitAddon } from 'xterm-addon-fit';
|
||||
import { WebglAddon } from 'xterm-addon-webgl';
|
||||
|
||||
/**
|
||||
* 终端处理器
|
||||
*/
|
||||
export default class TerminalHandler implements ITerminalHandler {
|
||||
|
||||
public connected: boolean = false;
|
||||
|
||||
private canWrite: boolean = false;
|
||||
|
||||
private readonly session: string;
|
||||
|
||||
public inst: Terminal;
|
||||
|
||||
private fitAddon?: FitAddon;
|
||||
|
||||
private addons: ITerminalAddon[] = [];
|
||||
|
||||
constructor(session: string, dom: HTMLElement) {
|
||||
this.session = session;
|
||||
const { preference } = useTerminalStore();
|
||||
// 初始化实例
|
||||
this.inst = new Terminal({
|
||||
...(preference.displaySetting as any),
|
||||
theme: preference.themeSchema,
|
||||
fastScrollModifier: 'shift',
|
||||
fontFamily: preference.displaySetting.fontFamily + fontFamilySuffix,
|
||||
});
|
||||
this.init(dom);
|
||||
}
|
||||
|
||||
// 初始化
|
||||
init(dom: HTMLElement): void {
|
||||
// 注册插件
|
||||
this.addons.push(
|
||||
this.fitAddon = new FitAddon(),
|
||||
new WebglAddon()
|
||||
);
|
||||
const inst = this.inst;
|
||||
this.addons.forEach(s => inst.loadAddon(s));
|
||||
// 打开终端
|
||||
this.inst.open(dom);
|
||||
// 自适应
|
||||
this.fitAddon.fit();
|
||||
}
|
||||
|
||||
// 设置已连接
|
||||
connect(): void {
|
||||
this.connected = true;
|
||||
// 注册输入事件
|
||||
this.inst.onData(s => {
|
||||
if (!this.canWrite) {
|
||||
return;
|
||||
}
|
||||
// 输入
|
||||
useTerminalStore().dispatcher.onMessage(this.session, s);
|
||||
});
|
||||
// 注册 resize 事件
|
||||
this.inst.onResize(({ cols, rows }) => {
|
||||
// 输入
|
||||
});
|
||||
}
|
||||
|
||||
// 设置是否可写
|
||||
setCanWrite(canWrite: boolean): void {
|
||||
this.canWrite = canWrite;
|
||||
}
|
||||
|
||||
// 写入数据
|
||||
write(value: string): void {
|
||||
this.inst.write(value);
|
||||
}
|
||||
|
||||
// 自适应
|
||||
fit(): void {
|
||||
this.fitAddon?.fit();
|
||||
}
|
||||
|
||||
// 关闭
|
||||
close(): void {
|
||||
try {
|
||||
for (let addon of this.addons) {
|
||||
addon.dispose();
|
||||
}
|
||||
this.inst.dispose();
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +1,68 @@
|
||||
import { OutputProtocol } from '@/views/host/terminal/types/terminal.protocol';
|
||||
import type { InputPayload, ITerminalChannel, ITerminalOutputProcessor, OutputPayload, Protocol, } from '@/views/host/terminal/types/terminal.type';
|
||||
|
||||
import type {
|
||||
InputPayload,
|
||||
ITerminalChannel,
|
||||
ITerminalOutputProcessor,
|
||||
OutputPayload,
|
||||
Protocol,
|
||||
} from '../types/terminal.type';
|
||||
import { OutputProtocol } from '../types/terminal.protocol';
|
||||
import { getHostTerminalAccessToken } from '@/api/asset/host-terminal';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { sleep } from '@/utils';
|
||||
|
||||
export const wsBase = import.meta.env.VITE_WS_BASE_URL;
|
||||
|
||||
// 终端通信处理器 实现
|
||||
export default class TerminalChannel implements ITerminalChannel {
|
||||
|
||||
private client?: WebSocket;
|
||||
|
||||
private readonly processor;
|
||||
|
||||
constructor(processor: ITerminalOutputProcessor) {
|
||||
this.processor = processor;
|
||||
}
|
||||
|
||||
send(protocol: Protocol, payload: InputPayload): void {
|
||||
|
||||
}
|
||||
|
||||
// 初始化
|
||||
async init() {
|
||||
// 获取 access
|
||||
const { data: accessToken } = await getHostTerminalAccessToken();
|
||||
// 打开会话
|
||||
this.client = new WebSocket(`${wsBase}/host/terminal/${accessToken}`);
|
||||
this.client.onerror = event => {
|
||||
Message.error('无法连接至服务器');
|
||||
console.error('error', event);
|
||||
};
|
||||
this.client.onclose = event => {
|
||||
console.warn('close', event);
|
||||
};
|
||||
this.client.onmessage = this.handlerMessage.bind(this);
|
||||
// 等待会话连接
|
||||
for (let i = 0; i < 100; i++) {
|
||||
await sleep(50);
|
||||
if (this.client.readyState !== WebSocket.CONNECTING) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 是否已连接
|
||||
isConnected(): boolean {
|
||||
return !!this.client && this.client.readyState === WebSocket.OPEN;
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
send(protocol: Protocol, payload: InputPayload): void {
|
||||
// 检查是否连接
|
||||
if (!this.isConnected()) {
|
||||
return;
|
||||
}
|
||||
// 发送命令
|
||||
this.client?.send(format(protocol, payload));
|
||||
}
|
||||
|
||||
// 处理消息
|
||||
handlerMessage({ data }: MessageEvent) {
|
||||
private handlerMessage({ data }: MessageEvent) {
|
||||
// 解析消息
|
||||
const payload = parse(data as string);
|
||||
if (!payload) {
|
||||
@@ -32,31 +72,38 @@ export default class TerminalChannel implements ITerminalChannel {
|
||||
switch (payload.type) {
|
||||
case OutputProtocol.CHECK.type:
|
||||
// 检查 回调
|
||||
this.processor.processCheck(payload);
|
||||
this.processor.processCheck.call(this.processor, payload);
|
||||
break;
|
||||
case OutputProtocol.CONNECT.type:
|
||||
// 连接 回调
|
||||
this.processor.processConnect(payload);
|
||||
this.processor.processConnect.call(this.processor, payload);
|
||||
break;
|
||||
case OutputProtocol.PONG.type:
|
||||
// pong 回调
|
||||
this.processor.processPong(payload);
|
||||
this.processor.processPong.call(this.processor, payload);
|
||||
break;
|
||||
case OutputProtocol.OUTPUT.type:
|
||||
// 输出 回调
|
||||
this.processor.processOutput(payload);
|
||||
this.processor.processOutput.call(this.processor, payload);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭
|
||||
close(): void {
|
||||
// 关闭 client
|
||||
if (this.client) {
|
||||
if (this.client.readyState === WebSocket.OPEN) {
|
||||
this.client.close();
|
||||
}
|
||||
this.client = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 分隔符
|
||||
export const SEPARATOR = '|';
|
||||
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
import type { ITerminalDispatcher, ITerminalHandler, TerminalTabItem } from '@/store/modules/terminal/types';
|
||||
import type { HostQueryResponse } from '@/api/asset/host';
|
||||
import type { HostTerminalAccessResponse } from '@/api/asset/host-terminal';
|
||||
import { getHostTerminalAccessToken } from '@/api/asset/host-terminal';
|
||||
import { TabType } from '@/views/host/terminal/types/terminal.const';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { sleep } from '@/utils';
|
||||
import { format, InputProtocol, OutputProtocol, parse, Payload } from '../types/terminal.protocol';
|
||||
import { useDebounceFn } from '@vueuse/core';
|
||||
import { addEventListen, removeEventListen } from '@/utils/event';
|
||||
import { useTerminalStore } from '@/store';
|
||||
|
||||
export const wsBase = import.meta.env.VITE_WS_BASE_URL;
|
||||
|
||||
// 拆分两套逻辑 1. tab处理, 2. terminal处理
|
||||
// 太多需要优化的地方了
|
||||
// 拆成 event
|
||||
|
||||
/**
|
||||
* 终端调度器
|
||||
*/
|
||||
export default class TerminalDispatcher implements ITerminalDispatcher {
|
||||
|
||||
private access?: HostTerminalAccessResponse;
|
||||
|
||||
private client?: WebSocket;
|
||||
|
||||
private handlers: Record<string, ITerminalHandler>;
|
||||
|
||||
private pingTask?: any;
|
||||
|
||||
private readonly dispatchResizeFn: () => {};
|
||||
|
||||
constructor() {
|
||||
this.handlers = {};
|
||||
this.dispatchResizeFn = useDebounceFn(this.dispatchResize).bind(this);
|
||||
}
|
||||
|
||||
|
||||
// 初始化客户端
|
||||
async initClient() {
|
||||
if (this.client) {
|
||||
return;
|
||||
}
|
||||
// 获取 access
|
||||
const { data: accessData } = await getHostTerminalAccessToken();
|
||||
this.access = accessData;
|
||||
// 打开会话
|
||||
this.client = new WebSocket(`${wsBase}/host/terminal/${accessData.accessToken}`);
|
||||
this.client.onerror = event => {
|
||||
Message.error('无法连接至服务器');
|
||||
console.error('error', event);
|
||||
};
|
||||
this.client.onclose = event => {
|
||||
console.warn('close', event);
|
||||
};
|
||||
this.client.onmessage = this.handlerMessage.bind(this);
|
||||
// 注册 ping 事件
|
||||
this.pingTask = setInterval(() => {
|
||||
this.client?.send(format(InputProtocol.PING, {} as Payload));
|
||||
}, 150000);
|
||||
// 注册 resize 事件
|
||||
addEventListen(window, 'resize', this.dispatchResizeFn);
|
||||
// 等待会话连接成功
|
||||
for (let i = 0; i < 100; i++) {
|
||||
await sleep(50);
|
||||
if (this.client.readyState !== WebSocket.CONNECTING) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理消息
|
||||
handlerMessage({ data }: MessageEvent) {
|
||||
const payload = parse(data as string);
|
||||
if (!payload) {
|
||||
return;
|
||||
}
|
||||
// 选取会话
|
||||
switch (payload.type) {
|
||||
case OutputProtocol.CHECK.type:
|
||||
// 检查信息回调
|
||||
this.onTerminalCheckCallback(payload.session, payload.result, payload.errorMessage);
|
||||
break;
|
||||
case OutputProtocol.CONNECT.type:
|
||||
// 连接信息回调
|
||||
this.onTerminalConnectCallback(payload.session, payload.result, payload.errorMessage);
|
||||
break;
|
||||
case OutputProtocol.OUTPUT.type:
|
||||
// 输出
|
||||
this.onTerminalOutputCallback(payload.session, payload.body);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 打开终端
|
||||
async openTerminal(record: HostQueryResponse) {
|
||||
// 初始化客户端
|
||||
await this.initClient();
|
||||
// uncheck
|
||||
if (!this.access) {
|
||||
return;
|
||||
}
|
||||
const session = this.access.sessionInitial = (parseInt(this.access.sessionInitial as string, 32) + 1).toString(32);
|
||||
// 打开会话
|
||||
useTerminalStore().tabs.openTab({
|
||||
type: TabType.TERMINAL,
|
||||
key: session,
|
||||
title: record.alias || (`${record.name} ${record.address}`),
|
||||
hostId: record.id,
|
||||
address: record.address
|
||||
});
|
||||
}
|
||||
|
||||
// 注册终端处理器
|
||||
registerTerminalHandler(tab: TerminalTabItem, handler: ITerminalHandler) {
|
||||
this.handlers[tab.key] = handler;
|
||||
// 发送 check 命令
|
||||
this.client?.send(format(InputProtocol.CHECK, { session: tab.key, hostId: tab.hostId }));
|
||||
}
|
||||
|
||||
// 调度重置大小
|
||||
dispatchResize() {
|
||||
Object.values(this.handlers)
|
||||
.filter(h => h.connected)
|
||||
.forEach(h => h.fit());
|
||||
}
|
||||
|
||||
// 终端检查回调
|
||||
onTerminalCheckCallback(session: string, result: string, errormessage: string) {
|
||||
const success = !!parseInt(result);
|
||||
const handler = this.handlers[session];
|
||||
// 未成功展示错误信息
|
||||
if (!success) {
|
||||
handler.write('[91m' + errormessage + '[0m');
|
||||
return;
|
||||
}
|
||||
// 发送 connect 命令
|
||||
this.client?.send(format(InputProtocol.CONNECT, { session, cols: handler.inst.cols, rows: handler.inst.rows }));
|
||||
}
|
||||
|
||||
// 终端连接回调
|
||||
onTerminalConnectCallback(session: string, result: string, errormessage: string) {
|
||||
const success = !!parseInt(result);
|
||||
const handler = this.handlers[session];
|
||||
// 未成功展示错误信息
|
||||
if (!success) {
|
||||
handler.write('[91m' + errormessage + '[0m');
|
||||
return;
|
||||
}
|
||||
// 设置可写
|
||||
handler.setCanWrite(true);
|
||||
handler.connect();
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
onMessage(session: string, value: string): void {
|
||||
// 发送命令
|
||||
this.client?.send(format(InputProtocol.INPUT, { session, command: value }));
|
||||
}
|
||||
|
||||
// 终端输出回调
|
||||
onTerminalOutputCallback(session: string, body: string) {
|
||||
this.handlers[session].write(body);
|
||||
}
|
||||
|
||||
// 关闭终端
|
||||
closeTerminal(session: string) {
|
||||
// 发送关闭消息
|
||||
this.client?.send(format(InputProtocol.CLOSE, { session }));
|
||||
// 关闭终端
|
||||
this.handlers[session].close();
|
||||
}
|
||||
|
||||
// 重置
|
||||
reset(): void {
|
||||
this.access = undefined;
|
||||
this.handlers = {};
|
||||
// 关闭 client
|
||||
if (this.client) {
|
||||
if (this.client.readyState === WebSocket.CONNECTING) {
|
||||
this.client.close();
|
||||
}
|
||||
this.client = undefined;
|
||||
}
|
||||
// 清除 ping 事件
|
||||
if (this.pingTask) {
|
||||
clearInterval(this.pingTask);
|
||||
this.pingTask = undefined;
|
||||
}
|
||||
// 移除 resize 事件
|
||||
removeEventListen(window, 'resize', this.dispatchResizeFn);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { ITerminalChannel, ITerminalOutputProcessor, OutputPayload, } from '@/views/host/terminal/types/terminal.type';
|
||||
import TerminalChannel from '@/views/host/terminal/handler/terminal-channel';
|
||||
|
||||
// 终端调度器实现
|
||||
export default class TerminalOutputProcessor implements ITerminalOutputProcessor {
|
||||
|
||||
private readonly channel: ITerminalChannel;
|
||||
|
||||
constructor() {
|
||||
this.channel = new TerminalChannel(this);
|
||||
}
|
||||
|
||||
// 处理检查消息
|
||||
processCheck(payload: OutputPayload): void {
|
||||
// const success = !!Number.parseInt(payload.result);
|
||||
// const handler = this.handlers[session];
|
||||
// // 未成功展示错误信息
|
||||
// if (!success) {
|
||||
// handler.write('[91m' + errormessage + '[0m');
|
||||
// return;
|
||||
// }
|
||||
// // 发送 connect 命令
|
||||
// this.channel.send(InputProtocol.CONNECT, { session, cols: handler.inst.cols, rows: handler.inst.rows });
|
||||
}
|
||||
|
||||
// 处理连接消息
|
||||
processConnect(payload: OutputPayload): void {
|
||||
const success = !!Number.parseInt(payload.result);
|
||||
// const handler = this.handlers[session];
|
||||
// // 未成功展示错误信息
|
||||
// if (!success) {
|
||||
// handler.write('[91m' + errormessage + '[0m');
|
||||
// return;
|
||||
// }
|
||||
// // 设置可写
|
||||
// handler.setCanWrite(true);
|
||||
// handler.connect();
|
||||
}
|
||||
|
||||
// 处理 pong 消息
|
||||
processPong(payload: OutputPayload): void {
|
||||
}
|
||||
|
||||
// 处理输出消息
|
||||
processOutput(payload: OutputPayload): void {
|
||||
// this.handlers[session].write(body);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +1,45 @@
|
||||
import type { ITerminalChannel, ITerminalSession } from '../types/terminal.type';
|
||||
import type { TerminalTabItem } from '@/store/modules/terminal/types';
|
||||
import type {
|
||||
ITerminalChannel,
|
||||
ITerminalSession,
|
||||
ITerminalSessionManager,
|
||||
ITerminalOutputProcessor,
|
||||
OutputPayload,
|
||||
TerminalTabItem
|
||||
} from '../types/terminal.type';
|
||||
import { sleep } from '@/utils';
|
||||
import { InputProtocol } from '../types/terminal.protocol';
|
||||
import TerminalSession from './terminal-session';
|
||||
|
||||
// 终端会话管理器定义
|
||||
export interface ITerminalSessionManager {
|
||||
// 打开终端
|
||||
openSession: (tab: TerminalTabItem, dom: HTMLElement) => void;
|
||||
// 获取终端会话
|
||||
getSession: (sessionId: string) => ITerminalSession;
|
||||
// 重置
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
// FIXME 去除 TOKEN 起始量
|
||||
import { useDebounceFn } from '@vueuse/core';
|
||||
import TerminalChannel from '@/views/host/terminal/handler/terminal-channel';
|
||||
import { addEventListen, removeEventListen } from '@/utils/event';
|
||||
|
||||
// 终端会话管理器实现
|
||||
export default class TerminalSessionManager implements ITerminalSessionManager {
|
||||
export default class TerminalSessionManager implements ITerminalSessionManager, ITerminalOutputProcessor {
|
||||
|
||||
private readonly channel: ITerminalChannel;
|
||||
|
||||
private sessions: Record<string, ITerminalSession>;
|
||||
|
||||
constructor(channel: ITerminalChannel) {
|
||||
this.channel = channel;
|
||||
private keepAliveTask?: any;
|
||||
|
||||
private readonly dispatchResizeFn: () => {};
|
||||
|
||||
constructor() {
|
||||
this.channel = new TerminalChannel(this);
|
||||
this.sessions = {};
|
||||
this.dispatchResizeFn = useDebounceFn(this.dispatchResize).bind(this);
|
||||
}
|
||||
|
||||
// 打开终端会话
|
||||
async openSession(tab: TerminalTabItem, dom: HTMLElement) {
|
||||
const sessionId = tab.key;
|
||||
const hostId = tab.hostId as number;
|
||||
// 初始化客户端
|
||||
await this.channel.init();
|
||||
await this.initChannel();
|
||||
// 新建会话
|
||||
const session = new TerminalSession(
|
||||
tab.hostId as number,
|
||||
tab.key,
|
||||
hostId,
|
||||
sessionId,
|
||||
this.channel
|
||||
);
|
||||
// 初始化
|
||||
@@ -42,7 +47,28 @@ export default class TerminalSessionManager implements ITerminalSessionManager {
|
||||
// 等待前端渲染完成
|
||||
await sleep(100);
|
||||
// 添加会话
|
||||
this.sessions[tab.key] = session;
|
||||
this.sessions[sessionId] = session;
|
||||
// 发送会话初始化请求
|
||||
this.channel.send(InputProtocol.CHECK, {
|
||||
session: sessionId,
|
||||
hostId: hostId
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化 channel
|
||||
private async initChannel() {
|
||||
// 检查 channel 是否已经初始化
|
||||
if (this.channel.isConnected()) {
|
||||
return;
|
||||
}
|
||||
// 初始化 channel
|
||||
await this.channel.init();
|
||||
// 注册 resize 事件
|
||||
addEventListen(window, 'resize', this.dispatchResizeFn);
|
||||
// 注册 ping 事件
|
||||
this.keepAliveTask = setInterval(() => {
|
||||
this.channel.send(InputProtocol.PING, {});
|
||||
}, 15000);
|
||||
}
|
||||
|
||||
// 获取终端会话
|
||||
@@ -50,9 +76,82 @@ export default class TerminalSessionManager implements ITerminalSessionManager {
|
||||
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() {
|
||||
// 对所有已连接的会话重置大小
|
||||
Object.values(this.sessions)
|
||||
.filter(h => h.connected)
|
||||
.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('[91m' + errorMessage + '[0m');
|
||||
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('[91m' + errorMessage + '[0m');
|
||||
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 = {};
|
||||
// 关闭 channel
|
||||
this.channel.close();
|
||||
// 清除 ping 事件
|
||||
if (this.keepAliveTask) {
|
||||
clearInterval(this.keepAliveTask);
|
||||
this.keepAliveTask = undefined;
|
||||
}
|
||||
// 移除 resize 事件
|
||||
removeEventListen(window, 'resize', this.dispatchResizeFn);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { ITerminalChannel, ITerminalSession } from '../types/terminal.type';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { fontFamilySuffix } from '@/views/host/terminal/types/terminal.const';
|
||||
import { InputProtocol } from '@/views/host/terminal/types/terminal.protocol';
|
||||
import { fontFamilySuffix } from '../types/terminal.const';
|
||||
import { InputProtocol } from '../types/terminal.protocol';
|
||||
import { Terminal } from 'xterm';
|
||||
import { FitAddon } from 'xterm-addon-fit';
|
||||
import { WebglAddon } from 'xterm-addon-webgl';
|
||||
@@ -54,14 +54,13 @@ export default class TerminalSession implements ITerminalSession {
|
||||
// 注册插件
|
||||
this.addons.fit = new FitAddon();
|
||||
this.addons.webgl = new WebglAddon();
|
||||
// TODO check
|
||||
const inst = this.inst;
|
||||
Object.values(this.addons).forEach(s => inst.loadAddon(s));
|
||||
for (const addon of Object.values(this.addons)) {
|
||||
this.inst.loadAddon(addon);
|
||||
}
|
||||
// 打开终端
|
||||
this.inst.open(dom);
|
||||
// 自适应
|
||||
this.addons.fit.fit();
|
||||
// TODO sendCheck
|
||||
}
|
||||
|
||||
// 设置已连接
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ITerminalTabManager, TerminalTabItem } from '@/store/modules/terminal/types';
|
||||
import { InnerTabs } from '@/views/host/terminal/types/terminal.const';
|
||||
import type { ITerminalTabManager, TerminalTabItem } from '../types/terminal.type';
|
||||
import { InnerTabs } from '../types/terminal.const';
|
||||
|
||||
// 终端 tab 管理器实现
|
||||
export default class TerminalTabManager implements ITerminalTabManager {
|
||||
@@ -28,7 +28,6 @@ export default class TerminalTabManager implements ITerminalTabManager {
|
||||
// 切换为前一个 tab
|
||||
this.active = this.items[Math.max(tabIndex - 1, 0)].key;
|
||||
}
|
||||
// fixme 关闭 ws
|
||||
}
|
||||
|
||||
// 打开 tab
|
||||
|
||||
Reference in New Issue
Block a user