Add per thread SQLObject DBConnection

make associated tests pass
SQLObject multi-thread access ***END OF DESCRIPTION***

Place the long patch description above the ***END OF DESCRIPTION*** marker.
The first line of this file will be the patch name.

This patch contains the following changes:

M ./run_tests.py -1 +6
M ./src/jcl/jabber/component.py -30 +70
M ./src/jcl/jabber/feeder.py -5 +11
M ./src/jcl/model/account.py +6
M ./tests/jcl/jabber/test_component.py -19 +62
M ./tests/jcl/jabber/test_feeder.py -7 +45

darcs-hash:20061009172608-86b55-804b8910c5ff19414a4f016289d3f03fb73866f9.gz
This commit is contained in:
David Rousselie
2006-10-09 19:26:08 +02:00
parent d505e65972
commit 9e28468b81
6 changed files with 200 additions and 62 deletions

View File

@@ -26,21 +26,27 @@
__revision__ = "$Id: component.py,v 1.3 2005/09/18 20:24:07 dax Exp $"
import thread
import sys
import threading
import time
import logging
import signal
import re
from Queue import Queue
from sqlobject.dbconnection import connectionForURI
from pyxmpp.jid import JID
from pyxmpp.jabberd.component import Component
from pyxmpp.jabber.disco import DiscoInfo, DiscoItems
from pyxmpp.jabber.disco import DiscoInfo, DiscoItems, DiscoItem
from pyxmpp.message import Message
from pyxmpp.presence import Presence
from pyxmpp.streambase import StreamError, FatalStreamError
from jcl.jabber.x import X
from jcl.model import account
from jcl.model.account import Account
VERSION = "0.1"
@@ -57,12 +63,28 @@ class JCLComponent(Component):
"""
timeout = 1
def set_account_class(self, account_class):
"""account_class attribut setter
create associated table via SQLObject"""
self.__account_class = account_class
self.db_connect()
self.__account_class.createTable() # TODO: ifNotExists = True)
self.db_disconnect()
def get_account_class(self):
"""account_class attribut getter"""
return self.__account_class
account_class = property(get_account_class, set_account_class)
def __init__(self,
jid,
secret,
server,
port,
db_connection_str,
disco_category = "gateway",
disco_type = "headline"):
Component.__init__(self, \
@@ -75,8 +97,9 @@ class JCLComponent(Component):
# default values
self.name = "Jabber Component Library generic component"
self.spool_dir = "."
self.db_connection_str = db_connection_str
self.__account_class = None
self.account_class = Account
self.set_account_class(Account)
self.version = VERSION
self.accounts = []
@@ -89,15 +112,6 @@ class JCLComponent(Component):
signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)
def set_account_class(self, account_class):
self.__account_class = account_class
self.__account_class.createTable(ifNotExists = True)
def get_account_class(self):
return self.__account_class
account_class = property(get_account_class, set_account_class)
def run(self):
"""Main loop
@@ -109,7 +123,12 @@ class JCLComponent(Component):
self.spool_dir += "/" + str(self.jid)
self.running = True
self.connect()
thread.start_new_thread(self.time_handler, ())
## TODO : workaround to make test_run pass on FeederComponent
# time.sleep(1)
##
timer_thread = threading.Thread(target = self.time_handler, \
name = "TimerThread")
timer_thread.start()
try:
while (self.running and self.stream
and not self.stream.eof and self.stream.socket is not None):
@@ -134,21 +153,34 @@ class JCLComponent(Component):
# to_jid = jid, \
# stanza_type = "unavailable")
# self.stream.send(p)
threads = threading.enumerate()
for _thread in threads:
try:
_thread.join(10 * JCLComponent.timeout)
except:
pass
for _thread in threads:
try:
_thread.join(JCLComponent.timeout)
except:
pass
# threads = threading.enumerate()
timer_thread.join(JCLComponent.timeout)
# for _thread in threads:
# try:
# _thread.join(10 * JCLComponent.timeout)
# except:
# pass
# for _thread in threads:
# try:
# _thread.join(JCLComponent.timeout)
# except:
# pass
self.disconnect()
# TODO : terminate SQLObject
self.__logger.debug("Exitting normally")
# TODO : terminate SQLObject
#################
# SQlite connections are not multi-threaded
# Utils workaround methods
#################
def db_connect(self):
account.hub.threadConnection = \
connectionForURI(self.db_connection_str)
def db_disconnect(self):
# account.hub.threadConnection.close()
del account.hub.threadConnection
###########################################################################
@@ -198,6 +230,7 @@ class JCLComponent(Component):
self.stream.set_message_handler("normal", \
self.handle_message)
current_jid = None
self.db_connect()
for account in self.account_class.select(orderBy = "user_jid"):
if account.user_jid != current_jid:
presence = Presence(from_jid = unicode(self.jid), \
@@ -209,6 +242,7 @@ class JCLComponent(Component):
to_jid = account.user_jid, \
stanza_type = "probe")
self.stream.send(presence)
self.db_disconnect()
def signal_handler(self, signum, frame):
"""Stop method handler
@@ -232,15 +266,19 @@ class JCLComponent(Component):
"""
self.__logger.debug("DISCO_GET_ITEMS")
## TODO Lang
## lang_class = self.__lang.get_lang_class_from_node(input_query.get_node())
## base_from_jid = unicode(input_query.get_from().bare())
## lang_class = self.__lang.get_lang_class_from_node(info_query.get_node())
base_from_jid = unicode(info_query.get_from().bare())
disco_items = DiscoItems()
if not node:
## TODO : list accounts
for account in self.accounts:
self.db_connect()
for account in self.account_class.select(Account.q.user_jid == \
base_from_jid):
self.__logger.debug(str(account))
## DiscoItem(di, JID(name + "@" + unicode(self.jid)), \
## name, str_name)
DiscoItem(disco_items, \
JID(account.jid), \
account.name, account.long_name)
self.db_disconnect()
return disco_items
def handle_get_version(self, input_query):
@@ -266,9 +304,11 @@ class JCLComponent(Component):
input_query = input_query.make_result_response()
query = input_query.new_query("jabber:iq:register")
if to_jid and to_jid != self.jid:
self.db_connect()
self.get_reg_form_init(lang_class, \
self.accounts.select() # TODO
self.account_class.select() # TODO
).attach_xml(query)
self.db_disconnect()
else:
self.get_reg_form(lang_class).attach_xml(query)
self.stream.send(input_query)

View File

@@ -40,12 +40,14 @@ class FeederComponent(JCLComponent):
jid,
secret,
server,
port):
port,
db_connection_str):
JCLComponent.__init__(self, \
jid, \
secret, \
server, \
port)
port, \
db_connection_str)
self.name = "Generic Feeder Component"
# Define default feeder and sender, can be override
self.feeder = Feeder()
@@ -56,9 +58,13 @@ class FeederComponent(JCLComponent):
def handle_tick(self):
"""Implement main feed/send behavior"""
for account in Account.select():
for data in self.feeder.feed(account):
self.sender.send(account, data)
pass
self.db_connect()
for acc in self.account_class.select():
print "OK"
# for data in self.feeder.feed(account):
# self.sender.send(account, data)
self.db_disconnect()

View File

@@ -28,9 +28,15 @@ __revision__ = "$Id: account.py,v 1.3 2005/09/18 20:24:07 dax Exp $"
from sqlobject.main import SQLObject
from sqlobject.col import StringCol
from sqlobject.dbconnection import ConnectionHub
# create a hub to attach a per thread connection
hub = ConnectionHub()
class Account(SQLObject):
"""Base Account class"""
_cacheValue = False
_connection = hub
user_jid = StringCol()
name = StringCol()
jid = StringCol()