# Copyright (c) 2013, 2018 National Technology and Engineering Solutions of Sandia, LLC . Under the terms of Contract
# DE-NA0003525 with National Technology and Engineering Solutions of Sandia, LLC, the U.S. Government
# retains certain rights in this software.
"""Slycat uses `CouchDB <http://couchdb.apache.org>`_ as its primary storage
for projects, models, bookmarks, metadata, and small model artifacts. For
large model artifacts such as :mod:`darrays<slycat.darray>`, the CouchDB
database stores links to HDF5 files stored on disk.
"""
import cherrypy
import couchdb.client
import threading
import time
import uuid
db_lock = threading.Lock()
session_locks = {}
[docs]
def get_session_lock(sid):
if sid in session_locks:
return session_locks[sid]
session_locks[sid] = threading.Lock()
return session_locks[sid]
[docs]
class Database:
"""Wraps a :class:`couchdb.client.Database` to convert CouchDB exceptions into CherryPy exceptions."""
def __init__(self, database):
self._database = database
def __getitem__(self, *arguments, **keywords):
return self._database.__getitem__(*arguments, **keywords)
[docs]
def changes(self, *arguments, **keywords):
return self._database.changes(*arguments, **keywords)
[docs]
def delete(self, *arguments, **keywords):
return self._database.delete(*arguments, **keywords)
[docs]
def get_attachment(self, *arguments, **keywords):
return self._database.get_attachment(*arguments, **keywords)
[docs]
def put_attachment(self, *arguments, **keywords):
return self._database.put_attachment(*arguments, **keywords)
[docs]
def save(self, *arguments, **keywords):
try:
return self._database.save(*arguments, **keywords)
except couchdb.http.ServerError as e:
cherrypy.log.error("slycat.web.server.database.couchdb.py save", "%s" % str(e))
raise cherrypy.HTTPError("%s" % str(e))
[docs]
def view(self, *arguments, **keywords):
return self._database.view(*arguments, **keywords)
[docs]
def scan(self, path, **keywords):
for row in self.view(path, include_docs=True, **keywords):
document = row["doc"]
yield document
[docs]
def get(self, type, id):
try:
document = self[id]
except couchdb.client.http.ResourceNotFound:
raise cherrypy.HTTPError(404)
if document["type"] != type:
cherrypy.log.error("slycat.web.server.database.couchdb.py get", "cherrypy.HTTPError 404 document type %s is different than input type: %s" % (document["type"], type))
raise cherrypy.HTTPError(404)
return document
[docs]
def write_file(self, document, content, content_type):
fid = uuid.uuid4().hex
self.put_attachment(document, content, filename=fid, content_type=content_type)
return fid
def __repr__(self):
"""
adding this so we can use the cache decorator
:return:
"""
return "<slycat.web.server.database.couchdb.Database instance>"
[docs]
def connect():
"""Connect to a CouchDB database.
Returns
-------
database : :class:`slycat.web.server.database.couchdb.Database`
"""
server = couchdb.client.Server(url=cherrypy.tree.apps[""].config["slycat"]["couchdb-host"])
database = Database(server[cherrypy.tree.apps[""].config["slycat"]["couchdb-database"]])
return database