1/** Convert chrome tabs API to promise */ 2const chromeTabs = { 3 get: function(tabId) { 4 return new Promise(function(resolve) { 5 chrome.tabs.get(tabId, resolve); 6 }); 7 }, 8 9 sendMessage: function(tabId, message, options) { 10 return new Promise(function(resolve) { 11 chrome.tabs.sendMessage(tabId, message, options, resolve); 12 }); 13 }, 14}; 15 16class TaskMonitor { 17 constructor() { 18 // Bind the callback 19 this._updated = this._updated.bind(this); 20 this._records = []; 21 } 22 23 bind() { 24 chrome.processes.onUpdated.addListener(this._updated); 25 } 26 27 unbind() { 28 chrome.processes.onUpdated.removeListener(this._updated); 29 } 30 31 _updated(processes) { 32 // Structure to hold synthesized data 33 const data = { 34 timestamp: Date.now(), 35 processes: [], 36 tabInfo: [], 37 }; 38 39 // Produce a set of tabId's to populate data.tabInfo in a separate loop 40 const tabset = new Set(); 41 42 // Only take a subset of the process data 43 for (const process of Object.values(processes)) { 44 // Skip processes that don't consume CPU 45 if (process.cpu == 0) { 46 continue; 47 } 48 49 // Only take a subset of the data 50 const currProcess = { 51 pid: process.osProcessId, 52 network: process.network, 53 cpu: process.cpu, 54 tasks: [], 55 }; 56 57 // Populate process info with 'tabId' and 'title' information 58 for (const task of Object.values(process.tasks)) { 59 if ('tabId' in task) { 60 tabset.add(task.tabId); 61 currProcess.tasks.push({ 62 tabId: task.tabId, 63 title: task.title, 64 }); 65 } else { 66 if ('title' in task) { 67 currProcess.tasks.push({title: task.title}); 68 } 69 } 70 } 71 data.processes.push(currProcess); 72 } 73 74 // Populate data.tabInfo with unique tabId's 75 for (const tabId of tabset) { 76 data.tabInfo.push({tabId: tabId}); 77 } 78 79 const promises = []; 80 81 // Record url, audio, muted, and video count 82 // information per currently open tab 83 for (const tabInfo of data.tabInfo) { 84 promises.push( 85 chromeTabs.get(tabInfo.tabId).then((tab) => { 86 tabInfo.title = tab.title; 87 tabInfo.url = tab.url; 88 tabInfo.audio_played = !!tab.audible; 89 tabInfo.muted = tab.mutedInfo.muted; 90 }) 91 ); 92 93 promises.push( 94 chromeTabs.sendMessage(tabInfo.tabId, 'numberOfVideosPlaying') 95 .then((n) => { 96 if (typeof n === 'undefined') { 97 tabInfo.videos_playing = 0; 98 return; 99 } else { 100 tabInfo.videos_playing = n; 101 } 102 }) 103 ); 104 } 105 106 Promise.all(promises).finally(() => { 107 this._records.push(data); 108 109 if (this._records.length >= 1) { 110 this._send(); 111 } 112 }); 113 } 114 115 _send() { 116 const formData = new FormData(); 117 this._records.forEach(function(record, index) { 118 formData.append(index, JSON.stringify(record)); 119 }); 120 this._records.length = 0; 121 122 const url = 'http://localhost:8001/task-monitor'; 123 const req = new XMLHttpRequest(); 124 req.open('POST', url, true); 125 req.send(formData); 126 } 127} 128 129this.task_monitor = new TaskMonitor(); 130