e8deff6108beb10927585fdc13c80957b106d758
[watersofshiloah] / src / index.py
1 import weakref
2 import logging
3
4 import util.misc as misc_utils
5 from util import go_utils
6 import backend
7
8
9 _moduleLogger = logging.getLogger(__name__)
10
11
12 class Connection(object):
13
14         def __init__(self):
15                 self._backend = backend.Backend()
16                 self._indexing = go_utils.AsyncPool()
17
18         def start(self):
19                 self._indexing.start()
20
21         def stop(self):
22                 self._indexing.stop()
23
24         def download(self, func, on_success, on_error, args = None, kwds = None):
25                 if args is None:
26                         args = ()
27                 if kwds is None:
28                         kwds = {}
29
30                 self._indexing.clear_tasks()
31                 self._indexing.add_task(
32                         getattr(self._backend, func),
33                         args,
34                         kwds,
35                         on_success,
36                         on_error,
37                 )
38
39
40 class AudioIndex(object):
41
42         def __init__(self):
43                 self._connection = Connection()
44                 self._languages = None
45                 self._languagesRequest = None
46                 self._sources = {}
47
48         def start(self):
49                 self._connection.start()
50
51         def stop(self):
52                 self._connection.stop()
53
54         def get_languages(self, on_success, on_error):
55                 if self._languages is None:
56                         assert self._languagesRequest is None
57                         self._languagesRequest = on_success, on_error
58                         self._connection.download(
59                                 "get_languages",
60                                 self._on_get_languages,
61                                 self._on_languages_error
62                         )
63                 else:
64                         on_success(self._languages)
65
66         def get_source(self, source, langId = None):
67                 key = (source, langId)
68                 if key in self._sources:
69                         node = self._sources[key]
70                 else:
71                         if source == "radio":
72                                 node = RadioNode(self._connection)
73                         elif source == "conferences":
74                                 assert langId is not None
75                                 node = ConferencesNode(self._connection, langId)
76                         else:
77                                 raise NotImplementedError(source)
78                         self._sources[key] = node
79
80                 return node
81
82         @misc_utils.log_exception(_moduleLogger)
83         def _on_get_languages(self, languages):
84                 assert self._languages is None
85                 assert self._languagesRequest is not None
86                 r = self._languagesRequest
87                 self._languagesRequest = None
88                 self._languages = languages
89                 r[0](self._languages)
90
91         @misc_utils.log_exception(_moduleLogger)
92         def _on_languages_error(self, e):
93                 assert self._languages is None
94                 assert self._languagesRequest is not None
95                 r = self._languagesRequest
96                 self._languagesRequest = None
97                 r[1](self._languages)
98
99
100 class Node(object):
101
102         def __init__(self, connection, parent, data):
103                 self._connection = connection
104                 self._parent = weakref.ref(parent) if parent is not None else None
105                 self._data = data
106                 self._children = None
107
108         def get_children(self, on_success, on_error):
109                 if self._children is None:
110                         self._get_children(on_success, on_error)
111                 else:
112                         on_success(self._children)
113
114         def get_parent(self):
115                 if self._parent is None:
116                         raise RuntimeError("")
117                 parent = self._parent()
118                 return parent
119
120         def get_properties(self):
121                 return self._data
122
123         def is_leaf(self):
124                 raise NotImplementedError("")
125
126         def _get_children(self, on_success, on_error):
127                 raise NotImplementedError("")
128
129
130 class ParentNode(Node):
131
132         def __init__(self, connection, parent, data):
133                 Node.__init__(self, connection, parent, data)
134                 self._request = None
135
136         def is_leaf(self):
137                 return False
138
139         def _get_children(self, on_success, on_error):
140                 assert self._request is None
141                 assert self._children is None
142                 self._request = on_success, on_error
143
144                 func, args, kwds = self._get_func()
145
146                 self._connection.download(
147                         func,
148                         self._on_success,
149                         self._on_error,
150                         args,
151                         kwds,
152                 )
153
154         def _get_func(self):
155                 raise NotImplementedError()
156
157         def _create_child(self, data):
158                 raise NotImplementedError()
159
160         @misc_utils.log_exception(_moduleLogger)
161         def _on_success(self, data):
162                 r = self._request
163                 self._request = None
164                 try:
165                         self._children = [
166                                 self._create_child(child)
167                                 for child in data
168                         ]
169                 except Exception, e:
170                         _moduleLogger.exception("Translating error")
171                         self._children = None
172                         r[1](e)
173                 else:
174                         r[0](self._children)
175
176         @misc_utils.log_exception(_moduleLogger)
177         def _on_error(self, error):
178                 r = self._request
179                 self._request = None
180                 r[1](error)
181
182
183 class LeafNode(Node):
184
185         def __init__(self, connection, parent, data):
186                 Node.__init__(self, connection, parent, data)
187
188         def is_leaf(self):
189                 return True
190
191         @property
192         def can_navigate(self):
193                 raise NotImplementedError("On %s" % type(self))
194
195         @property
196         def title(self):
197                 raise NotImplementedError("On %s" % type(self))
198
199         @property
200         def subtitle(self):
201                 raise NotImplementedError("On %s" % type(self))
202
203         def _get_children(self, on_success, on_error):
204                 raise RuntimeError("Not is a leaf")
205
206
207 class RadioNode(ParentNode):
208
209         def __init__(self, connection):
210                 ParentNode.__init__(self, connection, None, {})
211
212         def _get_func(self):
213                 return "get_radio_channels", (), {}
214
215         def _create_child(self, data):
216                 return RadioChannelNode(self._connection, self, data)
217
218
219 class RadioChannelNode(LeafNode):
220
221         def __init__(self, connection, parent, data):
222                 LeafNode.__init__(self, connection, parent, data)
223                 self._extendedData = {}
224                 self._request = None
225
226         @property
227         def can_navigate(self):
228                 return False
229
230         @property
231         def title(self):
232                 return "Radio"
233
234         @property
235         def subtitle(self):
236                 return ""
237
238         def get_programming(self, date, on_success, on_error):
239                 date = date.strftime("%Y-%m-%d")
240                 try:
241                         programming = self._extendedData[date]
242                 except KeyError:
243                         self._get_programming(date, on_success, on_error)
244                 else:
245                         on_success(programming)
246
247         def _get_programming(self, date, on_success, on_error):
248                 assert self._request is None
249                 assert date not in self._extendedData
250                 self._request = on_success, on_error, date
251
252                 self._connection.download(
253                         "get_radio_channel_programming",
254                         self._on_success,
255                         self._on_error,
256                         (self._data["id"], date),
257                         {},
258                 )
259
260         @misc_utils.log_exception(_moduleLogger)
261         def _on_success(self, data):
262                 r = self._request
263                 date = r[2]
264                 self._request = None
265                 try:
266                         self._extendedData[date] = [
267                                 child
268                                 for child in data
269                         ]
270                 except Exception, e:
271                         _moduleLogger.exception("Translating error")
272                         del self._extendedData[date]
273                         r[1](e)
274                 else:
275                         r[0](self._extendedData[date])
276
277         @misc_utils.log_exception(_moduleLogger)
278         def _on_error(self, error):
279                 r = self._request
280                 self._request = None
281                 r[1](error)
282
283
284 class ConferencesNode(ParentNode):
285
286         def __init__(self, connection, langId):
287                 ParentNode.__init__(self, connection, None, {})
288                 self._langId = langId
289
290         def _get_func(self):
291                 return "get_conferences", (self._langId, ), {}
292
293         def _create_child(self, data):
294                 return ConferenceNode(self._connection, self, data)
295
296
297 class ConferenceNode(ParentNode):
298
299         def __init__(self, connection, parent, data):
300                 ParentNode.__init__(self, connection, parent, data)
301
302         def _get_func(self):
303                 return "get_conference_sessions", (self._data["id"], ), {}
304
305         def _create_child(self, data):
306                 return SessionNode(self._connection, self, data)
307
308
309 class SessionNode(ParentNode):
310
311         def __init__(self, connection, parent, data):
312                 ParentNode.__init__(self, connection, parent, data)
313
314         def _get_func(self):
315                 return "get_conference_talks", (self._data["id"], ), {}
316
317         def _create_child(self, data):
318                 return TalkNode(self._connection, self, data)
319
320
321 class TalkNode(LeafNode):
322
323         def __init__(self, connection, parent, data):
324                 LeafNode.__init__(self, connection, parent, data)
325
326         @property
327         def can_navigate(self):
328                 return True
329
330         @property
331         def title(self):
332                 return self._date["title"]
333
334         @property
335         def subtitle(self):
336                 return self._date["speaker"]