Working around a bug for some and providing more helpful error message for others
[theonering] / src / channel / debug_log.py
1 from __future__ import with_statement
2
3 import os
4 import socket
5 import logging
6
7 import telepathy
8
9 import constants
10 import tp
11 import util.go_utils as gobject_utils
12 import util.misc as misc_utils
13
14
15 _moduleLogger = logging.getLogger(__name__)
16
17
18 class DebugLogChannel(tp.ChannelTypeFileTransfer):
19
20         def __init__(self, connection, manager, props, contactHandle):
21                 self.__manager = manager
22                 self.__props = props
23                 self.__otherHandle = contactHandle
24                 self.__socket = None
25                 self.__socketName = ""
26                 self.__delayWrite = gobject_utils.Timeout(self._on_write)
27
28                 tp.ChannelTypeFileTransfer.__init__(self, connection, manager, props)
29
30                 dbus_interface = telepathy.CHANNEL_TYPE_FILE_TRANSFER
31                 self._implement_property_get(
32                         dbus_interface,
33                         {
34                                 'State': self.get_state,
35                                 "ContentType": self.get_content_type,
36                                 "Filename": self.get_filename,
37                                 "Size": self.get_size,
38                                 "Description": self.get_description,
39                                 "AvailableSocketTypes": self.get_available_socket_types,
40                                 "TransferredBytes": self.get_transferred_bytes,
41                                 "InitialOffset": self.get_initial_offset,
42                         },
43                 )
44                 self._add_immutables({
45                         'Filename': dbus_interface,
46                         'Size': dbus_interface,
47                 })
48
49                 # grab a snapshot of the log so that we are always in a consistent
50                 # state between calls
51                 with open(constants._user_logpath_, "r") as f:
52                         logLines = f.xreadlines()
53                         self._log = "".join(logLines)
54                 self._transferredBytes = 0
55
56                 self._state = 0
57                 self.set_state(
58                         telepathy.constants.FILE_TRANSFER_STATE_PENDING,
59                         telepathy.constants.FILE_TRANSFER_STATE_CHANGE_REASON_REQUESTED,
60                 )
61
62         def get_state(self):
63                 return self._state
64
65         def set_state(self, state, reason):
66                 if self._state == state:
67                         return
68                 self._state = state
69
70                 self.FileTransferStateChanged(
71                         self._state,
72                         reason,
73                 )
74
75         def get_content_type(self):
76                 return "application/octet-stream"
77
78         def get_filename(self):
79                 return "%s.log" % constants._telepathy_implementation_name_
80
81         def get_size(self):
82                 return len(self._log)
83
84         def get_description(self):
85                 return "Debug log for The One Ring"
86
87         def get_available_socket_types(self):
88                 return {
89                         telepathy.constants.SOCKET_ADDRESS_TYPE_UNIX: [
90                                 telepathy.constants.SOCKET_ACCESS_CONTROL_LOCALHOST,
91                                 telepathy.constants.SOCKET_ACCESS_CONTROL_CREDENTIALS,
92                         ],
93                 }
94
95         def get_transferred_bytes(self):
96                 return self._transferredBytes
97
98         def get_initial_offset(self):
99                 return 0
100
101         @misc_utils.log_exception(_moduleLogger)
102         def AcceptFile(self, addressType, accessControl, accessControlParam, offset):
103                 # @bug All wrong
104                 _moduleLogger.info("%r %r %r %r" % (addressType, accessControl, accessControlParam, offset))
105                 assert not self.__socketName, self.__socketName
106                 self.__socketName = os.tempnam()
107
108                 assert self.__socket is None, self.__socket
109                 self.__socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
110                 self.__socket.bind(self.__socketName)
111
112                 self._state = telepathy.constants.FILE_TRANSFER_STATE_ACCEPTED
113                 self.FileTransferStateChanged(
114                         self._state,
115                         telepathy.constants.FILE_TRANSFER_STATE_CHANGE_REASON_REQUESTED,
116                 )
117
118                 self.__delayWrite.start(seconds=0)
119
120                 return self.__socketName
121
122         @misc_utils.log_exception(_moduleLogger)
123         def ProvideFile(self, addressType, accessControl, accessControlParam):
124                 raise telepathy.errors.NotImplemented("Cannot send outbound files")
125
126         @misc_utils.log_exception(_moduleLogger)
127         def Close(self):
128                 self.close()
129
130         def close(self):
131                 _moduleLogger.debug("Closing log")
132                 if self._state != telepathy.FILE_TRANSFER_STATE_COMPLETED:
133                         self.set_state(
134                                 telepathy.FILE_TRANSFER_STATE_CANCELLED,
135                                 telepathy.FILE_TRANSFER_STATE_CHANGE_REASON_LOCAL_STOPPED
136                         )
137
138                 if self.__socket is not None:
139                         self.__socket.close()
140
141                 tp.ChannelTypeFileTransfer.Close(self)
142                 self.remove_from_connection()
143
144         @misc_utils.log_exception(_moduleLogger)
145         def _on_write(self):
146                 self.__socket.listen(1)
147                 conn, addr = self.__socket.accept()
148
149                 self.InitialOffsetDefined(0)
150                 self._state = telepathy.constants.FILE_TRANSFER_STATE_OPEN
151                 self.FileTransferStateChanged(
152                         self._state,
153                         telepathy.constants.FILE_TRANSFER_STATE_CHANGE_REASON_NONE,
154                 )
155
156                 conn.send(self._log)
157
158                 self._transferredBytes = len(self._log)
159                 self.TransferredBytesChanged(self._transferredBytes)
160
161                 self._state = telepathy.constants.FILE_TRANSFER_STATE_COMPLETED
162                 self.FileTransferStateChanged(
163                         self._state,
164                         telepathy.constants.FILE_TRANSFER_STATE_CHANGE_REASON_NONE,
165                 )