Move IdleCommand from resolver.py to idlequeue.py
This commit is contained in:
parent
0f61260578
commit
541167aa3e
|
@ -20,14 +20,10 @@
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import logging
|
||||||
|
log = logging.getLogger('gajim.c.resolver')
|
||||||
|
|
||||||
from xmpp.idlequeue import *
|
from xmpp.idlequeue import IdleCommand
|
||||||
|
|
||||||
# needed for nslookup
|
|
||||||
if os.name == 'nt':
|
|
||||||
from subprocess import * # python24 only. we ask this for Windows
|
|
||||||
elif os.name == 'posix':
|
|
||||||
import fcntl
|
|
||||||
|
|
||||||
# it is good to check validity of arguments, when calling system commands
|
# it is good to check validity of arguments, when calling system commands
|
||||||
ns_type_pattern = re.compile('^[a-z]+$')
|
ns_type_pattern = re.compile('^[a-z]+$')
|
||||||
|
@ -35,14 +31,13 @@ ns_type_pattern = re.compile('^[a-z]+$')
|
||||||
# match srv host_name
|
# match srv host_name
|
||||||
host_pattern = re.compile('^[a-z0-9\-._]*[a-z0-9]\.[a-z]{2,}$')
|
host_pattern = re.compile('^[a-z0-9\-._]*[a-z0-9]\.[a-z]{2,}$')
|
||||||
|
|
||||||
USE_LIBASYNCNS = False
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
#raise ImportError("Manually disabled libasync")
|
#raise ImportError("Manually disabled libasync")
|
||||||
import libasyncns
|
import libasyncns
|
||||||
USE_LIBASYNCNS = True
|
USE_LIBASYNCNS = True
|
||||||
log.info("libasyncns-python loaded")
|
log.info("libasyncns-python loaded")
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
USE_LIBASYNCNS = False
|
||||||
log.debug("Import of libasyncns-python failed, getaddrinfo will block", exc_info=True)
|
log.debug("Import of libasyncns-python failed, getaddrinfo will block", exc_info=True)
|
||||||
|
|
||||||
# FIXME: Remove these prints before release, replace with a warning dialog.
|
# FIXME: Remove these prints before release, replace with a warning dialog.
|
||||||
|
@ -98,11 +93,11 @@ class CommonResolver():
|
||||||
def start_resolve(self, host, type):
|
def start_resolve(self, host, type):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# FIXME: API usage is not consistent! This one requires that process is called
|
||||||
class LibAsyncNSResolver(CommonResolver):
|
class LibAsyncNSResolver(CommonResolver):
|
||||||
'''
|
'''
|
||||||
Asynchronous resolver using libasyncns-python. process() method has to be called
|
Asynchronous resolver using libasyncns-python. process() method has to be
|
||||||
in order to proceed the pending requests.
|
called in order to proceed the pending requests.
|
||||||
Based on patch submitted by Damien Thebault.
|
Based on patch submitted by Damien Thebault.
|
||||||
'''
|
'''
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -126,7 +121,6 @@ class LibAsyncNSResolver(CommonResolver):
|
||||||
|
|
||||||
CommonResolver._on_ready(self, host, type, result_list)
|
CommonResolver._on_ready(self, host, type, result_list)
|
||||||
|
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
try:
|
try:
|
||||||
self.asyncns.wait(False)
|
self.asyncns.wait(False)
|
||||||
|
@ -157,6 +151,7 @@ class LibAsyncNSResolver(CommonResolver):
|
||||||
resq.userdata['callback'](resq.userdata['dname'], rl)
|
resq.userdata['callback'](resq.userdata['dname'], rl)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class NSLookupResolver(CommonResolver):
|
class NSLookupResolver(CommonResolver):
|
||||||
'''
|
'''
|
||||||
Asynchronous DNS resolver calling nslookup. Processing of pending requests
|
Asynchronous DNS resolver calling nslookup. Processing of pending requests
|
||||||
|
@ -264,112 +259,14 @@ class NSLookupResolver(CommonResolver):
|
||||||
result_list = self.parse_srv_result(host, result)
|
result_list = self.parse_srv_result(host, result)
|
||||||
CommonResolver._on_ready(self, host, type, result_list)
|
CommonResolver._on_ready(self, host, type, result_list)
|
||||||
|
|
||||||
|
|
||||||
def start_resolve(self, host, type):
|
def start_resolve(self, host, type):
|
||||||
''' spawn new nslookup process and start waiting for results '''
|
''' spawn new nslookup process and start waiting for results '''
|
||||||
ns = NsLookup(self._on_ready, host, type)
|
ns = NsLookup(self._on_ready, host, type)
|
||||||
ns.set_idlequeue(self.idlequeue)
|
ns.set_idlequeue(self.idlequeue)
|
||||||
ns.commandtimeout = 10
|
ns.commandtimeout = 10
|
||||||
ns.start()
|
ns.start()
|
||||||
|
|
||||||
|
|
||||||
# TODO: move IdleCommand class in other file, maybe helpers ?
|
|
||||||
class IdleCommand(IdleObject):
|
|
||||||
def __init__(self, on_result):
|
|
||||||
# how long (sec.) to wait for result ( 0 - forever )
|
|
||||||
# it is a class var, instead of a constant and we can override it.
|
|
||||||
self.commandtimeout = 0
|
|
||||||
# when we have some kind of result (valid, ot not) we call this handler
|
|
||||||
self.result_handler = on_result
|
|
||||||
# if it is True, we can safetely execute the command
|
|
||||||
self.canexecute = True
|
|
||||||
self.idlequeue = None
|
|
||||||
self.result =''
|
|
||||||
|
|
||||||
def set_idlequeue(self, idlequeue):
|
|
||||||
self.idlequeue = idlequeue
|
|
||||||
|
|
||||||
def _return_result(self):
|
|
||||||
if self.result_handler:
|
|
||||||
self.result_handler(self.result)
|
|
||||||
self.result_handler = None
|
|
||||||
|
|
||||||
def _compose_command_args(self):
|
|
||||||
return ['echo', 'da']
|
|
||||||
|
|
||||||
def _compose_command_line(self):
|
|
||||||
''' return one line representation of command and its arguments '''
|
|
||||||
return reduce(lambda left, right: left + ' ' + right, self._compose_command_args())
|
|
||||||
|
|
||||||
def wait_child(self):
|
|
||||||
if self.pipe.poll() is None:
|
|
||||||
# result timeout
|
|
||||||
if self.endtime < self.idlequeue.current_time():
|
|
||||||
self._return_result()
|
|
||||||
self.pipe.stdout.close()
|
|
||||||
self.pipe.stdin.close()
|
|
||||||
else:
|
|
||||||
# child is still active, continue to wait
|
|
||||||
self.idlequeue.set_alarm(self.wait_child, 0.1)
|
|
||||||
else:
|
|
||||||
# child has quit
|
|
||||||
self.result = self.pipe.stdout.read()
|
|
||||||
self._return_result()
|
|
||||||
self.pipe.stdout.close()
|
|
||||||
self.pipe.stdin.close()
|
|
||||||
def start(self):
|
|
||||||
if not self.canexecute:
|
|
||||||
self.result = ''
|
|
||||||
self._return_result()
|
|
||||||
return
|
|
||||||
if os.name == 'nt':
|
|
||||||
self._start_nt()
|
|
||||||
elif os.name == 'posix':
|
|
||||||
self._start_posix()
|
|
||||||
|
|
||||||
def _start_nt(self):
|
|
||||||
# if gajim is started from noninteraactive shells stdin is closed and
|
|
||||||
# cannot be forwarded, so we have to keep it open
|
|
||||||
self.pipe = Popen(self._compose_command_args(), stdout=PIPE,
|
|
||||||
bufsize = 1024, shell = True, stderr = STDOUT, stdin = PIPE)
|
|
||||||
if self.commandtimeout >= 0:
|
|
||||||
self.endtime = self.idlequeue.current_time() + self.commandtimeout
|
|
||||||
self.idlequeue.set_alarm(self.wait_child, 0.1)
|
|
||||||
|
|
||||||
def _start_posix(self):
|
|
||||||
self.pipe = os.popen(self._compose_command_line())
|
|
||||||
self.fd = self.pipe.fileno()
|
|
||||||
fcntl.fcntl(self.pipe, fcntl.F_SETFL, os.O_NONBLOCK)
|
|
||||||
self.idlequeue.plug_idle(self, False, True)
|
|
||||||
if self.commandtimeout >= 0:
|
|
||||||
self.idlequeue.set_read_timeout(self.fd, self.commandtimeout)
|
|
||||||
|
|
||||||
def end(self):
|
|
||||||
self.idlequeue.unplug_idle(self.fd)
|
|
||||||
try:
|
|
||||||
self.pipe.close()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def pollend(self):
|
|
||||||
self.idlequeue.remove_timeout(self.fd)
|
|
||||||
self.end()
|
|
||||||
self._return_result()
|
|
||||||
|
|
||||||
def pollin(self):
|
|
||||||
try:
|
|
||||||
res = self.pipe.read()
|
|
||||||
except Exception, e:
|
|
||||||
res = ''
|
|
||||||
if res == '':
|
|
||||||
return self.pollend()
|
|
||||||
else:
|
|
||||||
self.result += res
|
|
||||||
|
|
||||||
def read_timeout(self):
|
|
||||||
self.end()
|
|
||||||
self._return_result()
|
|
||||||
|
|
||||||
class NsLookup(IdleCommand):
|
class NsLookup(IdleCommand):
|
||||||
def __init__(self, on_result, host='_xmpp-client', type='srv'):
|
def __init__(self, on_result, host='_xmpp-client', type='srv'):
|
||||||
IdleCommand.__init__(self, on_result)
|
IdleCommand.__init__(self, on_result)
|
||||||
|
@ -378,11 +275,11 @@ class NsLookup(IdleCommand):
|
||||||
self.type = type.lower()
|
self.type = type.lower()
|
||||||
if not host_pattern.match(self.host):
|
if not host_pattern.match(self.host):
|
||||||
# invalid host name
|
# invalid host name
|
||||||
print >> sys.stderr, 'Invalid host: %s' % self.host
|
log.error('Invalid host: %s' % self.host)
|
||||||
self.canexecute = False
|
self.canexecute = False
|
||||||
return
|
return
|
||||||
if not ns_type_pattern.match(self.type):
|
if not ns_type_pattern.match(self.type):
|
||||||
print >> sys.stderr, 'Invalid querytype: %s' % self.type
|
log.error('Invalid querytype: %s' % self.type)
|
||||||
self.canexecute = False
|
self.canexecute = False
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -396,15 +293,12 @@ class NsLookup(IdleCommand):
|
||||||
|
|
||||||
# below lines is on how to use API and assist in testing
|
# below lines is on how to use API and assist in testing
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if os.name == 'posix':
|
|
||||||
idlequeue = IdleQueue()
|
|
||||||
elif os.name == 'nt':
|
|
||||||
idlequeue = SelectIdleQueue()
|
|
||||||
# testing Resolver class
|
|
||||||
import gobject
|
import gobject
|
||||||
import gtk
|
import gtk
|
||||||
|
from xmpp import idlequeue
|
||||||
|
|
||||||
resolver = Resolver(idlequeue)
|
idlequeue = idlequeue.get_idlequeue()
|
||||||
|
resolver = get_resolver(idlequeue)
|
||||||
|
|
||||||
def clicked(widget):
|
def clicked(widget):
|
||||||
global resolver
|
global resolver
|
||||||
|
|
|
@ -20,12 +20,19 @@ import os
|
||||||
import select
|
import select
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger('gajim.c.x.idlequeue')
|
log = logging.getLogger('gajim.c.x.idlequeue')
|
||||||
|
|
||||||
|
# needed for get_idleqeue
|
||||||
try:
|
try:
|
||||||
import gobject
|
import gobject
|
||||||
HAVE_GOBJECT = True
|
HAVE_GOBJECT = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAVE_GOBJECT = False
|
HAVE_GOBJECT = False
|
||||||
|
|
||||||
|
# needed for idlecommand
|
||||||
|
if os.name == 'nt':
|
||||||
|
from subprocess import * # python24 only. we ask this for Windows
|
||||||
|
elif os.name == 'posix':
|
||||||
|
import fcntl
|
||||||
|
|
||||||
FLAG_WRITE = 20 # write only
|
FLAG_WRITE = 20 # write only
|
||||||
FLAG_READ = 19 # read only
|
FLAG_READ = 19 # read only
|
||||||
|
@ -36,6 +43,7 @@ PENDING_READ = 3 # waiting read event
|
||||||
PENDING_WRITE = 4 # waiting write event
|
PENDING_WRITE = 4 # waiting write event
|
||||||
IS_CLOSED = 16 # channel closed
|
IS_CLOSED = 16 # channel closed
|
||||||
|
|
||||||
|
|
||||||
def get_idlequeue():
|
def get_idlequeue():
|
||||||
''' Get an appropriate idlequeue '''
|
''' Get an appropriate idlequeue '''
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
|
@ -74,6 +82,110 @@ class IdleObject:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class IdleCommand(IdleObject):
|
||||||
|
'''
|
||||||
|
Can be subclassed to execute commands asynchronously by the idlequeue.
|
||||||
|
Result will be optained via file descriptor of created pipe
|
||||||
|
'''
|
||||||
|
def __init__(self, on_result):
|
||||||
|
IdleObject.__init__(self)
|
||||||
|
# how long (sec.) to wait for result ( 0 - forever )
|
||||||
|
# it is a class var, instead of a constant and we can override it.
|
||||||
|
self.commandtimeout = 0
|
||||||
|
# when we have some kind of result (valid, ot not) we call this handler
|
||||||
|
self.result_handler = on_result
|
||||||
|
# if it is True, we can safetely execute the command
|
||||||
|
self.canexecute = True
|
||||||
|
self.idlequeue = None
|
||||||
|
self.result =''
|
||||||
|
|
||||||
|
def set_idlequeue(self, idlequeue):
|
||||||
|
self.idlequeue = idlequeue
|
||||||
|
|
||||||
|
def _return_result(self):
|
||||||
|
if self.result_handler:
|
||||||
|
self.result_handler(self.result)
|
||||||
|
self.result_handler = None
|
||||||
|
|
||||||
|
def _compose_command_args(self):
|
||||||
|
return ['echo', 'da']
|
||||||
|
|
||||||
|
def _compose_command_line(self):
|
||||||
|
''' return one line representation of command and its arguments '''
|
||||||
|
return reduce(lambda left, right: left + ' ' + right,
|
||||||
|
self._compose_command_args())
|
||||||
|
|
||||||
|
def wait_child(self):
|
||||||
|
if self.pipe.poll() is None:
|
||||||
|
# result timeout
|
||||||
|
if self.endtime < self.idlequeue.current_time():
|
||||||
|
self._return_result()
|
||||||
|
self.pipe.stdout.close()
|
||||||
|
self.pipe.stdin.close()
|
||||||
|
else:
|
||||||
|
# child is still active, continue to wait
|
||||||
|
self.idlequeue.set_alarm(self.wait_child, 0.1)
|
||||||
|
else:
|
||||||
|
# child has quit
|
||||||
|
self.result = self.pipe.stdout.read()
|
||||||
|
self._return_result()
|
||||||
|
self.pipe.stdout.close()
|
||||||
|
self.pipe.stdin.close()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
if not self.canexecute:
|
||||||
|
self.result = ''
|
||||||
|
self._return_result()
|
||||||
|
return
|
||||||
|
if os.name == 'nt':
|
||||||
|
self._start_nt()
|
||||||
|
elif os.name == 'posix':
|
||||||
|
self._start_posix()
|
||||||
|
|
||||||
|
def _start_nt(self):
|
||||||
|
# if gajim is started from noninteraactive shells stdin is closed and
|
||||||
|
# cannot be forwarded, so we have to keep it open
|
||||||
|
self.pipe = Popen(self._compose_command_args(), stdout=PIPE,
|
||||||
|
bufsize = 1024, shell = True, stderr = STDOUT, stdin = PIPE)
|
||||||
|
if self.commandtimeout >= 0:
|
||||||
|
self.endtime = self.idlequeue.current_time() + self.commandtimeout
|
||||||
|
self.idlequeue.set_alarm(self.wait_child, 0.1)
|
||||||
|
|
||||||
|
def _start_posix(self):
|
||||||
|
self.pipe = os.popen(self._compose_command_line())
|
||||||
|
self.fd = self.pipe.fileno()
|
||||||
|
fcntl.fcntl(self.pipe, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||||
|
self.idlequeue.plug_idle(self, False, True)
|
||||||
|
if self.commandtimeout >= 0:
|
||||||
|
self.idlequeue.set_read_timeout(self.fd, self.commandtimeout)
|
||||||
|
|
||||||
|
def end(self):
|
||||||
|
self.idlequeue.unplug_idle(self.fd)
|
||||||
|
try:
|
||||||
|
self.pipe.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def pollend(self):
|
||||||
|
self.idlequeue.remove_timeout(self.fd)
|
||||||
|
self.end()
|
||||||
|
self._return_result()
|
||||||
|
|
||||||
|
def pollin(self):
|
||||||
|
try:
|
||||||
|
res = self.pipe.read()
|
||||||
|
except Exception, e:
|
||||||
|
res = ''
|
||||||
|
if res == '':
|
||||||
|
return self.pollend()
|
||||||
|
else:
|
||||||
|
self.result += res
|
||||||
|
|
||||||
|
def read_timeout(self):
|
||||||
|
self.end()
|
||||||
|
self._return_result()
|
||||||
|
|
||||||
|
|
||||||
class IdleQueue:
|
class IdleQueue:
|
||||||
'''
|
'''
|
||||||
IdleQueue provide three distinct time based features. Uses select.poll()
|
IdleQueue provide three distinct time based features. Uses select.poll()
|
||||||
|
|
Loading…
Reference in New Issue