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
=== modified file 'RescueTimeUploader/extensions/Gnome-terminal/app_name'
--- RescueTimeUploader/extensions/Gnome-terminal/app_name 2008-02-03 16:54:21 +0000
+++ RescueTimeUploader/extensions/Gnome-terminal/app_name 2012-08-14 18:23:19 +0000
@@ -1,5 +1,10 @@
1#!/usr/bin/env python1#!/usr/bin/env python
22
3"""
4Returns the remote host name if the terminal is an ssh session, otherwise it
5returns given app_name (in this case 'Gnome-terminal')
6"""
7
3import sys8import sys
4import os9import os
5app_name = raw_input("")10app_name = raw_input("")
611
=== added directory 'RescueTimeUploader/extensions/Google-chrome'
=== added file 'RescueTimeUploader/extensions/Google-chrome/extended_info'
--- RescueTimeUploader/extensions/Google-chrome/extended_info 1970-01-01 00:00:00 +0000
+++ RescueTimeUploader/extensions/Google-chrome/extended_info 2012-08-14 18:23:19 +0000
@@ -0,0 +1,136 @@
1#!/usr/bin/env python
2
3# Copyright (c) 2010 Joseph Lisee <jlisee@gmail.com>
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in
13# all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21# THE SOFTWARE.
22
23# White list checking and URL parsing our borrowed from the firefox extension
24# in the future the code should be merged somehow
25
26
27import os
28import subprocess
29from urlparse import urlparse
30from os.path import expanduser, join, exists
31
32"""
33Extracts the current google chrome URL local HTML storage of the extension and
34prints it to stdout. It is intelligent about searching out and finding the
35write google extension local storage database, and cashes the result for use.
36"""
37
38# Overall settings and paths
39preferenceDir = join(expanduser('~'), '.rescuetime')
40whitelist_file = join(preferenceDir, 'domainwhitelist.txt')
41extensionID_file = join(preferenceDir, 'google-chrome_extension-id.txt')
42localStorageDir = join(os.getenv("HOME"), ".config", "google-chrome",
43 "Default", "Local Storage")
44
45# Load whitelist
46allowed_domains = []
47
48if exists(whitelist_file):
49 have_whitelist = True
50 for line in open(whitelist_file):
51 # strip comments and whitespace
52 line = line.split('#', 1)[0].strip()
53 if line:
54 allowed_domains.append(line)
55else:
56 have_whitelist = False
57
58def findExtensionID():
59 dirs = os.listdir(localStorageDir)
60 extensionDirs = [d for d in dirs if d.startswith('chrome-extension_')]
61
62 for extensionDir in extensionDirs:
63 extID = extensionDir.split('_')[1]
64 url = retrieveURL(extID)
65
66 if len(url) > 0:
67 return extID
68
69def findAndStoreExtensionID():
70 extID = findExtensionID()
71 f = open(extensionID_file, 'w')
72 f.write(extID)
73 f.close()
74 return extID
75
76def retrieveURL(extID):
77 # Build the complete path to the database inside goolge chrome directory
78 databaseName = "chrome-extension_%s_0.localstorage" % extID
79 databasePath = join(localStorageDir, databaseName)
80
81 currentURL = ''
82
83 if exists(databasePath):
84 # Form the SQLlite3 command to extract the data
85 sql = "SELECT value FROM ItemTable WHERE key = 'RescueTimeLinuxUrl';"
86 command = "sqlite3 \"%s\" \"%s\"" % (databasePath, sql)
87
88 runner = subprocess.Popen(command, shell=True,
89 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
90 currentURL = runner.communicate()[0][:-1]
91
92 return currentURL
93
94
95def check_whitelist(urlparse_tuple):
96 """urlparse_tuple is a tuple returned by urlparse
97 Return True if domain is allowed, False if not.
98 """
99 if not have_whitelist:
100 # let everything through
101 return True
102 name = urlparse_tuple[1]
103 for domain in allowed_domains:
104 if name.find(domain) != -1:
105 return True
106 return False
107
108# Find and verify our extenionID
109extensionID = ''
110
111if exists(extensionID_file):
112 f = open(extensionID_file)
113 extensionID = f.read()
114 f.close()
115else:
116 extensionID = findAndStoreExtensionID()
117
118# Attempt to get URL
119url = retrieveURL(extensionID)
120
121if len(url) == 0:
122 # Extension ID must have changed
123 extensionID = findAndStoreExtensionID()
124 url = retrieveURL(extensionID)
125
126# Break it up into its parts
127info = urlparse(url)
128
129# Check white list and log just the needed parts of the URL
130allowed = check_whitelist(info)
131if not allowed:
132 print 'unlisted'
133elif "google" in info[1].lower():
134 print info[0] + "://" + info[1] + info[2]
135else:
136 print info[0] + "://" + info[1]
0137
=== modified file 'RescueTimeUploader/uploader.py'
--- RescueTimeUploader/uploader.py 2012-08-14 17:19:37 +0000
+++ RescueTimeUploader/uploader.py 2012-08-14 18:23:19 +0000
@@ -23,6 +23,7 @@
23socket.setdefaulttimeout(15)23socket.setdefaulttimeout(15)
24import urllib24import urllib
25import urllib225import urllib2
26import threading
2627
27import RescueTimeUploader.options28import RescueTimeUploader.options
28import RescueTimeUploader.dirstructure29import RescueTimeUploader.dirstructure
@@ -178,12 +179,12 @@
178 if idle_time > (self.options.max_idle_minutes * 60):179 if idle_time > (self.options.max_idle_minutes * 60):
179 return None180 return None
180 try:181 try:
181 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'"""182 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'"""
182 runner = subprocess.Popen(exec_cmd, shell=True, 183 runner = subprocess.Popen(exec_cmd, shell=True,
183 stdin=subprocess.PIPE, stdout=subprocess.PIPE)184 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
184 runner_res = runner.communicate()[0][:-1]185 runner_res = runner.communicate()[0][:-1]
185 if not runner_res.isalnum():186 if len(runner_res) == 0:
186 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'"""187 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'"""
187 runner = subprocess.Popen(exec_cmd, shell=True,188 runner = subprocess.Popen(exec_cmd, shell=True,
188 stdin=subprocess.PIPE, stdout=subprocess.PIPE)189 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
189 runner_res = runner.communicate()[0][:-1]190 runner_res = runner.communicate()[0][:-1]
@@ -259,7 +260,7 @@
259 260
260 encoded_title_re = re.compile("(0x[0-9abcdefABCDEF]*,* *)+$")261 encoded_title_re = re.compile("(0x[0-9abcdefABCDEF]*,* *)+$")
261 def _get_raw_window_title(self):262 def _get_raw_window_title(self):
262 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'"""263 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'"""
263 try:264 try:
264 runner = subprocess.Popen(exec_cmd, shell=True, 265 runner = subprocess.Popen(exec_cmd, shell=True,
265 stdin=subprocess.PIPE, stdout=subprocess.PIPE)266 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
@@ -333,6 +334,7 @@
333 ##out.flush()334 ##out.flush()
334 self.dir_structure = RescueTimeUploader.dirstructure.DirStructure()335 self.dir_structure = RescueTimeUploader.dirstructure.DirStructure()
335 self.options = RescueTimeUploader.options.Options(self.dir_structure)336 self.options = RescueTimeUploader.options.Options(self.dir_structure)
337 self.time_objs_lock = threading.RLock()
336338
337 signal.signal(signal.SIGTERM, handle_signal)339 signal.signal(signal.SIGTERM, handle_signal)
338 signal.signal(signal.SIGHUP, handle_signal)340 signal.signal(signal.SIGHUP, handle_signal)
@@ -365,6 +367,8 @@
365 367
366 368
367 def get_latest_time_obj(self):369 def get_latest_time_obj(self):
370 self.time_objs_lock.acquire()
371
368 f = file(os.path.join(self.dir_structure.tmp_dir, "notifier.debuglog"), "a")372 f = file(os.path.join(self.dir_structure.tmp_dir, "notifier.debuglog"), "a")
369 f.write("---- STARTING CHECK ----\n")373 f.write("---- STARTING CHECK ----\n")
370 f.write("archived_time_objs: %s\n" % self.archived_time_objs)374 f.write("archived_time_objs: %s\n" % self.archived_time_objs)
@@ -398,6 +402,8 @@
398 latest_time_obj = timeobj402 latest_time_obj = timeobj
399 f.write("Returning %s\n" % latest_time_obj)403 f.write("Returning %s\n" % latest_time_obj)
400 f.close()404 f.close()
405
406 self.time_objs_lock.release()
401 return latest_time_obj407 return latest_time_obj
402 408
403 def retrieve_credentials(self):409 def retrieve_credentials(self):
@@ -435,8 +441,10 @@
435 print "Failed to save preferences on shutdown."441 print "Failed to save preferences on shutdown."
436 ##out.flush()442 ##out.flush()
437 try:443 try:
444 self.time_objs_lock.acquire()
438 self.time_objs[-1].close()445 self.time_objs[-1].close()
439 self.prepare_data(self.time_objs)446 self.prepare_data(self.time_objs)
447 self.time_objs_lock.release()
440 except:448 except:
441 print "Failed to prepare data on shutdown."449 print "Failed to prepare data on shutdown."
442 ##out.flush()450 ##out.flush()
@@ -494,6 +502,8 @@
494502
495 try:503 try:
496 while True:504 while True:
505 self.time_objs_lock.acquire()
506
497 # If the focused window has changed507 # If the focused window has changed
498 if not self.time_objs[len(self.time_objs) - 1].still_active():508 if not self.time_objs[len(self.time_objs) - 1].still_active():
499 self.time_objs[len(self.time_objs) - 1].close()509 self.time_objs[len(self.time_objs) - 1].close()
@@ -507,6 +517,8 @@
507 next_upload_time = datetime.datetime.today() + self.options.upload_interval517 next_upload_time = datetime.datetime.today() + self.options.upload_interval
508 # Sleep for a few seconds518 # Sleep for a few seconds
509 time.sleep(self.options.scan_interval_seconds)519 time.sleep(self.options.scan_interval_seconds)
520
521 self.time_objs_lock.release()
510 # Aborted by keyboard522 # Aborted by keyboard
511 except KeyboardInterrupt:523 except KeyboardInterrupt:
512 self.time_objs[-1].close()524 self.time_objs[-1].close()
513525
=== added directory 'chrome_extension'
=== added file 'chrome_extension/background.html'
--- chrome_extension/background.html 1970-01-01 00:00:00 +0000
+++ chrome_extension/background.html 2012-08-14 18:23:19 +0000
@@ -0,0 +1,55 @@
1<!--
2Copyright (c) 2010 Joseph Lisee <jlisee@gmail.com>
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20THE SOFTWARE.
21-->
22
23<html>
24 <script>
25 // Logs the tab into local storage for reading later
26 function logTab(tab) {
27 // Grab the URL and chop to 1024 charaters
28 extended_info = tab.url;
29 if (extended_info.length > 1024)
30 extended_info = extended_info.substring(0, 1023);
31
32 // Store in our local storage for later retrieval
33 localStorage['RescueTimeLinuxUrl'] = extended_info
34
35 // Log to console (for debugging only)
36 //console.log(localStorage['RescueTimeLinuxUrl']);
37 }
38
39 // Wrapper to grab tabId then call logTab
40 function logTabById(tabId) {
41 chrome.tabs.get(tabId, logTab);
42 }
43
44 // Subscribe to the tab change event
45 chrome.tabs.onSelectionChanged.addListener(function(tabId, selectionInfo) {
46 logTabById(tabId);
47 });
48
49 // Subscribe to the new tab creation event
50 chrome.tabs.onCreated.addListener(logTab);
51
52 // Subscribe to when the current tab is changed
53 chrome.tabs.onUpdated.addListener(logTabById);
54 </script>
55</html>
056
=== added file 'chrome_extension/icon128.png'
1Binary files chrome_extension/icon128.png 1970-01-01 00:00:00 +0000 and chrome_extension/icon128.png 2012-08-14 18:23:19 +0000 differ57Binary 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
=== added file 'chrome_extension/icon48.png'
2Binary files chrome_extension/icon48.png 1970-01-01 00:00:00 +0000 and chrome_extension/icon48.png 2012-08-14 18:23:19 +0000 differ58Binary 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
=== added file 'chrome_extension/manifest.json'
--- chrome_extension/manifest.json 1970-01-01 00:00:00 +0000
+++ chrome_extension/manifest.json 2012-08-14 18:23:19 +0000
@@ -0,0 +1,14 @@
1{
2 "name": "RescueTime Linux",
3 "version": "1.0",
4 "description": "Logs current URL data for use by RescueTime Linux Uploader.",
5 "browser_action": {
6 "default_icon": "toolbar-button.png"
7 },
8 "icons": {
9 "128": "icon128.png",
10 "48": "icon48.png"
11 },
12 "permissions": ["tabs"],
13 "background_page" : "background.html"
14}
015
=== added file 'chrome_extension/toolbar-button.png'
1Binary 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 differ16Binary 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