🔨 添加 sftp 会话类型.

This commit is contained in:
lijiahangmax
2024-02-06 11:52:02 +08:00
parent 13b2a7030c
commit 9b79ebb6e6
14 changed files with 219 additions and 103 deletions

View File

@@ -8,7 +8,7 @@ import type {
TerminalShortcutSetting, TerminalShortcutSetting,
TerminalState TerminalState
} from './types'; } from './types';
import type { PanelSessionTab, TerminalPanelTabItem } from '@/views/host/terminal/types/terminal.type'; import type { ISshSession, PanelSessionTab, TerminalPanelTabItem } from '@/views/host/terminal/types/terminal.type';
import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data'; import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
import { getCurrentAuthorizedHost } from '@/api/asset/asset-authorized-data'; import { getCurrentAuthorizedHost } from '@/api/asset/asset-authorized-data';
import type { HostQueryResponse } from '@/api/asset/host'; import type { HostQueryResponse } from '@/api/asset/host';
@@ -64,7 +64,8 @@ export default defineStore('terminal', {
} as TerminalShortcutSetting, } as TerminalShortcutSetting,
}, },
hosts: {} as AuthorizedHostQueryResponse, hosts: {} as AuthorizedHostQueryResponse,
tabManager: new TerminalTabManager(TerminalTabs.NEW_CONNECTION), // fixme
tabManager: new TerminalTabManager(TerminalTabs.TERMINAL_PANEL),
panelManager: new TerminalPanelManager(), panelManager: new TerminalPanelManager(),
sessionManager: new TerminalSessionManager() sessionManager: new TerminalSessionManager()
}), }),
@@ -173,8 +174,8 @@ export default defineStore('terminal', {
} }
}, },
// 检查当前是否为终端页面 并且获取当前终端会话 // 检查当前是否为终端页面 并且获取当前 ssh 会话
getAndCheckCurrentTerminalSession(tips: boolean = true) { getAndCheckCurrentSshSession(tips: boolean = true) {
// 获取当前 activeTab // 获取当前 activeTab
const activeTab = this.tabManager.active; const activeTab = this.tabManager.active;
if (activeTab !== TerminalTabs.TERMINAL_PANEL.key) { if (activeTab !== TerminalTabs.TERMINAL_PANEL.key) {
@@ -184,15 +185,15 @@ export default defineStore('terminal', {
return; return;
} }
// 获取当前会话 // 获取当前会话
const session = this.getCurrentTerminalSession(); const session = this.getCurrentSshSession();
if (!session && tips) { if (!session && tips) {
Message.warning('请打开终端'); Message.warning('请打开终端');
} }
return session; return session;
}, },
// 获取当前终端会话 // 获取当前 ssh 会话
getCurrentTerminalSession() { getCurrentSshSession() {
// 获取面板会话 // 获取面板会话
const sessionTab = this.panelManager const sessionTab = this.panelManager
.getCurrentPanel() .getCurrentPanel()
@@ -201,7 +202,7 @@ export default defineStore('terminal', {
return; return;
} }
// 获取会话 // 获取会话
return this.sessionManager.getSession(sessionTab.key); return this.sessionManager.getSession<ISshSession>(sessionTab.key);
}, },
}, },

View File

@@ -83,7 +83,7 @@
const { loading, setLoading } = useLoading(); const { loading, setLoading } = useLoading();
const { visible, setVisible } = useVisible(); const { visible, setVisible } = useVisible();
const { getCurrentTerminalSession } = useTerminalStore(); const { getCurrentSshSession } = useTerminalStore();
const cacheStore = useCacheStore(); const cacheStore = useCacheStore();
const formDrawer = ref(); const formDrawer = ref();
@@ -267,7 +267,7 @@
// 关闭回调 // 关闭回调
const onClose = () => { const onClose = () => {
// 聚焦终端 // 聚焦终端
getCurrentTerminalSession()?.focus(); getCurrentSshSession()?.focus();
}; };
</script> </script>

View File

@@ -125,7 +125,7 @@
}>(); }>();
const { copy } = useCopy(); const { copy } = useCopy();
const { getAndCheckCurrentTerminalSession } = useTerminalStore(); const { getAndCheckCurrentSshSession } = useTerminalStore();
let clickCount = 0; let clickCount = 0;
@@ -184,7 +184,7 @@
// 写入命令 // 写入命令
const write = (command: string) => { const write = (command: string) => {
const handler = getAndCheckCurrentTerminalSession()?.handler; const handler = getAndCheckCurrentSshSession()?.handler;
if (handler && handler.enabledStatus('checkAppendMissing')) { if (handler && handler.enabledStatus('checkAppendMissing')) {
handler.checkAppendMissing(command); handler.checkAppendMissing(command);
} }

View File

@@ -45,17 +45,17 @@
import TerminalShortcutSetting from '../setting/shortcut/terminal-shortcut-setting.vue'; import TerminalShortcutSetting from '../setting/shortcut/terminal-shortcut-setting.vue';
import TerminalPanelsView from '@/views/host/terminal/components/layout/terminal-panels-view.vue'; import TerminalPanelsView from '@/views/host/terminal/components/layout/terminal-panels-view.vue';
const { preference, tabManager, getCurrentTerminalSession } = useTerminalStore(); const { preference, tabManager, getCurrentSshSession } = useTerminalStore();
// 监听 tab 切换 // 监听 tab 切换
watch(() => tabManager.active, (active, before) => { watch(() => tabManager.active, (active, before) => {
// 失焦 tab // 失焦 tab
if (before === TerminalTabs.TERMINAL_PANEL.key) { if (before === TerminalTabs.TERMINAL_PANEL.key) {
getCurrentTerminalSession()?.blur(); getCurrentSshSession()?.blur();
} }
// 聚焦 tab // 聚焦 tab
if (active === TerminalTabs.TERMINAL_PANEL.key) { if (active === TerminalTabs.TERMINAL_PANEL.key) {
getCurrentTerminalSession()?.focus(); getCurrentSshSession()?.focus();
} }
// 修改标题 // 修改标题
document.title = Object.values(TerminalTabs) document.title = Object.values(TerminalTabs)

View File

@@ -28,7 +28,7 @@
const emits = defineEmits(['openTransfer']); const emits = defineEmits(['openTransfer']);
const { getAndCheckCurrentTerminalSession } = useTerminalStore(); const { getAndCheckCurrentSshSession } = useTerminalStore();
const snippetRef = ref(); const snippetRef = ref();
@@ -59,7 +59,7 @@
// 终端截屏 // 终端截屏
const screenshot = () => { const screenshot = () => {
const handler = getAndCheckCurrentTerminalSession()?.handler; const handler = getAndCheckCurrentSshSession()?.handler;
if (handler && handler.enabledStatus('screenshot')) { if (handler && handler.enabledStatus('screenshot')) {
handler.screenshot(); handler.screenshot();
} }

View File

@@ -44,7 +44,7 @@
</script> </script>
<script lang="ts" setup> <script lang="ts" setup>
import type { ITerminalTabManager, TerminalPanelTabItem } from '../../types/terminal.type'; import type { ISshSession, ITerminalTabManager, TerminalPanelTabItem } from '../../types/terminal.type';
import { watch } from 'vue'; import { watch } from 'vue';
import { useTerminalStore } from '@/store'; import { useTerminalStore } from '@/store';
import { PanelSessionType } from '../../types/terminal.const'; import { PanelSessionType } from '../../types/terminal.const';
@@ -66,14 +66,14 @@
if (before) { if (before) {
const beforeTab = props.panel.items.find(s => s.key === before); const beforeTab = props.panel.items.find(s => s.key === before);
if (beforeTab && beforeTab?.type === PanelSessionType.SSH.type) { if (beforeTab && beforeTab?.type === PanelSessionType.SSH.type) {
sessionManager.getSession(before)?.blur(); sessionManager.getSession<ISshSession>(before)?.blur();
} }
} }
// 终端自动聚焦 // 终端自动聚焦
if (active) { if (active) {
const activeTab = props.panel.items.find(s => s.key === active); const activeTab = props.panel.items.find(s => s.key === active);
if (activeTab && activeTab?.type === PanelSessionType.SSH.type) { if (activeTab && activeTab?.type === PanelSessionType.SSH.type) {
sessionManager.getSession(active)?.focus(); sessionManager.getSession<ISshSession>(active)?.focus();
} }
} }
// 无终端自动关闭 // 无终端自动关闭
@@ -214,12 +214,13 @@
} }
.arco-tabs-tab-title { .arco-tabs-tab-title {
padding: 11px 18px 11px 14px; padding: 11px 18px 7px 14px;
background: var(--color-bg-panel-tabs); background: var(--color-bg-panel-tabs);
font-size: 14px; font-size: 14px;
height: var(--panel-nav-height); height: var(--panel-nav-height);
display: flex; display: flex;
align-items: center; align-items: center;
border-bottom: 4px transparent solid;
&::before { &::before {
display: none; display: none;

View File

@@ -31,12 +31,12 @@
</script> </script>
<script lang="ts" setup> <script lang="ts" setup>
import type { ContextMenuItem, ITerminalSession } from '../../types/terminal.type'; import type { ContextMenuItem, ISshSession } from '../../types/terminal.type';
import { ActionBarItems } from '../../types/terminal.const'; import { ActionBarItems } from '../../types/terminal.const';
import { useTerminalStore } from '@/store'; import { useTerminalStore } from '@/store';
defineProps<{ defineProps<{
session: ITerminalSession | undefined session: ISshSession | undefined
}>(); }>();
const emits = defineEmits(['click']); const emits = defineEmits(['click']);

View File

@@ -67,7 +67,7 @@
</script> </script>
<script lang="ts" setup> <script lang="ts" setup>
import type { ITerminalSession, TerminalTabItem, SidebarAction } from '../../types/terminal.type'; import type { ISshSession, TerminalTabItem, SidebarAction } from '../../types/terminal.type';
import { computed, onMounted, onUnmounted, ref } from 'vue'; import { computed, onMounted, onUnmounted, ref } from 'vue';
import { useDictStore, useTerminalStore } from '@/store'; import { useDictStore, useTerminalStore } from '@/store';
import useCopy from '@/hooks/copy'; import useCopy from '@/hooks/copy';
@@ -89,7 +89,7 @@
const searchModal = ref(); const searchModal = ref();
const commandInput = ref(); const commandInput = ref();
const terminalRef = ref(); const terminalRef = ref();
const session = ref<ITerminalSession>(); const session = ref<ISshSession>();
// 发送命令 // 发送命令
const writeCommandInput = async (e: KeyboardEvent) => { const writeCommandInput = async (e: KeyboardEvent) => {
@@ -138,7 +138,7 @@
// 初始化会话 // 初始化会话
onMounted(async () => { onMounted(async () => {
// 创建终端处理器 // 创建终端处理器
session.value = await sessionManager.openSession(props.tab, { session.value = await sessionManager.openSsh(props.tab, {
el: terminalRef.value, el: terminalRef.value,
editorModal: editorModal.value, editorModal: editorModal.value,
searchModal: searchModal.value searchModal: searchModal.value

View File

@@ -0,0 +1,41 @@
import type { ISftpSession, ITerminalChannel } from '../types/terminal.type';
import { InputProtocol } from '../types/terminal.protocol';
// sftp 会话实现
export default class SftpSession implements ISftpSession {
public readonly hostId: number;
public sessionId: string;
public connected: boolean;
private readonly channel: ITerminalChannel;
constructor(hostId: number,
sessionId: string,
channel: ITerminalChannel) {
this.hostId = hostId;
this.sessionId = sessionId;
this.channel = channel;
this.connected = false;
}
// 设置已连接
connect(): void {
this.connected = true;
}
// 断开连接
disconnect(): void {
// 发送关闭消息
this.channel.send(InputProtocol.CLOSE, {
sessionId: this.sessionId
});
}
// 关闭
close(): void {
}
}

View File

@@ -1,5 +1,5 @@
import type { ShortcutKey, TerminalInteractSetting, TerminalShortcutKey } from '@/store/modules/terminal/types'; import type { ShortcutKey, TerminalInteractSetting, TerminalShortcutKey } from '@/store/modules/terminal/types';
import type { ITerminalSession, ITerminalSessionHandler, TerminalDomRef } from '../types/terminal.type'; import type { ISshSession, ISshSessionHandler, XtermDomRef } from '../types/terminal.type';
import type { Terminal } from 'xterm'; import type { Terminal } from 'xterm';
import useCopy from '@/hooks/copy'; import useCopy from '@/hooks/copy';
import html2canvas from 'html2canvas'; import html2canvas from 'html2canvas';
@@ -31,21 +31,21 @@ const preventKeys: Array<ShortcutKey> = [
const { copy: copyValue, readText } = useCopy(); const { copy: copyValue, readText } = useCopy();
// 终端会话处理器实现 // ssh 会话处理器实现
export default class TerminalSessionHandler implements ITerminalSessionHandler { export default class SshSessionHandler implements ISshSessionHandler {
private readonly domRef: TerminalDomRef; private readonly domRef: XtermDomRef;
private readonly inst: Terminal; private readonly inst: Terminal;
private readonly session: ITerminalSession; private readonly session: ISshSession;
private readonly interactSetting: TerminalInteractSetting; private readonly interactSetting: TerminalInteractSetting;
private readonly shortcutKeys: Array<TerminalShortcutKey>; private readonly shortcutKeys: Array<TerminalShortcutKey>;
constructor(session: ITerminalSession, constructor(session: ISshSession,
domRef: TerminalDomRef) { domRef: XtermDomRef) {
this.session = session; this.session = session;
this.inst = session.inst; this.inst = session.inst;
this.domRef = domRef; this.domRef = domRef;

View File

@@ -1,6 +1,6 @@
import type { UnwrapRef } from 'vue'; import type { UnwrapRef } from 'vue';
import type { TerminalPreference } from '@/store/modules/terminal/types'; import type { TerminalPreference } from '@/store/modules/terminal/types';
import type { ITerminalChannel, ITerminalSession, ITerminalSessionHandler, TerminalAddons, TerminalDomRef } from '../types/terminal.type'; import type { ISshSession, ISshSessionHandler, ITerminalChannel, XtermAddons, XtermDomRef } from '../types/terminal.type';
import { useTerminalStore } from '@/store'; import { useTerminalStore } from '@/store';
import { InputProtocol } from '../types/terminal.protocol'; import { InputProtocol } from '../types/terminal.protocol';
import { fontFamilySuffix, TerminalShortcutType, TerminalStatus } from '../types/terminal.const'; import { fontFamilySuffix, TerminalShortcutType, TerminalStatus } from '../types/terminal.const';
@@ -13,10 +13,10 @@ import { CanvasAddon } from 'xterm-addon-canvas';
import { WebglAddon } from 'xterm-addon-webgl'; import { WebglAddon } from 'xterm-addon-webgl';
import { playBell } from '@/utils/bell'; import { playBell } from '@/utils/bell';
import { addEventListen } from '@/utils/event'; import { addEventListen } from '@/utils/event';
import TerminalSessionHandler from './terminal-session-handler'; import SshSessionHandler from './ssh-session-handler';
// 终端会话实现 // ssh 会话实现
export default class TerminalSession implements ITerminalSession { export default class SshSession implements ISshSession {
public readonly hostId: number; public readonly hostId: number;
@@ -30,11 +30,11 @@ export default class TerminalSession implements ITerminalSession {
public status: number; public status: number;
public handler: ITerminalSessionHandler; public handler: ISshSessionHandler;
private readonly channel: ITerminalChannel; private readonly channel: ITerminalChannel;
private readonly addons: TerminalAddons; private readonly addons: XtermAddons;
constructor(hostId: number, constructor(hostId: number,
sessionId: string, sessionId: string,
@@ -46,12 +46,12 @@ export default class TerminalSession implements ITerminalSession {
this.canWrite = false; this.canWrite = false;
this.status = TerminalStatus.CONNECTING; this.status = TerminalStatus.CONNECTING;
this.inst = undefined as unknown as Terminal; this.inst = undefined as unknown as Terminal;
this.handler = undefined as unknown as ITerminalSessionHandler; this.handler = undefined as unknown as ISshSessionHandler;
this.addons = {} as TerminalAddons; this.addons = {} as XtermAddons;
} }
// 初始化 // 初始化
init(domRef: TerminalDomRef): void { init(domRef: XtermDomRef): void {
const { preference } = useTerminalStore(); const { preference } = useTerminalStore();
// 初始化实例 // 初始化实例
this.inst = new Terminal({ this.inst = new Terminal({
@@ -65,7 +65,7 @@ export default class TerminalSession implements ITerminalSession {
scrollback: preference.sessionSetting.scrollBackLine, scrollback: preference.sessionSetting.scrollBackLine,
}); });
// 处理器 // 处理器
this.handler = new TerminalSessionHandler(this, domRef); this.handler = new SshSessionHandler(this, domRef);
// 注册快捷键 // 注册快捷键
this.registerShortcut(preference); this.registerShortcut(preference);
// 注册事件 // 注册事件

View File

@@ -1,7 +1,10 @@
import { ITerminalChannel, ITerminalOutputProcessor, ITerminalSessionManager, OutputPayload } from '../types/terminal.type'; import { ISshSession, ITerminalChannel, ITerminalOutputProcessor, ITerminalSessionManager, OutputPayload } from '../types/terminal.type';
import { InputProtocol } from '../types/terminal.protocol'; import { InputProtocol } from '../types/terminal.protocol';
import { TerminalStatus } from '../types/terminal.const'; import { TerminalStatus } from '../types/terminal.const';
import { useTerminalStore } from '@/store'; import { useTerminalStore } from '@/store';
import { Message } from '@arco-design/web-vue';
import SshSession from './ssh-session';
import SftpSession from './sftp-session';
// 终端输出消息体处理器实现 // 终端输出消息体处理器实现
export default class TerminalOutputProcessor implements ITerminalOutputProcessor { export default class TerminalOutputProcessor implements ITerminalOutputProcessor {
@@ -19,50 +22,81 @@ export default class TerminalOutputProcessor implements ITerminalOutputProcessor
processCheck({ sessionId, result, msg }: OutputPayload): void { processCheck({ sessionId, result, msg }: OutputPayload): void {
const success = !!Number.parseInt(result); const success = !!Number.parseInt(result);
const session = this.sessionManager.getSession(sessionId); const session = this.sessionManager.getSession(sessionId);
// 未成功展示错误信息 if (session instanceof SshSession) {
if (!success) { // ssh 会话
session.write(`${msg || ''}`); if (success) {
session.status = TerminalStatus.CLOSED; // 检查成功发送 connect 命令
return; const { preference } = useTerminalStore();
this.channel.send(InputProtocol.CONNECT, {
sessionId,
terminalType: preference.sessionSetting.terminalEmulationType || 'xterm',
cols: session.inst.cols,
rows: session.inst.rows
});
} else {
// 未成功展示错误信息
session.write(`${msg || ''}`);
session.status = TerminalStatus.CLOSED;
}
} else if (session instanceof SftpSession) {
// sftp 会话
if (success) {
// 检查成功发送 connect 命令
// TODO
} else {
// 未成功提示错误信息
Message.error(msg || '建立 SFTP 失败');
}
} }
const { preference } = useTerminalStore();
// 发送 connect 命令
this.channel.send(InputProtocol.CONNECT, {
sessionId,
terminalType: preference.sessionSetting.terminalEmulationType || 'xterm',
cols: session.inst.cols,
rows: session.inst.rows
});
} }
// 处理连接消息 // 处理连接消息
processConnect({ sessionId, result, msg }: OutputPayload): void { processConnect({ sessionId, result, msg }: OutputPayload): void {
const success = !!Number.parseInt(result); const success = !!Number.parseInt(result);
const session = this.sessionManager.getSession(sessionId); const session = this.sessionManager.getSession(sessionId);
// 未成功展示错误信息 if (session instanceof SshSession) {
if (!success) { // ssh 会话
session.write(`${msg || ''}`); if (success) {
session.status = TerminalStatus.CLOSED; // 设置可写
return; session.setCanWrite(true);
// 执行连接逻辑
session.connect();
} else {
// 未成功展示错误信息
session.write(`${msg || ''}`);
session.status = TerminalStatus.CLOSED;
}
} else if (session instanceof SftpSession) {
// sftp 会话
if (success) {
// 执行连接逻辑
session.connect();
} else {
// 未成功提示错误信息
Message.error(msg || '打开 SFTP 失败');
}
} }
// 设置可写
session.setCanWrite(true);
// 执行连接逻辑
session.connect();
} }
// 处理关闭消息 // 处理关闭消息
processClose({ sessionId, msg }: OutputPayload): void { processClose({ sessionId, msg }: OutputPayload): void {
const session = this.sessionManager.getSession(sessionId); const session = this.sessionManager.getSession(sessionId);
// 关闭 tab 则无需处理 // 无需处理 (直接关闭 tab )
if (session) { if (!session) {
// 提示消息 return;
}
if (session instanceof SshSession) {
// ssh 拼接关闭消息
session.write(`\r\n${msg || ''}`); session.write(`\r\n${msg || ''}`);
// 设置状态 // 设置状态
session.status = TerminalStatus.CLOSED; session.status = TerminalStatus.CLOSED;
session.connected = false; session.connected = false;
// 设置不可写 // 设置不可写
session.setCanWrite(false); session.setCanWrite(false);
} else if (session instanceof SftpSession) {
// sftp 设置状态
session.connected = false;
} }
} }
@@ -73,7 +107,7 @@ export default class TerminalOutputProcessor implements ITerminalOutputProcessor
// 处理输出消息 // 处理输出消息
processOutput({ sessionId, body }: OutputPayload): void { processOutput({ sessionId, body }: OutputPayload): void {
const session = this.sessionManager.getSession(sessionId); const session = this.sessionManager.getSession<ISshSession>(sessionId);
session && session.write(body); session && session.write(body);
} }

View File

@@ -1,10 +1,12 @@
import type { ITerminalChannel, ITerminalSession, ITerminalSessionManager, TerminalDomRef, TerminalTabItem } from '../types/terminal.type'; import type { ISftpSession, ITerminalChannel, ITerminalSession, ITerminalSessionManager, TerminalTabItem, XtermDomRef } from '../types/terminal.type';
import { sleep } from '@/utils'; import { sleep } from '@/utils';
import { InputProtocol } from '../types/terminal.protocol'; import { InputProtocol } from '../types/terminal.protocol';
import { PanelSessionType } from '../types/terminal.const';
import { useDebounceFn } from '@vueuse/core'; import { useDebounceFn } from '@vueuse/core';
import { addEventListen, removeEventListen } from '@/utils/event'; import { addEventListen, removeEventListen } from '@/utils/event';
import TerminalSession from './terminal-session';
import TerminalChannel from './terminal-channel'; import TerminalChannel from './terminal-channel';
import SshSession from './ssh-session';
import SftpSession from './sftp-session';
// 终端会话管理器实现 // 终端会话管理器实现
export default class TerminalSessionManager implements ITerminalSessionManager { export default class TerminalSessionManager implements ITerminalSessionManager {
@@ -23,15 +25,15 @@ export default class TerminalSessionManager implements ITerminalSessionManager {
this.dispatchResizeFn = useDebounceFn(this.dispatchResize).bind(this); this.dispatchResizeFn = useDebounceFn(this.dispatchResize).bind(this);
} }
// 打开终端会话 // 打开 ssh 会话
async openSession(tab: TerminalTabItem, async openSsh(tab: TerminalTabItem,
domRef: TerminalDomRef) { domRef: XtermDomRef) {
const sessionId = tab.key; const sessionId = tab.key;
const hostId = tab.hostId as number; const hostId = tab.hostId as number;
// 初始化客户端 // 初始化客户端
await this.initChannel(); await this.initChannel();
// 新建会话 // 新建会话
const session = new TerminalSession( const session = new SshSession(
hostId, hostId,
sessionId, sessionId,
this.channel this.channel
@@ -46,14 +48,37 @@ export default class TerminalSessionManager implements ITerminalSessionManager {
this.channel.send(InputProtocol.CHECK, { this.channel.send(InputProtocol.CHECK, {
sessionId, sessionId,
hostId, hostId,
connectType: 'SSH' connectType: PanelSessionType.SSH.type
});
return session;
}
// 打开 sftp 会话
async openSftp(tab: TerminalTabItem): Promise<ISftpSession> {
const sessionId = tab.key;
const hostId = tab.hostId as number;
// 初始化客户端
await this.initChannel();
// 新建会话
const session = new SftpSession(
hostId,
sessionId,
this.channel
);
// 添加会话
this.sessions[sessionId] = session;
// 发送会话初始化请求
this.channel.send(InputProtocol.CHECK, {
sessionId,
hostId,
connectType: PanelSessionType.SFTP.type
}); });
return session; return session;
} }
// 获取终端会话 // 获取终端会话
getSession(sessionId: string): ITerminalSession { getSession<T>(sessionId: string): T {
return this.sessions[sessionId]; return this.sessions[sessionId] as T;
} }
// 关闭终端会话 // 关闭终端会话
@@ -64,7 +89,7 @@ export default class TerminalSessionManager implements ITerminalSessionManager {
} }
// 关闭连接 // 关闭连接
session.disconnect(); session.disconnect();
// 关闭 session // 关闭会话
session.close(); session.close();
// 移除 session // 移除 session
this.sessions[sessionId] = undefined as unknown as ITerminalSession; this.sessions[sessionId] = undefined as unknown as ITerminalSession;
@@ -94,6 +119,8 @@ export default class TerminalSessionManager implements ITerminalSessionManager {
private dispatchResize() { private dispatchResize() {
// 对所有已连接的会话重置大小 // 对所有已连接的会话重置大小
Object.values(this.sessions) Object.values(this.sessions)
.filter(s => s instanceof SshSession)
.map(s => s as SshSession)
.filter(h => h.connected) .filter(h => h.connected)
.forEach(h => h.fit()); .forEach(h => h.fit());
} }

View File

@@ -96,13 +96,6 @@ export interface OutputPayload {
[key: string]: string; [key: string]: string;
} }
// 终端 dom 元素引用
export interface TerminalDomRef {
el: HTMLElement;
searchModal: any;
editorModal: any;
}
// 终端 tab 管理器定义 // 终端 tab 管理器定义
export interface ITerminalTabManager<T extends TerminalTabItem = TerminalTabItem> { export interface ITerminalTabManager<T extends TerminalTabItem = TerminalTabItem> {
// 当前 tab // 当前 tab
@@ -149,10 +142,12 @@ export interface ITerminalPanelManager<T extends TerminalPanelTabItem = Terminal
// 终端会话管理器定义 // 终端会话管理器定义
export interface ITerminalSessionManager { export interface ITerminalSessionManager {
// 打开终端会话 // 打开 ssh 会话
openSession: (tab: TerminalTabItem, domRef: TerminalDomRef) => Promise<ITerminalSession>; openSsh: (tab: TerminalTabItem, domRef: XtermDomRef) => Promise<ISshSession>;
// 打开 sftp 会话
openSftp: (tab: TerminalTabItem) => Promise<ISftpSession>;
// 获取终端会话 // 获取终端会话
getSession: (sessionId: string) => ITerminalSession; getSession: <T extends ITerminalSession>(sessionId: string) => T;
// 关闭终端会话 // 关闭终端会话
closeSession: (sessionId: string) => void; closeSession: (sessionId: string) => void;
// 重置 // 重置
@@ -185,8 +180,15 @@ export interface ITerminalOutputProcessor {
processOutput: (payload: OutputPayload) => void; processOutput: (payload: OutputPayload) => void;
} }
// 终端 dom 元素引用
export interface XtermDomRef {
el: HTMLElement;
searchModal: any;
editorModal: any;
}
// 终端插件 // 终端插件
export interface TerminalAddons { export interface XtermAddons {
fit: FitAddon; fit: FitAddon;
webgl: WebglAddon; webgl: WebglAddon;
canvas: CanvasAddon; canvas: CanvasAddon;
@@ -199,21 +201,30 @@ export interface TerminalAddons {
export interface ITerminalSession { export interface ITerminalSession {
hostId: number; hostId: number;
sessionId: string; sessionId: string;
// terminal 实例
inst: Terminal;
// 是否已连接 // 是否已连接
connected: boolean; connected: boolean;
// 连接
connect: () => void;
// 断开连接
disconnect: () => void;
// 关闭
close: () => void;
}
// ssh 会话定义
export interface ISshSession extends ITerminalSession {
// terminal 实例
inst: Terminal;
// 是否可写 // 是否可写
canWrite: boolean; canWrite: boolean;
// 状态 // 状态
status: number; status: number;
// 处理器 // 处理器
handler: ITerminalSessionHandler; handler: ISshSessionHandler;
// 初始化 // 初始化
init: (domRef: TerminalDomRef) => void; init: (domRef: XtermDomRef) => void;
// 连接
connect: () => void;
// 设置是否可写 // 设置是否可写
setCanWrite: (canWrite: boolean) => void; setCanWrite: (canWrite: boolean) => void;
// 写入数据 // 写入数据
@@ -226,14 +237,10 @@ export interface ITerminalSession {
fit: () => void; fit: () => void;
// 查找 // 查找
find: (word: string, next: boolean, options: ISearchOptions) => void; find: (word: string, next: boolean, options: ISearchOptions) => void;
// 断开连接
disconnect: () => void;
// 关闭
close: () => void;
} }
// 终端会话处理器定义 // ssh 会话处理器定义
export interface ITerminalSessionHandler { export interface ISshSessionHandler {
// 检测是否忽略默认行为 // 检测是否忽略默认行为
checkPreventDefault: (e: KeyboardEvent) => boolean; checkPreventDefault: (e: KeyboardEvent) => boolean;
// 启用状态 // 启用状态
@@ -278,3 +285,8 @@ export interface ITerminalSessionHandler {
// 检查追加缺失的部分 // 检查追加缺失的部分
checkAppendMissing: (value: string) => void; checkAppendMissing: (value: string) => void;
} }
// sftp 会话定义
export interface ISftpSession extends ITerminalSession {
}