Hooking SocketService.subscribe function to $stateExtender

so that socket rooms can be configured on each route that needs sockets s
This commit is contained in:
Jared Tabor
2016-09-07 15:48:56 -07:00
parent 5b1d4f3d67
commit aa4a8f6089
6 changed files with 295 additions and 448 deletions

View File

@@ -240,87 +240,98 @@ var tower = angular.module('Tower', [
}); });
$stateProvider. $stateProvider.
state('dashboard', { // state('dashboard', {
url: '/home', // url: '/home',
templateUrl: urlPrefix + 'partials/home.html', // templateUrl: urlPrefix + 'partials/home.html',
controller: Home, // controller: Home,
params: { licenseMissing: null }, // params: { licenseMissing: null },
data: { // data: {
activityStream: true, // activityStream: true,
refreshButton: true // refreshButton: true
}, // },
ncyBreadcrumb: { // ncyBreadcrumb: {
label: "DASHBOARD" // label: "DASHBOARD"
}, // },
resolve: { // resolve: {
graphData: ['$q', 'jobStatusGraphData', '$rootScope', // graphData: ['$q', 'jobStatusGraphData', '$rootScope',
function($q, jobStatusGraphData, $rootScope) { // function($q, jobStatusGraphData, $rootScope) {
return $rootScope.featuresConfigured.promise.then(function() { // return $rootScope.featuresConfigured.promise.then(function() {
return $q.all({ // return $q.all({
jobStatus: jobStatusGraphData.get("month", "all"), // jobStatus: jobStatusGraphData.get("month", "all"),
}); // });
}); // });
} // }
] // ]
} // }
}). // }).
//
state('jobs', { // state('jobs', {
url: '/jobs', // url: '/jobs',
templateUrl: urlPrefix + 'partials/jobs.html', // templateUrl: urlPrefix + 'partials/jobs.html',
controller: JobsListController, // controller: JobsListController,
ncyBreadcrumb: { // ncyBreadcrumb: {
label: "JOBS" // label: "JOBS"
} // }
}). // }).
//
state('projects', { // state('projects', {
url: '/projects?{status}', // url: '/projects?{status}',
templateUrl: urlPrefix + 'partials/projects.html', // templateUrl: urlPrefix + 'partials/projects.html',
controller: ProjectsList, // controller: ProjectsList,
data: { // data: {
activityStream: true, // activityStream: true,
activityStreamTarget: 'project' // activityStreamTarget: 'project'
}, // },
ncyBreadcrumb: { // ncyBreadcrumb: {
label: "PROJECTS" // label: "PROJECTS"
} // },
}). // // socket: '{"groups":{"jobs": ["status_changed"]}}'
// // resolve: {
state('projects.add', { // // socket: ['SocketService', '$rootScope',
url: '/add', // // function(SocketService, $rootScope) {
templateUrl: urlPrefix + 'partials/projects.html', // // var self = this;
controller: ProjectsAdd, // // $rootScope.socketPromise.promise.then(function(){
ncyBreadcrumb: { // // SocketService.subscribe(self);
parent: "projects", // // return true;
label: "CREATE PROJECT" // // });
} // // }]
}). // // },
// }).
state('projects.edit', { //
url: '/:id', // state('projects.add', {
templateUrl: urlPrefix + 'partials/projects.html', // url: '/add',
controller: ProjectsEdit, // templateUrl: urlPrefix + 'partials/projects.html',
data: { // controller: ProjectsAdd,
activityStreamId: 'id' // ncyBreadcrumb: {
}, // parent: "projects",
ncyBreadcrumb: { // label: "CREATE PROJECT"
parent: 'projects', // }
label: '{{name}}' // }).
} //
}). // state('projects.edit', {
// url: '/:id',
state('projectOrganizations', { // templateUrl: urlPrefix + 'partials/projects.html',
url: '/projects/:project_id/organizations', // controller: ProjectsEdit,
templateUrl: urlPrefix + 'partials/projects.html', // data: {
controller: OrganizationsList // activityStreamId: 'id'
}). // },
// ncyBreadcrumb: {
state('projectOrganizationAdd', { // parent: 'projects',
url: '/projects/:project_id/organizations/add', // label: '{{name}}'
templateUrl: urlPrefix + 'partials/projects.html', // }
controller: OrganizationsAdd // }).
}). //
// state('projectOrganizations', {
// url: '/projects/:project_id/organizations',
// templateUrl: urlPrefix + 'partials/projects.html',
// controller: OrganizationsList
// }).
//
// state('projectOrganizationAdd', {
// url: '/projects/:project_id/organizations/add',
// templateUrl: urlPrefix + 'partials/projects.html',
// controller: OrganizationsAdd
// }).
state('teams', { state('teams', {
url: '/teams', url: '/teams',
@@ -523,18 +534,126 @@ var tower = angular.module('Tower', [
}]); }]);
}]) }])
.run(['$q', '$compile', '$cookieStore', '$rootScope', '$log', .run(['$stateExtender', '$q', '$compile', '$cookieStore', '$rootScope', '$log',
'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer',
'ClearScope', 'LoadConfig', 'Store', 'ClearScope', 'LoadConfig', 'Store', 'pendoService', 'Prompt', 'Rest',
'pendoService', 'Prompt', 'Rest', 'Wait', 'Wait', 'ProcessErrors', '$state', 'GetBasePath', 'ConfigService',
'ProcessErrors', '$state', 'GetBasePath', 'ConfigService',
'FeaturesService', '$filter', 'SocketService', 'FeaturesService', '$filter', 'SocketService',
function($q, $compile, $cookieStore, $rootScope, $log, CheckLicense, function($stateExtender, $q, $compile, $cookieStore, $rootScope, $log,
$location, Authorization, LoadBasePaths, Timer, ClearScope, CheckLicense, $location, Authorization, LoadBasePaths, Timer,
LoadConfig, Store, pendoService, Prompt, Rest, Wait, ClearScope, LoadConfig, Store, pendoService, Prompt, Rest, Wait,
ProcessErrors, $state, GetBasePath, ConfigService, FeaturesService, ProcessErrors, $state, GetBasePath, ConfigService, FeaturesService,
$filter, SocketService) { $filter, SocketService) {
var sock;
$stateExtender.addState({
name: 'dashboard',
url: '/home',
templateUrl: urlPrefix + 'partials/home.html',
controller: Home,
params: { licenseMissing: null },
socket: {
"groups":{
"jobs": ["status_changed"]
}
},
data: {
activityStream: true,
refreshButton: true
},
ncyBreadcrumb: {
label: "DASHBOARD"
},
resolve: {
graphData: ['$q', 'jobStatusGraphData', '$rootScope',
function($q, jobStatusGraphData, $rootScope) {
return $rootScope.featuresConfigured.promise.then(function() {
return $q.all({
jobStatus: jobStatusGraphData.get("month", "all"),
});
});
}
]
}
});
$stateExtender.addState({
name: 'jobs',
url: '/jobs',
templateUrl: urlPrefix + 'partials/jobs.html',
controller: JobsListController,
ncyBreadcrumb: {
label: "JOBS"
},
params: {
search: {
value: {order_by:'-finished'}
}
},
socket: {
"groups":{
"jobs": ["status_changed"],
"schedules": ["changed"]
}
}
});
$stateExtender.addState({
name: 'projects',
url: '/projects?{status}',
templateUrl: urlPrefix + 'partials/projects.html',
controller: ProjectsList,
data: {
activityStream: true,
activityStreamTarget: 'project'
},
ncyBreadcrumb: {
label: "PROJECTS"
},
socket: {
"groups":{
"jobs": ["status_changed"]
}
}
});
$stateExtender.addState({
name: 'projects.add',
url: '/add',
templateUrl: urlPrefix + 'partials/projects.html',
controller: ProjectsAdd,
ncyBreadcrumb: {
parent: "projects",
label: "CREATE PROJECT"
}
});
$stateExtender.addState({
name: 'projects.edit',
url: '/:id',
templateUrl: urlPrefix + 'partials/projects.html',
controller: ProjectsEdit,
data: {
activityStreamId: 'id'
},
ncyBreadcrumb: {
parent: 'projects',
label: '{{name}}'
}
});
$stateExtender.addState({
name: 'projectOrganizations',
url: '/projects/:project_id/organizations',
templateUrl: urlPrefix + 'partials/projects.html',
controller: OrganizationsList
});
$stateExtender.addState({
name: 'projectOrganizationAdd',
url: '/projects/:project_id/organizations/add',
templateUrl: urlPrefix + 'partials/projects.html',
controller: OrganizationsAdd
});
$rootScope.addPermission = function(scope) { $rootScope.addPermission = function(scope) {
$compile("<add-permissions class='AddPermissions'></add-permissions>")(scope); $compile("<add-permissions class='AddPermissions'></add-permissions>")(scope);
}; };
@@ -706,121 +825,9 @@ var tower = angular.module('Tower', [
$rootScope.crumbCache = []; $rootScope.crumbCache = [];
if ($rootScope.removeOpenSocket) { // $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState) {
$rootScope.removeOpenSocket(); // SocketService.subscribe(toState, toParams);
} // });
$rootScope.removeOpenSocket = $rootScope.$on('OpenSocket', function() {
function openSocket() {
// $rootScope.socket = Socket({ scope: $rootScope});
$rootScope.socket.init();
// $rootScope.socket.on("status_changed", function(data) {
// $log.debug('Job ' + data.unified_job_id +
// ' status changed to ' + data.status +
// ' send to ' + $location.$$url);
//
// // this acts as a router...it emits the proper
// // value based on what URL the user is currently
// // accessing.
// if ($state.is('jobs')) {
// $rootScope.$emit('JobStatusChange-jobs', data);
// } else if ($state.includes('jobDetail') ||
// $state.is('adHocJobStdout') ||
// $state.is('inventorySyncStdout') ||
// $state.is('managementJobStdout') ||
// $state.is('scmUpdateStdout')) {
//
// $log.debug("sending status to standard out");
// $rootScope.$emit('JobStatusChange-jobStdout', data);
// }
// if ($state.includes('jobDetail')) {
// $rootScope.$emit('JobStatusChange-jobDetails', data);
// } else if ($state.is('dashboard')) {
// $rootScope.$emit('JobStatusChange-home', data);
// } else if ($state.is('portalMode')) {
// $rootScope.$emit('JobStatusChange-portal', data);
// } else if ($state.is('projects')) {
// $rootScope.$emit('JobStatusChange-projects', data);
// } else if ($state.is('inventoryManage')) {
// $rootScope.$emit('JobStatusChange-inventory', data);
// }
// });
// $rootScope.socket.on("summary_complete", function(data) {
// $log.debug('Job summary_complete ' + data.unified_job_id);
// $rootScope.$emit('JobSummaryComplete', data);
// });
// schedule_socket = Socket({
// scope: $rootScope,
// endpoint: "schedules"
// });
// schedule_socket.init();
// $rootScope.socket.on("schedule_changed", function(data) {
// $log.debug('Schedule ' + data.unified_job_id + ' status changed to ' + data.status);
// $rootScope.$emit('ScheduleStatusChange', data);
// });
// control_socket = Socket({
// scope: $rootScope,
// endpoint: "control"
// });
// control_socket.init();
// $rootScope.socket.on("limit_reached", function(data) {
// $log.debug(data.reason);
// $rootScope.sessionTimer.expireSession('session_limit');
// $state.go('signOut');
// });
}
openSocket();
setTimeout(function() {
$rootScope.$apply(function() {
$rootScope.socket.checkStatus();
$log.debug('socket status: ' + $rootScope.socketStatus);
});
}, 2000);
});
// {'groups':
// {'jobs': ['status_changed', 'summary'],
// 'schedules': ['changed'],
// 'ad_hoc_command_events': [ids,],
// 'job_events': [ids,],
// 'control': ['limit_reached'],
// }
// }
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState) {
if(toState.name === 'dashboard'){
SocketService.emit('{"groups":{"jobs": ["status_changed"]}}');
console.log(toState.name);
}
else if(toState.name === 'jobDetail'){
SocketService.emit(`{"groups":{"jobs": ["status_changed", "summary"] , "job_events":[${toParams.id}]}}`);
console.log(toState.name);
}
else if(toState.name === 'jobStdout'){
SocketService.emit('{"groups":{"jobs": ["status_changed"]}}');
console.log(toState.name);
}
else if(toState.name === 'jobs'){
SocketService.emit('{"groups":{"jobs": ["status_changed"] , "schedules": ["changed"]}}');
console.log(toState.name);
}
else if(toState.name === 'portalMode'){
SocketService.emit('{"groups":{"jobs": ["status_changed"]}}');
console.log(toState.name);
}
else if(toState.name === 'projects'){
SocketService.emit('{"groups":{"jobs": ["status_changed"]}}');
console.log(toState.name);
}
else if(toState.name === 'inventory'){
SocketService.emit('{"groups":{"jobs": ["status_changed"]}}');
console.log(toState.name);
}
else if(toState.name === 'adHocJobStdout'){
SocketService.emit(`{"groups":{"jobs": ["status_changed"] , "ad_hoc_command_events": [${toParams.id}]}}`);
console.log(toState.name);
}
});
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState) { $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState) {

View File

@@ -13,6 +13,11 @@ import GroupsListController from './groups/groups-list.controller';
export default { export default {
name: 'inventoryManage', name: 'inventoryManage',
url: '/inventories/:inventory_id/manage?{group:int}{failed}', url: '/inventories/:inventory_id/manage?{group:int}{failed}',
socket: {
"groups":{
"jobs": ["status_changed"]
}
},
params:{ params:{
group:{ group:{
array: true array: true

View File

@@ -13,22 +13,12 @@ export default {
parent: 'jobs', parent: 'jobs',
label: "{{ job.id }} - {{ job.name }}" label: "{{ job.id }} - {{ job.name }}"
}, },
// resolve: { socket: {
// jobEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { "groups":{
// if (!$rootScope.event_socket) { "jobs": ["status_changed", "summary"]
// $rootScope.event_socket = Socket({ // "job_events": `[${stateParams.id}]`
// scope: $rootScope, }
// endpoint: "job_events" },
// });
// $rootScope.event_socket.init();
// // returns should really be providing $rootScope.event_socket
// // otherwise, we have to inject the entire $rootScope into the controller
// return true;
// } else {
// return true;
// }
// }]
// },
templateUrl: templateUrl('job-detail/job-detail'), templateUrl: templateUrl('job-detail/job-detail'),
controller: 'JobDetailController' controller: 'JobDetailController'
}; };

View File

@@ -1,207 +0,0 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
/**
* @ngdoc function
* @name shared.function:Socket
* @description
* Socket.js
*
* Wrapper for lib/socket.io-client/dist/socket.io.js.
*/
/* global io */
/**
* @ngdoc method
* @name shared.function:Socket#SocketIO
* @methodOf shared.function:Socket
* @description
*/
import ReconnectingWebSocket from 'reconnectingwebsocket'
export default
angular.module('SocketIO', ['Utilities'])
.factory('Socket', ['$rootScope', '$location', '$log', 'Authorization',
'$state',
function ($rootScope, $location, $log, Authorization, $state) {
return function(params) {
var scope = params.scope,
host = window.location.host,
url;
url = "ws://" + host + "/websocket/";
$log.debug('opening socket connection to: ' + url);
function getSocketTip(status) {
var result = '';
switch(status) {
case 'error':
result = "Live events: error connecting to the Tower server.";
break;
case 'connecting':
result = "Live events: attempting to connect to the Tower server.";
break;
case "ok":
result = "Live events: connected. Pages containing job status information will automatically update in real-time.";
}
return result;
}
return {
scope: scope,
url: url,
socket: null,
init: function() {
var self = this,
token = Authorization.getToken();
if (!$rootScope.sessionTimer || ($rootScope.sessionTimer && !$rootScope.sessionTimer.isExpired())) {
// We have a valid session token, so attempt socket connection
$log.debug('Socket connecting to: ' + url);
self.scope.socket_url = url;
self.socket = new ReconnectingWebSocket(url, null, {
debug: true,
timeoutInterval: 3000,
maxReconnectAttempts: 10
});
self.socket.onopen = function () {
console.log('websocket connected'); //log errors
};
self.socket.onerror = function (error) {
console.log('Error Logged: ' + error); //log errors
};
self.socket.onmessage = function (e) {
console.log('Received From Server: ' + e.data);
var data = JSON.parse(e.data);
// {'groups':
// {'jobs': ['status_changed', 'summary'],
// 'schedules': ['changed'],
// 'ad_hoc_command_events': [ids,],
// 'job_events': [ids,],
// 'control': ['limit_reached'],
// }
// }
if(data.group_name==="jobs"){
if (!('status' in data)){
// we know that this must have been a
// summary complete message
$log.debug('Job summary_complete ' + data.unified_job_id);
$rootScope.$emit('JobSummaryComplete', data);
}
if ($state.is('jobs')) {
$rootScope.$emit('JobStatusChange-jobs', data);
} else if ($state.includes('jobDetail') ||
$state.is('adHocJobStdout') ||
$state.is('inventorySyncStdout') ||
$state.is('managementJobStdout') ||
$state.is('scmUpdateStdout')) {
$log.debug("sending status to standard out");
$rootScope.$emit('JobStatusChange-jobStdout', data);
}
if ($state.includes('jobDetail')) {
$rootScope.$emit('JobStatusChange-jobDetails', data);
} else if ($state.is('dashboard')) {
$rootScope.$emit('JobStatusChange-home', data);
} else if ($state.is('portalMode')) {
$rootScope.$emit('JobStatusChange-portal', data);
} else if ($state.is('projects')) {
$rootScope.$emit('JobStatusChange-projects', data);
} else if ($state.is('inventoryManage')) {
$rootScope.$emit('JobStatusChange-inventory', data);
}
}
if(data.group_name==="job_events"){
$rootScope.$emit('job_events-'+data.job, data);
}
if(data.group_name==="schedules"){
$log.debug('Schedule ' + data.unified_job_id + ' status changed to ' + data.status);
$rootScope.$emit('ScheduleStatusChange', data);
}
if(data.group_name==="ad_hoc_command_events"){
}
if(data.group_name==="control"){
$log.debug(data.reason);
$rootScope.sessionTimer.expireSession('session_limit');
$state.go('signOut');
}
};
}
else {
// encountered expired token, redirect to login page
$rootScope.sessionTimer.expireSession('idle');
$location.url('/login');
}
},
checkStatus: function() {
// Check connection status
var self = this;
if(self){
if(self.socket){
if (self.socket.readyState === 0 ) {
self.scope.socketStatus = 'connecting';
}
else if (self.socket.readyState === 1){
self.scope.socketStatus = 'ok';
}
else if (self.socket.readyState === 2 || self.socket.readyState === 3 ){
self.scope.socketStatus = 'error';
}
self.scope.socketTip = getSocketTip(self.scope.socketStatus);
return self.scope.socketStatus;
}
}
},
on: function (eventName, callback) {
var self = this;
if(self){
if(self.socket){
// self.socket.onmessage(function (e) {
// var args = arguments;
// self.scope.$apply(function () {
// callback.apply(self.socket, args);
// });
// });
}
}
},
emit: function (eventName, data, callback) {
var self = this;
// console.log(eventName)
self.socket.send(eventName, data, function () {
var args = arguments;
self.scope.$apply(function () {
if (callback) {
callback.apply(self.socket, args);
}
});
});
},
getUrl: function() {
return url;
},
removeAllListeners: function (eventName) {
var self = this;
if(self){
if(self.socket){
self.socket.removeEventListener(eventName);
}
}
},
};
};
}]);

View File

@@ -5,12 +5,12 @@
*************************************************/ *************************************************/
import ReconnectingWebSocket from 'reconnectingwebsocket'; import ReconnectingWebSocket from 'reconnectingwebsocket';
export default export default
['$rootScope', '$location', '$log', 'Authorization','$state', '$q', ['$rootScope', '$location', '$log', 'Authorization','$state',
function ($rootScope, $location, $log, Authorization, $state, $q) { function ($rootScope, $location, $log, Authorization, $state) {
return { return {
init: function() { init: function() {
var self = this, var self = this,
token = Authorization.getToken(), // token = Authorization.getToken(),
host = window.location.host, host = window.location.host,
url = "ws://" + host + "/websocket/"; url = "ws://" + host + "/websocket/";
if (!$rootScope.sessionTimer || ($rootScope.sessionTimer && !$rootScope.sessionTimer.isExpired())) { if (!$rootScope.sessionTimer || ($rootScope.sessionTimer && !$rootScope.sessionTimer.isExpired())) {
@@ -103,6 +103,44 @@ export default
$log.debug('socket status: ' + $rootScope.socketStatus); $log.debug('socket status: ' + $rootScope.socketStatus);
}, 2000); }, 2000);
}, },
subscribe2: function(state){
console.log(state.name);
this.emit(JSON.stringify(state.socket));
},
// subscribe: function(toState, toParams){
// if(toState.name === 'dashboard'){
// this.emit('{"groups":{"jobs": ["status_changed"]}}');
// console.log(toState.name);
// }
// if(toState.name === 'jobDetail'){
// this.emit(`{"groups":{"jobs": ["status_changed", "summary"] , "job_events":[${toParams.id}]}}`);
// console.log(toState.name);
// }
// if(toState.name === 'jobStdout'){
// this.emit('{"groups":{"jobs": ["status_changed"]}}');
// console.log(toState.name);
// }
// if(toState.name === 'jobs'){
// this.emit('{"groups":{"jobs": ["status_changed"] , "schedules": ["changed"]}}');
// console.log(toState.name);
// }
// if(toState.name === 'portalMode'){
// this.emit('{"groups":{"jobs": ["status_changed"]}}');
// console.log(toState.name);
// }
// if(toState.name === 'projects'){
// this.emit('{"groups":{"jobs": ["status_changed"]}}');
// console.log(toState.name);
// }
// if(toState.name === 'inventoryManage'){
// this.emit('{"groups":{"jobs": ["status_changed"]}}');
// console.log(toState.name);
// }
// if(toState.name === 'adHocJobStdout'){
// this.emit(`{"groups":{"jobs": ["status_changed"] , "ad_hoc_command_events": [${toParams.id}]}}`);
// console.log(toState.name);
// }
// },
checkStatus: function() { checkStatus: function() {
function getSocketTip(status) { function getSocketTip(status) {
@@ -138,23 +176,22 @@ export default
} }
}, },
on: function (eventName, callback) { // on: function (eventName, callback) {
var self = this; // var self = this;
if(self){ // if(self){
if(self.socket){ // if(self.socket){
// self.socket.onmessage(function (e) { // // self.socket.onmessage(function (e) {
// var args = arguments; // // var args = arguments;
// self.scope.$apply(function () { // // self.scope.$apply(function () {
// callback.apply(self.socket, args); // // callback.apply(self.socket, args);
// }); // // });
// }); // // });
} // }
} // }
//
}, // },
emit: function (eventName, data, callback) { emit: function (eventName, data, callback) {
var self = this; var self = this;
// console.log(eventName)
$rootScope.socketPromise.promise.then(function(){ $rootScope.socketPromise.promise.then(function(){
self.socket.send(eventName, data, function () { self.socket.send(eventName, data, function () {
var args = arguments; var args = arguments;
@@ -166,9 +203,6 @@ export default
}); });
}); });
}, },
getUrl: function() {
return url;
},
removeAllListeners: function (eventName) { removeAllListeners: function (eventName) {
var self = this; var self = this;
if(self){ if(self){

View File

@@ -1,10 +1,28 @@
export default function($stateProvider) { export default function($stateProvider) {
this.$get = function() { this.$get = function() {
return { return {
addSocket: function(state){
// var resolve = state.resolve || {};
if(!state.resolve){
state.resolve = {};
}
state.resolve.socket = ['SocketService', '$rootScope',
function(SocketService, $rootScope) {
// var self = this;
$rootScope.socketPromise.promise.then(function(){
SocketService.subscribe2(state);
return true;
});
}]
},
addState: function(state) { addState: function(state) {
var route = state.route || state.url; var route = state.route || state.url;
if(state.socket){
this.addSocket(state);
}
$stateProvider.state(state.name, { $stateProvider.state(state.name, {
url: route, url: route,
controller: state.controller, controller: state.controller,