Merge lp:~thisfred/u1db/cosas-bg-sync into lp:u1db

Proposed by Eric Casteleijn
Status: Merged
Approved by: Eric Casteleijn
Approved revision: 376
Merged at revision: 371
Proposed branch: lp:~thisfred/u1db/cosas-bg-sync
Merge into: lp:u1db
Diff against target: 284 lines (+136/-47)
4 files modified
cosas/cosas.ui (+1/-1)
cosas/sync.ui (+13/-2)
cosas/ui.py (+121/-43)
html-docs/index.rst (+1/-1)
To merge this branch: bzr merge lp:~thisfred/u1db/cosas-bg-sync
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Review via email: mp+118398@code.launchpad.net

Commit message

Added background synchronisation to cosas.

Description of the change

Added background synchronisation to cosas.

Still to do:

- error handling
- conflict handling
- storing of the configuration, so it doesn't get forgotten on startup
- a way to store credentials for non u1 servers

To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) wrote :

Please don't start depending on qt4reactor :-)

review: Needs Fixing
lp:~thisfred/u1db/cosas-bg-sync updated
373. By Eric Casteleijn

s/reactor.callLater/QTimer.setSingleShot/

374. By Eric Casteleijn

store actual timer

375. By Eric Casteleijn

hmmmm

376. By Eric Casteleijn

fixed by not abusing singleshot

Revision history for this message
Roberto Alsina (ralsina) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cosas/cosas.ui'
2--- cosas/cosas.ui 2012-08-01 20:34:31 +0000
3+++ cosas/cosas.ui 2012-08-06 18:51:19 +0000
4@@ -60,7 +60,6 @@
5 border: 1px solid rgb(102,102,102);
6 }
7
8-*[foo="bar"] {color:red;}
9 </string>
10 </property>
11 <property name="toolButtonStyle">
12@@ -212,6 +211,7 @@
13 </widget>
14 <addaction name="menu_File"/>
15 </widget>
16+ <widget class="QStatusBar" name="statusBar"/>
17 <action name="action_synchronize">
18 <property name="text">
19 <string>&amp;Synchronize</string>
20
21=== modified file 'cosas/sync.ui'
22--- cosas/sync.ui 2012-05-11 14:16:36 +0000
23+++ cosas/sync.ui 2012-08-06 18:51:19 +0000
24@@ -7,7 +7,7 @@
25 <x>0</x>
26 <y>0</y>
27 <width>329</width>
28- <height>169</height>
29+ <height>200</height>
30 </rect>
31 </property>
32 <property name="windowTitle">
33@@ -114,13 +114,24 @@
34 </item>
35 </layout>
36 </item>
37+ <item>
38+ <layout class="QHBoxLayout" name="horizontalLayout">
39+ <item>
40+ <widget class="QCheckBox" name="auto_sync">
41+ <property name="text">
42+ <string>Automatically sync every 30 minutes</string>
43+ </property>
44+ </widget>
45+ </item>
46+ </layout>
47+ </item>
48 </layout>
49 </widget>
50 </item>
51 <item>
52 <widget class="QPushButton" name="sync_button">
53 <property name="text">
54- <string>Syn&amp;chronize</string>
55+ <string>Syn&amp;chronize now</string>
56 </property>
57 </widget>
58 </item>
59
60=== modified file 'cosas/ui.py'
61--- cosas/ui.py 2012-08-02 14:32:47 +0000
62+++ cosas/ui.py 2012-08-06 18:51:19 +0000
63@@ -44,6 +44,8 @@
64 (159, 197, 232),
65 (180, 167, 214),
66 (213, 166, 189)]
67+U1_URL = 'https://u1db.one.ubuntu.com/~/cosas'
68+TIMEOUT = 1000 * 0.5 * 60 * 60 # 30 minutes
69
70
71 class UITask(QtGui.QTreeWidgetItem):
72@@ -131,58 +133,73 @@
73 uifile = os.path.join(
74 os.path.abspath(os.path.dirname(__file__)), 'sync.ui')
75 uic.loadUi(uifile, self)
76- self.connect_events()
77 self.other = other
78+ if other.auto_sync:
79+ self.auto_sync.setChecked(True)
80+ if other.sync_target == U1_URL:
81+ self.u1_radio.setChecked(True)
82+ self.url_radio.setChecked(False)
83+ else:
84+ self.url_radio.setChecked(True)
85+ self.u1_radio.setChecked(False)
86+ self.url_edit.setText(other.sync_target)
87+ self.connect_events()
88
89 def connect_events(self):
90 """Hook up all the signal handlers."""
91 self.sync_button.clicked.connect(self.synchronize)
92+ self.u1_radio.toggled.connect(self.toggle_u1)
93+ self.url_radio.toggled.connect(self.toggle_url)
94+ self.auto_sync.toggled.connect(self.toggle_sync)
95+ self.url_edit.editingFinished.connect(self.url_changed)
96
97- def get_ubuntuone_credentials(self):
98- cmt = CredentialsManagementTool()
99- return cmt.find_credentials()
100+ def enable_button(self, _=None):
101+ self.sync_button.setEnabled(True)
102
103 def synchronize(self):
104 self.sync_button.setEnabled(False)
105- if self.u1_radio.isChecked():
106- d = self.get_ubuntuone_credentials()
107- d.addCallback(self._synchronize)
108- else:
109- # TODO: add ui for entering creds for non u1 servers.
110- self._synchronize()
111-
112- def _synchronize(self, creds=None):
113- if self.u1_radio.isChecked():
114- # TODO: not hardcode
115- target = 'https://u1db.one.ubuntu.com/~/cosas'
116- else:
117- target = self.url_edit.text()
118- if target.startswith('http://') or target.startswith('https://'):
119- st = HTTPSyncTarget.connect(target)
120- oauth_creds = {
121- 'token_key': creds['token'],
122- 'token_secret': creds['token_secret'],
123- 'consumer_key': creds['consumer_key'],
124- 'consumer_secret': creds['consumer_secret']}
125- if creds:
126- st.set_oauth_credentials(**oauth_creds)
127- else:
128- db = u1db.open(target, create=True)
129- st = db.get_sync_target()
130- syncer = Synchronizer(self.store.db, st)
131- try:
132- syncer.sync()
133- except DatabaseDoesNotExist:
134- # The server does not yet have the database, so create it.
135- if target.startswith('http://') or target.startswith('https://'):
136- db = HTTPDatabase(target)
137- db.set_oauth_credentials(**oauth_creds)
138- db.open(create=True)
139- syncer.sync()
140- self.other.refresh_filter()
141+ self.other.synchronize(self.enable_button)
142 self.last_synced.setText(
143- '<span style="color:green">%s</span>' % (datetime.now()))
144- self.sync_button.setEnabled(True)
145+ '<span style="color:green">%s</span>' % (datetime.now(),))
146+
147+ def toggle_u1(self, value):
148+ if value:
149+ self.other.sync_target = U1_URL
150+ else:
151+ text = unicode(self.url_edit.text(), 'utf-8')
152+ if not text:
153+ # There was no text in the edit field so do nothing.
154+ self.other.sync_target = None
155+ return
156+ self.other.sync_target = text
157+
158+ def toggle_url(self, value):
159+ if value:
160+ text = unicode(self.url_edit.text(), 'utf-8')
161+ if not text:
162+ # There was no text in the edit field so do nothing.
163+ self.other.sync_target = None
164+ return
165+ else:
166+ self.other.sync_target = U1_URL
167+ self.other.sync_target = text
168+
169+ def toggle_sync(self, value):
170+ self.other.auto_sync = value
171+ if value:
172+ self.other.start_auto_sync()
173+ else:
174+ self.other.stop_auto_sync()
175+
176+ def url_changed(self):
177+ if not self.url_radio.isChecked():
178+ return
179+ text = unicode(self.url_edit.text(), 'utf-8')
180+ if not text:
181+ # There was no text in the edit field so do nothing.
182+ self.other.sync_target = None
183+ return
184+ self.other.sync_target = text
185
186
187 class Main(QtGui.QMainWindow):
188@@ -194,7 +211,6 @@
189 uifile = os.path.join(
190 os.path.abspath(os.path.dirname(__file__)), 'cosas.ui')
191 uic.loadUi(uifile, self)
192- # set the model for the treeview
193 self.buttons_frame.hide()
194 # hook up the signals to the signal handlers.
195 self.connect_events()
196@@ -220,6 +236,13 @@
197 # Give the edit field focus.
198 self.title_edit.setFocus()
199 self.editing = False
200+ self.last_synced = None
201+ self.sync_target = U1_URL
202+ self.auto_sync = False
203+ self._timer = QtCore.QTimer()
204+
205+ def update_status_bar(self, message):
206+ self.statusBar.showMessage(message)
207
208 def keyPressEvent(self, event):
209 if event.key() == QtCore.Qt.Key_Delete:
210@@ -405,6 +428,61 @@
211 return
212 item.set_color(WHITE)
213
214+ def get_ubuntuone_credentials(self):
215+ cmt = CredentialsManagementTool()
216+ return cmt.find_credentials()
217+
218+ def synchronize(self, finalize):
219+ if self.sync_target == 'https://u1db.one.ubuntu.com/~/cosas':
220+ d = self.get_ubuntuone_credentials()
221+ d.addCallback(self._synchronize)
222+ d.addCallback(finalize)
223+ else:
224+ # TODO: add ui for entering creds for non u1 servers.
225+ self._synchronize()
226+ finalize()
227+
228+ def _auto_sync(self):
229+ self._timer.stop()
230+ try:
231+ self.synchronize(lambda _: None)
232+ finally:
233+ self._timer.start(TIMEOUT)
234+
235+ def start_auto_sync(self):
236+ self._timer.timeout.connect(self._auto_sync)
237+ self._timer.start(TIMEOUT)
238+
239+ def stop_auto_sync(self):
240+ self._timer.stop()
241+
242+ def _synchronize(self, creds=None):
243+ target = self.sync_target
244+ if target.startswith('http://') or target.startswith('https://'):
245+ st = HTTPSyncTarget.connect(target)
246+ oauth_creds = {
247+ 'token_key': creds['token'],
248+ 'token_secret': creds['token_secret'],
249+ 'consumer_key': creds['consumer_key'],
250+ 'consumer_secret': creds['consumer_secret']}
251+ if creds:
252+ st.set_oauth_credentials(**oauth_creds)
253+ else:
254+ db = u1db.open(target, create=True)
255+ st = db.get_sync_target()
256+ syncer = Synchronizer(self.store.db, st)
257+ try:
258+ syncer.sync()
259+ except DatabaseDoesNotExist:
260+ # The server does not yet have the database, so create it.
261+ if target.startswith('http://') or target.startswith('https://'):
262+ db = HTTPDatabase(target)
263+ db.set_oauth_credentials(**oauth_creds)
264+ db.open(create=True)
265+ syncer.sync()
266+ self.refresh_filter()
267+ self.update_status_bar("last synced: %s" % (datetime.now(),))
268+
269
270 if __name__ == "__main__":
271 # TODO: Unfortunately, to be able to use ubuntuone.platform.credentials on
272
273=== modified file 'html-docs/index.rst'
274--- html-docs/index.rst 2012-07-16 16:45:45 +0000
275+++ html-docs/index.rst 2012-08-06 18:51:19 +0000
276@@ -43,7 +43,7 @@
277 ===================== =========== ================= ==============
278 Ubuntu, Windows, OS X Python SQLite :ref:`reference-implementation`
279 Ubuntu Vala SQLite `lp:shardbridge <http://launchpad.net/shardbridge/>`_
280- Ubuntu, Windows, OS X C SQLite planned
281+ Ubuntu, Windows, OS X C SQLite part of `lp:u1db <http://launchpad.net/u1db/>`_
282 Web JavaScript localStorage planned
283 Android Java SQLite planned
284 iOS Objective C SQLite planned

Subscribers

People subscribed via source and target branches