X-Git-Url: http://git.maemo.org/git/?p=gc-dialer;a=blobdiff_plain;f=src%2Fsession.py;h=a50245ab5335aa17f29feb211ec2f68e1b0babfa;hp=949b29adf9d3c5b875ea8ee8ee96238cecef0775;hb=51fac4abe1d256a58d3d62e41dc631eb58795d2b;hpb=124ae601f9e7432512b6c41c3e4fed71a0c427db diff --git a/src/session.py b/src/session.py index 949b29a..a50245a 100644 --- a/src/session.py +++ b/src/session.py @@ -3,6 +3,7 @@ from __future__ import with_statement import os import time import datetime +import contextlib import logging try: @@ -14,6 +15,7 @@ except ImportError: from PyQt4 import QtCore from util import qore_utils +from util import qui_utils from util import concurrent from util import misc as misc_utils @@ -44,29 +46,45 @@ class Draft(QtCore.QObject): recipientsChanged = QtCore.pyqtSignal() - def __init__(self, pool, backend): + def __init__(self, pool, backend, errorLog): QtCore.QObject.__init__(self) + self._errorLog = errorLog self._contacts = {} self._pool = pool self._backend = backend + self._busyReason = None + self._message = "" - def send(self, text): - assert 0 < len(self._contacts) + def send(self): + assert 0 < len(self._contacts), "No contacts selected" + assert 0 < len(self._message), "No message to send" numbers = [misc_utils.make_ugly(contact.selectedNumber) for contact in self._contacts.itervalues()] le = concurrent.AsyncLinearExecution(self._pool, self._send) - le.start(numbers, text) + le.start(numbers, self._message) def call(self): - assert len(self._contacts) == 1 + assert len(self._contacts) == 1, "Must select 1 and only 1 contact" + assert len(self._message) == 0, "Cannot send message with call" (contact, ) = self._contacts.itervalues() + number = misc_utils.make_ugly(contact.selectedNumber) le = concurrent.AsyncLinearExecution(self._pool, self._call) - le.start(contact.selectedNumber) + le.start(number) def cancel(self): le = concurrent.AsyncLinearExecution(self._pool, self._cancel) le.start() + def _get_message(self): + return self._message + + def _set_message(self, message): + self._message = message + + message = property(_get_message, _set_message) + def add_contact(self, contactId, title, description, numbersWithDescriptions): + if self._busyReason is not None: + raise RuntimeError("Please wait for %r" % self._busyReason) if contactId in self._contacts: _moduleLogger.info("Adding duplicate contact %r" % contactId) # @todo Remove this evil hack to re-popup the dialog @@ -77,7 +95,9 @@ class Draft(QtCore.QObject): self.recipientsChanged.emit() def remove_contact(self, contactId): - assert contactId in self._contacts + if self._busyReason is not None: + raise RuntimeError("Please wait for %r" % self._busyReason) + assert contactId in self._contacts, "Contact missing" del self._contacts[contactId] self.recipientsChanged.emit() @@ -102,51 +122,75 @@ class Draft(QtCore.QObject): def set_selected_number(self, cid, number): # @note I'm lazy, this isn't firing any kind of signal since only one # controller right now and that is the viewer - assert number in (nWD[0] for nWD in self._contacts[cid].numbers) + assert number in (nWD[0] for nWD in self._contacts[cid].numbers), "Number not selectable" self._contacts[cid].selectedNumber = number def clear(self): + if self._busyReason is not None: + raise RuntimeError("Please wait for %r" % self._busyReason) + self._clear() + + def _clear(self): oldContacts = self._contacts self._contacts = {} + self._message = "" if oldContacts: self.recipientsChanged.emit() + @contextlib.contextmanager + def _busy(self, message): + if self._busyReason is not None: + raise RuntimeError("Already busy doing %r" % self._busyReason) + try: + self._busyReason = message + yield + finally: + self._busyReason = None + def _send(self, numbers, text): self.sendingMessage.emit() try: - yield ( - self._backend[0].send_sms, - (numbers, text), - {}, - ) - self.sentMessage.emit() - self.clear() + with self._busy("Sending Text"): + with qui_utils.notify_busy(self._errorLog, "Sending Text"): + yield ( + self._backend[0].send_sms, + (numbers, text), + {}, + ) + self.sentMessage.emit() + self._clear() except Exception, e: + _moduleLogger.exception("Reporting error to user") self.error.emit(str(e)) def _call(self, number): self.calling.emit() try: - yield ( - self._backend[0].call, - (number, ), - {}, - ) - self.called.emit() - self.clear() + with self._busy("Calling"): + with qui_utils.notify_busy(self._errorLog, "Calling"): + yield ( + self._backend[0].call, + (number, ), + {}, + ) + self.called.emit() + self._clear() except Exception, e: + _moduleLogger.exception("Reporting error to user") self.error.emit(str(e)) def _cancel(self): self.cancelling.emit() try: - yield ( - self._backend[0].cancel, - (), - {}, - ) + with qui_utils.notify_busy(self._errorLog, "Cancelling"): + yield ( + self._backend[0].cancel, + (), + {}, + ) self.cancelled.emit() except Exception, e: + _moduleLogger.exception("Reporting error to user") self.error.emit(str(e)) @@ -175,15 +219,16 @@ class Session(QtCore.QObject): _LOGGEDOUT_TIME = -1 _LOGGINGIN_TIME = 0 - def __init__(self, cachePath = None): + def __init__(self, errorLog, cachePath = None): QtCore.QObject.__init__(self) + self._errorLog = errorLog self._pool = qore_utils.AsyncPool() self._backend = [] self._loggedInTime = self._LOGGEDOUT_TIME self._loginOps = [] self._cachePath = cachePath self._username = None - self._draft = Draft(self._pool, self._backend) + self._draft = Draft(self._pool, self._backend, self._errorLog) self._contacts = {} self._contactUpdateTime = datetime.datetime(1971, 1, 1) @@ -206,8 +251,8 @@ class Session(QtCore.QObject): return self._draft def login(self, username, password): - assert self.state == self.LOGGEDOUT_STATE - assert username != "" + assert self.state == self.LOGGEDOUT_STATE, "Can only log-in when logged out (currently %s" % self.state + assert username != "", "No username specified" if self._cachePath is not None: cookiePath = os.path.join(self._cachePath, "%s.cookies" % username) else: @@ -223,24 +268,30 @@ class Session(QtCore.QObject): le.start(username, password) def logout(self): - assert self.state != self.LOGGEDOUT_STATE + assert self.state != self.LOGGEDOUT_STATE, "Can only logout if logged in (currently %s" % self.state + _moduleLogger.info("Logging out") self._pool.stop() self._loggedInTime = self._LOGGEDOUT_TIME self._backend[0].persist() self._save_to_cache() + self.stateChange.emit(self.LOGGEDOUT_STATE) + self.loggedOut.emit() def clear(self): - assert self.state == self.LOGGEDOUT_STATE + assert self.state == self.LOGGEDOUT_STATE, "Can only clear when logged out (currently %s" % self.state self._backend[0].logout() del self._backend[0] self._clear_cache() self._draft.clear() def logout_and_clear(self): - assert self.state != self.LOGGEDOUT_STATE + assert self.state != self.LOGGEDOUT_STATE, "Can only logout if logged in (currently %s" % self.state + _moduleLogger.info("Logging out and clearing the account") self._pool.stop() self._loggedInTime = self._LOGGEDOUT_TIME self.clear() + self.stateChange.emit(self.LOGGEDOUT_STATE) + self.loggedOut.emit() def update_contacts(self, force = True): if not force and self._contacts: @@ -287,17 +338,17 @@ class Session(QtCore.QObject): le.start(dnd) def _set_dnd(self, dnd): - # I'm paranoid about our state geting out of sync so we set no matter - # what but act as if we have the cannonical state - assert self.state == self.LOGGEDIN_STATE oldDnd = self._dnd try: - yield ( - self._backend[0].set_dnd, - (dnd, ), - {}, - ) + assert self.state == self.LOGGEDIN_STATE, "DND requires being logged in (currently %s" % self.state + with qui_utils.notify_busy(self._errorLog, "Setting DND Status"): + yield ( + self._backend[0].set_dnd, + (dnd, ), + {}, + ) except Exception, e: + _moduleLogger.exception("Reporting error to user") self.error.emit(str(e)) return self._dnd = dnd @@ -308,10 +359,13 @@ class Session(QtCore.QObject): return self._dnd def get_account_number(self): + if self.state != self.LOGGEDIN_STATE: + return "" return self._backend[0].get_account_number() def get_callback_numbers(self): - # @todo Remove evilness (might call is_authed which can block) + if self.state != self.LOGGEDIN_STATE: + return {} return self._backend[0].get_callback_numbers() def get_callback_number(self): @@ -322,17 +376,16 @@ class Session(QtCore.QObject): le.start(callback) def _set_callback_number(self, callback): - # I'm paranoid about our state geting out of sync so we set no matter - # what but act as if we have the cannonical state - assert self.state == self.LOGGEDIN_STATE oldCallback = self._callback try: + assert self.state == self.LOGGEDIN_STATE, "Callbacks configurable only when logged in (currently %s" % self.state yield ( self._backend[0].set_callback_number, (callback, ), {}, ) except Exception, e: + _moduleLogger.exception("Reporting error to user") self.error.emit(str(e)) return self._callback = callback @@ -340,58 +393,70 @@ class Session(QtCore.QObject): self.callbackNumberChanged.emit(self._callback) def _login(self, username, password): - self._loggedInTime = self._LOGGINGIN_TIME - self.stateChange.emit(self.LOGGINGIN_STATE) - finalState = self.LOGGEDOUT_STATE - try: + with qui_utils.notify_busy(self._errorLog, "Logging In"): + self._loggedInTime = self._LOGGINGIN_TIME + self.stateChange.emit(self.LOGGINGIN_STATE) + finalState = self.LOGGEDOUT_STATE isLoggedIn = False - - if not isLoggedIn and self._backend[0].is_quick_login_possible(): - isLoggedIn = yield ( - self._backend[0].is_authed, - (), - {}, - ) - if isLoggedIn: - _moduleLogger.info("Logged in through cookies") - else: - # Force a clearing of the cookies - yield ( - self._backend[0].logout, + try: + if not isLoggedIn and self._backend[0].is_quick_login_possible(): + isLoggedIn = yield ( + self._backend[0].is_authed, (), {}, ) + if isLoggedIn: + _moduleLogger.info("Logged in through cookies") + else: + # Force a clearing of the cookies + yield ( + self._backend[0].logout, + (), + {}, + ) + + if not isLoggedIn: + isLoggedIn = yield ( + self._backend[0].login, + (username, password), + {}, + ) + if isLoggedIn: + _moduleLogger.info("Logged in through credentials") - if not isLoggedIn: - isLoggedIn = yield ( - self._backend[0].login, - (username, password), - {}, - ) if isLoggedIn: - _moduleLogger.info("Logged in through credentials") - - if isLoggedIn: - self._loggedInTime = int(time.time()) - oldUsername = self._username - self._username = username - finalState = self.LOGGEDIN_STATE - self.loggedIn.emit() - if oldUsername != self._username: - needOps = not self._load() + self._loggedInTime = int(time.time()) + oldUsername = self._username + self._username = username + finalState = self.LOGGEDIN_STATE + if oldUsername != self._username: + needOps = not self._load() + else: + needOps = True + + self.loggedIn.emit() + self.stateChange.emit(finalState) + finalState = None # Mark it as already set + + if needOps: + loginOps = self._loginOps[:] + else: + loginOps = [] + del self._loginOps[:] + for asyncOp in loginOps: + asyncOp.start() else: - needOps = True - if needOps: - loginOps = self._loginOps[:] - else: - loginOps = [] - del self._loginOps[:] - for asyncOp in loginOps: - asyncOp.start() - except Exception, e: - self.error.emit(str(e)) - finally: - self.stateChange.emit(finalState) + self._loggedInTime = self._LOGGEDOUT_TIME + self.error.emit("Error logging in") + except Exception, e: + self._loggedInTime = self._LOGGEDOUT_TIME + _moduleLogger.exception("Reporting error to user") + self.error.emit(str(e)) + finally: + if finalState is not None: + self.stateChange.emit(finalState) + if isLoggedIn and self._callback: + self.set_callback_number(self._callback) def _load(self): updateContacts = len(self._contacts) != 0 @@ -498,11 +563,11 @@ class Session(QtCore.QObject): oldCallback = self._callback self._contacts = {} - self._contactUpdateTime = datetime.datetime(1, 1, 1) + self._contactUpdateTime = datetime.datetime(1971, 1, 1) self._messages = [] - self._messageUpdateTime = datetime.datetime(1, 1, 1) + self._messageUpdateTime = datetime.datetime(1971, 1, 1) self._history = [] - self._historyUpdateTime = datetime.datetime(1, 1, 1) + self._historyUpdateTime = datetime.datetime(1971, 1, 1) self._dnd = False self._callback = "" @@ -521,12 +586,15 @@ class Session(QtCore.QObject): def _update_contacts(self): try: - self._contacts = yield ( - self._backend[0].get_contacts, - (), - {}, - ) + assert self.state == self.LOGGEDIN_STATE, "Contacts requires being logged in (currently %s" % self.state + with qui_utils.notify_busy(self._errorLog, "Updating Contacts"): + self._contacts = yield ( + self._backend[0].get_contacts, + (), + {}, + ) except Exception, e: + _moduleLogger.exception("Reporting error to user") self.error.emit(str(e)) return self._contactUpdateTime = datetime.datetime.now() @@ -534,12 +602,15 @@ class Session(QtCore.QObject): def _update_messages(self): try: - self._messages = yield ( - self._backend[0].get_messages, - (), - {}, - ) + assert self.state == self.LOGGEDIN_STATE, "Messages requires being logged in (currently %s" % self.state + with qui_utils.notify_busy(self._errorLog, "Updating Messages"): + self._messages = yield ( + self._backend[0].get_messages, + (), + {}, + ) except Exception, e: + _moduleLogger.exception("Reporting error to user") self.error.emit(str(e)) return self._messageUpdateTime = datetime.datetime.now() @@ -547,12 +618,15 @@ class Session(QtCore.QObject): def _update_history(self): try: - self._history = yield ( - self._backend[0].get_recent, - (), - {}, - ) + assert self.state == self.LOGGEDIN_STATE, "History requires being logged in (currently %s" % self.state + with qui_utils.notify_busy(self._errorLog, "Updating History"): + self._history = yield ( + self._backend[0].get_recent, + (), + {}, + ) except Exception, e: + _moduleLogger.exception("Reporting error to user") self.error.emit(str(e)) return self._historyUpdateTime = datetime.datetime.now() @@ -561,12 +635,14 @@ class Session(QtCore.QObject): def _update_dnd(self): oldDnd = self._dnd try: + assert self.state == self.LOGGEDIN_STATE, "DND requires being logged in (currently %s" % self.state self._dnd = yield ( self._backend[0].is_dnd, (), {}, ) except Exception, e: + _moduleLogger.exception("Reporting error to user") self.error.emit(str(e)) return if oldDnd != self._dnd: @@ -579,7 +655,7 @@ class Session(QtCore.QObject): self._push_login_op(op) def _push_login_op(self, asyncOp): - assert self.state != self.LOGGEDIN_STATE + assert self.state != self.LOGGEDIN_STATE, "Can only queue work when logged out" if asyncOp in self._loginOps: _moduleLogger.info("Skipping queueing duplicate op: %r" % asyncOp) return