Changeset 487


Ignore:
Timestamp:
Jan 5, 2013, 10:19:44 AM (7 years ago)
Author:
darcy
Message:

Add pgnotify method.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/module/pg.py

    r464 r487  
    1818
    1919"""
     20
     21import select
    2022
    2123from _pg import *
     
    127129    return _db_error(msg, ProgrammingError)
    128130
     131class pgnotify(object):
     132    """A PostgreSQL client-side asynchronous notification handler."""
     133
     134    def __init__(self, pgconn, event, callback, arg_dict={}, timeout=None):
     135        """
     136        pgconn   - PostgreSQL connection object.
     137        event    - Event to LISTEN for.
     138        callback - Event callback.
     139        arg_dict - A dictionary passed as the argument to the callback.
     140        timeout  - Timeout in seconds; a floating point number denotes
     141                    fractions of seconds. If it is absent or None, the
     142                    callers will never time out."""
     143
     144        self.pgconn = pgconn
     145        self.event = event
     146        self.stop = 'stop_%s' % event
     147        self.callback = callback
     148        self.arg_dict = arg_dict
     149        self.timeout = timeout
     150
     151    def __del__(self):
     152        try:
     153            self.pgconn.query('unlisten "%s"' % self.event)
     154            self.pgconn.query('unlisten "%s"' % self.stop)
     155        except pg.DatabaseError:
     156            pass
     157
     158    def __call__(self):
     159        """
     160        Invoke the handler.
     161        The handler actually LISTENs for two NOTIFY messages:
     162
     163        <event> and stop_<event>.
     164
     165        When either of these NOTIFY messages are received, its associated
     166        'pid' and 'event' are inserted into <arg_dict>, and the callback is
     167        invoked with <arg_dict>. If the NOTIFY message is stop_<event>, the
     168        handler UNLISTENs both <event> and stop_<event> and exits."""
     169
     170        self.pgconn.query('listen "%s"' % self.event)
     171        self.pgconn.query('listen "%s"' % self.stop)
     172        _ilist = [self.pgconn.fileno()]
     173
     174        while 1:
     175            ilist, olist, elist = select.select(_ilist, [], [], self.timeout)
     176            if ilist == []:
     177                # We timed out.
     178                self.pgconn.query('unlisten "%s"' % self.event)
     179                self.pgconn.query('unlisten "%s"' % self.stop)
     180                self.callback(None)
     181                return
     182            else:
     183                notice = self.pgconn.getnotify()
     184                if notice is None:
     185                    continue
     186                event, pid, extra = notice
     187                if event in (self.event, self.stop):
     188                    self.arg_dict['pid'] = pid
     189                    self.arg_dict['event'] = event
     190                    self.callback(self.arg_dict)
     191                    if event == self.stop:
     192                        self.pgconn.query('unlisten "%s"' % self.event)
     193                        self.pgconn.query('unlisten "%s"' % self.stop)
     194                        return
     195                else:
     196                    self.pgconn.query('unlisten "%s"' % self.event)
     197                    self.pgconn.query('unlisten "%s"' % self.stop)
     198                    raise pgnotifyError, \
     199                        'listening for ("%s", "%s") but notified of "%s"' \
     200                        % (self.event, self.stop, event)
     201
    129202
    130203# The PostGreSQL database connection interface:
    131 
    132204class DB(object):
    133205    """Wrapper class for the _pg connection type."""
     
    839911        return int(self.db.query(q, params))
    840912
     913    def pgnotify(self, event, callback, arg_dict={}, timeout=None):
     914        return pgnotify(self.db, event, callback, arg_dict, timeout)
    841915
    842916# if run as script, print some information
Note: See TracChangeset for help on using the changeset viewer.