-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathKalturaClient.py
executable file
·361 lines (299 loc) · 12.7 KB
/
KalturaClient.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
from KalturaCoreClient import *
from KalturaClientBase import *
from xml.parsers.expat import ExpatError
from xml.dom import minidom
from threading import Timer
import socket
import time
import sys
import os
from poster.streaminghttp import register_openers
from poster.encode import multipart_encode
try:
import urllib2
except ImportError:
import urllib.request as urllib2
if sys.version_info[0] > 2:
import urllib
urllib.urlopen = urllib2.urlopen
else:
import urllib
from utils import urlencode
# Register the streaming http handlers with urllib.request
register_openers()
pluginsFolder = os.path.normpath(os.path.join(os.path.dirname(__file__), 'KalturaPlugins'))
if not pluginsFolder in sys.path:
sys.path.append(pluginsFolder)
class MultiRequestSubResult:
def __init__(self, value):
self.value = value
def __str__(self):
return '{%s}' % self.value
def __repr__(self):
return '{%s}' % self.value
def __getattr__(self, name):
if name.startswith('__') or name.endswith('__'):
raise AttributeError
return MultiRequestSubResult('%s:%s' % (self.value, name))
def __getitem__(self, key):
return MultiRequestSubResult('%s:%s' % (self.value, key))
class PluginServicesProxy:
def addService(self, serviceName, serviceClass):
setattr(self, serviceName, serviceClass)
class KalturaClient:
def __init__(self, config):
self.apiVersion = API_VERSION
self.config = None
self.ks = NotImplemented
self.shouldLog = False
self.multiRequest = False
self.callsQueue = []
self.config = config
logger = self.config.getLogger()
if (logger):
self.shouldLog = True
self.loadPlugins()
def loadPlugins(self):
if not os.path.isdir(pluginsFolder):
return
pluginList = ['KalturaCoreClient']
for fileName in os.listdir(pluginsFolder):
(pluginClass, fileExt) = os.path.splitext(fileName)
if fileExt.lower() != '.py':
continue
pluginList.append(pluginClass)
for pluginClass in pluginList:
self.loadPlugin(pluginClass)
def loadPlugin(self, pluginClass):
pluginModule = __import__(pluginClass)
if not pluginClass in dir(pluginModule):
return
pluginClassType = getattr(pluginModule, pluginClass)
plugin = pluginClassType.get(self)
if not isinstance(plugin, IKalturaClientPlugin):
return
self.registerPluginServices(plugin)
self.registerPluginObjects(plugin)
def registerPluginServices(self, plugin):
pluginName = plugin.getName()
if pluginName != '':
pluginProxy = PluginServicesProxy()
setattr(self, pluginName, pluginProxy)
for (serviceName, serviceFactory) in plugin.getServices().items():
serviceClass = serviceFactory(self)
if pluginName == '':
self.addCoreService(serviceName, serviceClass)
else:
pluginProxy.addService(serviceName, serviceClass)
def registerPluginObjects(self, plugin):
KalturaEnumsFactory.registerEnums(plugin.getEnums())
KalturaObjectFactory.registerObjects(plugin.getTypes())
def addCoreService(self, serviceName, serviceClass):
setattr(self, serviceName, serviceClass)
def getServeUrl(self):
if len(self.callsQueue) != 1:
return None
(url, params, _) = self.getRequestParams()
# reset state
self.callsQueue = []
self.multiRequest = False
result = '%s&%s' % (url, urlencode(params.get()))
self.log("Returned url [%s]" % result)
return result
def queueServiceActionCall(self, service, action, params = KalturaParams(), files = KalturaFiles()):
# in start session partner id is optional (default -1). if partner id was not set, use the one in the config
if not "partnerId" in params.get() or params.get()["partnerId"] == -1:
params.put("partnerId", self.config.partnerId)
params.addStringIfDefined("ks", self.ks)
call = KalturaServiceActionCall(service, action, params, files)
self.callsQueue.append(call)
def getRequestParams(self):
params = KalturaParams()
files = KalturaFiles()
params.put("apiVersion", self.apiVersion)
params.put("format", self.config.format)
params.put("clientTag", self.config.clientTag)
url = self.config.serviceUrl + "/api_v3/index.php?service="
if self.multiRequest:
url += "multirequest"
i = 1
for call in self.callsQueue:
callParams = call.getParamsForMultiRequest(i)
params.update(callParams)
files.update(call.files)
i += 1
else:
call = self.callsQueue[0]
url += call.service + "&action=" + call.action
params.update(call.params)
files.update(call.files)
signature = params.signature()
params.put("kalsig", signature)
self.log("request url: [%s]" % url)
return (url, params, files)
@staticmethod
def closeHandle(fh):
fh.close()
@staticmethod
def openRequestUrl(url, params, files):
if len(files.get()) == 0:
try:
paramsdict = params.get()
sanitized_params = {}
for k, v in paramsdict.items():
if hasattr(k, 'encode'):
key = k.encode('utf-8')
elif hasattr(k, 'decode'):
key = k.decode('utf-8').encode('utf-8')
else:
key = str(k).encode('utf-8')
if hasattr(v, 'encode'):
val = v.encode('utf-8')
elif hasattr(k, 'decode'):
val = v.decode('utf-8').encode('utf-8')
else:
val = str(v).encode('utf-8')
sanitized_params[key] = val
f = urllib.urlopen(url, urlencode(sanitized_params))
#except Exception, e:
except Exception as e:
raise KalturaClientException(e, KalturaClientException.ERROR_CONNECTION_FAILED)
else:
fullParams = params
fullParams.update(files)
datagen, headers = multipart_encode(fullParams.get())
request = urllib2.Request(url, datagen, headers)
try:
f = urllib2.urlopen(request)
except Exception as e:
raise KalturaClientException(e, KalturaClientException.ERROR_CONNECTION_FAILED)
return f
@staticmethod
def readHttpResponse(f, requestTimeout):
if requestTimeout != None:
readTimer = Timer(requestTimeout, KalturaClient.closeHandle, [f])
readTimer.start()
try:
try:
data = f.read()
except AttributeError as e:
raise KalturaClientException(e, KalturaClientException.ERROR_READ_TIMEOUT)
except Exception as e:
raise KalturaClientException(e, KalturaClientException.ERROR_READ_FAILED)
finally:
if requestTimeout != None:
readTimer.cancel()
return data
# Send http request
def doHttpRequest(self, url, params = KalturaParams(), files = KalturaFiles()):
if len(files.get()) == 0:
requestTimeout = self.config.requestTimeout
else:
requestTimeout = None
if requestTimeout != None:
origSocketTimeout = socket.getdefaulttimeout()
socket.setdefaulttimeout(requestTimeout)
try:
f = self.openRequestUrl(url, params, files)
data = self.readHttpResponse(f, requestTimeout)
finally:
if requestTimeout != None:
socket.setdefaulttimeout(origSocketTimeout)
return data
def parsePostResult(self, postResult):
if len(postResult) > 1024:
self.log("result (xml): %s bytes" % len(postResult))
else:
self.log("result (xml): %s" % postResult)
try:
resultXml = minidom.parseString(postResult)
except ExpatError as e:
raise KalturaClientException(e, KalturaClientException.ERROR_INVALID_XML)
resultNode = getChildNodeByXPath(resultXml, 'xml/result')
if resultNode == None:
raise KalturaClientException('Could not find result node in response xml', KalturaClientException.ERROR_RESULT_NOT_FOUND)
self.throwExceptionIfError(resultNode)
return resultNode
# Call all API services that are in queue
def doQueue(self):
if len(self.callsQueue) == 0:
self.multiRequest = False
return None
if self.config.format != KALTURA_SERVICE_FORMAT_XML:
raise KalturaClientException("unsupported format: %s" % (postResult), KalturaClientException.ERROR_FORMAT_NOT_SUPPORTED)
startTime = time.time()
# get request params
(url, params, files) = self.getRequestParams()
# reset state
self.callsQueue = []
self.multiRequest = False
# issue the request
postResult = self.doHttpRequest(url, params, files)
# parse the result
resultNode = self.parsePostResult(postResult)
endTime = time.time()
self.log("execution time for [%s]: [%s]" % (url, endTime - startTime))
return resultNode
def getKs(self):
return self.ks
def setKs(self, ks):
self.ks = ks
def getConfig(self):
return self.config
def setConfig(self, config):
self.config = config
logger = self.config.getLogger()
if isinstance(logger, IKalturaLogger):
self.shouldLog = True
def getExceptionIfError(self, resultNode):
errorNode = getChildNodeByXPath(resultNode, 'error')
if errorNode == None:
return None
messageNode = getChildNodeByXPath(errorNode, 'message')
codeNode = getChildNodeByXPath(errorNode, 'code')
if messageNode == None or codeNode == None:
return None
return KalturaException(getXmlNodeText(messageNode), getXmlNodeText(codeNode))
# Validate the result xml node and raise exception if its an error
def throwExceptionIfError(self, resultNode):
exceptionObj = self.getExceptionIfError(resultNode)
if exceptionObj == None:
return
raise exceptionObj
def startMultiRequest(self):
self.multiRequest = True
def doMultiRequest(self):
resultXml = self.doQueue()
if resultXml == None:
return []
result = []
for childNode in resultXml.childNodes:
exceptionObj = self.getExceptionIfError(childNode)
if exceptionObj != None:
result.append(exceptionObj)
elif getChildNodeByXPath(childNode, 'objectType') != None:
result.append(KalturaObjectFactory.create(childNode, KalturaObjectBase))
else:
result.append(getXmlNodeText(childNode))
return result
def isMultiRequest(self):
return self.multiRequest
def getMultiRequestResult(self):
return MultiRequestSubResult('%s:result' % len(self.callsQueue))
def log(self, msg):
if self.shouldLog:
self.config.getLogger().log(msg)
class KalturaServiceActionCall:
def __init__(self, service, action, params = KalturaParams(), files = KalturaFiles()):
self.service = service
self.action = action
self.params = params
self.files = files
# Return the parameters for a multi request
def getParamsForMultiRequest(self, multiRequestIndex):
multiRequestParams = KalturaParams()
multiRequestParams.put("%s:service" % multiRequestIndex, self.service)
multiRequestParams.put("%s:action" % multiRequestIndex, self.action)
for (key, val) in self.params.get().items():
multiRequestParams.put("%s:%s" % (multiRequestIndex, key), val)
return multiRequestParams