mirror of
https://github.com/bingohuang/docker-labs.git
synced 2025-10-05 18:03:21 +08:00
Huge refactor to have everything working with socket.io
It fixes lots of bugs, can fallback to long polling, resize viewport of terminals and share clients state of the session, so they all see the same thing.
This commit is contained in:
@@ -3,34 +3,59 @@
|
||||
|
||||
var app = angular.module('DockerPlay', ['ngMaterial']);
|
||||
|
||||
app.controller('PlayController', ['$scope', '$log', '$http', '$location', '$timeout', '$mdDialog', function($scope, $log, $http, $location, $timeout, $mdDialog) {
|
||||
app.controller('PlayController', ['$scope', '$log', '$http', '$location', '$timeout', '$mdDialog', '$window', function($scope, $log, $http, $location, $timeout, $mdDialog, $window) {
|
||||
$scope.sessionId = window.location.pathname.replace('/p/', '');
|
||||
$scope.instances = [];
|
||||
$scope.idx = {};
|
||||
$scope.selectedInstance = null;
|
||||
$scope.isAlive = true;
|
||||
|
||||
$scope.showAlert = function(title, content) {
|
||||
angular.element($window).bind('resize', function(){
|
||||
if ($scope.selectedInstance) {
|
||||
$scope.resize($scope.selectedInstance.term.proposeGeometry());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$scope.showAlert = function(title, content, parent) {
|
||||
$mdDialog.show(
|
||||
$mdDialog.alert()
|
||||
.parent(angular.element(document.querySelector('#popupContainer')))
|
||||
.parent(angular.element(document.querySelector(parent || '#popupContainer')))
|
||||
.clickOutsideToClose(true)
|
||||
.title(title)
|
||||
.textContent(content)
|
||||
.ok('Got it!')
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$scope.resize = function(geometry) {
|
||||
$scope.socket.emit('viewport resize', geometry.cols, geometry.rows);
|
||||
}
|
||||
|
||||
$scope.upsertInstance = function(info) {
|
||||
var i = info;
|
||||
if (!$scope.idx[i.name]) {
|
||||
$scope.instances.push(i);
|
||||
i.buffer = '';
|
||||
$scope.idx[i.name] = i;
|
||||
} else {
|
||||
$scope.idx[i.name].ip = i.ip;
|
||||
}
|
||||
|
||||
return $scope.idx[i.name];
|
||||
}
|
||||
|
||||
$scope.newInstance = function() {
|
||||
$http({
|
||||
method: 'POST',
|
||||
url: '/sessions/' + $scope.sessionId + '/instances',
|
||||
}).then(function(response) {
|
||||
var i = response.data;
|
||||
$scope.instances.push(i);
|
||||
$scope.showInstance(i);
|
||||
var i = $scope.upsertInstance(response.data);
|
||||
$scope.showInstance(i);
|
||||
}, function(response) {
|
||||
if (response.status == 409) {
|
||||
$scope.showAlert('Max instances reached', 'Maximum number of instances reached')
|
||||
}
|
||||
if (response.status == 409) {
|
||||
$scope.showAlert('Max instances reached', 'Maximum number of instances reached')
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -39,18 +64,64 @@
|
||||
method: 'GET',
|
||||
url: '/sessions/' + $scope.sessionId,
|
||||
}).then(function(response) {
|
||||
var socket = io({path: '/sessions/' + sessionId + '/ws'});
|
||||
|
||||
socket.on('terminal out', function(name, data) {
|
||||
var instance = $scope.idx[name];
|
||||
|
||||
if (!instance) {
|
||||
// instance is new and was created from another client, we should add it
|
||||
$scope.upsertInstance({name: name});
|
||||
instance = $scope.idx[name];
|
||||
}
|
||||
if (!instance.term) {
|
||||
instance.buffer += data;
|
||||
} else {
|
||||
instance.term.write(data);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('session end', function() {
|
||||
$scope.showAlert('Session timedout!', 'Your session has expire and all your instances has been deleted.', '#sessionEnd')
|
||||
$scope.isAlive = false;
|
||||
});
|
||||
|
||||
socket.on('viewport', function(rows, cols) {
|
||||
});
|
||||
|
||||
socket.on('new instance', function(name, ip) {
|
||||
$scope.upsertInstance({name: name, ip: ip});
|
||||
$scope.$apply(function() {
|
||||
if ($scope.instances.length == 1) {
|
||||
$scope.showInstance($scope.instances[0]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('delete instance', function(name) {
|
||||
$scope.removeInstance(name);
|
||||
$scope.$apply();
|
||||
});
|
||||
|
||||
socket.on('viewport resize', function(cols, rows) {
|
||||
// viewport has changed, we need to resize all terminals
|
||||
|
||||
$scope.instances.forEach(function(instance) {
|
||||
instance.term.resize(cols, rows);
|
||||
});
|
||||
});
|
||||
|
||||
$scope.socket = socket;
|
||||
|
||||
var i = response.data;
|
||||
for (var k in i.instances) {
|
||||
var instance = i.instances[k];
|
||||
|
||||
$scope.instances.push(instance);
|
||||
$scope.idx[instance.name] = instance;
|
||||
}
|
||||
if ($scope.instances.length) {
|
||||
$scope.showInstance($scope.instances[0]);
|
||||
$scope.showInstance($scope.instances[0]);
|
||||
}
|
||||
|
||||
// Since session exists, we check it still exists every 10 seconds
|
||||
$scope.checkHandler = setInterval(checkSession, 10*1000);
|
||||
}, function(response) {
|
||||
if (response.status == 404) {
|
||||
document.write('session not found');
|
||||
@@ -59,25 +130,41 @@
|
||||
});
|
||||
}
|
||||
|
||||
$scope.showInstance = function(instance) {
|
||||
$scope.selectedInstance = instance;
|
||||
if (!instance.isAttached) {
|
||||
$timeout(function() {instance.term = createTerminal(instance.name);});
|
||||
instance.isAttached = true;
|
||||
} else {
|
||||
$timeout(function() {instance.term.focus()});
|
||||
}
|
||||
}
|
||||
$scope.showInstance = function(instance) {
|
||||
$scope.selectedInstance = instance;
|
||||
if (!instance.creatingTerminal) {
|
||||
instance.creatingTerminal = true;
|
||||
if (!instance.term) {
|
||||
$timeout(function() {
|
||||
createTerminal(instance);
|
||||
instance.term.focus();
|
||||
}, 0, false);
|
||||
} else {
|
||||
$timeout(function() {
|
||||
instance.term.focus();
|
||||
}, 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scope.removeInstance = function(name) {
|
||||
if ($scope.idx[name]) {
|
||||
delete $scope.idx[name];
|
||||
$scope.instances = $scope.instances.filter(function(i) {
|
||||
return i.name != name;
|
||||
});
|
||||
if ($scope.instances.length) {
|
||||
$scope.showInstance($scope.instances[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scope.deleteInstance = function(instance) {
|
||||
$http({
|
||||
method: 'DELETE',
|
||||
url: '/sessions/' + $scope.sessionId + '/instances/' + instance.name,
|
||||
}).then(function(response) {
|
||||
$scope.instances = $scope.instances.filter(function(i) { return i.name != instance.name });
|
||||
if ($scope.instances.length) {
|
||||
$scope.showInstance($scope.instances[0]);
|
||||
}
|
||||
$scope.removeInstance(instance.name);
|
||||
}, function(response) {
|
||||
console.log('error', response);
|
||||
});
|
||||
@@ -85,16 +172,35 @@
|
||||
|
||||
$scope.getSession($scope.sessionId);
|
||||
|
||||
function checkSession() {
|
||||
$http({
|
||||
method: 'GET',
|
||||
url: '/sessions/' + $scope.sessionId,
|
||||
}).then(function(response) {}, function(response) {
|
||||
if (response.status == 404) {
|
||||
clearInterval($scope.checkHandler);
|
||||
$scope.showAlert('Session timedout!', 'Your session has expire and all your instances has been deleted.')
|
||||
}
|
||||
});
|
||||
}
|
||||
function createTerminal(instance, cb) {
|
||||
if (instance.term) {
|
||||
return instance.term;
|
||||
}
|
||||
|
||||
var terminalContainer = document.getElementById('terminal-'+ instance.name);
|
||||
|
||||
var term = new Terminal({
|
||||
cursorBlink: false
|
||||
});
|
||||
|
||||
term.open(terminalContainer);
|
||||
|
||||
$scope.resize(term.proposeGeometry());
|
||||
|
||||
term.on('data', function(d) {
|
||||
$scope.socket.emit('terminal in', instance.name, d);
|
||||
});
|
||||
|
||||
instance.term = term;
|
||||
|
||||
if (instance.buffer) {
|
||||
term.write(instance.buffer);
|
||||
instance.buffer = '';
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}]);
|
||||
})();
|
||||
|
Reference in New Issue
Block a user