forgeplus-react/src/modules/page/component/WebSSHTimer.js

335 lines
10 KiB
JavaScript
Raw Normal View History

2020-03-16 14:12:11 +08:00
// WebSSHTimer.js
import React, { Component } from 'react';
import Drawer from 'material-ui/Drawer';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import { green } from 'material-ui/colors';
import { CircularProgress } from 'material-ui/Progress';
import Tooltip from 'material-ui/Tooltip';
import Dialog, {
2020-04-28 17:23:34 +08:00
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
2020-03-16 14:12:11 +08:00
} from 'material-ui/Dialog';
import Button from 'material-ui/Button';
import axios from 'axios';
import moment from 'moment';
import MUIDialogStyleUtil from './MUIDialogStyleUtil'
import './WebSSHTimer.css'
import Popconfirm from 'antd/lib/popconfirm';
import 'antd/lib/popconfirm/style/css';
import { on, off } from 'educoder'
const styles = MUIDialogStyleUtil.getTwoButtonStyle()
const $ = window.$;
const five_min = 5 * 60 * 1000;
/*
当倒计时为0时客户端发起主动关闭ssh的请求 `close_webssh`
当倒计时到5分钟的时候提示用户是否续时每次续时时长为20分钟
如果ssh因为服务端的某些未知原因中断这里需要提供重连的策略
有输入时会暂停第一个倒计时并开启一个60s的倒计时
如果用户一直不输入则60s倒计时结束时重置第一个倒计时为20分钟并继续倒计时
https://www.trustie.net/issues/17698
TODO 每次点击申请延时按钮直接增加20分钟的时间
倒计时为0时出现重启按钮
*/
const isSSHInIframe = false;
class WebSSHTimer extends Component {
constructor(props) {
super(props)
this.startTimeRemain = 0;
// 用户点击取消时变量设置为true
2020-04-28 17:23:34 +08:00
this.isUserChoseNotConcern = false
2020-03-16 14:12:11 +08:00
this.state = {
showTimer: true, // 倒计时为0时设置为false
loading: false,
2020-04-28 17:23:34 +08:00
dialogOpen: false
2020-03-16 14:12:11 +08:00
}
}
init() {
console.log('调用定时器开始: =========>>>>>>>>>>>>');
// 20分钟倒计时
this.timeRemain = 20 * 60 * 1000;
this.startTimeRemain = 0
// 倒计时出来!
this.forceUpdate()
const { game } = this.props;
if (this.intervalHandler) {
clearInterval(this.intervalHandler);
this.intervalHandler = null;
}
this.intervalHandler = setInterval(() => {
if (this.startTimeRemain > 0) { // 等倒计时结束了再计算时间
this.startTimeRemain--;
if (this.startTimeRemain === 0) {
// 重置主倒计时时长20分钟
this.timeRemain = 20 * 60 * 1000;
$('.webSSHTimer').html(moment(this.timeRemain).format('mm:ss'))
this.forceUpdate()
}
return;
2020-04-28 17:23:34 +08:00
}
2020-03-16 14:12:11 +08:00
let _timeRemain = this.timeRemain;
$('.webSSHTimer').html(moment(_timeRemain).format('mm:ss'))
_timeRemain -= 1000
this.timeRemain = _timeRemain;
2020-04-28 17:23:34 +08:00
if (this.state.dialogOpen && _timeRemain % (60 * 1000) === 0) { //
2020-03-16 14:12:11 +08:00
this.forceUpdate()
}
// 余5分钟的时候弹框通知 // 从代码文件切换回命令行时,要查看该时间
if (_timeRemain === five_min) {
2020-04-28 17:23:34 +08:00
2020-03-16 14:12:11 +08:00
this.setState({
2020-04-28 17:23:34 +08:00
dialogOpen: true
})
2020-03-16 14:12:11 +08:00
} else if (_timeRemain <= 0) {
// 到时间了触发删除pod的请求
clearInterval(this.intervalHandler);
this.intervalHandler = null;
this.closeWebsshSocket();
// this.closeWebssh()
this.props.setSSHClosed(true)
this.setState({
showTimer: false,
2020-04-28 17:23:34 +08:00
dialogOpen: false // 弹框可能未被关闭
2020-03-16 14:12:11 +08:00
})
}
}, 1000)
}
closeWebsshSocket = () => {
// 非iframe模式使用
2020-04-28 17:23:34 +08:00
window.postMessage({ tp: 'close_ssh_cocket' }, "*");
2020-03-16 14:12:11 +08:00
/**
启用iframe模式需要改的地方
ssh消息的发送和接收消息得种类有
发送
1postMessage({tp: 'sshWorking'}, "*"); ssh正在被使用
2window.parent.postMessage({tp: 'setSSHConnectStatus', tab: options.tab}, "*");
接收
1 if(event.data.tp === 'resize'){ 改变命令行窗体大小
2 } else if (event.data.tp === 'reload') { 异常中断后重连
3 } else if (event.data.tp === 'close_ssh_cocket') { 中断命令行websocket
接收1的发送代码位于
js_min_all.js的这个方法function update_rows_and_cols(rows) {
其余的代码位于CodeRepository.js WebSSHTimer.js
*/
// iframe模式使用
// TODO 这里多ssh tab的话需要调用每个window的 close_ssh_cocket
// let windows = this.getWebsshWindows();
// for (let i = 0; i < windows.length; i++) {
// let _w = windows[i].contentWindow
// _w && _w.postMessage({tp: 'close_ssh_cocket'}, "*");
// }
}
// 重置命令行的时候调用的接口会删pod
closeWebssh = (callback) => {
// 先关socket
this.closeWebsshSocket()
const { game } = this.props;
// const url = `/api/v1/games/${game.identifier}/close_webssh`
const url = `/tasks/${game.identifier}/close_webssh.json`
2020-04-28 17:23:34 +08:00
axios.get(url, {},
{
// withCredentials: true
}
2020-03-16 14:12:11 +08:00
).then((response) => {
2020-04-28 17:23:34 +08:00
if (response.data.status === 1) {
2020-03-16 14:12:11 +08:00
}
callback && callback(response)
}).catch((error) => {
console.log(error)
})
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 仅初始化一次
if (prevProps.showTimerProp === false && this.props.showTimerProp === true) {
if (this.intervalHandler) {
const { showTimer } = this.state;
// 用户从代码切换命令行,如果时间不够了也要提示是否续时
if (this.isUserChoseNotConcern === false && showTimer === true && this.timeRemain < five_min) {
this.setState({
dialogOpen: true
})
}
} else {
this.init()
}
}
}
componentDidMount() {
// 发现非iframe ssh也能使用postMessage
// iframe时使用的消息机制
// if (isSSHInIframe === true) {
2020-04-28 17:23:34 +08:00
window.addEventListener('message', (e) => {
if (this.state.showTimer === false) { // 已经触发了close_webssh
return;
}
if (e.data.tp === "setSSHConnectStatus") {
this.props.reInitSsh(window.$, null, true)
} else if (e.data.tp === "sshWorking") {
}
});
2020-03-16 14:12:11 +08:00
}
getWebsshWindows = () => {
return $('.game_webssh')
}
componentWillUnmount() {
this.intervalHandler && clearInterval(this.intervalHandler);
}
handleDialogClose = () => {
this.setState({
dialogOpen: false
})
}
onNope = () => {
// 用户不续时移除interval无需再显示Timer
// 用户不续时隐藏dialog
this.setState({
2020-04-28 17:23:34 +08:00
// showTimer: false,
2020-03-16 14:12:11 +08:00
dialogOpen: false
})
this.isUserChoseNotConcern = true
// this.intervalHandler && clearInterval(this.intervalHandler);
}
onOK = () => {
// 用户续时,+15min // 用户操作多次后,自动续时?
if (this.timeRemain > 0) {
this.timeRemain += 20 * 60 * 1000;
}
this.setState({
dialogOpen: false
})
}
reInitSsh = () => {
this.setState({
showTimer: true
})
this.init();
this.props.reInitSsh(window.$, null, true)
}
resetSsh = () => {
this.closeWebssh((res) => {
// message: webssh closed
if (res.data.status === 1) {
this.reInitSsh()
}
})
}
render() {
const { myshixun, showUpdateDialog, classes } = this.props;
const { showTimer, loading, dialogOpen } = this.state;
2020-04-28 17:23:34 +08:00
return (
<React.Fragment>
<Dialog
disableBackdropClick={true}
className="updateDialog"
open={dialogOpen && this.isUserChoseNotConcern === false}
onClose={() => this.handleDialogClose()}
>
<DialogTitle id="alert-dialog-title">{"命令行连接时长提醒"}</DialogTitle>
<DialogContent id="dialog-content">
<div style={{ textAlign: 'center' }}>
命令行将于 {moment(this.timeRemain).format('m')} 分钟后中断需要延长使用时间吗
2020-03-16 14:12:11 +08:00
</div>
2020-04-28 17:23:34 +08:00
</DialogContent>
<DialogActions id="dialog-actions">
<React.Fragment>
<Button
disabled={loading}
className={"nextUpdate " + classes.button + ' ' + classes.buttonGray} onClick={() => this.onNope()} color="primary" >
不需要
2020-03-16 14:12:11 +08:00
</Button>
2020-04-28 17:23:34 +08:00
<Button
disabled={loading}
variant="raised" onClick={() => this.onOK()} color="primary" className={"updateNow " + classes.button}>
立即延长
2020-03-16 14:12:11 +08:00
</Button>
2020-04-28 17:23:34 +08:00
{/* loading && <CircularProgress size={24} className={classes.buttonProgress} /> */}
</React.Fragment>
2020-03-16 14:12:11 +08:00
}
</DialogActions>
2020-04-28 17:23:34 +08:00
</Dialog>
<Tooltip title="中断命令行连接的倒计时">
{/* <span className="webSSHTimer"
2020-03-16 14:12:11 +08:00
style={{ display: (showTimer && this.props.showTimerProp === true &&
this.startTimeRemain <= 0 ? 'inline-block' : 'none')}}>
</span> */}
2020-04-28 17:23:34 +08:00
<a className="iconButton"
style={{
display: (showTimer && this.props.showTimerProp === true &&
this.startTimeRemain <= 0 ? 'inline-block' : 'none'),
cursor: 'default'
}} >
<i className="iconfont icon-shijian font-16 "></i>
<span className="webSSHTimer"></span>
</a>
</Tooltip>
{this.props.showTimerProp === true && showTimer === true &&
<Popconfirm
title={<React.Fragment><div>实验环境将恢复到初始状态</div><div>?</div></React.Fragment>}
placement="bottom"
onConfirm={this.resetSsh} okText="确定" cancelText="取消">
<a className="iconButton" >
2020-03-16 14:12:11 +08:00
<i className="iconfont icon-zhongzhi2 font-16 "></i>
2020-04-28 17:23:34 +08:00
<span style={{
userSelect: 'none', verticalAlign: 'middle',
fontSize: '13px', marginLeft: '2px'
}}>
重置命令行</span>
2020-03-16 14:12:11 +08:00
</a>
2020-04-28 17:23:34 +08:00
</Popconfirm>
}
{/* <Tooltip title={ ""} disableFocusListener={true}>
2020-03-16 14:12:11 +08:00
</Tooltip> */}
2020-04-28 17:23:34 +08:00
{showTimer === false && this.props.showTimerProp === true &&
<a className="iconButton" onClick={this.reInitSsh} >
<i className="iconfont icon-congshulianjie font-16 "></i>
<span style={{
userSelect: 'none', verticalAlign: 'middle',
fontSize: '13px', marginLeft: '2px'
}}>
重连命令行</span>
</a>
}
{/* <Tooltip title={ "命令行重连"} disableFocusListener={true}></Tooltip> */}
</React.Fragment>
);
}
2020-03-16 14:12:11 +08:00
}
2020-04-28 17:23:34 +08:00
export default withStyles(styles)(WebSSHTimer);