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.
state('dashboard', {
url: '/home',
templateUrl: urlPrefix + 'partials/home.html',
controller: Home,
params: { licenseMissing: null },
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"),
});
});
}
]
}
}).
state('jobs', {
url: '/jobs',
templateUrl: urlPrefix + 'partials/jobs.html',
controller: JobsListController,
ncyBreadcrumb: {
label: "JOBS"
}
}).
state('projects', {
url: '/projects?{status}',
templateUrl: urlPrefix + 'partials/projects.html',
controller: ProjectsList,
data: {
activityStream: true,
activityStreamTarget: 'project'
},
ncyBreadcrumb: {
label: "PROJECTS"
}
}).
state('projects.add', {
url: '/add',
templateUrl: urlPrefix + 'partials/projects.html',
controller: ProjectsAdd,
ncyBreadcrumb: {
parent: "projects",
label: "CREATE PROJECT"
}
}).
state('projects.edit', {
url: '/:id',
templateUrl: urlPrefix + 'partials/projects.html',
controller: ProjectsEdit,
data: {
activityStreamId: 'id'
},
ncyBreadcrumb: {
parent: 'projects',
label: '{{name}}'
}
}).
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('dashboard', {
// url: '/home',
// templateUrl: urlPrefix + 'partials/home.html',
// controller: Home,
// params: { licenseMissing: null },
// 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"),
// });
// });
// }
// ]
// }
// }).
//
// state('jobs', {
// url: '/jobs',
// templateUrl: urlPrefix + 'partials/jobs.html',
// controller: JobsListController,
// ncyBreadcrumb: {
// label: "JOBS"
// }
// }).
//
// state('projects', {
// url: '/projects?{status}',
// templateUrl: urlPrefix + 'partials/projects.html',
// controller: ProjectsList,
// data: {
// activityStream: true,
// activityStreamTarget: 'project'
// },
// ncyBreadcrumb: {
// label: "PROJECTS"
// },
// // socket: '{"groups":{"jobs": ["status_changed"]}}'
// // resolve: {
// // socket: ['SocketService', '$rootScope',
// // function(SocketService, $rootScope) {
// // var self = this;
// // $rootScope.socketPromise.promise.then(function(){
// // SocketService.subscribe(self);
// // return true;
// // });
// // }]
// // },
// }).
//
// state('projects.add', {
// url: '/add',
// templateUrl: urlPrefix + 'partials/projects.html',
// controller: ProjectsAdd,
// ncyBreadcrumb: {
// parent: "projects",
// label: "CREATE PROJECT"
// }
// }).
//
// state('projects.edit', {
// url: '/:id',
// templateUrl: urlPrefix + 'partials/projects.html',
// controller: ProjectsEdit,
// data: {
// activityStreamId: 'id'
// },
// ncyBreadcrumb: {
// parent: 'projects',
// label: '{{name}}'
// }
// }).
//
// 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', {
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',
'ClearScope', 'LoadConfig', 'Store',
'pendoService', 'Prompt', 'Rest', 'Wait',
'ProcessErrors', '$state', 'GetBasePath', 'ConfigService',
'ClearScope', 'LoadConfig', 'Store', 'pendoService', 'Prompt', 'Rest',
'Wait', 'ProcessErrors', '$state', 'GetBasePath', 'ConfigService',
'FeaturesService', '$filter', 'SocketService',
function($q, $compile, $cookieStore, $rootScope, $log, CheckLicense,
$location, Authorization, LoadBasePaths, Timer, ClearScope,
LoadConfig, Store, pendoService, Prompt, Rest, Wait,
function($stateExtender, $q, $compile, $cookieStore, $rootScope, $log,
CheckLicense, $location, Authorization, LoadBasePaths, Timer,
ClearScope, LoadConfig, Store, pendoService, Prompt, Rest, Wait,
ProcessErrors, $state, GetBasePath, ConfigService, FeaturesService,
$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) {
$compile("<add-permissions class='AddPermissions'></add-permissions>")(scope);
};
@ -706,121 +825,9 @@ var tower = angular.module('Tower', [
$rootScope.crumbCache = [];
if ($rootScope.removeOpenSocket) {
$rootScope.removeOpenSocket();
}
$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('$stateChangeStart', function(event, toState, toParams, fromState) {
// SocketService.subscribe(toState, toParams);
// });
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState) {

View File

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

View File

@ -13,22 +13,12 @@ export default {
parent: 'jobs',
label: "{{ job.id }} - {{ job.name }}"
},
// resolve: {
// jobEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) {
// if (!$rootScope.event_socket) {
// $rootScope.event_socket = Socket({
// 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;
// }
// }]
// },
socket: {
"groups":{
"jobs": ["status_changed", "summary"]
// "job_events": `[${stateParams.id}]`
}
},
templateUrl: templateUrl('job-detail/job-detail'),
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';
export default
['$rootScope', '$location', '$log', 'Authorization','$state', '$q',
function ($rootScope, $location, $log, Authorization, $state, $q) {
['$rootScope', '$location', '$log', 'Authorization','$state',
function ($rootScope, $location, $log, Authorization, $state) {
return {
init: function() {
var self = this,
token = Authorization.getToken(),
// token = Authorization.getToken(),
host = window.location.host,
url = "ws://" + host + "/websocket/";
if (!$rootScope.sessionTimer || ($rootScope.sessionTimer && !$rootScope.sessionTimer.isExpired())) {
@ -103,6 +103,44 @@ export default
$log.debug('socket status: ' + $rootScope.socketStatus);
}, 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() {
function getSocketTip(status) {
@ -138,23 +176,22 @@ export default
}
},
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);
// });
// });
}
}
},
// 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)
$rootScope.socketPromise.promise.then(function(){
self.socket.send(eventName, data, function () {
var args = arguments;
@ -166,9 +203,6 @@ export default
});
});
},
getUrl: function() {
return url;
},
removeAllListeners: function (eventName) {
var self = this;
if(self){

View File

@ -1,10 +1,28 @@
export default function($stateProvider) {
this.$get = function() {
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) {
var route = state.route || state.url;
if(state.socket){
this.addSocket(state);
}
$stateProvider.state(state.name, {
url: route,
controller: state.controller,