diff --git a/http/autocomplete.py b/http/autocomplete.py index 4f7a692..9d0bd5c 100755 --- a/http/autocomplete.py +++ b/http/autocomplete.py @@ -18,10 +18,12 @@ # You should have received a copy of the GNU Affero General Public License # along with Elixir. If not, see . -import falcon -from urllib import parse import sys import os +import json +from urllib import parse +from bsddb3.db import DB_SET_RANGE +import falcon ELIXIR_DIR = os.path.dirname(os.path.realpath(__file__)) + '/..' @@ -29,6 +31,7 @@ if ELIXIR_DIR not in sys.path: sys.path = [ ELIXIR_DIR ] + sys.path import query +from lib import autoBytes class AutocompleteResource: def on_get(self, req, resp): @@ -44,57 +47,42 @@ class AutocompleteResource: q = query.Query(datadir, repodir) - # Create tmp directory for autocomplete - tmpdir = '/tmp/autocomplete/' + query_project - if not(os.path.isdir(tmpdir)): - os.makedirs(tmpdir, exist_ok=True) - latest = q.query('latest') - # Define some specific values for some families if query_family == 'B': - name = 'comps' + # DTS identifiers are stored quoted process = lambda x: parse.unquote(x) + db = q.db.comps else: - name = 'defs' process = lambda x: x + db = q.db.defs - # Init values for tmp files - filename = tmpdir + '/' + name - mode = 'r+' if os.path.exists(filename) else 'w+' + response = [] - # Open tmp file - # Fill it with the keys of the database only - # if the file is older than the database - f = open(filename, mode) - if not f.readline()[:-1] == latest: - f.seek(0) - f.truncate() - f.write(latest + "\n") - f.write('\n'.join([process(x.decode()) for x in q.query('keys', name)])) - f.seek(0) - f.readline() # Skip first line that store the version number - - # Prepare http response - response = '[' - - # Search for the 10 first matching elements in the tmp file - index = 0 - for i in f: - if i.startswith(query_string): - response += '"' + i[:-1] + '",' - index += 1 - - if index == 10: + i = 0 + cur = db.db.cursor() + query_bytes = autoBytes(parse.quote(query_string)) + # Find "the smallest key greater than or equal to the specified key" + # https://docs.oracle.com/cd/E17276_01/html/api_reference/C/dbcget.html + # In practice this should mean "the key that starts with provided prefix" + # See docs about the default comparison function for B-Tree databases: + # https://docs.oracle.com/cd/E17276_01/html/api_reference/C/dbset_bt_compare.html + key, _ = cur.get(query_bytes, DB_SET_RANGE) + while i <= 10: + if key.startswith(query_bytes): + # If found key starts with the prefix, add to response + # and move to the next key + i += 1 + response.append(process(key.decode("utf-8"))) + key, _ = cur.next() + else: + # If found key does not start with the prefix, stop break - # Complete and send response - response = response[:-1] + ']' - resp.text = response resp.status = falcon.HTTP_200 + resp.content_type = falcon.MEDIA_JSON + resp.media = response - # Close tmp file - f.close() def get_application(): app = falcon.App()