Improving logging
[theonering] / src / channel / debug_prompt.py
1 from __future__ import with_statement
2
3 import os
4 import cmd
5 import StringIO
6 import time
7 import datetime
8 import logging
9
10 import telepathy
11
12 import constants
13 import tp
14 import util.misc as misc_utils
15 import util.go_utils as gobject_utils
16 import gvoice
17
18
19 _moduleLogger = logging.getLogger(__name__)
20
21
22 class DebugPromptChannel(tp.ChannelTypeText, cmd.Cmd):
23
24         def __init__(self, connection, manager, props, contactHandle):
25                 self.__manager = manager
26                 self.__props = props
27
28                 cmd.Cmd.__init__(self, "Debug Prompt")
29                 self.use_rawinput = False
30                 tp.ChannelTypeText.__init__(self, connection, manager, props)
31                 self.__nextRecievedId = 0
32                 self.__lastMessageTimestamp = datetime.datetime(1, 1, 1)
33
34                 self.__otherHandle = contactHandle
35                 self._conn.add_logger(self)
36
37         @misc_utils.log_exception(_moduleLogger)
38         def Send(self, messageType, text):
39                 if messageType != telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL:
40                         raise telepathy.errors.NotImplemented("Unhandled message type: %r" % messageType)
41
42                 self.Sent(int(time.time()), messageType, text)
43
44                 oldStdin, oldStdout = self.stdin, self.stdout
45                 try:
46                         self.stdin = currentStdin = StringIO.StringIO()
47                         self.stdout = currentStdout = StringIO.StringIO()
48                         self.onecmd(text)
49                 finally:
50                         self.stdin, self.stdout = oldStdin, oldStdout
51
52                 stdoutData = currentStdout.getvalue().strip()
53                 if stdoutData:
54                         self._report_new_message(stdoutData)
55
56         @misc_utils.log_exception(_moduleLogger)
57         def Close(self):
58                 self.close()
59
60         def close(self):
61                 _moduleLogger.debug("Closing debug")
62                 tp.ChannelTypeText.Close(self)
63                 self.remove_from_connection()
64                 self._conn.remove_logger(self)
65
66         def log_message(self, component, message):
67                 formattedMessage = "LOG: %s\n%s" % (component, message)
68                 self._report_new_message(formattedMessage)
69
70         def _report_new_message(self, message):
71                 currentReceivedId = self.__nextRecievedId
72
73                 timestamp = int(time.time())
74                 type = telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL
75
76                 self.Received(currentReceivedId, timestamp, self.__otherHandle, type, 0, message.strip())
77
78                 self.__nextRecievedId += 1
79
80         def do_reset_state_machine(self, args):
81                 try:
82                         args = args.strip().lower()
83                         if not args:
84                                 args  = "all"
85                         if args == "all":
86                                 for machine in self._conn.session.stateMachine._machines:
87                                         machine.reset_timers()
88                         elif args == "contacts":
89                                 self._conn.session.addressbookStateMachine.reset_timers()
90                         elif args == "voicemail":
91                                 self._conn.session.voicemailsStateMachine.reset_timers()
92                         elif args == "texts":
93                                 self._conn.session.textsStateMachine.reset_timers()
94                         else:
95                                 self._report_new_message('Unknown machine "%s"' % (args, ))
96                 except Exception, e:
97                         self._report_new_message(str(e))
98
99         def help_reset_state_machine(self):
100                 self._report_new_message("""Reset the refreshing state machine.
101 "reset_state_machine" - resets all
102 "reset_state_machine all"
103 "reset_state_machine contacts"
104 "reset_state_machine voicemail"
105 "reset_state_machine texts"
106 """)
107
108         def do_get_state(self, args):
109                 if args:
110                         self._report_new_message("No arguments supported")
111                         return
112
113                 try:
114                         state = self._conn.session.stateMachine.state
115                         self._report_new_message(str(state))
116                 except Exception, e:
117                         self._report_new_message(str(e))
118
119         def help_get_state(self):
120                 self._report_new_message("Print the current state the refreshing state machine is in")
121
122         def do_get_polling(self, args):
123                 if args:
124                         self._report_new_message("No arguments supported")
125                         return
126                 self._report_new_message("\n".join((
127                         "Contacts:", repr(self._conn.session.addressbookStateMachine)
128                 )))
129                 self._report_new_message("\n".join((
130                         "Voicemail:", repr(self._conn.session.voicemailsStateMachine)
131                 )))
132                 self._report_new_message("\n".join((
133                         "Texts:", repr(self._conn.session.textsStateMachine)
134                 )))
135
136         def help_get_polling(self):
137                 self._report_new_message("Prints the frequency each of the state machines updates")
138
139         def do_get_state_status(self, args):
140                 if args:
141                         self._report_new_message("No arguments supported")
142                         return
143                 self._report_new_message("\n".join((
144                         "Contacts:", str(self._conn.session.addressbookStateMachine)
145                 )))
146                 self._report_new_message("\n".join((
147                         "Voicemail:", str(self._conn.session.voicemailsStateMachine)
148                 )))
149                 self._report_new_message("\n".join((
150                         "Texts:", str(self._conn.session.textsStateMachine)
151                 )))
152
153         def help_get_state_status(self):
154                 self._report_new_message("Prints the current setting for the state machines")
155
156         def do_is_authed(self, args):
157                 le = gobject_utils.AsyncLinearExecution(self._conn.session.pool, self._is_authed)
158                 le.start(args)
159
160         @misc_utils.log_exception(_moduleLogger)
161         def _is_authed(self, args):
162                 if args:
163                         self._report_new_message("No arguments supported")
164                         return
165
166                 try:
167                         isAuthed = yield (
168                                 self._conn.session.backend.is_authed,
169                                 (),
170                                 {}
171                         )
172                         self._report_new_message(str(isAuthed))
173                 except Exception, e:
174                         self._report_new_message(str(e))
175                         return
176
177         def help_is_authed(self):
178                 self._report_new_message("Print whether logged in to Google Voice")
179
180         def do_is_dnd(self, args):
181                 le = gobject_utils.AsyncLinearExecution(self._conn.session.pool, self._is_dnd)
182                 le.start(args)
183
184         @misc_utils.log_exception(_moduleLogger)
185         def _is_dnd(self, args):
186                 if args:
187                         self._report_new_message("No arguments supported")
188                         return
189
190                 try:
191                         isDnd = yield (
192                                 self._conn.session.backend.is_dnd,
193                                 (),
194                                 {}
195                         )
196                         self._report_new_message(str(isDnd))
197                 except Exception, e:
198                         self._report_new_message(str(e))
199                         return
200
201         def help_is_dnd(self):
202                 self._report_new_message("Print whether Do-Not-Disturb mode enabled on the Google Voice account")
203
204         def do_get_account_number(self, args):
205                 if args:
206                         self._report_new_message("No arguments supported")
207                         return
208
209                 try:
210                         number = self._conn.session.backend.get_account_number()
211                         self._report_new_message(number)
212                 except Exception, e:
213                         self._report_new_message(str(e))
214
215         def help_get_account_number(self):
216                 self._report_new_message("Print the Google Voice account number")
217
218         def do_get_callback_numbers(self, args):
219                 if args:
220                         self._report_new_message("No arguments supported")
221                         return
222
223                 try:
224                         numbers = self._conn.session.backend.get_callback_numbers()
225                         numbersDisplay = "\n".join(
226                                 "%s: %s" % (name, number)
227                                 for (number, name) in numbers.iteritems()
228                         )
229                         self._report_new_message(numbersDisplay)
230                 except Exception, e:
231                         self._report_new_message(str(e))
232
233         def help_get_callback_numbers(self):
234                 self._report_new_message("Print a list of all configured callback numbers")
235
236         def do_get_sane_callback_number(self, args):
237                 if args:
238                         self._report_new_message("No arguments supported")
239                         return
240
241                 try:
242                         number = gvoice.backend.get_sane_callback(self._conn.session.backend)
243                         self._report_new_message(number)
244                 except Exception, e:
245                         self._report_new_message(str(e))
246
247         def help_get_sane_callback_number(self):
248                 self._report_new_message("Print the best guess of callback numbers to use")
249
250         def do_get_callback_number(self, args):
251                 if args:
252                         self._report_new_message("No arguments supported")
253                         return
254
255                 try:
256                         number = self._conn.session.backend.get_callback_number()
257                         self._report_new_message(number)
258                 except Exception, e:
259                         self._report_new_message(str(e))
260
261         def help_get_callback_number(self):
262                 self._report_new_message("Print the callback number currently enabled")
263
264         def do_call(self, args):
265                 le = gobject_utils.AsyncLinearExecution(self._conn.session.pool, self._call)
266                 le.start(args)
267
268         @misc_utils.log_exception(_moduleLogger)
269         def _call(self, args):
270                 if not args:
271                         self._report_new_message("Must specify the phone number and only the phone nunber")
272                         return
273
274                 try:
275                         number = args
276                         yield (
277                                 self._conn.session.backend.call,
278                                 (number),
279                                 {}
280                         )
281                 except Exception, e:
282                         self._report_new_message(str(e))
283
284         def help_call(self):
285                 self._report_new_message("\n".join(["call NUMBER", "Initiate a callback, Google forwarding the call to the callback number"]))
286
287         def do_send_sms(self, args):
288                 le = gobject_utils.AsyncLinearExecution(self._conn.session.pool, self._send_sms)
289                 le.start(args)
290
291         @misc_utils.log_exception(_moduleLogger)
292         def _send_sms(self, args):
293                 args = args.split(" ")
294                 if 1 < len(args):
295                         self._report_new_message("Must specify the phone number and then message")
296                         return
297
298                 try:
299                         number = args[0]
300                         message = " ".join(args[1:])
301                         yield (
302                                 self._conn.session.backend.send_sms,
303                                 ([number], message),
304                                 {},
305                         )
306                 except Exception, e:
307                         self._report_new_message(str(e))
308
309         def help_send_sms(self):
310                 self._report_new_message("\n".join(["send_sms NUMBER MESSAGE0 MESSAGE1 ...", "Send an sms to number NUMBER"]))
311
312         def do_version(self, args):
313                 if args:
314                         self._report_new_message("No arguments supported")
315                         return
316                 self._report_new_message("%s-%s" % (constants.__version__, constants.__build__))
317
318         def help_version(self):
319                 self._report_new_message("Prints the version (hint: %s-%s)" % (constants.__version__, constants.__build__))
320
321         def do_grab_log(self, args):
322                 if args:
323                         self._report_new_message("No arguments supported")
324                         return
325
326                 try:
327                         publishProps = self._conn.generate_props(telepathy.CHANNEL_TYPE_FILE_TRANSFER, self.__otherHandle, False)
328                         self._conn._channel_manager.channel_for_props(publishProps, signal=True)
329                 except Exception, e:
330                         self._report_new_message(str(e))
331
332         def help_grab_log(self):
333                 self._report_new_message("Download the debug log for including with bug report")
334                 self._report_new_message("Warning: this may contain sensitive information")
335
336         def do_save_log(self, args):
337                 if not args:
338                         self._report_new_message("Must specify a filename to save the log to")
339                         return
340
341                 try:
342                         filename = os.path.expanduser(args)
343                         with open(constants._user_logpath_, "r") as f:
344                                 logLines = f.xreadlines()
345                                 log = "".join(logLines)
346                         with open(filename, "w") as f:
347                                 f.write(log)
348                 except Exception, e:
349                         self._report_new_message(str(e))
350
351         def help_save_log(self):
352                 self._report_new_message("Save the log to a specified location")