def on_response(self, session, msg, data): status = msg.status_code if not 200 <= status < 400: logger.error( 'Subscriptions synchronization failed {0}'.format(status)) return # Clear database, it's easier than updating everything ;) q = '; DELETE FROM '.join(('subscriptions', 'labels', 'labels_fk')) sqlite.executescript('DELETE FROM ' + q) res = json.loads(msg.response_body.data)['subscriptions'] # Some items do not have htmlUrl for d in res: d.setdefault('htmlUrl') # Reinsert items q = '''INSERT INTO subscriptions(id, url, title) VALUES(:id, :htmlUrl, :title)''' sqlite.executemany(q, res) lid = lambda x: x['id'].split('/', 2)[-1] # Reinsert labels q = 'INSERT OR IGNORE INTO labels(id, name) VALUES (?, ?)' values = {(lid(l), l['label']) for s in res for l in s['categories']} sqlite.executemany(q, values) # Estabilish foreign keys via labels_fk q = 'INSERT INTO labels_fk(item_id, label_id) VALUES(?, ?)' values = ((s['id'], lid(l)) for s in res for l in s['categories']) sqlite.executemany(q, values) logger.debug('Subscriptions synchronization completed') GLib.idle_add(self.emit, 'sync-done')
def on_sync_ids(self, job, success): if not success: logger.error('Could not get data from SQLite') return if len(job.result) == 0: logger.debug('Items doesn\'t need synchronization') GLib.idle_add(self.emit, 'sync-done') return # Somewhy when streaming items and asking more than 512 returns 400. # Asking anything in between 250 and 512 returns exactly 250 items. chunks = split_chunks((('i', i) for i, in job.result), 250, ('', '')) # Asynchronous job queue for items parsing # We will, unless we have a bug, have only one synchronization at time # thus it is safe to initialize it like that. executor = JobExecutor() executor.start() uri = api_method('stream/items/contents') req_type = 'application/x-www-form-urlencoded' for chunk in chunks: self.sync_status += 1 data = urlencode(chunk) message = self.auth.message('POST', uri) message.set_request(req_type, Soup.MemoryUse.COPY, data, len(data)) session.queue_message(message, self.on_response, executor) self.connect('notify::sync-status', self.on_sync_status, executor)
def on_data(self, job, success, data): flag, st = data self.sync_status -= 1 if not success: logger.error('Could not get data from SQLite correctly') return if not len(job.result) == 0: uri = api_method('edit-tag') req_type = 'application/x-www-form-urlencoded' post = ( ( 'r' if st else 'a', flag, ), ('T', self.auth.edit_token), ) chunks = split_chunks(job.result, 250, None) for chunk in chunks: iids, ids = zip(*filter(lambda x: x is not None, chunk)) iids = tuple(zip(itertools.repeat('i'), iids)) payload = urlencode(iids + post) msg = self.auth.message('POST', uri) msg.set_request(req_type, Soup.MemoryUse.COPY, payload, len(payload)) session.queue_message(msg, self.on_response, ids) self.sync_status += 1 if self.sync_status == 0: # In case we didn't have any flags to synchronize logger.debug('There were no flags to synchronize') GLib.idle_add(self.emit, 'sync-done')
def __setitem__(self, key, value): logger.debug('{0} = {1}'.format(key, value)) if key not in self.types: logger.error('Cannot set value, because we don\'t know type (it\'s' ' not in self.types') return value = getattr(GLib.Variant, 'new_{0}'.format(self.types[key]))(value) self.set_value(key, value)
def on_token(self, session, message, data=None): status = message.status_code if not 200 <= status < 400: logger.error('Token request failed (HTTP {0})'.format(status)) else: self.edit_token = message.response_body.data self.edit_token_expire = int(GLib.get_real_time() + 1.5E9) #µs self.status.update({'PROGRESS': False, 'OK': 200 <= status < 400}) self.notify('status')
def on_response(self, session, message, executor): status = message.status_code if not 200 <= status < 400: logger.error('Items synchronization failed {0}'.format(status)) return job = executor.submit(itemparse.process_items, message.response_body.data) job.connect('finished', self.on_chunk_parsed, executor)
def on_navigate(self, frame, request, action, policy): policy.ignore() uri = action.get_original_uri() if frame is not self.get_main_frame(): return True elif uri.startswith('file://'): return False elif not Gio.AppInfo.launch_default_for_uri(uri, None): logger.error('System could not open {0}'.format(uri)) return True
def sync(self): if self.sync_status > 0: logger.error('Flags are already being synchronized') return False self.sync_status = 0 query = 'SELECT item_id, id FROM flags WHERE flag=? AND remove=?' for flag, st in itertools.product(StateIds, [True, False]): self.sync_status += 1 sqlite.execute(query, (flag, st)).connect('finished', self.on_data, (flag, st))
def _on_item_status(self, column, value): item_view = self._builder.get_object('item-view') items = self._builder.get_object('items-view') item_id = item_view.item_id for row in items.main_model: if row[ItemsColumn.ID] == item_id: row[ItemsColumn.FORCE_VISIBLE] = True row[column] = value return logger.error( "Couldn't set status for item {0}, it doesn't exist".format( item_id))
def on_login(self, session, message, data): status = message.status_code if not 200 <= status < 400: logger.error('Authentication failed (HTTP {0})'.format(status)) self.status.update({'OK': False, 'PROGRESS': False, 'BAD_CREDENTIALS': status == 403}) self.notify('status') else: # Login was likely successful for line in message.response_body.data.splitlines(): if line.startswith('Auth'): self.login_token = line[5:] message = self.message('GET', api_method('token')) session.queue_message(message, self.on_token, None) break
def on_response(self, session, message, data): self.sync_status -= 1 if self.sync_status == 0: logger.debug('Flags synchronizaton completed') GLib.idle_add(self.emit, 'sync-done') status = message.status_code if not 200 <= status < 400: logger.error('Flags synchronizaton failed {0}'.format(status)) return False data = ((i, ) for i in data) sqlite.executemany('DELETE FROM flags WHERE id=?', data) if self.sync_status == 0: sqlite.commit()
def sync(self): if self.sync_status.get('synchronizing', False): logger.error('IDs are already being synchronized') return False self.sync_status['synchronizing'] = True item_limit = settings.settings['cache-items'] for name, state in self.states.items(): getargs = state + [('n', item_limit)] url = api_method('stream/items/ids', getargs) msg = self.auth.message('GET', url) session.queue_message(msg, self.on_response, name) # Initially mark everything as deletable and unflag all items. # Laten in process items that are still important will be unmarked # and reflagged again. query = 'UPDATE items SET to_delete=1, unread=0, starred=0, to_sync=0' sqlite.execute(query)
def on_response(self, session, msg, data): status = msg.status_code if not 200 <= status < 400: logger.error('IDs synchronization failed: {0}'.format(status)) return False res = json.loads(msg.response_body.data)['itemRefs'] id_list = [(int(i['id']), ) for i in res] self.ensure_ids(id_list) self.set_sync_flag({ 'update_time': int(i['timestampUsec']), 'id': int(i['id']) } for i in res) if data in ['unread', 'starred']: self.set_flag(data, id_list) self.sync_status[data] = True GLib.idle_add(self.notify, 'sync-status')
def set_item_label(self, vals, label_id, value): if vals[0] != SubscriptionType.SUBSCRIPTION: logger.error('Adding label to non-subscription!') return False uri = api_method('subscription/edit') req_type = 'application/x-www-form-urlencoded' label_id = 'user/-/{0}'.format(label_id) action = 'a' if value else 'r' item_id = split_id(vals[1])[1] data = urlencode({ 'T': self.auth.edit_token, 's': item_id, 'ac': 'edit', action: label_id }) msg = self.auth.message('POST', uri) msg.set_request(req_type, Soup.MemoryUse.COPY, data, len(data)) session.queue_message(msg, self.on_sub_edit, None)
def stored(source, result, data): if not Secret.password_store_finish(result): logger.error('Could not store password into keyring')
def on_quickadd(self, session, msg, data=None): if not 200 <= msg.status_code < 400: logger.error('Add request returned {0}'.format(msg.status_code)) GLib.idle_add(self.emit, 'subscribed', False) res = json.loads(msg.response_body.data) GLib.idle_add(self.emit, 'subscribed', 'streamId' in res)
def on_sub_edit(self, session, msg, data=None): if not 200 <= msg.status_code < 400: logger.error('Edit request returned {0}'.format(msg.status_code)) return False GLib.idle_add(self.emit, 'label-set', 200 <= msg.status_code < 400)