12 import util.go_utils as gobject_utils
13 import util.misc as misc_utils
16 _moduleLogger = logging.getLogger(__name__)
19 class Session(object):
22 "contacts": (12, "hours"),
23 "voicemail": (120, "minutes"),
24 "texts": (10, "minutes"),
27 _MINIMUM_MESSAGE_PERIOD = state_machine.to_seconds(minutes=30)
29 def __init__(self, cookiePath = None, defaults = None):
31 defaults = self._DEFAULTS
33 for key, (quant, unit) in defaults.iteritems():
35 defaults[key] = (self._DEFAULTS[key], unit)
37 defaults[key] = (state_machine.UpdateStateMachine.INFINITE_PERIOD, unit)
41 self._asyncPool = gobject_utils.AsyncPool()
42 self._backend = backend.GVoiceBackend(cookiePath)
44 if defaults["contacts"][0] == state_machine.UpdateStateMachine.INFINITE_PERIOD:
45 contactsPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
47 contactsPeriodInSeconds = state_machine.to_seconds(
48 **{defaults["contacts"][1]: defaults["contacts"][0],}
50 self._addressbook = addressbook.Addressbook(self._backend, self._asyncPool)
51 self._addressbookStateMachine = state_machine.UpdateStateMachine([self.addressbook], "Addressbook")
52 self._addressbookStateMachine.set_state_strategy(
53 state_machine.StateMachine.STATE_DND,
54 state_machine.NopStateStrategy()
56 self._addressbookStateMachine.set_state_strategy(
57 state_machine.StateMachine.STATE_IDLE,
58 state_machine.NopStateStrategy()
60 self._addressbookStateMachine.set_state_strategy(
61 state_machine.StateMachine.STATE_ACTIVE,
62 state_machine.ConstantStateStrategy(contactsPeriodInSeconds)
65 if defaults["voicemail"][0] == state_machine.UpdateStateMachine.INFINITE_PERIOD:
66 voicemailPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
67 idleVoicemailPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
69 voicemailPeriodInSeconds = state_machine.to_seconds(
70 **{defaults["voicemail"][1]: defaults["voicemail"][0],}
72 idleVoicemailPeriodInSeconds = max(voicemailPeriodInSeconds * 4, self._MINIMUM_MESSAGE_PERIOD)
73 self._voicemails = conversations.Conversations(self._backend.get_voicemails, self._asyncPool)
74 self._voicemailsStateMachine = state_machine.UpdateStateMachine([self.voicemails], "Voicemail")
75 self._voicemailsStateMachine.set_state_strategy(
76 state_machine.StateMachine.STATE_DND,
77 state_machine.NopStateStrategy()
79 self._voicemailsStateMachine.set_state_strategy(
80 state_machine.StateMachine.STATE_IDLE,
81 state_machine.ConstantStateStrategy(idleVoicemailPeriodInSeconds)
83 self._voicemailsStateMachine.set_state_strategy(
84 state_machine.StateMachine.STATE_ACTIVE,
85 state_machine.NTimesStateStrategy(
86 3 * [state_machine.to_seconds(minutes=1)], voicemailPeriodInSeconds
89 self._voicemails.updateSignalHandler.register_sink(
90 self._voicemailsStateMachine.request_reset_timers
93 if defaults["texts"][0] == state_machine.UpdateStateMachine.INFINITE_PERIOD:
94 initTextsPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
95 minTextsPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
96 textsPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
97 idleTextsPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
99 initTextsPeriodInSeconds = state_machine.to_seconds(seconds=20)
100 minTextsPeriodInSeconds = state_machine.to_seconds(seconds=1)
101 textsPeriodInSeconds = state_machine.to_seconds(
102 **{defaults["texts"][1]: defaults["texts"][0],}
104 idleTextsPeriodInSeconds = max(textsPeriodInSeconds * 4, self._MINIMUM_MESSAGE_PERIOD)
105 self._texts = conversations.Conversations(self._backend.get_texts, self._asyncPool)
106 self._textsStateMachine = state_machine.UpdateStateMachine([self.texts], "Texting")
107 self._textsStateMachine.set_state_strategy(
108 state_machine.StateMachine.STATE_DND,
109 state_machine.NopStateStrategy()
111 self._textsStateMachine.set_state_strategy(
112 state_machine.StateMachine.STATE_IDLE,
113 state_machine.ConstantStateStrategy(idleTextsPeriodInSeconds)
115 self._textsStateMachine.set_state_strategy(
116 state_machine.StateMachine.STATE_ACTIVE,
117 state_machine.GeometricStateStrategy(
118 initTextsPeriodInSeconds,
119 minTextsPeriodInSeconds,
120 textsPeriodInSeconds,
123 self._texts.updateSignalHandler.register_sink(
124 self._textsStateMachine.request_reset_timers
127 self._masterStateMachine = state_machine.MasterStateMachine()
128 self._masterStateMachine.append_machine(self._addressbookStateMachine)
129 self._masterStateMachine.append_machine(self._voicemailsStateMachine)
130 self._masterStateMachine.append_machine(self._textsStateMachine)
132 self._lastDndCheck = 0
133 self._cachedIsDnd = False
135 def load(self, path):
136 self._texts.load(os.sep.join((path, "texts.cache")))
137 self._voicemails.load(os.sep.join((path, "voicemails.cache")))
139 def save(self, path):
140 self._texts.save(os.sep.join((path, "texts.cache")))
141 self._voicemails.save(os.sep.join((path, "voicemails.cache")))
144 self._voicemails.updateSignalHandler.unregister_sink(
145 self._voicemailsStateMachine.request_reset_timers
147 self._texts.updateSignalHandler.unregister_sink(
148 self._textsStateMachine.request_reset_timers
150 self._masterStateMachine.close()
152 def login(self, username, password, on_success, on_error):
153 self._asyncPool.start()
155 le = gobject_utils.AsyncLinearExecution(self._asyncPool, self._login)
156 le.start(username, password, on_success, on_error)
158 @misc_utils.log_exception(_moduleLogger)
159 def _login(self, username, password, on_success, on_error):
160 self._username = username
161 self._password = password
165 if not isLoggedIn and self._backend.is_quick_login_possible():
168 self._backend.is_authed,
176 _moduleLogger.info("Logged in through cookies")
182 (self._username, self._password),
189 _moduleLogger.info("Logged in through credentials")
191 self._masterStateMachine.start()
192 on_success(isLoggedIn)
195 self._asyncPool.stop()
196 self._masterStateMachine.stop()
197 self._backend.shutdown()
199 self._username = None
200 self._password = None
203 self._asyncPool.stop()
204 self._masterStateMachine.stop()
205 self._backend.logout()
207 self._username = None
208 self._password = None
210 def is_logged_in(self):
211 if self._username is None and self._password is None:
212 _moduleLogger.info("Hasn't even attempted to login yet")
215 isLoggedIn = self._backend.is_authed()
217 _moduleLogger.error("Not logged in anymore")
220 def set_dnd(self, doNotDisturb):
221 if self._cachedIsDnd != doNotDisturb:
222 self._backend.set_dnd(doNotDisturb)
223 self._cachedIsDnd = doNotDisturb
226 # To throttle checking with the server, use a 30s cache
227 newTime = time.time()
228 if self._lastDndCheck + 30 < newTime:
229 self._lastDndCheck = newTime
230 self._cachedIsDnd = self._backend.is_dnd()
231 return self._cachedIsDnd
235 assert self.is_logged_in()
240 return self._asyncPool
243 def addressbook(self):
244 return self._addressbook
251 def voicemails(self):
252 return self._voicemails
255 def stateMachine(self):
256 return self._masterStateMachine
259 def addressbookStateMachine(self):
260 return self._addressbookStateMachine
263 def voicemailsStateMachine(self):
264 return self._voicemailsStateMachine
267 def textsStateMachine(self):
268 return self._textsStateMachine