import React, {Component} from 'react';
import Guacamole from 'guacamole-common-js';
import {Affix, Button, Drawer, Dropdown, Form, Input, Menu, message, Modal, Tooltip} from 'antd'
import qs from "qs";
import request from "../../common/request";
import {wsServer} from "../../common/env";
import {
CodeOutlined,
CopyOutlined,
ExclamationCircleOutlined,
ExpandOutlined,
FolderOutlined,
LineChartOutlined,
WindowsOutlined
} from '@ant-design/icons';
import {exitFull, getToken, isEmpty, requestFullScreen, setToken} from "../../utils/utils";
import './Access.css'
import Draggable from 'react-draggable';
import FileSystem from "../devops/FileSystem";
import Stats from "./Stats";
import {Base64} from "js-base64";
const {TextArea} = Input;
const STATE_IDLE = 0;
const STATE_CONNECTING = 1;
const STATE_WAITING = 2;
const STATE_CONNECTED = 3;
const STATE_DISCONNECTING = 4;
const STATE_DISCONNECTED = 5;
class Access extends Component {
clipboardFormRef = React.createRef();
statsRef = undefined;
error = false;
state = {
session: {},
sessionId: '',
client: undefined,
scale: 1,
clientState: STATE_IDLE,
clipboardVisible: false,
clipboardText: '',
containerOverflow: 'hidden',
containerWidth: 1024,
containerHeight: 768,
uploadAction: '',
uploadHeaders: {},
keyboard: {},
protocol: '',
confirmLoading: false,
uploadVisible: false,
uploadLoading: false,
startTime: new Date(),
fullScreen: false,
fullScreenBtnText: '进入全屏',
sink: undefined,
commands: [],
showFileSystem: false,
external: false,
fixedSize: false,
};
async componentDidMount() {
let href = window.location.href;
let search = href.split('?')[1];
let urlParams = new URLSearchParams(search);
let assetId = urlParams.get('assetId');
document.title = urlParams.get('assetName');
if (!assetId) {
this.showMessage('获取资产ID失败');
return;
}
let protocol = urlParams.get('protocol');
let width = urlParams.get('width');
let height = urlParams.get('height');
let fixedSize = false;
if (width && height) {
fixedSize = true
} else {
width = window.innerWidth;
height = window.innerHeight;
}
let shareSessionId = urlParams.get('shareSessionId');
let external = false;
if (shareSessionId && shareSessionId !== '') {
setToken(shareSessionId);
external = true;
let shareSession = await this.getShareSession(shareSessionId);
if (!shareSession) {
return
}
assetId = shareSession['assetId'];
}
let session = await this.createSession(assetId);
if (!session) {
return;
}
let sessionId = session['id'];
if (isEmpty(sessionId)) {
return;
}
this.setState({
session: session,
sessionId: sessionId,
protocol: protocol,
showFileSystem: session['fileSystem'] === '1',
external: external,
fixedSize: fixedSize,
containerWidth: width,
containerHeight: height,
});
this.renderDisplay(sessionId, protocol, width, height);
window.addEventListener('resize', this.onWindowResize);
window.addEventListener('beforeunload', this.handleUnload);
window.onfocus = this.onWindowFocus;
}
componentWillUnmount() {
if (this.state.client) {
this.state.client.disconnect();
}
window.removeEventListener('beforeunload', this.handleUnload);
}
sendClipboard(data) {
if (this.state.session['paste'] === '0') {
// message.warn('禁止粘贴');
return
}
let writer;
// Create stream with proper mimetype
const stream = this.state.client.createClipboardStream(data.type);
// Send data as a string if it is stored as a string
if (typeof data.data === 'string') {
writer = new Guacamole.StringWriter(stream);
writer.sendText(data.data);
writer.sendEnd();
} else {
// Write File/Blob asynchronously
writer = new Guacamole.BlobWriter(stream);
writer.oncomplete = function clipboardSent() {
writer.sendEnd();
};
// Begin sending data
writer.sendBlob(data.data);
}
this.setState({
clipboardText: data.data
})
if (this.state.protocol === 'ssh') {
if (data.data && data.data.length > 0) {
// message.info('您输入的内容已复制到远程服务器上,使用右键将自动粘贴。');
}
} else {
if (data.data && data.data.length > 0) {
// message.info('您输入的内容已复制到远程服务器上');
}
}
}
onTunnelStateChange = (state) => {
console.log(state)
if (state === Guacamole.Tunnel.State.CLOSED) {
console.log('web socket 已关闭');
}
};
updateSessionStatus = async (sessionId) => {
let result = await request.post(`/sessions/${sessionId}/connect`);
if (result.code !== 1) {
message.error(result.message);
}
}
getCommands = async () => {
let result = await request.get('/commands');
if (result.code !== 1) {
message.error(result.message);
return;
}
this.setState({
commands: result['data']
})
}
onClientStateChange = (state) => {
this.setState({
clientState: state
});
switch (state) {
case STATE_IDLE:
message.destroy();
message.loading('正在初始化中...', 0);
break;
case STATE_CONNECTING:
message.destroy();
message.loading('正在努力连接中...', 0);
break;
case STATE_WAITING:
message.destroy();
message.loading('正在等待服务器响应...', 0);
break;
case STATE_CONNECTED:
this.onWindowResize(null);
Modal.destroyAll();
message.destroy();
message.success('连接成功');
// 向后台发送请求,更新会话的状态
this.updateSessionStatus(this.state.sessionId).then(_ => {
})
if (this.state.protocol === 'ssh' && !this.state.external) {
// 加载指令
this.getCommands();
}
break;
case STATE_DISCONNECTING:
break;
case STATE_DISCONNECTED:
if (!this.error) {
this.showMessage('连接已关闭');
}
break;
default:
break;
}
};
onError = (status) => {
this.error = true;
console.log('通道异常。', status);
switch (status.code) {
case 256:
this.showMessage('未支持的访问');
break;
case 512:
this.showMessage('远程服务异常,请检查目标设备能否正常访问。');
break;
case 513:
this.showMessage('服务器忙碌');
break;
case 514:
this.showMessage('服务器连接超时');
break;
case 515:
this.showMessage('远程服务异常');
break;
case 516:
this.showMessage('资源未找到');
break;
case 517:
this.showMessage('资源冲突');
break;
case 518:
this.showMessage('资源已关闭');
break;
case 519:
this.showMessage('远程服务未找到');
break;
case 520:
this.showMessage('远程服务不可用');
break;
case 521:
this.showMessage('会话冲突');
break;
case 522:
this.showMessage('会话连接超时');
break;
case 523:
this.showMessage('会话已关闭');
break;
case 768:
this.showMessage('网络不可达');
break;
case 769:
this.showMessage('服务器密码验证失败');
break;
case 771:
this.showMessage('客户端被禁止');
break;
case 776:
this.showMessage('客户端连接超时');
break;
case 781:
this.showMessage('客户端异常');
break;
case 783:
this.showMessage('错误的请求类型');
break;
case 800:
this.showMessage('会话不存在');
break;
case 801:
this.showMessage('创建隧道失败,请检查Guacd服务是否正常。');
break;
case 802:
this.showMessage('管理员强制关闭了此会话');
break;
default:
if (status.message) {
// guacd 无法处理中文字符,所以进行了base64编码。
this.showMessage(Base64.decode(status.message));
} else {
this.showMessage('未知错误。');
}
}
};
showMessage(msg) {
message.destroy();
Modal.confirm({
title: '提示',
icon: