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
=== modified file 'cosas/cosas.ui'
--- cosas/cosas.ui 2012-08-01 20:34:31 +0000
+++ cosas/cosas.ui 2012-08-06 18:51:19 +0000
@@ -60,7 +60,6 @@
60 border: 1px solid rgb(102,102,102);60 border: 1px solid rgb(102,102,102);
61}61}
6262
63*[foo="bar"] {color:red;}
64</string>63</string>
65 </property>64 </property>
66 <property name="toolButtonStyle">65 <property name="toolButtonStyle">
@@ -212,6 +211,7 @@
212 </widget>211 </widget>
213 <addaction name="menu_File"/>212 <addaction name="menu_File"/>
214 </widget>213 </widget>
214 <widget class="QStatusBar" name="statusBar"/>
215 <action name="action_synchronize">215 <action name="action_synchronize">
216 <property name="text">216 <property name="text">
217 <string>&amp;Synchronize</string>217 <string>&amp;Synchronize</string>
218218
=== modified file 'cosas/sync.ui'
--- cosas/sync.ui 2012-05-11 14:16:36 +0000
+++ cosas/sync.ui 2012-08-06 18:51:19 +0000
@@ -7,7 +7,7 @@
7 <x>0</x>7 <x>0</x>
8 <y>0</y>8 <y>0</y>
9 <width>329</width>9 <width>329</width>
10 <height>169</height>10 <height>200</height>
11 </rect>11 </rect>
12 </property>12 </property>
13 <property name="windowTitle">13 <property name="windowTitle">
@@ -114,13 +114,24 @@
114 </item>114 </item>
115 </layout>115 </layout>
116 </item>116 </item>
117 <item>
118 <layout class="QHBoxLayout" name="horizontalLayout">
119 <item>
120 <widget class="QCheckBox" name="auto_sync">
121 <property name="text">
122 <string>Automatically sync every 30 minutes</string>
123 </property>
124 </widget>
125 </item>
126 </layout>
127 </item>
117 </layout>128 </layout>
118 </widget>129 </widget>
119 </item>130 </item>
120 <item>131 <item>
121 <widget class="QPushButton" name="sync_button">132 <widget class="QPushButton" name="sync_button">
122 <property name="text">133 <property name="text">
123 <string>Syn&amp;chronize</string>134 <string>Syn&amp;chronize now</string>
124 </property>135 </property>
125 </widget>136 </widget>
126 </item>137 </item>
127138
=== modified file 'cosas/ui.py'
--- cosas/ui.py 2012-08-02 14:32:47 +0000
+++ cosas/ui.py 2012-08-06 18:51:19 +0000
@@ -44,6 +44,8 @@
44 (159, 197, 232),44 (159, 197, 232),
45 (180, 167, 214),45 (180, 167, 214),
46 (213, 166, 189)]46 (213, 166, 189)]
47U1_URL = 'https://u1db.one.ubuntu.com/~/cosas'
48TIMEOUT = 1000 * 0.5 * 60 * 60 # 30 minutes
4749
4850
49class UITask(QtGui.QTreeWidgetItem):51class UITask(QtGui.QTreeWidgetItem):
@@ -131,58 +133,73 @@
131 uifile = os.path.join(133 uifile = os.path.join(
132 os.path.abspath(os.path.dirname(__file__)), 'sync.ui')134 os.path.abspath(os.path.dirname(__file__)), 'sync.ui')
133 uic.loadUi(uifile, self)135 uic.loadUi(uifile, self)
134 self.connect_events()
135 self.other = other136 self.other = other
137 if other.auto_sync:
138 self.auto_sync.setChecked(True)
139 if other.sync_target == U1_URL:
140 self.u1_radio.setChecked(True)
141 self.url_radio.setChecked(False)
142 else:
143 self.url_radio.setChecked(True)
144 self.u1_radio.setChecked(False)
145 self.url_edit.setText(other.sync_target)
146 self.connect_events()
136147
137 def connect_events(self):148 def connect_events(self):
138 """Hook up all the signal handlers."""149 """Hook up all the signal handlers."""
139 self.sync_button.clicked.connect(self.synchronize)150 self.sync_button.clicked.connect(self.synchronize)
151 self.u1_radio.toggled.connect(self.toggle_u1)
152 self.url_radio.toggled.connect(self.toggle_url)
153 self.auto_sync.toggled.connect(self.toggle_sync)
154 self.url_edit.editingFinished.connect(self.url_changed)
140155
141 def get_ubuntuone_credentials(self):156 def enable_button(self, _=None):
142 cmt = CredentialsManagementTool()157 self.sync_button.setEnabled(True)
143 return cmt.find_credentials()
144158
145 def synchronize(self):159 def synchronize(self):
146 self.sync_button.setEnabled(False)160 self.sync_button.setEnabled(False)
147 if self.u1_radio.isChecked():161 self.other.synchronize(self.enable_button)
148 d = self.get_ubuntuone_credentials()
149 d.addCallback(self._synchronize)
150 else:
151 # TODO: add ui for entering creds for non u1 servers.
152 self._synchronize()
153
154 def _synchronize(self, creds=None):
155 if self.u1_radio.isChecked():
156 # TODO: not hardcode
157 target = 'https://u1db.one.ubuntu.com/~/cosas'
158 else:
159 target = self.url_edit.text()
160 if target.startswith('http://') or target.startswith('https://'):
161 st = HTTPSyncTarget.connect(target)
162 oauth_creds = {
163 'token_key': creds['token'],
164 'token_secret': creds['token_secret'],
165 'consumer_key': creds['consumer_key'],
166 'consumer_secret': creds['consumer_secret']}
167 if creds:
168 st.set_oauth_credentials(**oauth_creds)
169 else:
170 db = u1db.open(target, create=True)
171 st = db.get_sync_target()
172 syncer = Synchronizer(self.store.db, st)
173 try:
174 syncer.sync()
175 except DatabaseDoesNotExist:
176 # The server does not yet have the database, so create it.
177 if target.startswith('http://') or target.startswith('https://'):
178 db = HTTPDatabase(target)
179 db.set_oauth_credentials(**oauth_creds)
180 db.open(create=True)
181 syncer.sync()
182 self.other.refresh_filter()
183 self.last_synced.setText(162 self.last_synced.setText(
184 '<span style="color:green">%s</span>' % (datetime.now()))163 '<span style="color:green">%s</span>' % (datetime.now(),))
185 self.sync_button.setEnabled(True)164
165 def toggle_u1(self, value):
166 if value:
167 self.other.sync_target = U1_URL
168 else:
169 text = unicode(self.url_edit.text(), 'utf-8')
170 if not text:
171 # There was no text in the edit field so do nothing.
172 self.other.sync_target = None
173 return
174 self.other.sync_target = text
175
176 def toggle_url(self, value):
177 if value:
178 text = unicode(self.url_edit.text(), 'utf-8')
179 if not text:
180 # There was no text in the edit field so do nothing.
181 self.other.sync_target = None
182 return
183 else:
184 self.other.sync_target = U1_URL
185 self.other.sync_target = text
186
187 def toggle_sync(self, value):
188 self.other.auto_sync = value
189 if value:
190 self.other.start_auto_sync()
191 else:
192 self.other.stop_auto_sync()
193
194 def url_changed(self):
195 if not self.url_radio.isChecked():
196 return
197 text = unicode(self.url_edit.text(), 'utf-8')
198 if not text:
199 # There was no text in the edit field so do nothing.
200 self.other.sync_target = None
201 return
202 self.other.sync_target = text
186203
187204
188class Main(QtGui.QMainWindow):205class Main(QtGui.QMainWindow):
@@ -194,7 +211,6 @@
194 uifile = os.path.join(211 uifile = os.path.join(
195 os.path.abspath(os.path.dirname(__file__)), 'cosas.ui')212 os.path.abspath(os.path.dirname(__file__)), 'cosas.ui')
196 uic.loadUi(uifile, self)213 uic.loadUi(uifile, self)
197 # set the model for the treeview
198 self.buttons_frame.hide()214 self.buttons_frame.hide()
199 # hook up the signals to the signal handlers.215 # hook up the signals to the signal handlers.
200 self.connect_events()216 self.connect_events()
@@ -220,6 +236,13 @@
220 # Give the edit field focus.236 # Give the edit field focus.
221 self.title_edit.setFocus()237 self.title_edit.setFocus()
222 self.editing = False238 self.editing = False
239 self.last_synced = None
240 self.sync_target = U1_URL
241 self.auto_sync = False
242 self._timer = QtCore.QTimer()
243
244 def update_status_bar(self, message):
245 self.statusBar.showMessage(message)
223246
224 def keyPressEvent(self, event):247 def keyPressEvent(self, event):
225 if event.key() == QtCore.Qt.Key_Delete:248 if event.key() == QtCore.Qt.Key_Delete:
@@ -405,6 +428,61 @@
405 return428 return
406 item.set_color(WHITE)429 item.set_color(WHITE)
407430
431 def get_ubuntuone_credentials(self):
432 cmt = CredentialsManagementTool()
433 return cmt.find_credentials()
434
435 def synchronize(self, finalize):
436 if self.sync_target == 'https://u1db.one.ubuntu.com/~/cosas':
437 d = self.get_ubuntuone_credentials()
438 d.addCallback(self._synchronize)
439 d.addCallback(finalize)
440 else:
441 # TODO: add ui for entering creds for non u1 servers.
442 self._synchronize()
443 finalize()
444
445 def _auto_sync(self):
446 self._timer.stop()
447 try:
448 self.synchronize(lambda _: None)
449 finally:
450 self._timer.start(TIMEOUT)
451
452 def start_auto_sync(self):
453 self._timer.timeout.connect(self._auto_sync)
454 self._timer.start(TIMEOUT)
455
456 def stop_auto_sync(self):
457 self._timer.stop()
458
459 def _synchronize(self, creds=None):
460 target = self.sync_target
461 if target.startswith('http://') or target.startswith('https://'):
462 st = HTTPSyncTarget.connect(target)
463 oauth_creds = {
464 'token_key': creds['token'],
465 'token_secret': creds['token_secret'],
466 'consumer_key': creds['consumer_key'],
467 'consumer_secret': creds['consumer_secret']}
468 if creds:
469 st.set_oauth_credentials(**oauth_creds)
470 else:
471 db = u1db.open(target, create=True)
472 st = db.get_sync_target()
473 syncer = Synchronizer(self.store.db, st)
474 try:
475 syncer.sync()
476 except DatabaseDoesNotExist:
477 # The server does not yet have the database, so create it.
478 if target.startswith('http://') or target.startswith('https://'):
479 db = HTTPDatabase(target)
480 db.set_oauth_credentials(**oauth_creds)
481 db.open(create=True)
482 syncer.sync()
483 self.refresh_filter()
484 self.update_status_bar("last synced: %s" % (datetime.now(),))
485
408486
409if __name__ == "__main__":487if __name__ == "__main__":
410 # TODO: Unfortunately, to be able to use ubuntuone.platform.credentials on488 # TODO: Unfortunately, to be able to use ubuntuone.platform.credentials on
411489
=== modified file 'html-docs/index.rst'
--- html-docs/index.rst 2012-07-16 16:45:45 +0000
+++ html-docs/index.rst 2012-08-06 18:51:19 +0000
@@ -43,7 +43,7 @@
43 ===================== =========== ================= ==============43 ===================== =========== ================= ==============
44 Ubuntu, Windows, OS X Python SQLite :ref:`reference-implementation`44 Ubuntu, Windows, OS X Python SQLite :ref:`reference-implementation`
45 Ubuntu Vala SQLite `lp:shardbridge <http://launchpad.net/shardbridge/>`_45 Ubuntu Vala SQLite `lp:shardbridge <http://launchpad.net/shardbridge/>`_
46 Ubuntu, Windows, OS X C SQLite planned46 Ubuntu, Windows, OS X C SQLite part of `lp:u1db <http://launchpad.net/u1db/>`_
47 Web JavaScript localStorage planned47 Web JavaScript localStorage planned
48 Android Java SQLite planned48 Android Java SQLite planned
49 iOS Objective C SQLite planned49 iOS Objective C SQLite planned

Subscribers

People subscribed via source and target branches