(web) more xtermjs related changes and cleanup

This commit is contained in:
Alexey Kontsevoy 2017-05-02 11:37:33 -04:00
parent 2cb82a5dbe
commit e969e55dc4
6 changed files with 119 additions and 106 deletions

View file

@ -15,16 +15,16 @@ limitations under the License.
*/
import React from 'react';
import PartyListPanel from './../partyListPanel';
import { connect } from 'nuclear-js-react-addons';
import { EventTypeEnum } from 'app/lib/term/enums';
import Terminal from 'app/lib/term/terminal';
import termGetters from 'app/flux/terminal/getters';
import Indicator from './../indicator.jsx';
import { initTerminal, updateRoute, close } from 'app/flux/terminal/actions';
import { updateSession } from 'app/flux/sessions/actions';
import { openPlayer } from 'app/flux/player/actions';
import PartyListPanel from './../partyListPanel';
import Indicator from './../indicator.jsx';
import PartyList from './terminalPartyList';
import { EventTypeEnum } from 'app/lib/term/enums';
import { connect } from 'nuclear-js-react-addons';
class TerminalHost extends React.Component {
@ -117,25 +117,13 @@ class TerminalContainer extends React.Component {
return ( <div ref="container"/> );
}
receiveEvents(data) {
// loop through events in reverse order to find the last resize event to sync the screen size.
data.events.reverse().every(item => {
let { event, size } = item;
// exit terminal if session is ended
if (event === EventTypeEnum.END) {
close();
}
if (event === EventTypeEnum.RESIZE) {
let [w, h] = size.split(':');
this.terminal.resize(Number(w), Number(h));
return false;
}
return true;
});
receiveEvents(data) {
let hasEnded = data.events.some(item => item.event === EventTypeEnum.END);
if (hasEnded) {
close();
}
// updates active sessin participant list
updateSession({
siteId: this.props.siteId,
json: data.session

View file

@ -1,6 +1,26 @@
/*
Copyright 2015 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export const EventTypeEnum = {
START: 'session.start',
END: 'session.end',
PRINT: 'print',
RESIZE: 'resize'
}
export const StatusCodeEnum = {
NORMAL: 1000
}

View file

@ -58,7 +58,7 @@ class TtyTerminal {
open() {
$(this._el).addClass(GRV_CLASS);
// render xtermjs with default values (will be used to calculate the character size)
// render xtermjs with default values
this.term = new Term({
cols: 15,
rows: 5,
@ -68,20 +68,25 @@ class TtyTerminal {
this.term.open(this._el);
// resize to available space (by given container)
// resize xterm to available space
this.resize(this.cols, this.rows);
// subscribe xtermjs output
// subscribe to xtermjs output
this.term.on('data', data => this.tty.send(data));
// subscribe to tty events
this.tty.on('resize', ({h, w}) => this.resize(w, h));
// subscribe to tty
this.tty.on('reset', this.reset.bind(this));
this.tty.on('close', this._processClose.bind(this));
this.tty.on('data', this._processData.bind(this));
this.connect();
this.tty.on('data', this._processData.bind(this));
// subscribe tty resize event (used by session player)
this.tty.on('resize', ({h, w}) => this.resize(w, h));
// subscribe to window resize events
window.addEventListener('resize', this.debouncedResize);
// subscribe to session resize events (triggered by other participants)
this.ttyEvents.on('resize', ({h, w}) => this.resize(w, h));
this.connect();
}
connect(){
@ -113,7 +118,7 @@ class TtyTerminal {
rows = dim.rows;
}
if( cols === this.cols && rows === this.rows){
if(cols === this.cols && rows === this.rows){
return;
}
@ -122,7 +127,7 @@ class TtyTerminal {
this.term.resize(cols, rows);
} catch (err) {
logger.info('resize', { w: cols, h: rows }, err);
logger.error('resize', { w: cols, h: rows }, err);
this.term.reset();
}
}
@ -149,15 +154,11 @@ class TtyTerminal {
this.term.write(displayText)
}
_disconnect() {
if(this.tty !== null){
this.tty.disconnect();
}
if(this.ttyEvents !== null){
this.ttyEvents.disconnect();
this.ttyEvents.removeAllListeners();
}
_disconnect() {
this.tty.disconnect();
this.tty.removeAllListeners();
this.ttyEvents.disconnect();
this.ttyEvents.removeAllListeners();
}
_requestResize(){
@ -174,7 +175,7 @@ class TtyTerminal {
logger.info('requesting new screen size', `w:${w} and h:${h}`);
this.resize(w, h);
api.put(`${url}/sessions/${sid}`, reqData)
api.put(`${url}/sessions/${sid}`, reqData)
.fail(err => logger.error('request new screen size', err));
}
@ -221,11 +222,9 @@ class TtyTerminal {
let urlPrefix = getWsHostName();
return `${urlPrefix}${url}/connect?access_token=${token}&params=${jsonEncoded}`;
}
}
}
function getWsHostName(){
var prefix = location.protocol == "https:"?"wss://":"ws://";
var hostport = location.hostname+(location.port ? ':'+location.port: '');

View file

@ -15,7 +15,10 @@ limitations under the License.
*/
import { EventEmitter } from 'events';
import { StatusCodeEnum } from './ttyEnums';
import { StatusCodeEnum } from './enums';
import Logger from './../logger';
const logger = Logger.create('Tty');
const defaultOptions = {
buffered: true
@ -41,19 +44,12 @@ class Tty extends EventEmitter {
this._onReceiveData = this._onReceiveData.bind(this);
}
disconnect(reasonCode = StatusCodeEnum.NORMAL){
this.socket.close(reasonCode);
disconnect(reasonCode = StatusCodeEnum.NORMAL) {
if (this.socket !== null) {
this.socket.close(reasonCode);
}
}
reconnect(options){
this.disconnect();
this.socket.onopen = null;
this.socket.onmessage = null;
this.socket.onclose = null;
this.socket = null;
this.connect(options);
}
connect(connStr) {
this.socket = new WebSocket(connStr);
this.socket.onopen = this._onOpenConnection;
@ -83,10 +79,16 @@ class Tty extends EventEmitter {
_onOpenConnection() {
this.emit('open');
logger.info('websocket is open');
}
_onCloseConnection(e) {
this.socket.onopen = null;
this.socket.onmessage = null;
this.socket.onclose = null;
this.socket = null;
this.emit('close', e);
logger.info('websocket is closed');
}
_onReceiveData(ev) {

View file

@ -1,24 +0,0 @@
/*
Copyright 2015 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const StatusCodeEnum = {
NORMAL: 1000
}
export {
StatusCodeEnum
}

View file

@ -15,42 +15,70 @@ limitations under the License.
*/
import { EventEmitter } from 'events';
import { StatusCodeEnum } from './ttyEnums';
import { StatusCodeEnum, EventTypeEnum } from './enums';
import { sortBy } from 'lodash';
const logger = require('./../logger').create('TtyEvents');
import Logger from './../logger';
const logger = Logger.create('TtyEvents');
class TtyEvents extends EventEmitter {
constructor(){
super();
super();
this.socket = null;
}
connect(connStr){
this.socket = new WebSocket(connStr);
this.socket.onmessage = this._onReceiveMessage.bind(this);
this.socket.onclose = this._onCloseConnection.bind(this);
this.socket.onopen = () => {
logger.info('Tty event stream is open');
}
this.socket.onmessage = (event) => {
try
{
let json = JSON.parse(event.data);
this.emit('data', json);
}
catch(err){
logger.error('failed to parse event stream data', err);
}
};
this.socket.onclose = () => {
logger.info('Tty event stream is closed');
};
logger.info('websocket is open');
}
}
disconnect(reasonCode = StatusCodeEnum.NORMAL){
this.socket.close(reasonCode);
disconnect(reasonCode = StatusCodeEnum.NORMAL) {
if (this.socket !== null) {
this.socket.close(reasonCode);
}
}
_onCloseConnection(e) {
this.socket.onmessage = null;
this.socket.onopen = null;
this.socket.onclose = null;
this.emit('close', e);
logger.info('websocket is closed');
}
_onReceiveMessage(message) {
try
{
let json = JSON.parse(message.data);
this._processResize(json.events)
this.emit('data', json);
}
catch(err){
logger.error('failed to parse event stream data', err);
}
}
_processResize(events){
events = events || [];
// filter resize events
let resizes = events.filter(
item => item.event === EventTypeEnum.RESIZE);
sortBy(resizes, ['ms']);
if(resizes.length > 0){
// get values from the last resize event
let [w, h] = resizes[resizes.length-1].size.split(':');
w = Number(w);
h = Number(h);
this.emit('resize', { w, h });
}
}
}