Add basic application_services SQL, and hook up parts of the appservice store to read from it.

This commit is contained in:
Kegan Dougal 2015-01-28 11:59:38 +00:00
parent b46fa8603e
commit 42876969b9
5 changed files with 117 additions and 16 deletions

View file

@ -16,7 +16,7 @@
from twisted.internet import defer from twisted.internet import defer
from ._base import BaseHandler from ._base import BaseHandler
from synapse.api.errors import StoreError, SynapseError from synapse.api.errors import Codes, StoreError, SynapseError
import logging import logging
@ -36,11 +36,12 @@ class ApplicationServicesHandler(BaseHandler):
try: try:
stored_service = yield self.store.get_app_service(app_service.token) stored_service = yield self.store.get_app_service(app_service.token)
if not stored_service: if not stored_service:
raise StoreError(404, "Not found") raise StoreError(404, "Application Service Not found")
except StoreError: except StoreError:
raise SynapseError( raise SynapseError(
403, "Unrecognised application services token. " 403, "Unrecognised application services token. "
"Consult the home server admin." "Consult the home server admin.",
errcode=Codes.FORBIDDEN
) )
# TODO store this AS # TODO store this AS

View file

@ -64,9 +64,9 @@ class RegisterRestServlet(AppServiceRestServlet):
yield self.handler.register(app_service) yield self.handler.register(app_service)
hs_token = "_not_implemented_yet" # TODO: Pull this from self.hs? hs_token = "_not_implemented_yet" # TODO: Pull this from self.hs?
defer.returnValue({ defer.returnValue((200, {
"hs_token": hs_token "hs_token": hs_token
}) }))
def _parse_namespace(self, target_ns, origin_ns, ns): def _parse_namespace(self, target_ns, origin_ns, ns):
if ns not in target_ns or ns not in origin_ns: if ns not in target_ns or ns not in origin_ns:

View file

@ -62,6 +62,7 @@ SCHEMAS = [
"event_edges", "event_edges",
"event_signatures", "event_signatures",
"media_repository", "media_repository",
"application_services"
] ]

View file

@ -12,12 +12,15 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import logging
from synapse.api.errors import StoreError from twisted.internet import defer
from ._base import SQLBaseStore from ._base import SQLBaseStore
logger = logging.getLogger(__name__)
# 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):
"""Defines an application service. """Defines an application service.
@ -30,7 +33,22 @@ class ApplicationService(object):
if url: if url:
self.url = url self.url = url
if namespaces: if namespaces:
self.namespaces = namespaces self._set_namespaces(namespaces)
def _set_namespaces(self, namespaces):
# Sanity check that it is of the form:
# {
# users: ["regex",...],
# aliases: ["regex",...],
# rooms: ["regex",...],
# }
for ns in ["users", "rooms", "aliases"]:
if type(namespaces[ns]) != list:
raise ValueError("Bad namespace value for '%s'", ns)
for regex in namespaces[ns]:
if not isinstance(regex, basestring):
raise ValueError("Expected string regex for ns '%s'", ns)
self.namespaces = 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.
@ -133,15 +151,64 @@ class ApplicationServiceStore(SQLBaseStore):
return service return service
return None return None
# TODO: The from_cache=False impl
# TODO: This should be JOINed with the application_services_regex table. # TODO: This should be JOINed with the application_services_regex table.
row = self._simple_select_one(
"application_services", {"token": token},
["url", "token"]
)
if not row:
raise StoreError(400, "Bad application services token supplied.")
return row
@defer.inlineCallbacks
def _populate_cache(self): def _populate_cache(self):
"""Populates the ApplicationServiceCache from the database.""" """Populates the ApplicationServiceCache from the database."""
pass sql = ("SELECT * FROM application_services LEFT JOIN "
"application_services_regex ON application_services.id = "
"application_services_regex.as_id")
namespace_enum = [
"users", # 0
"aliases", # 1
"rooms" # 2
]
# SQL results in the form:
# [
# {
# 'regex': "something",
# 'url': "something",
# 'namespace': enum,
# 'as_id': 0,
# 'token': "something",
# 'id': 0
# }
# ]
services = {}
results = yield self._execute_and_decode(sql)
for res in results:
as_token = res["token"]
if as_token not in services:
# add the service
services[as_token] = {
"url": res["url"],
"token": as_token,
"namespaces": {
"users": [],
"aliases": [],
"rooms": []
}
}
# add the namespace regex if one exists
ns_int = res["namespace"]
if ns_int is None:
continue
try:
services[as_token]["namespaces"][namespace_enum[ns_int]].append(
res["regex"]
)
except IndexError:
logger.error("Bad namespace enum '%s'. %s", ns_int, res)
for service in services.values():
logger.info("Found application service: %s", service)
self.cache.services.append(ApplicationService(
service["token"],
service["url"],
service["namespaces"]
))

View file

@ -0,0 +1,32 @@
/* Copyright 2015 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
CREATE TABLE IF NOT EXISTS application_services(
id INTEGER PRIMARY KEY AUTOINCREMENT,
url TEXT,
token TEXT,
UNIQUE(token) ON CONFLICT ROLLBACK
);
CREATE TABLE IF NOT EXISTS application_services_regex(
id INTEGER PRIMARY KEY AUTOINCREMENT,
as_id INTEGER NOT NULL,
namespace INTEGER, /* enum[room_id|room_alias|user_id] */
regex TEXT,
FOREIGN KEY(as_id) REFERENCES application_services(id)
);