11 import util.go_utils as gobject_utils
12 import util.misc as misc_utils
15 _moduleLogger = logging.getLogger(__name__)
18 class Session(object):
21 "contacts": (12, "hours"),
22 "voicemail": (120, "minutes"),
23 "texts": (10, "minutes"),
26 _MINIMUM_MESSAGE_PERIOD = state_machine.to_seconds(minutes=30)
28 def __init__(self, cookiePath = None, defaults = None):
30 defaults = self._DEFAULTS
32 for key, (quant, unit) in defaults.iteritems():
34 defaults[key] = (self._DEFAULTS[key], unit)
36 defaults[key] = (state_machine.UpdateStateMachine.INFINITE_PERIOD, unit)
39 self._cookiePath = cookiePath
41 self._lastDndCheck = 0
42 self._cachedIsDnd = False
44 self._asyncPool = gobject_utils.AsyncPool()
46 self._backend = backend.GVoiceBackend(self._cookiePath)
48 if defaults["contacts"][0] == state_machine.UpdateStateMachine.INFINITE_PERIOD:
49 contactsPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
51 contactsPeriodInSeconds = state_machine.to_seconds(
52 **{defaults["contacts"][1]: defaults["contacts"][0],}
54 self._addressbook = addressbook.Addressbook(self._backend, self._asyncPool)
55 self._addressbookStateMachine = state_machine.UpdateStateMachine([self.addressbook], "Addressbook")
56 self._addressbookStateMachine.set_state_strategy(
57 state_machine.StateMachine.STATE_DND,
58 state_machine.NopStateStrategy()
60 self._addressbookStateMachine.set_state_strategy(
61 state_machine.StateMachine.STATE_IDLE,
62 state_machine.NopStateStrategy()
64 self._addressbookStateMachine.set_state_strategy(
65 state_machine.StateMachine.STATE_ACTIVE,
66 state_machine.ConstantStateStrategy(contactsPeriodInSeconds)
69 if defaults["voicemail"][0] == state_machine.UpdateStateMachine.INFINITE_PERIOD:
70 voicemailPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
71 idleVoicemailPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
73 voicemailPeriodInSeconds = state_machine.to_seconds(
74 **{defaults["voicemail"][1]: defaults["voicemail"][0],}
76 idleVoicemailPeriodInSeconds = max(voicemailPeriodInSeconds * 4, self._MINIMUM_MESSAGE_PERIOD)
77 self._voicemails = conversations.Conversations(self._backend.get_voicemails, self._asyncPool)
78 self._voicemailsStateMachine = state_machine.UpdateStateMachine([self.voicemails], "Voicemail")
79 self._voicemailsStateMachine.set_state_strategy(
80 state_machine.StateMachine.STATE_DND,
81 state_machine.NopStateStrategy()
83 self._voicemailsStateMachine.set_state_strategy(
84 state_machine.StateMachine.STATE_IDLE,
85 state_machine.ConstantStateStrategy(idleVoicemailPeriodInSeconds)
87 self._voicemailsStateMachine.set_state_strategy(
88 state_machine.StateMachine.STATE_ACTIVE,
89 state_machine.NTimesStateStrategy(
90 3 * [state_machine.to_seconds(minutes=1)], voicemailPeriodInSeconds
93 self._voicemails.updateSignalHandler.register_sink(
94 self._voicemailsStateMachine.request_reset_timers
97 if defaults["texts"][0] == state_machine.UpdateStateMachine.INFINITE_PERIOD:
98 initTextsPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
99 minTextsPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
100 textsPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
101 idleTextsPeriodInSeconds = state_machine.UpdateStateMachine.INFINITE_PERIOD
103 initTextsPeriodInSeconds = state_machine.to_seconds(seconds=20)
104 minTextsPeriodInSeconds = state_machine.to_seconds(seconds=1)
105 textsPeriodInSeconds = state_machine.to_seconds(
106 **{defaults["texts"][1]: defaults["texts"][0],}
108 idleTextsPeriodInSeconds = max(textsPeriodInSeconds * 4, self._MINIMUM_MESSAGE_PERIOD)
109 self._texts = conversations.Conversations(self._backend.get_texts, self._asyncPool)
110 self._textsStateMachine = state_machine.UpdateStateMachine([self.texts], "Texting")
111 self._textsStateMachine.set_state_strategy(
112 state_machine.StateMachine.STATE_DND,
113 state_machine.NopStateStrategy()
115 self._textsStateMachine.set_state_strategy(
116 state_machine.StateMachine.STATE_IDLE,
117 state_machine.ConstantStateStrategy(idleTextsPeriodInSeconds)
119 self._textsStateMachine.set_state_strategy(
120 state_machine.StateMachine.STATE_ACTIVE,
121 state_machine.GeometricStateStrategy(
122 initTextsPeriodInSeconds,
123 minTextsPeriodInSeconds,
124 textsPeriodInSeconds,
127 self._texts.updateSignalHandler.register_sink(
128 self._textsStateMachine.request_reset_timers
131 self._masterStateMachine = state_machine.MasterStateMachine()
132 self._masterStateMachine.append_machine(self._addressbookStateMachine)
133 self._masterStateMachine.append_machine(self._voicemailsStateMachine)
134 self._masterStateMachine.append_machine(self._textsStateMachine)
136 def load(self, path):
137 self._texts.load(os.sep.join((path, "texts.cache")))
138 self._voicemails.load(os.sep.join((path, "voicemails.cache")))
140 def save(self, path):
141 self._texts.save(os.sep.join((path, "texts.cache")))
142 self._voicemails.save(os.sep.join((path, "voicemails.cache")))
145 self._voicemails.updateSignalHandler.unregister_sink(
146 self._voicemailsStateMachine.request_reset_timers
148 self._texts.updateSignalHandler.unregister_sink(
149 self._textsStateMachine.request_reset_timers
151 self._masterStateMachine.close()
153 def login(self, username, password, on_success, on_error):
154 self._asyncPool.start()
156 le = gobject_utils.AsyncLinearExecution(self._asyncPool, self._login)
157 le.start(username, password, on_success, on_error)
159 @misc_utils.log_exception(_moduleLogger)
160 def _login(self, username, password, on_success, on_error):
161 self._username = username
162 self._password = password
166 if not isLoggedIn and self._backend.is_quick_login_possible():
169 self._backend.is_authed,
177 _moduleLogger.info("Logged in through cookies")
183 (self._username, self._password),
190 _moduleLogger.info("Logged in through credentials")
192 self._masterStateMachine.start()
193 on_success(isLoggedIn)
196 self._asyncPool.stop()
197 self._masterStateMachine.stop()
198 self._backend.shutdown()
200 self._username = None
201 self._password = None
204 self._asyncPool.stop()
205 self._masterStateMachine.stop()
206 self._backend.logout()
208 self._username = None
209 self._password = None
211 def is_logged_in(self):
212 if self._username is None and self._password is None:
213 _moduleLogger.info("Hasn't even attempted to login yet")
216 isLoggedIn = self._backend.is_authed()
218 _moduleLogger.error("Not logged in anymore")
221 def set_dnd(self, doNotDisturb):
222 if self._cachedIsDnd != doNotDisturb:
223 self._backend.set_dnd(doNotDisturb)
224 self._cachedIsDnd = doNotDisturb
227 # To throttle checking with the server, use a 30s cache
228 newTime = time.time()
229 if self._lastDndCheck + 30 < newTime:
230 self._lastDndCheck = newTime
231 self._cachedIsDnd = self._backend.is_dnd()
232 return self._cachedIsDnd
236 assert self.is_logged_in()
241 return self._asyncPool
244 def addressbook(self):
245 return self._addressbook
252 def voicemails(self):
253 return self._voicemails
256 def stateMachine(self):
257 return self._masterStateMachine
260 def addressbookStateMachine(self):
261 return self._addressbookStateMachine
264 def voicemailsStateMachine(self):
265 return self._voicemailsStateMachine
268 def textsStateMachine(self):
269 return self._textsStateMachine