7e9341cee158bbe5fbcf5d45289a9e1e54ba203c
[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         def _get_children(self, on_success, on_error):
192                 raise RuntimeError("Not is a leaf")
193
194
195 class RadioNode(ParentNode):
196
197         def __init__(self, connection):
198                 ParentNode.__init__(self, connection, None, {})
199
200         def _get_func(self):
201                 return "get_radio_channels", (), {}
202
203         def _create_child(self, data):
204                 return RadioChannelNode(self._connection, self, data)
205
206
207 class RadioChannelNode(LeafNode):
208
209         def __init__(self, connection, parent, data):
210                 LeafNode.__init__(self, connection, parent, data)
211                 self._extendedData = {}
212                 self._request = None
213
214         def get_programming(self, date, on_success, on_error):
215                 date = date.strftime("%Y-%m-%d")
216                 try:
217                         programming = self._extendedData[date]
218                 except KeyError:
219                         self._get_programming(date, on_success, on_error)
220                 else:
221                         on_success(programming)
222
223         def _get_programming(self, date, on_success, on_error):
224                 assert self._request is None
225                 assert date not in self._extendedData
226                 self._request = on_success, on_error, date
227
228                 self._connection.download(
229                         "get_radio_channel_programming",
230                         self._on_success,
231                         self._on_error,
232                         (self._data["id"], date),
233                         {},
234                 )
235
236         @misc_utils.log_exception(_moduleLogger)
237         def _on_success(self, data):
238                 r = self._request
239                 date = r[2]
240                 self._request = None
241                 try:
242                         self._extendedData[date] = [
243                                 child
244                                 for child in data
245                         ]
246                 except Exception, e:
247                         _moduleLogger.exception("Translating error")
248                         del self._extendedData[date]
249                         r[1](e)
250                 else:
251                         r[0](self._extendedData[date])
252
253         @misc_utils.log_exception(_moduleLogger)
254         def _on_error(self, error):
255                 r = self._request
256                 self._request = None
257                 r[1](error)
258
259
260 class ConferencesNode(ParentNode):
261
262         def __init__(self, connection, langId):
263                 ParentNode.__init__(self, connection, None, {})
264                 self._langId = langId
265
266         def _get_func(self):
267                 return "get_conferences", (self._langId, ), {}
268
269         def _create_child(self, data):
270                 return ConferenceNode(self._connection, self, data)
271
272
273 class ConferenceNode(ParentNode):
274
275         def __init__(self, connection, parent, data):
276                 ParentNode.__init__(self, connection, parent, data)
277
278         def _get_func(self):
279                 return "get_conference_sessions", (self._data["id"], ), {}
280
281         def _create_child(self, data):
282                 return SessionNode(self._connection, self, data)
283
284
285 class SessionNode(ParentNode):
286
287         def __init__(self, connection, parent, data):
288                 ParentNode.__init__(self, connection, parent, data)
289
290         def _get_func(self):
291                 return "get_conference_talks", (self._data["id"], ), {}
292
293         def _create_child(self, data):
294                 return TalkNode(self._connection, self, data)
295
296
297 class TalkNode(LeafNode):
298
299         def __init__(self, connection, parent, data):
300                 LeafNode.__init__(self, connection, parent, data)