You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

datamediator.js 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. /**
  2. * @fileOverview Deferred data loader / cacher singleton. Provides vboxDataMediator
  3. * @author Ian Moore (imoore76 at yahoo dot com)
  4. * @version $Id: datamediator.js 591 2015-04-11 22:40:47Z imoore76 $
  5. * @copyright Copyright (C) 2010-2015 Ian Moore (imoore76 at yahoo dot com)
  6. */
  7. /**
  8. * vboxVMDataMediator
  9. *
  10. * @see jQuery.deferred
  11. * @namespace vboxVMDataMediator
  12. */
  13. var vboxVMDataMediator = {
  14. /* Promises for data */
  15. promises : {
  16. 'getVMDetails':{},
  17. 'getVMRuntimeData':{}
  18. },
  19. /* Holds Basic VM data */
  20. vmData : null,
  21. /* Holds VM details */
  22. vmDetailsData : {},
  23. /* Holds VM runtime data */
  24. vmRuntimeData : {},
  25. /* Expire cached promise / data */
  26. expireVMDetails: function(vmid) {
  27. vboxVMDataMediator.promises.getVMDetails[vmid] = null;
  28. vboxVMDataMediator.vmDetailsData[vmid] = null;
  29. },
  30. expireVMRuntimeData: function(vmid) {
  31. vboxVMDataMediator.promises.getVMRuntimeData[vmid] = null;
  32. vboxVMDataMediator.vmRuntimeData[vmid] = null;
  33. },
  34. expireAll: function() {
  35. for(var i in vboxVMDataMediator.promises) {
  36. if(typeof(i) != 'string') continue;
  37. vboxVMDataMediator.promises[i] = {};
  38. }
  39. vboxVMDataMediator.vmData = null;
  40. vboxVMDataMediator.vmRuntimeData = {};
  41. vboxVMDataMediator.vmDetailsData = {};
  42. },
  43. /**
  44. * Get basic vm data
  45. *
  46. * @param vmid {String} ID of VM
  47. * @returns {Object} vm data
  48. */
  49. getVMData: function(vmid) {
  50. // VMList must exist
  51. if(!vboxVMDataMediator.vmData) {
  52. return;
  53. }
  54. return vboxVMDataMediator.vmData[vmid];
  55. },
  56. /**
  57. * Return list of machines, subscribe to running VM events
  58. * and start the event listener
  59. *
  60. * @returns {Object} promise
  61. */
  62. getVMList: function() {
  63. // Return array from existing data
  64. if(vboxVMDataMediator.vmData) {
  65. var list = [];
  66. for(var i in vboxVMDataMediator.vmData) {
  67. if(typeof i != 'string') continue;
  68. if(i == 'host') continue;
  69. list.push(vboxVMDataMediator.vmData[i]);
  70. }
  71. return list;
  72. }
  73. var mList = $.Deferred();
  74. $.when(vboxAjaxRequest('vboxGetMachines')).done(function(d) {
  75. var vmData = {};
  76. var subscribeList = [];
  77. for(var i = 0; i < d.responseData.length; i++) {
  78. // Enforce VM ownership
  79. if($('#vboxPane').data('vboxConfig').enforceVMOwnership && !$('#vboxPane').data('vboxSession').admin && d.responseData[i].owner != $('#vboxPane').data('vboxSession').user) {
  80. continue;
  81. }
  82. vmData[d.responseData[i].id] = d.responseData[i];
  83. if(vboxVMStates.isRunning({'state':d.responseData[i].state}) || vboxVMStates.isPaused({'state':d.responseData[i].state}))
  84. subscribeList[subscribeList.length] = d.responseData[i].id;
  85. }
  86. // Start event listener
  87. $.when(vboxEventListener.start(subscribeList)).done(function(){
  88. vboxVMDataMediator.vmData = vmData;
  89. mList.resolve(d.responseData);
  90. }).fail(function() {
  91. mList.reject();
  92. });
  93. }).fail(function() {
  94. mList.reject();
  95. });
  96. return mList.promise();
  97. },
  98. /**
  99. * Get VM details data
  100. *
  101. * @param vmid {String} ID of VM to get data for
  102. * @param forceRefresh {Boolean} force refresh of VM data
  103. * @returns {Object} vm data or promise
  104. */
  105. getVMDetails: function(vmid, forceRefresh) {
  106. // Data exists
  107. if(vboxVMDataMediator.vmDetailsData[vmid] && !forceRefresh) {
  108. vboxVMDataMediator.promises.getVMDetails[vmid] = null;
  109. return vboxVMDataMediator.vmDetailsData[vmid];
  110. }
  111. // Promise does not yet exist?
  112. if(!vboxVMDataMediator.promises.getVMDetails[vmid]) {
  113. vboxVMDataMediator.promises.getVMDetails[vmid] = $.Deferred();
  114. $.when(vboxAjaxRequest('machineGetDetails',{vm:vmid})).done(function(d){
  115. vboxVMDataMediator.vmDetailsData[d.responseData.id] = d.responseData;
  116. vboxVMDataMediator.promises.getVMDetails[vmid].resolve(d.responseData);
  117. }).fail(function(){
  118. vboxVMDataMediator.promises.getVMDetails[vmid].reject();
  119. vboxVMDataMediator.promises.getVMDetails[vmid] = null;
  120. });
  121. }
  122. return vboxVMDataMediator.promises.getVMDetails[vmid];
  123. },
  124. /**
  125. * Get VM's runtime data
  126. *
  127. * @param vmid {String} ID of VM to get data for
  128. * @returns {Object} VM runtime data or promise
  129. */
  130. getVMRuntimeData: function(vmid) {
  131. // Data exists
  132. if(vboxVMDataMediator.vmRuntimeData[vmid]) {
  133. vboxVMDataMediator.promises.getVMRuntimeData[vmid] = null;
  134. return vboxVMDataMediator.vmRuntimeData[vmid];
  135. }
  136. // Promise does not yet exist?
  137. if(!vboxVMDataMediator.promises.getVMRuntimeData[vmid]) {
  138. vboxVMDataMediator.promises.getVMRuntimeData[vmid] = $.Deferred();
  139. $.when(vboxAjaxRequest('machineGetRuntimeData',{vm:vmid})).done(function(d){
  140. vboxVMDataMediator.vmRuntimeData[d.responseData.id] = d.responseData;
  141. if(vboxVMDataMediator.promises.getVMRuntimeData[vmid])
  142. vboxVMDataMediator.promises.getVMRuntimeData[vmid].resolve(d.responseData);
  143. }).fail(function(){
  144. vboxVMDataMediator.promises.getVMRuntimeData[vmid].reject();
  145. vboxVMDataMediator.promises.getVMRuntimeData[vmid] = null;
  146. });
  147. }
  148. return vboxVMDataMediator.promises.getVMRuntimeData[vmid];
  149. },
  150. /**
  151. * Return all data for a VM
  152. * @param vmid {String} ID of VM to get data for
  153. * @returns promise
  154. */
  155. getVMDataCombined : function(vmid) {
  156. // Special case for 'host'
  157. if(vmid == 'host') {
  158. var def = $.Deferred();
  159. $.when(vboxVMDataMediator.getVMDetails(vmid)).done(function(d){
  160. def.resolve(d);
  161. }).fail(function(){
  162. def.reject();
  163. });
  164. return def.promise();
  165. }
  166. if(!vboxVMDataMediator.vmData[vmid]) return;
  167. var runtime = function() { return {};};
  168. if(vboxVMStates.isRunning({'state':vboxVMDataMediator.vmData[vmid].state}) || vboxVMStates.isPaused({'state':vboxVMDataMediator.vmData[vmid].state})) {
  169. runtime = vboxVMDataMediator.getVMRuntimeData(vmid);
  170. }
  171. var def = $.Deferred();
  172. $.when(vboxVMDataMediator.getVMDetails(vmid), runtime, vboxVMDataMediator.getVMData(vmid)).done(function(d1,d2,d3){
  173. def.resolve($.extend(true,{},d1,d2,d3));
  174. }).fail(function(){
  175. def.reject();
  176. });
  177. return def.promise();
  178. },
  179. /**
  180. * Get new VM data
  181. * @param vmid {String} ID of VM to get data for
  182. * @returns {Object} promise
  183. */
  184. refreshVMData : function(vmid) {
  185. // Special case for host
  186. if(vmid == 'host') {
  187. $('#vboxPane').trigger('vboxOnMachineDataChanged', [{machineId:'host'}]);
  188. $('#vboxPane').trigger('vboxEvents', [[{eventType:'OnMachineDataChanged',machineId:'host'}]]);
  189. return;
  190. }
  191. if(!vboxVMDataMediator.vmData[vmid]) return;
  192. var def = $.Deferred();
  193. $.when(vboxAjaxRequest('vboxGetMachines',{'vm':vmid})).done(function(d) {
  194. vm = d.responseData[0];
  195. vboxVMDataMediator.vmData[vm.id] = vm;
  196. def.resolve();
  197. $('#vboxPane').trigger('vboxOnMachineDataChanged', [{machineId:vm.id,enrichmentData:vm}]);
  198. $('#vboxPane').trigger('vboxEvents', [[{eventType:'OnMachineDataChanged',machineId:vm.id,enrichmentData:vm}]]);
  199. }).fail(function(){
  200. def.reject();
  201. });
  202. return def.promise();
  203. }
  204. };
  205. /* Events to bind for vboxVMDataMediator when everything is loaded */
  206. $(document).ready(function(){
  207. /*
  208. *
  209. * VirtualBox events
  210. *
  211. */
  212. // Raw event to data handlers
  213. $('#vboxPane').on('vboxOnMachineDataChanged',function(e, eventData) {
  214. vboxVMDataMediator.expireVMDetails(eventData.machineId);
  215. vboxVMDataMediator.expireVMRuntimeData(eventData.machineId);
  216. if(vboxVMDataMediator.vmData[eventData.machineId] && eventData.enrichmentData) {
  217. $.extend(true, vboxVMDataMediator.vmData[eventData.machineId], eventData.enrichmentData);
  218. // $.extend doesn't seem to handle this for some reason
  219. vboxVMDataMediator.vmData[eventData.machineId].groups = eventData.enrichmentData.groups;
  220. }
  221. // Machine state change
  222. }).on('vboxOnMachineStateChanged', function(e, eventData) {
  223. // Only care about it if its in our list
  224. if(vboxVMDataMediator.vmData[eventData.machineId]) {
  225. vboxVMDataMediator.vmData[eventData.machineId].state = eventData.state;
  226. vboxVMDataMediator.vmData[eventData.machineId].lastStateChange = eventData.enrichmentData.lastStateChange;
  227. vboxVMDataMediator.vmData[eventData.machineId].currentStateModified = eventData.enrichmentData.currentStateModified;
  228. // If it's running, subscribe to its events
  229. if(vboxVMStates.isRunning({'state':eventData.state}) || vboxVMStates.isPaused({'state':eventData.state})) {
  230. // If we already have runtime data, assume we were already subscribed
  231. if(!vboxVMDataMediator.vmRuntimeData[eventData.machineId]) {
  232. // Tell event listener to subscribe to this machine's events
  233. vboxEventListener.subscribeVMEvents(eventData.machineId);
  234. }
  235. } else {
  236. vboxVMDataMediator.expireVMRuntimeData(eventData.machineId);
  237. }
  238. }
  239. // Session state change
  240. }).on('vboxOnSessionStateChanged', function(e, eventData) {
  241. if(vboxVMDataMediator.vmData[eventData.machineId])
  242. vboxVMDataMediator.vmData[eventData.machineId].sessionState = eventData.state;
  243. // Snapshot changed
  244. }).on('vboxOnSnapshotTaken vboxOnSnapshotDeleted vboxOnSnapshotChanged vboxOnSnapshotRestored',function(e,eventData) {
  245. if(vboxVMDataMediator.vmData[eventData.machineId]) {
  246. vboxVMDataMediator.vmData[eventData.machineId].currentSnapshotName = eventData.enrichmentData.currentSnapshotName;
  247. vboxVMDataMediator.vmData[eventData.machineId].currentStateModified = eventData.enrichmentData.currentStateModified;
  248. // Get media again
  249. $.when(vboxAjaxRequest('vboxGetMedia')).done(function(d){$('#vboxPane').data('vboxMedia',d.responseData);});
  250. }
  251. if(vboxVMDataMediator.vmDetailsData[eventData.machineId])
  252. vboxVMDataMediator.vmDetailsData[eventData.machineId].snapshotCount = eventData.enrichmentData.snapshotCount;
  253. // Expire all data for a VM when machine is unregistered
  254. }).on('vboxOnMachineRegistered', function(e, eventData) {
  255. if(!eventData.registered) {
  256. vboxVMDataMediator.expireVMDetails(eventData.machineId);
  257. vboxVMDataMediator.expireVMRuntimeData(eventData.machineId);
  258. vboxVMDataMediator.vmData[eventData.machineId] = null;
  259. } else if(eventData.enrichmentData) {
  260. // Enforce VM ownership
  261. if($('#vboxPane').data('vboxConfig').enforceVMOwnership && !$('#vboxPane').data('vboxSession').admin && eventData.enrichmentData.owner != $('#vboxPane').data('vboxSession').user) {
  262. return;
  263. }
  264. vboxVMDataMediator.vmData[eventData.enrichmentData.id] = eventData.enrichmentData;
  265. }
  266. //}).on('vboxOnCPUChanged', function(e, vmid) {
  267. /*
  268. case 'OnCPUChanged':
  269. $data['cpu'] = $eventDataObject->cpu;
  270. $data['add'] = $eventDataObject->add;
  271. $data['dedupId'] .= '-' . $data['cpu'];
  272. break;
  273. */
  274. }).on('vboxOnNetworkAdapterChanged', function(e, eventData) {
  275. if(vboxVMDataMediator.vmRuntimeData[eventData.machineId]) {
  276. $.extend(vboxVMDataMediator.vmRuntimeData[eventData.machineId].networkAdapters[eventData.networkAdapterSlot], eventData.enrichmentData);
  277. }
  278. /* Storage controller of VM changed */
  279. //}).on('vboxOnStorageControllerChanged', function() {
  280. /*
  281. case 'OnStorageControllerChanged':
  282. $data['machineId'] = $eventDataObject->machineId;
  283. $data['dedupId'] .= '-'. $data['machineId'];
  284. break;
  285. */
  286. }).on('vboxOnMediumChanged', function(e, eventData) {
  287. /* Medium attachment changed */
  288. if(vboxVMDataMediator.vmRuntimeData[eventData.machineId]) {
  289. for(var a = 0; a < vboxVMDataMediator.vmRuntimeData[eventData.machineId].storageControllers.length; a++) {
  290. if(vboxVMDataMediator.vmRuntimeData[eventData.machineId].storageControllers[a].name == eventData.controller) {
  291. for(var b = 0; b < vboxVMDataMediator.vmRuntimeData[eventData.machineId].storageControllers[a].mediumAttachments.length; b++) {
  292. if(vboxVMDataMediator.vmRuntimeData[eventData.machineId].storageControllers[a].mediumAttachments[b].port == eventData.port &&
  293. vboxVMDataMediator.vmRuntimeData[eventData.machineId].storageControllers[a].mediumAttachments[b].device == eventData.device) {
  294. vboxVMDataMediator.vmRuntimeData[eventData.machineId].storageControllers[a].mediumAttachments[b].medium = (eventData.medium ? {id:eventData.medium} : null);
  295. break;
  296. }
  297. }
  298. break;
  299. }
  300. }
  301. }
  302. /* Shared folders changed */
  303. //}).on('vboxOnSharedFolderChanged', function() {
  304. // VRDE runtime info
  305. }).on('vboxOnVRDEServerChanged', function(e, eventData) {
  306. if(vboxVMDataMediator.vmRuntimeData[eventData.machineId]) {
  307. $.extend(true,vboxVMDataMediator.vmRuntimeData[eventData.machineId].VRDEServer, eventData.enrichmentData);
  308. }
  309. // This only fires when it is enabled
  310. }).on('vboxOnVRDEServerInfoChanged', function(e, eventData) {
  311. if(vboxVMDataMediator.vmRuntimeData[eventData.machineId]) {
  312. vboxVMDataMediator.vmRuntimeData[eventData.machineId].VRDEServerInfo.port = eventData.enrichmentData.port;
  313. vboxVMDataMediator.vmRuntimeData[eventData.machineId].VRDEServer.enabled = eventData.enrichmentData.enabled;
  314. }
  315. // Execution cap
  316. }).on('vboxOnCPUExecutionCapChanged', function(e, eventData) {
  317. if(vboxVMDataMediator.vmRuntimeData[eventData.machineId]) {
  318. vboxVMDataMediator.vmRuntimeData[eventData.machineId].CPUExecutionCap = eventData.executionCap;
  319. }
  320. // Special cases for where phpvirtualbox keeps its extra data
  321. }).on('vboxOnExtraDataChanged', function(e, eventData) {
  322. // No vm id is a global change
  323. if(!eventData.machineId || !vboxVMDataMediator.vmData[eventData.machineId]) return;
  324. switch(eventData.key) {
  325. // Startup mode
  326. case 'pvbx/startupMode':
  327. if(vboxVMDataMediator.vmDetailsData[eventData.machineId])
  328. vboxVMDataMediator.vmDetailsData[eventData.machineId].startupMode = eventData.value;
  329. break;
  330. // Owner
  331. case 'phpvb/sso/owner':
  332. vboxVMDataMediator.vmData[eventData.machineId].owner = eventData.value;
  333. break;
  334. // Custom icon
  335. case 'phpvb/icon':
  336. vboxVMDataMediator.vmData[eventData.machineId].customIcon = eventData.value;
  337. if(vboxVMDataMediator.vmDetailsData[eventData.machineId])
  338. vboxVMDataMediator.vmDetailsData[eventData.machineId].customIcon = eventData.value;
  339. break;
  340. // First time run
  341. case 'GUI/FirstRun':
  342. if(vboxVMDataMediator.vmDetailsData[eventData.machineId])
  343. vboxVMDataMediator.vmDetailsData[eventData.machineId].GUI.FirstRun = eventData.value;
  344. break;
  345. }
  346. /*
  347. *
  348. * phpVirtualBox events
  349. *
  350. */
  351. // Expire everything when host changes
  352. }).on('hostChange',function(){
  353. vboxVMDataMediator.expireAll();
  354. });
  355. });