diff options
| author | Antti Ajanki <antti.ajanki@iki.fi> | 2011-07-06 17:04:33 +0300 |
|---|---|---|
| committer | Antti Ajanki <antti.ajanki@iki.fi> | 2011-07-06 17:04:33 +0300 |
| commit | bd88072b5df85c392917e4bce11a40c0058c4657 (patch) | |
| tree | c822a94e501a1f6fecf6d0742b772771f2b34441 /src/libwebvi/webvi | |
| parent | 195fcc2ea284489240d58a72859f0963ad82e27a (diff) | |
| download | vdr-plugin-webvideo-bd88072b5df85c392917e4bce11a40c0058c4657.tar.gz vdr-plugin-webvideo-bd88072b5df85c392917e4bce11a40c0058c4657.tar.bz2 | |
Properly implement timeout callback (bug #619), bump SONAME because of API changes
Diffstat (limited to 'src/libwebvi/webvi')
| -rw-r--r-- | src/libwebvi/webvi/api.py | 66 | ||||
| -rw-r--r-- | src/libwebvi/webvi/asyncurl.py | 34 | ||||
| -rw-r--r-- | src/libwebvi/webvi/constants.py | 7 | ||||
| -rw-r--r-- | src/libwebvi/webvi/request.py | 6 |
4 files changed, 77 insertions, 36 deletions
diff --git a/src/libwebvi/webvi/api.py b/src/libwebvi/webvi/api.py index f7f4ad1..6dfa31e 100644 --- a/src/libwebvi/webvi/api.py +++ b/src/libwebvi/webvi/api.py @@ -23,29 +23,45 @@ Example workflow: handle = new_request(ref, WebviRequestType.MENU) -2) Setup a callback function: +2) Setup a timeout callback: -setopt(handle, WebviOpt.WRITEFUNC, my_callback) +def timeout_func(t, ignored): + global alarm + now = current_time_in_milliseconds() + alarm = now + t -3) Start the network transfer: +set_config(WebviConfig.TIMEOUT_CALLBACK, timeout_func) + +3) Setup a data callback: + +set_opt(handle, WebviOpt.WRITEFUNC, write_func) + +4) Start the network transfer: start_handle(handle) -4) Get active file descriptors, wait for activity on them, and let -webvi process the file descriptor. +5) Get active file descriptors, wait for activity using the timeout +value supplied by timeout callback, and let webvi process the file +descriptor. import select ... readfd, writefd, excfd = fdset()[1:4] -readfd, writefd, excfd = select.select(readfd, writefd, excfd, 5.0) -for fd in readfd: - perform(fd, WebviSelectBitmask.READ) -for fd in writefd: - perform(fd, WebviSelectBitmask.WRITE) - -5) Iterate 4) until pop_message returns handle, which indicates that +timeout = alarm - current_time_in_milliseconds() +if timeout < 0: + timeout = 10.0 +readfd, writefd, excfd = select.select(readfd, writefd, excfd, timeout) +if readfd == writefd == excfd == []: # timeout + perform(WebviSelect.TIMEOUT, WebviSelectBitmask.CHECK) +else: + for fd in readfd: + perform(fd, WebviSelectBitmask.READ) + for fd in writefd: + perform(fd, WebviSelectBitmask.WRITE) + +6) Iterate 5) until pop_message returns handle, which indicates that the request has been completed. finished, status, errmsg, remaining = pop_message() @@ -105,6 +121,12 @@ def set_config(conf, value): else: request.DEBUG = True return WebviErr.OK + elif conf == WebviConfig.TIMEOUT_CALLBACK: + request.set_timeout_callback(value) + return WebviErr.OK + elif conf == WebviConfig.TIMEOUT_DATA: + request.timeout_data = value + return WebviErr.OK else: return WebviErr.INVALID_PARAMETER @@ -242,7 +264,7 @@ def fdset(): """Get the list of file descriptors that are currently in use by the library. - Returrns a tuple, where the first item is a constants.WebviErr + Returns a tuple, where the first item is a constants.WebviErr value indicating the success of the call, the next three values are lists of descriptors that should be monitored for reading, writing, and exceptional conditions, respectively. The last item @@ -272,24 +294,24 @@ def perform(fd, ev_bitmask): select() or similar system call. ev_bitmask specifies what kind of activity has been detected using values of constants.WebviSelectBitmask. If ev_bitmask is - constants.WebviSelectBitmask.TIMEOUT the type of activity is check - by the function. + constants.WebviSelectBitmask.CHECK the type of activity is + checked by the function. - This function should be called every few seconds with fd=-1, - ev_bitmask=constants.WebviSelectBitmask.TIMEOUT even if no - activity has been signalled on the file descriptors to ensure - correct handling of timeouts and other internal processing. + If a timeout occurs before any file descriptor becomes ready, this + function should be called with fd set to + constants.WebviSelect.TIMEOUT and ev_bitmask set to + constants.WebviSelectBitmask.CHECK. """ if fd < 0: - asyncurl.poll() + asyncurl.poll_timeout() else: disp = socket_map.get(fd) if disp is not None: if ev_bitmask & WebviSelectBitmask.READ != 0 or \ - (ev_bitmask == 0 and disp.readable()): + (ev_bitmask == WebviSelectBitmask.CHECK and disp.readable()): disp.handle_read_event() if ev_bitmask & WebviSelectBitmask.WRITE != 0 or \ - (ev_bitmask == 0 and disp.writable()): + (ev_bitmask == WebviSelectBitmask.CHECK and disp.writable()): disp.handle_write_event() return (WebviErr.OK, len(socket_map)) diff --git a/src/libwebvi/webvi/asyncurl.py b/src/libwebvi/webvi/asyncurl.py index 585f090..6b17893 100644 --- a/src/libwebvi/webvi/asyncurl.py +++ b/src/libwebvi/webvi/asyncurl.py @@ -40,7 +40,8 @@ def poll(timeout=0.0, map=None, mdisp=None): if mdisp is None: mdisp = multi_dispatcher if map: - timeout = min(timeout, mdisp.timeout/1000.0) + if mdisp.timeout != -1: + timeout = min(timeout, mdisp.timeout/1000.0) r = []; w = []; e = [] for fd, obj in map.items(): @@ -53,7 +54,8 @@ def poll(timeout=0.0, map=None, mdisp=None): if is_r or is_w: e.append(fd) if [] == r == w == e: - time.sleep(timeout) + if timeout > 0: + time.sleep(timeout) else: try: r, w, e = select.select(r, w, e, timeout) @@ -85,6 +87,11 @@ def poll(timeout=0.0, map=None, mdisp=None): continue asyncore._exception(obj) +def poll_timeout(mdisp=None): + if mdisp is None: + mdisp = multi_dispatcher + mdisp.socket_action(SOCKET_TIMEOUT, 0) + def loop(timeout=30.0, use_poll=False, map=None, count=None, mdisp=None): if map is None: map = asyncore.socket_map @@ -118,13 +125,15 @@ class curl_multi_dispatcher: else: self._map = socket_map self.dispatchers = {} - self.timeout = 1000 + self.timeout = -1 + # The lambda is to avoid "not callable" error from pylint + self.timeout_callback = lambda x, y: None self._sockets_removed = False self._curlm = pycurl.CurlMulti() - self._curlm.setopt(pycurl.M_SOCKETFUNCTION, self.socket_callback) - self._curlm.setopt(pycurl.M_TIMERFUNCTION, self.timeout_callback) + self._curlm.setopt(pycurl.M_SOCKETFUNCTION, self._socket_callback) + self._curlm.setopt(pycurl.M_TIMERFUNCTION, self._update_timeout) - def socket_callback(self, action, socket, user_data, socket_data): + def _socket_callback(self, action, socket, user_data, socket_data): # print 'socket callback: %d, %s' % \ # (socket, {pycurl.POLL_NONE: "NONE", # pycurl.POLL_IN: "IN", @@ -155,8 +164,10 @@ class curl_multi_dispatcher: obj.set_readable(True) obj.set_writable(True) - def timeout_callback(self, msec): + def _update_timeout(self, msec): self.timeout = msec + if self.timeout_callback: + self.timeout_callback(self, msec) def attach(self, curldisp): """Starts a transfer on curl handle by attaching it to this @@ -168,9 +179,9 @@ class curl_multi_dispatcher: # the curl object is already on this multi-stack pass - while self._curlm.socket_all()[0] == pycurl.E_CALL_MULTI_PERFORM: - pass - + # _curlm.timeout() seems to be needed, although curl + # documentation doesn't mention it. + self._update_timeout(self._curlm.timeout()) self.check_completed(True) def detach(self, curldisp): @@ -181,9 +192,6 @@ class curl_multi_dispatcher: # libcurl does not send POLL_REMOVE when a handle is aborted for socket, curlobj in self._map.items(): if curlobj == curldisp: - - print 'handle stopped but socket in map' - del self._map[socket] break diff --git a/src/libwebvi/webvi/constants.py b/src/libwebvi/webvi/constants.py index 2d29700..16e1f92 100644 --- a/src/libwebvi/webvi/constants.py +++ b/src/libwebvi/webvi/constants.py @@ -41,11 +41,16 @@ class WebviInfo: STREAM_TITLE = 3 class WebviSelectBitmask: - TIMEOUT = 0 + CHECK = 0 READ = 1 WRITE = 2 EXCEPTION = 4 +class WebviSelect: + TIMEOUT = -1 + class WebviConfig: TEMPLATE_PATH = 0 DEBUG = 1 + TIMEOUT_CALLBACK = 2 + TIMEOUT_DATA = 3 diff --git a/src/libwebvi/webvi/request.py b/src/libwebvi/webvi/request.py index 87dcf87..cab15f7 100644 --- a/src/libwebvi/webvi/request.py +++ b/src/libwebvi/webvi/request.py @@ -24,12 +24,14 @@ import download import sys import utils import json2xml +import asyncurl from constants import WebviRequestType DEBUG = False DEFAULT_TEMPLATE_PATH = '/usr/local/share/webvi/templates' template_path = DEFAULT_TEMPLATE_PATH +timeout_data = None def debug(msg): if DEBUG: @@ -49,6 +51,10 @@ def set_template_path(path): debug("set_template_path " + template_path) +def set_timeout_callback(callback): + c_api_callback = lambda mdisp, timeout: callback(timeout, timeout_data) + asyncurl.multi_dispatcher.timeout_callback = c_api_callback + def parse_reference(reference): """Parses URLs of the following form: |
