Implement txns for AS (un)registration.

This commit is contained in:
Kegan Dougal 2015-02-02 17:39:41 +00:00
parent a006d168c5
commit 1a2de0c5fe
3 changed files with 102 additions and 23 deletions

View file

@ -43,7 +43,8 @@ class ApplicationServicesHandler(BaseHandler):
"Consult the home server admin.", "Consult the home server admin.",
errcode=Codes.FORBIDDEN errcode=Codes.FORBIDDEN
) )
# TODO store this AS logger.info("Updating application service info...")
yield self.store.update_app_service(app_service)
def unregister(self, token): def unregister(self, token):
logger.info("Unregister as_token=%s", token) logger.info("Unregister as_token=%s", token)

View file

@ -67,7 +67,7 @@ SCHEMAS = [
"event_signatures", "event_signatures",
"pusher", "pusher",
"media_repository", "media_repository",
"application_services" "application_services",
"filtering", "filtering",
"rejections", "rejections",
] ]

View file

@ -15,11 +15,17 @@
import logging import logging
from twisted.internet import defer from twisted.internet import defer
from synapse.api.errors import StoreError
from ._base import SQLBaseStore from ._base import SQLBaseStore
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
namespace_enum = [
"users", # 0
"aliases", # 1
"rooms" # 2
]
# XXX: This feels like it should belong in a "models" module, not storage. # XXX: This feels like it should belong in a "models" module, not storage.
class ApplicationService(object): class ApplicationService(object):
@ -30,25 +36,26 @@ class ApplicationService(object):
def __init__(self, token, url=None, namespaces=None): def __init__(self, token, url=None, namespaces=None):
self.token = token self.token = token
if url: self.url = url
self.url = url self.namespaces = self._get_namespaces(namespaces)
if namespaces:
self._set_namespaces(namespaces)
def _set_namespaces(self, namespaces): def _get_namespaces(self, namespaces):
# Sanity check that it is of the form: # Sanity check that it is of the form:
# { # {
# users: ["regex",...], # users: ["regex",...],
# aliases: ["regex",...], # aliases: ["regex",...],
# rooms: ["regex",...], # rooms: ["regex",...],
# } # }
if not namespaces:
return None
for ns in ["users", "rooms", "aliases"]: for ns in ["users", "rooms", "aliases"]:
if type(namespaces[ns]) != list: if type(namespaces[ns]) != list:
raise ValueError("Bad namespace value for '%s'", ns) raise ValueError("Bad namespace value for '%s'", ns)
for regex in namespaces[ns]: for regex in namespaces[ns]:
if not isinstance(regex, basestring): if not isinstance(regex, basestring):
raise ValueError("Expected string regex for ns '%s'", ns) raise ValueError("Expected string regex for ns '%s'", ns)
self.namespaces = namespaces return namespaces
def is_interested(self, event): def is_interested(self, event):
"""Check if this service is interested in this event. """Check if this service is interested in this event.
@ -110,10 +117,38 @@ class ApplicationServiceStore(SQLBaseStore):
This removes all AS specific regex and the base URL. The token is the This removes all AS specific regex and the base URL. The token is the
only thing preserved for future registration attempts. only thing preserved for future registration attempts.
""" """
# TODO: DELETE FROM application_services_regex WHERE id=this service yield self.runInteraction(
# TODO: SET url=NULL WHERE token=token "unregister_app_service",
# TODO: Update cache self._unregister_app_service_txn,
pass token,
)
# update cache TODO: Should this be in the txn?
for service in self.cache.services:
if service.token == token:
service.url = None
service.namespaces = None
def _unregister_app_service_txn(self, txn, token):
# kill the url to prevent pushes
txn.execute(
"UPDATE application_services SET url=NULL WHERE token=?",
(token,)
)
# cleanup regex
as_id = self._get_as_id_txn(txn, token)
if not as_id:
logger.warning(
"unregister_app_service_txn: Failed to find as_id for token=",
token
)
return False
txn.execute(
"DELETE FROM application_services_regex WHERE as_id=?",
(as_id,)
)
return True
def update_app_service(self, service): def update_app_service(self, service):
"""Update an application service, clobbering what was previously there. """Update an application service, clobbering what was previously there.
@ -124,12 +159,61 @@ class ApplicationServiceStore(SQLBaseStore):
# NB: There is no "insert" since we provide no public-facing API to # NB: There is no "insert" since we provide no public-facing API to
# allocate new ASes. It relies on the server admin inserting the AS # allocate new ASes. It relies on the server admin inserting the AS
# token into the database manually. # token into the database manually.
if not service.token or not service.url:
raise StoreError(400, "Token and url must be specified.")
# TODO: UPDATE application_services, SET url WHERE token=service.token yield self.runInteraction(
# TODO: DELETE FROM application_services_regex WHERE id=this service "update_app_service",
# TODO: INSERT INTO application_services_regex <new namespace regex> self._update_app_service_txn,
# TODO: Update cache service
pass )
# update cache TODO: Should this be in the txn?
for (index, cache_service) in enumerate(self.cache.services):
if service.token == cache_service.token:
self.cache.services[index] = service
logger.info("Updated: %s", service)
return
# new entry
self.cache.services.append(service)
logger.info("Updated(new): %s", service)
def _update_app_service_txn(self, txn, service):
as_id = self._get_as_id_txn(txn, service.token)
if not as_id:
logger.warning(
"update_app_service_txn: Failed to find as_id for token=",
service.token
)
return False
txn.execute(
"UPDATE application_services SET url=? WHERE id=?",
(service.url, as_id,)
)
# cleanup regex
txn.execute(
"DELETE FROM application_services_regex WHERE id=?",
(as_id,)
)
for (ns_int, ns_str) in enumerate(namespace_enum):
if ns_str in service.namespaces:
for regex in service.namespaces[ns_str]:
txn.execute(
"INSERT INTO application_services_regex("
"as_id, namespace, regex) values(?,?,?)",
(as_id, ns_int, regex)
)
return True
def _get_as_id_txn(self, txn, token):
cursor = txn.execute(
"SELECT id FROM application_services WHERE token=?",
(token,)
)
res = cursor.fetchone()
if res:
return res[0]
def get_services_for_event(self, event): def get_services_for_event(self, event):
return self.cache.get_services_for_event(event) return self.cache.get_services_for_event(event)
@ -161,12 +245,6 @@ class ApplicationServiceStore(SQLBaseStore):
sql = ("SELECT * FROM application_services LEFT JOIN " sql = ("SELECT * FROM application_services LEFT JOIN "
"application_services_regex ON application_services.id = " "application_services_regex ON application_services.id = "
"application_services_regex.as_id") "application_services_regex.as_id")
namespace_enum = [
"users", # 0
"aliases", # 1
"rooms" # 2
]
# SQL results in the form: # SQL results in the form:
# [ # [
# { # {