Merge lp:~jlisee/rescuetime-linux-uploader/experimental into lp:rescuetime-linux-uploader

Proposed by Dirk T
Status: Merged
Merged at revision: 105
Proposed branch: lp:~jlisee/rescuetime-linux-uploader/experimental
Merge into: lp:rescuetime-linux-uploader
Diff against target: 335 lines (+226/-4)
5 files modified
RescueTimeUploader/extensions/Gnome-terminal/app_name (+5/-0)
RescueTimeUploader/extensions/Google-chrome/extended_info (+136/-0)
RescueTimeUploader/uploader.py (+16/-4)
chrome_extension/background.html (+55/-0)
chrome_extension/manifest.json (+14/-0)
To merge this branch: bzr merge lp:~jlisee/rescuetime-linux-uploader/experimental
Reviewer Review Type Date Requested Status
Joseph Lisee (community) Approve
Dirk T Needs Information
Review via email: mp+119601@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Dirk T (miriup) wrote :

Joseph, not sure if you're still active in this project. Do you remember what made you create revision 105?

review: Needs Information
Revision history for this message
Joseph Lisee (jlisee) wrote :

> Joseph, not sure if you're still active in this project. Do you remember what
> made you create revision 105?

I am pretty sure I found a race condition between two threads. Even through threading isn't used explicitly with the way things are done the Uploader class runs in a different thread then whatever runs the gnome panel.

Revision history for this message
Joseph Lisee (jlisee) wrote :

I approve of the merge. My only reservation is that I have not used the Chrome plugin in a while so I am not sure if it still works. Even if it doesn't I think it would only require minor updates to get it working again.

review: Approve
Revision history for this message
Dirk T (miriup) wrote :

> I approve of the merge. My only reservation is that I have not used the Chrome
> plugin in a while so I am not sure if it still works.

I will know. I'm using as my primary browser. :)

Cheers,
Dirk.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'RescueTimeUploader/extensions/Gnome-terminal/app_name'
2--- RescueTimeUploader/extensions/Gnome-terminal/app_name 2008-02-03 16:54:21 +0000
3+++ RescueTimeUploader/extensions/Gnome-terminal/app_name 2012-08-14 18:23:19 +0000
4@@ -1,5 +1,10 @@
5 #!/usr/bin/env python
6
7+"""
8+Returns the remote host name if the terminal is an ssh session, otherwise it
9+returns given app_name (in this case 'Gnome-terminal')
10+"""
11+
12 import sys
13 import os
14 app_name = raw_input("")
15
16=== added directory 'RescueTimeUploader/extensions/Google-chrome'
17=== added file 'RescueTimeUploader/extensions/Google-chrome/extended_info'
18--- RescueTimeUploader/extensions/Google-chrome/extended_info 1970-01-01 00:00:00 +0000
19+++ RescueTimeUploader/extensions/Google-chrome/extended_info 2012-08-14 18:23:19 +0000
20@@ -0,0 +1,136 @@
21+#!/usr/bin/env python
22+
23+# Copyright (c) 2010 Joseph Lisee <jlisee@gmail.com>
24+#
25+# Permission is hereby granted, free of charge, to any person obtaining a copy
26+# of this software and associated documentation files (the "Software"), to deal
27+# in the Software without restriction, including without limitation the rights
28+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29+# copies of the Software, and to permit persons to whom the Software is
30+# furnished to do so, subject to the following conditions:
31+#
32+# The above copyright notice and this permission notice shall be included in
33+# all copies or substantial portions of the Software.
34+#
35+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41+# THE SOFTWARE.
42+
43+# White list checking and URL parsing our borrowed from the firefox extension
44+# in the future the code should be merged somehow
45+
46+
47+import os
48+import subprocess
49+from urlparse import urlparse
50+from os.path import expanduser, join, exists
51+
52+"""
53+Extracts the current google chrome URL local HTML storage of the extension and
54+prints it to stdout. It is intelligent about searching out and finding the
55+write google extension local storage database, and cashes the result for use.
56+"""
57+
58+# Overall settings and paths
59+preferenceDir = join(expanduser('~'), '.rescuetime')
60+whitelist_file = join(preferenceDir, 'domainwhitelist.txt')
61+extensionID_file = join(preferenceDir, 'google-chrome_extension-id.txt')
62+localStorageDir = join(os.getenv("HOME"), ".config", "google-chrome",
63+ "Default", "Local Storage")
64+
65+# Load whitelist
66+allowed_domains = []
67+
68+if exists(whitelist_file):
69+ have_whitelist = True
70+ for line in open(whitelist_file):
71+ # strip comments and whitespace
72+ line = line.split('#', 1)[0].strip()
73+ if line:
74+ allowed_domains.append(line)
75+else:
76+ have_whitelist = False
77+
78+def findExtensionID():
79+ dirs = os.listdir(localStorageDir)
80+ extensionDirs = [d for d in dirs if d.startswith('chrome-extension_')]
81+
82+ for extensionDir in extensionDirs:
83+ extID = extensionDir.split('_')[1]
84+ url = retrieveURL(extID)
85+
86+ if len(url) > 0:
87+ return extID
88+
89+def findAndStoreExtensionID():
90+ extID = findExtensionID()
91+ f = open(extensionID_file, 'w')
92+ f.write(extID)
93+ f.close()
94+ return extID
95+
96+def retrieveURL(extID):
97+ # Build the complete path to the database inside goolge chrome directory
98+ databaseName = "chrome-extension_%s_0.localstorage" % extID
99+ databasePath = join(localStorageDir, databaseName)
100+
101+ currentURL = ''
102+
103+ if exists(databasePath):
104+ # Form the SQLlite3 command to extract the data
105+ sql = "SELECT value FROM ItemTable WHERE key = 'RescueTimeLinuxUrl';"
106+ command = "sqlite3 \"%s\" \"%s\"" % (databasePath, sql)
107+
108+ runner = subprocess.Popen(command, shell=True,
109+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
110+ currentURL = runner.communicate()[0][:-1]
111+
112+ return currentURL
113+
114+
115+def check_whitelist(urlparse_tuple):
116+ """urlparse_tuple is a tuple returned by urlparse
117+ Return True if domain is allowed, False if not.
118+ """
119+ if not have_whitelist:
120+ # let everything through
121+ return True
122+ name = urlparse_tuple[1]
123+ for domain in allowed_domains:
124+ if name.find(domain) != -1:
125+ return True
126+ return False
127+
128+# Find and verify our extenionID
129+extensionID = ''
130+
131+if exists(extensionID_file):
132+ f = open(extensionID_file)
133+ extensionID = f.read()
134+ f.close()
135+else:
136+ extensionID = findAndStoreExtensionID()
137+
138+# Attempt to get URL
139+url = retrieveURL(extensionID)
140+
141+if len(url) == 0:
142+ # Extension ID must have changed
143+ extensionID = findAndStoreExtensionID()
144+ url = retrieveURL(extensionID)
145+
146+# Break it up into its parts
147+info = urlparse(url)
148+
149+# Check white list and log just the needed parts of the URL
150+allowed = check_whitelist(info)
151+if not allowed:
152+ print 'unlisted'
153+elif "google" in info[1].lower():
154+ print info[0] + "://" + info[1] + info[2]
155+else:
156+ print info[0] + "://" + info[1]
157
158=== modified file 'RescueTimeUploader/uploader.py'
159--- RescueTimeUploader/uploader.py 2012-08-14 17:19:37 +0000
160+++ RescueTimeUploader/uploader.py 2012-08-14 18:23:19 +0000
161@@ -23,6 +23,7 @@
162 socket.setdefaulttimeout(15)
163 import urllib
164 import urllib2
165+import threading
166
167 import RescueTimeUploader.options
168 import RescueTimeUploader.dirstructure
169@@ -178,12 +179,12 @@
170 if idle_time > (self.options.max_idle_minutes * 60):
171 return None
172 try:
173- exec_cmd = """xprop -id `xprop -root |awk '/_NET_ACTIVE_WINDOW/ {print $5; exit;}'` |awk -F = '/WM_CLASS/ {print $2; exit;}'| awk '{print $2}' | sed 's/^"//g' | sed 's/"$//g'"""
174+ exec_cmd = """xprop -id `xprop -root |awk '/^_NET_ACTIVE_WINDOW/ {print $5; exit;}'` |awk -F = '/WM_CLASS/ {print $2; exit;}'| awk '{print $2}' | sed 's/^"//g' | sed 's/"$//g'"""
175 runner = subprocess.Popen(exec_cmd, shell=True,
176 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
177 runner_res = runner.communicate()[0][:-1]
178- if not runner_res.isalnum():
179- exec_cmd = """xprop -id `xprop -root |awk '/_NET_ACTIVE_WINDOW/ {print $5; exit;}'` |awk -F = '/^WM_NAME/ {print $2; exit;}' | sed -e's/^ *"//g' | sed -e's/\"$//g'"""
180+ if len(runner_res) == 0:
181+ exec_cmd = """xprop -id `xprop -root |awk '/^_NET_ACTIVE_WINDOW/ {print $5; exit;}'` |awk -F = '/^WM_NAME/ {print $2; exit;}' | sed -e's/^ *"//g' | sed -e's/\"$//g'"""
182 runner = subprocess.Popen(exec_cmd, shell=True,
183 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
184 runner_res = runner.communicate()[0][:-1]
185@@ -259,7 +260,7 @@
186
187 encoded_title_re = re.compile("(0x[0-9abcdefABCDEF]*,* *)+$")
188 def _get_raw_window_title(self):
189- exec_cmd = """xprop -id `xprop -root |awk '/_NET_ACTIVE_WINDOW/ {print $5; exit;}'` |awk -F = '/^WM_NAME/ {print $2; exit;}' | sed -e's/^ *"//g' | sed -e's/\\"$//g'"""
190+ exec_cmd = """xprop -id `xprop -root |awk '/^_NET_ACTIVE_WINDOW/ {print $5; exit;}'` |awk -F = '/^WM_NAME/ {print $2; exit;}' | sed -e's/^ *"//g' | sed -e's/\\"$//g'"""
191 try:
192 runner = subprocess.Popen(exec_cmd, shell=True,
193 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
194@@ -333,6 +334,7 @@
195 ##out.flush()
196 self.dir_structure = RescueTimeUploader.dirstructure.DirStructure()
197 self.options = RescueTimeUploader.options.Options(self.dir_structure)
198+ self.time_objs_lock = threading.RLock()
199
200 signal.signal(signal.SIGTERM, handle_signal)
201 signal.signal(signal.SIGHUP, handle_signal)
202@@ -365,6 +367,8 @@
203
204
205 def get_latest_time_obj(self):
206+ self.time_objs_lock.acquire()
207+
208 f = file(os.path.join(self.dir_structure.tmp_dir, "notifier.debuglog"), "a")
209 f.write("---- STARTING CHECK ----\n")
210 f.write("archived_time_objs: %s\n" % self.archived_time_objs)
211@@ -398,6 +402,8 @@
212 latest_time_obj = timeobj
213 f.write("Returning %s\n" % latest_time_obj)
214 f.close()
215+
216+ self.time_objs_lock.release()
217 return latest_time_obj
218
219 def retrieve_credentials(self):
220@@ -435,8 +441,10 @@
221 print "Failed to save preferences on shutdown."
222 ##out.flush()
223 try:
224+ self.time_objs_lock.acquire()
225 self.time_objs[-1].close()
226 self.prepare_data(self.time_objs)
227+ self.time_objs_lock.release()
228 except:
229 print "Failed to prepare data on shutdown."
230 ##out.flush()
231@@ -494,6 +502,8 @@
232
233 try:
234 while True:
235+ self.time_objs_lock.acquire()
236+
237 # If the focused window has changed
238 if not self.time_objs[len(self.time_objs) - 1].still_active():
239 self.time_objs[len(self.time_objs) - 1].close()
240@@ -507,6 +517,8 @@
241 next_upload_time = datetime.datetime.today() + self.options.upload_interval
242 # Sleep for a few seconds
243 time.sleep(self.options.scan_interval_seconds)
244+
245+ self.time_objs_lock.release()
246 # Aborted by keyboard
247 except KeyboardInterrupt:
248 self.time_objs[-1].close()
249
250=== added directory 'chrome_extension'
251=== added file 'chrome_extension/background.html'
252--- chrome_extension/background.html 1970-01-01 00:00:00 +0000
253+++ chrome_extension/background.html 2012-08-14 18:23:19 +0000
254@@ -0,0 +1,55 @@
255+<!--
256+Copyright (c) 2010 Joseph Lisee <jlisee@gmail.com>
257+
258+Permission is hereby granted, free of charge, to any person obtaining a copy
259+of this software and associated documentation files (the "Software"), to deal
260+in the Software without restriction, including without limitation the rights
261+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
262+copies of the Software, and to permit persons to whom the Software is
263+furnished to do so, subject to the following conditions:
264+
265+The above copyright notice and this permission notice shall be included in
266+all copies or substantial portions of the Software.
267+
268+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
269+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
270+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
271+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
272+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
273+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
274+THE SOFTWARE.
275+-->
276+
277+<html>
278+ <script>
279+ // Logs the tab into local storage for reading later
280+ function logTab(tab) {
281+ // Grab the URL and chop to 1024 charaters
282+ extended_info = tab.url;
283+ if (extended_info.length > 1024)
284+ extended_info = extended_info.substring(0, 1023);
285+
286+ // Store in our local storage for later retrieval
287+ localStorage['RescueTimeLinuxUrl'] = extended_info
288+
289+ // Log to console (for debugging only)
290+ //console.log(localStorage['RescueTimeLinuxUrl']);
291+ }
292+
293+ // Wrapper to grab tabId then call logTab
294+ function logTabById(tabId) {
295+ chrome.tabs.get(tabId, logTab);
296+ }
297+
298+ // Subscribe to the tab change event
299+ chrome.tabs.onSelectionChanged.addListener(function(tabId, selectionInfo) {
300+ logTabById(tabId);
301+ });
302+
303+ // Subscribe to the new tab creation event
304+ chrome.tabs.onCreated.addListener(logTab);
305+
306+ // Subscribe to when the current tab is changed
307+ chrome.tabs.onUpdated.addListener(logTabById);
308+ </script>
309+</html>
310
311=== added file 'chrome_extension/icon128.png'
312Binary files chrome_extension/icon128.png 1970-01-01 00:00:00 +0000 and chrome_extension/icon128.png 2012-08-14 18:23:19 +0000 differ
313=== added file 'chrome_extension/icon48.png'
314Binary files chrome_extension/icon48.png 1970-01-01 00:00:00 +0000 and chrome_extension/icon48.png 2012-08-14 18:23:19 +0000 differ
315=== added file 'chrome_extension/manifest.json'
316--- chrome_extension/manifest.json 1970-01-01 00:00:00 +0000
317+++ chrome_extension/manifest.json 2012-08-14 18:23:19 +0000
318@@ -0,0 +1,14 @@
319+{
320+ "name": "RescueTime Linux",
321+ "version": "1.0",
322+ "description": "Logs current URL data for use by RescueTime Linux Uploader.",
323+ "browser_action": {
324+ "default_icon": "toolbar-button.png"
325+ },
326+ "icons": {
327+ "128": "icon128.png",
328+ "48": "icon48.png"
329+ },
330+ "permissions": ["tabs"],
331+ "background_page" : "background.html"
332+}
333
334=== added file 'chrome_extension/toolbar-button.png'
335Binary files chrome_extension/toolbar-button.png 1970-01-01 00:00:00 +0000 and chrome_extension/toolbar-button.png 2012-08-14 18:23:19 +0000 differ

Subscribers

People subscribed via source and target branches