def cache_tiddlers(package_name): """ Stores instance tiddlers in the package. reads store_contents from <package>.instance tiddler files are stored in <package>/resources/store """ instance_module = __import__('%s.instance' % package_name, None, None, ['instance']) store_contents = instance_module.store_contents target_store = Store('tiddlywebplugins.pkgstore', {'package': package_name, 'read_only': False}, {}) sources = {} for bag, uris in store_contents.items(): sources[bag] = [] for uri in uris: if uri.endswith('.recipe'): urls = recipe_to_urls(uri) sources[bag].extend(urls) else: sources[bag].append(uri) for bag_name, uris in sources.items(): bag = Bag(bag_name) target_store.put(bag) for uri in uris: std_error_message('retrieving %s' % uri) tiddler = url_to_tiddler(uri) tiddler.bag = bag.name target_store.put(tiddler)
def setup_module(module): # cleanup try: shutil.rmtree('store') except OSError: pass # establish web server app = load_app() def app_fn(): return app httplib2_intercept.install() wsgi_intercept.add_wsgi_intercept('our_test_domain', 8001, app_fn) # establish store store = Store(config['server_store'][0], config['server_store'][1], environ={'tiddlyweb.config': config}) # make some stuff bag = Bag('place') store.put(bag) for i in range(1, 10): tiddler = Tiddler('tiddler%s' % i, 'place') tiddler.text = 'hi%s' store.put(tiddler) module.http = httplib2.Http()
def _make_recipe(recipe_name, bags): """Make a recipe with recipe_name.""" recipe = Recipe(recipe_name) recipe_list = [[bag, ''] for bag in bags] recipe.set_recipe(recipe_list) store = Store(config['server_store'][0], environ={'tiddlyweb.config': config}) store.put(recipe)
def make_tiddlers_for_bag(): store = Store('text', environ=environ) print 'store', time() bag = Bag('profiler') store.put(bag) for name in range(1, 1000): name = str(name) tiddler = Tiddler(name, bag.name) tiddler.text = name store.put(tiddler)
def test_where_it_goes(): store = Store(SAMPLE_CONFIG['server_store'][0], SAMPLE_CONFIG['server_store'][1], environ=ENVIRON) bbag = Bag('bbag') cbag = Bag('cbag') store.put(bbag) store.put(cbag) assert os.path.exists('store1/bags/bbag/tiddlers') assert os.path.exists('store2/bags/cbag/tiddlers') assert not os.path.exists('store2/bags/bbag/tiddlers') assert not os.path.exists('store1/bags/cbag/tiddlers')
def setup_module(module): bag = Bag('holder') store = Store(config['server_store'][0], config['server_store'][1], {'tiddlyweb.config': config}) store.put(bag) import_one('holder', IMAGE, store) import_one('holder', ZERO, store) tiddler = Tiddler('index', 'holder') tiddler.text = open(HTML).read().decode('UTF-8') tiddler.type = 'text/html' store.put(tiddler) module.store = store
def test_recipe_put_to_store(): _cleanup() config = { "server_store": ["tiddlywebplugins.devstore", { "store_root": STORE_DIR }], "instance_tiddlers": {}, "root_dir": "" } env = { "tiddlyweb.config": config } store = Store(config["server_store"][0], config["server_store"][1], env) name = "foo" recipe = Recipe(name) store.put(recipe) assert os.path.exists("%s.recipe" % os.path.join(STORE_DIR, name))
def make_tiddlers_for_bag(): store = Store('text', environ=environ) print 'store', time() bag = Bag('profiler') store.put(bag) for name in range(1, 10000): tag = name % 10 name = str(name) tag = str(tag) tiddler = Tiddler(name, bag.name) tiddler.text = name tiddler.tags.append(tag) store.put(tiddler) print 'stored', time()
def make_tiddlers_for_bag(): store = Store('text', environ['tiddlyweb.config']['server_store'][1], environ) print 'store', time() bag = Bag('profiler') store.put(bag) for name in range(1, 10000): tag = name % 10 name = str(name) tag = str(tag) tiddler = Tiddler(name, bag.name) tiddler.text = name tiddler.tags.append(tag) store.put(tiddler) print 'stored', time()
def test_get_tiddler_revision(): _cleanup() config = { "server_store": ["tiddlywebplugins.devstore", { "store_root": STORE_DIR }], "instance_tiddlers": { "myBag": ["%s/alpha/index.recipe" % REPO_DIR] }, "root_dir": "" } env = { "tiddlyweb.config": config } store = Store(config["server_store"][0], config["server_store"][1], env) tiddler = Tiddler("lorem") tiddler.bag = "myBag" t = store.get(tiddler) assert t.title == "lorem" assert t.bag == "myBag" assert t.revision == 1 assert t.tags == [] assert t.creator == "FND" assert t.modifier == "FND" assert len(t.created) == 14 assert len(t.modified) == 14 assert t.created == t.modified assert t.text == "lorem ipsum" tiddler = Tiddler("hello world") tiddler.bag = "myBag" tiddler.tags = ["foo", "bar"] tiddler.modifier = "FND" tiddler.text = "lorem ipsum" store.put(tiddler) tiddler = Tiddler("hello world") tiddler.bag = "myBag" t = store.get(tiddler) assert t.title == "hello world" assert t.bag == "myBag" assert t.revision == 1 assert t.tags == ["foo", "bar"] assert t.creator == "FND" assert t.modifier == "FND" assert len(t.created) == 14 assert len(t.modified) == 14 assert t.created == t.modified assert t.text == "lorem ipsum"
def test_recipe_delete_from_store(): _cleanup() config = { "server_store": ["tiddlywebplugins.devstore", { "store_root": STORE_DIR }], "instance_tiddlers": {}, "root_dir": "" } env = { "tiddlyweb.config": config } store = Store(config["server_store"][0], config["server_store"][1], env) name = "foo" recipe = Recipe(name) recipe.desc = "lorem ipsum" store.put(recipe) recipe = Recipe(name) store.delete(recipe) recipe = Recipe(name) raises(NoRecipeError, "store.get(recipe)")
def test_serialization(): _cleanup() config = { "server_store": ["tiddlywebplugins.devstore", { "store_root": STORE_DIR }], "instance_tiddlers": {}, "root_dir": "" } env = { "tiddlyweb.config": config } store = Store(config["server_store"][0], config["server_store"][1], env) name = "foo" recipe = Recipe(name) recipe.desc = "lorem ipsum" store.put(recipe) f = open("%s.recipe" % os.path.join(STORE_DIR, name)) actual = f.read() f.close() expected = """desc: lorem ipsum policy: {"read": [], "create": [], "manage": [], "accept": [], "write": [], "owner": null, "delete": []} """ assert actual == expected
def test_basic_search_store(): _cleanup() config = { "server_store": ["tiddlywebplugins.devstore", { "store_root": STORE_DIR }], "instance_tiddlers": {}, "root_dir": "" } env = { "tiddlyweb.config": config } store = Store(config["server_store"][0], config["server_store"][1], env) bagone = Bag('bagone') bagtwo = Bag('bagtwo') tiddler1 = Tiddler('tiddler1', 'bagone') tiddler2 = Tiddler('tiddler2', 'bagtwo') tiddler1.text = tiddler2.text = 'ohhai' store.put(bagone) store.put(bagtwo) store.put(tiddler1) store.put(tiddler2) tiddlers = list(store.search('ohhai')) assert len(tiddlers) == 2 assert ['tiddler1', 'tiddler2'] == sorted([tiddler.title for tiddler in tiddlers])
def setup_module(module): # cleanup try: shutil.rmtree("store") except OSError: pass # establish web server app = load_app() def app_fn(): return app httplib2_intercept.install() wsgi_intercept.add_wsgi_intercept("our_test_domain", 8001, app_fn) # establish store store = Store(config["server_store"][0], config["server_store"][1], environ={"tiddlyweb.config": config}) # make some stuff bag = Bag("place") store.put(bag) recipe = Recipe("plaice") recipe.set_recipe([("place", "")]) store.put(recipe) tiddler = Tiddler("one", "place") tiddler.text = "hi" store.put(tiddler) tiddler = Tiddler("two", "place") tiddler.tags = ["tagged"] tiddler.text = "hi" store.put(tiddler) module.store = store # module.http = httplib2.Http('.test_cache') module.http = httplib2.Http()
def test_put_tiddler_to_store(): _cleanup() config = { "server_store": ["tiddlywebplugins.devstore", { "store_root": STORE_DIR }], "instance_tiddlers": { "myBag": ["%s/alpha/index.recipe" % REPO_DIR] }, "root_dir": "" } env = { "tiddlyweb.config": config } store = Store(config["server_store"][0], config["server_store"][1], env) tiddler = Tiddler("lorem") tiddler.bag = "myBag" store.put(tiddler) tiddler_path = os.path.join(STORE_DIR, tiddler.bag, "%s.tid" % tiddler.title) assert os.path.exists(tiddler_path) tiddler = Tiddler("foo bar") tiddler.bag = "myBag" store.put(tiddler) tiddler_path = os.path.join(STORE_DIR, "myBag", "foo%20bar.tid") assert os.path.exists(tiddler_path) assert store.get(tiddler).title == "foo bar" # XXX: testing get operation here for convenience bag = Bag("myBag") try: assert "foo bar" in [t.title for t in store.list_bag_tiddlers(bag)] except AttributeError: # TiddlyWeb 1.0 has no list_bag_tiddlers method pass tiddler = Tiddler("foo/bar") tiddler.bag = "myBag" store.put(tiddler) tiddler_path = os.path.join(STORE_DIR, "myBag", "foo%2Fbar.tid") assert os.path.exists(tiddler_path) assert store.get(tiddler).title == "foo/bar"
class Store(StorageInterface): def __init__(self, store_config=None, environ=None): super(Store, self).__init__(store_config, environ) self.main_store = None self.stores = [] self._init_store() def _init_store(self): server_store = self.environ['tiddlyweb.config']['server_store'] server_store_copy = copy.deepcopy(server_store) extra_store_config = server_store[1]['extras'] main_store_config = server_store[1]['main'] self.environ['tiddlyweb.config']['server_store'] = main_store_config self.main_store = Storer(main_store_config[0], main_store_config[1], self.environ) for rule, store in extra_store_config: pattern = re.compile(rule) self.environ['tiddlyweb.config']['server_store'] = store self.environ['tiddlyweb.config']['main_store'] = self.main_store self.stores.append((pattern, Storer(store[0], store[1], self.environ))) self.environ['tiddlyweb.config']['server_store'] = server_store_copy def recipe_delete(self, recipe): self.main_store.delete(recipe) def recipe_get(self, recipe): return self.main_store.get(recipe) def recipe_put(self, recipe): self.main_store.put(recipe) def bag_delete(self, bag): store = self._determine_store(bag.name) store.delete(bag) def bag_get(self, bag): store = self._determine_store(bag.name) return store.get(bag) def bag_put(self, bag): store = self._determine_store(bag.name) store.put(bag) def tiddler_delete(self, tiddler): store = self._determine_store(tiddler.bag) store.delete(tiddler) def tiddler_get(self, tiddler): store = self._determine_store(tiddler.bag) return store.get(tiddler) def tiddler_put(self, tiddler): store = self._determine_store(tiddler.bag) store.put(tiddler) def user_delete(self, user): self.main_store.delete(user) def user_get(self, user): return self.main_store.get(user) def user_put(self, user): return self.main_store.put(user) def list_recipes(self): return self.main_store.list_recipes() def list_bags(self): bags = [] for rule, store in self.stores: bags.extend(store.list_bags()) bags.extend(self.main_store.list_bags()) return bags def list_bag_tiddlers(self, bag): store = self._determine_store(bag.name) return store.list_bag_tiddlers(bag) def list_users(self): return self.main_store.list_users() def list_tiddler_revisions(self, tiddler): store = self._determine_store(tiddler.bag) return store.list_tiddler_revisions(tiddler) def search(self, search_query): tiddlers = [] searched = False for rule, store in self.stores: try: tiddlers.extend(store.search(search_query)) searched = True except StoreMethodNotImplemented: pass # just ride right over those stores that don't search try: tiddlers.extend(self.main_store.search(search_query)) searched = True except StoreMethodNotImplemented: pass if not searched: raise StoreMethodNotImplemented return tiddlers def _determine_store(self, name): for pattern, store in self.stores: # XXX should this be search or match? if pattern.match(name): return store return self.main_store
class Store(StorageInterface): def __init__(self, store_config=None, environ=None): super(Store, self).__init__(store_config, environ) self.main_store = None self.stores = [] self._init_store() def _init_store(self): server_store = self.environ['tiddlyweb.config']['server_store'] server_store_copy = copy.deepcopy(server_store) extra_store_config = server_store[1]['extras'] main_store_config = server_store[1]['main'] self.environ['tiddlyweb.config']['server_store'] = main_store_config self.main_store = Storer(main_store_config[0], main_store_config[1], self.environ) for rule, store in extra_store_config: pattern = re.compile(rule) self.environ['tiddlyweb.config']['server_store'] = store self.environ['tiddlyweb.config']['main_store'] = self.main_store self.stores.append( (pattern, Storer(store[0], store[1], self.environ))) self.environ['tiddlyweb.config']['server_store'] = server_store_copy def recipe_delete(self, recipe): self.main_store.delete(recipe) def recipe_get(self, recipe): return self.main_store.get(recipe) def recipe_put(self, recipe): self.main_store.put(recipe) def bag_delete(self, bag): store = self._determine_store(bag.name) store.delete(bag) def bag_get(self, bag): store = self._determine_store(bag.name) return store.get(bag) def bag_put(self, bag): store = self._determine_store(bag.name) store.put(bag) def tiddler_delete(self, tiddler): store = self._determine_store(tiddler.bag) store.delete(tiddler) def tiddler_get(self, tiddler): store = self._determine_store(tiddler.bag) return store.get(tiddler) def tiddler_put(self, tiddler): store = self._determine_store(tiddler.bag) store.put(tiddler) def user_delete(self, user): self.main_store.delete(user) def user_get(self, user): return self.main_store.get(user) def user_put(self, user): return self.main_store.put(user) def list_recipes(self): return self.main_store.list_recipes() def list_bags(self): bags = [] for rule, store in self.stores: bags.extend(store.list_bags()) bags.extend(self.main_store.list_bags()) return bags def list_users(self): return self.main_store.list_users() def list_tiddler_revisions(self, tiddler): store = self._determine_store(tiddler.bag) return store.list_tiddler_revisions(tiddler) def search(self, search_query): tiddlers = [] searched = False for rule, store in self.stores: try: tiddlers.extend(store.search(search_query)) searched = True except StoreMethodNotImplemented: pass # just ride right over those stores that don't search try: tiddlers.extend(self.main_store.search(search_query)) searched = True except StoreMethodNotImplemented: pass if not searched: raise StoreMethodNotImplemented return tiddlers def _determine_store(self, name): for pattern, store in self.stores: # XXX should this be search or match? if pattern.match(name): return store return self.main_store
class Store(StorageInterface): _MC = None def __init__(self, store_config=None, environ=None): if store_config is None: store_config = {} if environ is None: environ = {} self.environ = environ self.config = environ.get("tiddlyweb.config") self._mc = self._MC if self._mc == None: try: from google.appengine.api import memcache self._MC = memcache except ImportError: import memcache try: self._MC = memcache.Client(self.config["memcache_hosts"]) except KeyError: from tiddlyweb.config import config self.config = config self._MC = memcache.Client(self.config["memcache_hosts"]) self._mc = self._MC self.cached_store = StoreBoss( self.config["cached_store"][0], self.config["cached_store"][1], environ=environ ) self.prefix = self.config["server_prefix"] self.host = self.config["server_host"]["host"] def recipe_delete(self, recipe): key = self._recipe_key(recipe) self._mc.delete(key) self.cached_store.delete(recipe) def recipe_get(self, recipe): key = self._recipe_key(recipe) cached_recipe = self._get(key) if cached_recipe: recipe = cached_recipe else: recipe = self.cached_store.get(recipe) del recipe.store self._mc.set(key, recipe) return recipe def recipe_put(self, recipe): key = self._recipe_key(recipe) self.cached_store.put(recipe) self._mc.delete(key) def bag_delete(self, bag): key = self._bag_key(bag) if self._mc.delete(key): tiddlers_in_bag = bag.list_tiddlers() for tiddler in tiddlers_in_bag: self._mc.delete_multi( [ self._tiddler_revision_key(self._create_tiddler_revision(tiddler, revision_id)) for revision_id in self.list_tiddler_revisions(tiddler) ] ) self._mc.delete_multi([self._tiddler_key(tiddler) for tiddler in tiddlers_in_bag]) self.cached_store.delete(bag) def bag_get(self, bag): if hasattr(bag, "skinny") and bag.skinny: key = self._bag_key(bag) cached_bag = self._get(key) if cached_bag: bag = cached_bag else: bag = self.cached_store.get(bag) del bag.store self._mc.set(key, bag) else: bag = self.cached_store.get(bag) del bag.store return bag def bag_put(self, bag): key = self._bag_key(bag) self.cached_store.put(bag) self._mc.delete(key) def tiddler_delete(self, tiddler): key = self._tiddler_key(tiddler) if self._mc.delete(key): self._mc.delete(self._bag_key(Bag(tiddler.bag))) self._mc.delete_multi( [ self._tiddler_revision_key(self._create_tiddler_revision(tiddler, revision_id)) for revision_id in self.list_tiddler_revisions(tiddler) ] ) self.cached_store.delete(tiddler) def tiddler_get(self, tiddler): if not tiddler.revision or tiddler.revision == 0: key = self._tiddler_key(tiddler) else: key = self._tiddler_revision_key(tiddler) cached_tiddler = self._get(key) if cached_tiddler: cached_tiddler.recipe = tiddler.recipe tiddler = cached_tiddler else: tiddler = self.cached_store.get(tiddler) del tiddler.store self._mc.set(key, tiddler) return tiddler def tiddler_put(self, tiddler): key = self._tiddler_key(tiddler) self.cached_store.put(tiddler) self._mc.delete(self._bag_key(Bag(tiddler.bag))) self._mc.delete(key) def user_delete(self, user): key = self._user_key(user) self._mc.delete(key) self.cached_store.delete(user) def user_get(self, user): key = self._user_key(user) cached_user = self._get(key) if cached_user: user = cached_user else: user = self.cached_store.get(user) del user.store self._mc.set(key, user) return user def user_put(self, user): key = self._user_key(user) self.cached_store.put(user) self._mc.delete(key) def list_recipes(self): return self.cached_store.list_recipes() def list_bags(self): return self.cached_store.list_bags() def list_users(self): return self.cached_store.list_users() def list_tiddler_revisions(self, tiddler): return self.cached_store.list_tiddler_revisions(tiddler) def search(self, search_query): return self.cached_store.search(search_query) def _create_tiddler_revision(self, tiddler, revision_id): revision = Tiddler(tiddler.title, tiddler.bag) revision.revision = revision_id return revision def _tiddler_key(self, tiddler): key = "tiddler:%s/%s" % (tiddler.bag, tiddler.title) return self._mangle(key) def _tiddler_revision_key(self, tiddler): key = "tiddler:%s/%s/%s" % (tiddler.bag, tiddler.title, tiddler.revision) return self._mangle(key) def _user_key(self, user): key = "user:%s" % user.usersign return self._mangle(key) def _bag_key(self, bag): key = "bag:%s" % bag.name return self._mangle(key) def _recipe_key(self, recipe): key = "recipe:%s" % recipe.name return self._mangle(key) def _mangle(self, key): key = "%s:%s:%s" % (self.host, self.prefix, key) return quote(key.encode("UTF-8"), safe="") def _get(self, key): object = self._mc.get(key) if object: logging.debug("cache hit for %s" % key) else: logging.debug("cache miss for %s" % key) return object
class Store(StorageInterface): def __init__(self, environ=None): logging.debug("initializing SSL Store") super(Store, self).__init__(environ) config = self.environ["tiddlyweb.config"] self.ssl_bags = config["ssl_bags"] # intentionally not providing empty fallback -- XXX: rename? real_store = config["server_store"][1]["store_module"] # XXX: rename? -- TODO: use pop method to keep config clean? self.real_store = Storage(real_store, self.environ) def recipe_delete(self, recipe): logging.debug("delete recipe %s" % recipe) self.real_store.delete(recipe) def recipe_get(self, recipe): logging.debug("get recipe %s" % recipe) return self.real_store.get(recipe) def recipe_put(self, recipe): logging.debug("put recipe %s" % recipe) self.real_store.put(recipe) def bag_delete(self, bag): logging.debug("delete bag %s" % bag) self._check_security(bag.name) self.real_store.delete(bag) def bag_get(self, bag): logging.debug("get bag %s" % bag) self._check_security(bag.name) return self.real_store.get(bag) def bag_put(self, bag): logging.debug("put bag %s" % bag) self._check_security(bag.name) self.real_store.put(bag) def tiddler_delete(self, tiddler): logging.debug("delete tiddler %s" % tiddler) self.real_store.delete(tiddler) def tiddler_get(self, tiddler): logging.debug("get tiddler %s" % tiddler) return self.real_store.get(tiddler) def tiddler_put(self, tiddler): logging.debug("put tiddler %s" % tiddler) self.real_store.put(tiddler) def user_delete(self, user): logging.debug("delete user %s" % user) self.real_store.delete(user) def user_get(self, user): logging.debug("get user %s" % user) return self.real_store.get(user) def user_put(self, user): logging.debug("put user %s" % user) self.real_store.put(user) def list_recipes(self): logging.debug("list recipes") return self.real_store.list_recipes() def list_bags(self): logging.debug("list bags") return self.real_store.list_bags() def list_users(self): logging.debug("list users") return self.real_store.list_users() def list_tiddler_revisions(self, tiddler): logging.debug("list revisions %s" % tiddler) return self.real_store.list_tiddler_revisions(tiddler) def search(self, search_query): logging.debug("search %s" % search_query) return self.real_store.search(search_query) def _check_security(self, bag_name): # TODO: rename? -- TODO: should be decorator!? protocol = self.environ.get("wsgi.url_scheme") if protocol != "https" and bag_name in self.ssl_bags: raise SecureConnectionError("secure connection required")
class Store(StorageInterface): def __init__(self, environ=None): if environ is None: environ = {} self.environ = environ internal_store_environ = { 'tiddlyweb.config': { 'server_store': config['cached_store'], } } self.cached_store = StoreBoss('text', environ=internal_store_environ) def recipe_delete(self, recipe): key = _recipe_key(recipe) MC.delete(key) self.cached_store.delete(recipe) def recipe_get(self, recipe): key = _recipe_key(recipe) cached_recipe = _get(key) if cached_recipe: recipe = cached_recipe else: recipe = self.cached_store.get(recipe) MC.set(key, recipe) return recipe def recipe_put(self, recipe): key = _recipe_key(recipe) self.cached_store.put(recipe) MC.delete(key) def bag_delete(self, bag): key = _bag_key(bag) if MC.delete(key): MC.delete_multi([_tiddler_key(tiddler) for tiddler in bag.list_tiddlers()]) self.cached_store.delete(bag) def bag_get(self, bag): key = _bag_key(bag) cached_bag = _get(key) if cached_bag: bag = cached_bag else: bag = self.cached_store.get(bag) MC.set(key, bag) return bag def bag_put(self, bag): key = _bag_key(bag) self.cached_store.put(bag) MC.delete(key) def tiddler_delete(self, tiddler): key = _tiddler_key(tiddler) if MC.delete(key): MC.delete(_bag_key(Bag(tiddler.bag))) self.cached_store.delete(tiddler) def tiddler_get(self, tiddler): key = _tiddler_key(tiddler) if not tiddler.revision or tiddler.revision == 0: cached_tiddler = _get(key) if cached_tiddler: tiddler = cached_tiddler else: tiddler = self.cached_store.get(tiddler) MC.set(key, tiddler) else: tiddler = self.cached_store.get(tiddler) return tiddler def tiddler_put(self, tiddler): key = _tiddler_key(tiddler) self.cached_store.put(tiddler) MC.delete(_bag_key(Bag(tiddler.bag))) MC.delete(key) def user_delete(self, user): key = _user_key(user) MC.delete(key) self.cached_store.delete(user) def user_get(self, user): key = _user_key(user) cached_user = _get(key) if cached_user: user = cached_user else: user = self.cached_store.get(user) MC.set(key, user) return user def user_put(self, user): key = _user_key(user) self.cached_store.put(user) MC.delete(key) def list_recipes(self): return self.cached_store.list_recipes() def list_bags(self): return self.cached_store.list_bags() def list_users(self): return self.cached_store.list_users() def list_tiddler_revisions(self, tiddler): return self.cached_store.list_tiddler_revisions(tiddler) def search(self, search_query): return self.cached_store.search(search_query)
def _make_bag(bag_name): """Make a bag with name bag_name to the store.""" bag = Bag(bag_name) store = Store(config['server_store'][0], environ={'tiddlyweb.config': config}) store.put(bag)
class Store(StorageInterface): _MC = None def __init__(self, store_config=None, environ=None): if store_config is None: store_config = {} if environ is None: environ = {} self.environ = environ self.config = environ.get('tiddlyweb.config') self._mc = self._MC if self._mc == None: try: from google.appengine.api import memcache self._MC = memcache except ImportError: import memcache try: self._MC = memcache.Client(self.config['memcache_hosts']) except KeyError: from tiddlyweb.config import config self.config = config self._MC = memcache.Client(self.config['memcache_hosts']) self._mc = self._MC self.cached_store = StoreBoss(self.config['cached_store'][0], self.config['cached_store'][1], environ=environ) self.prefix = self.config['server_prefix'] self.host = self.config['server_host']['host'] def recipe_delete(self, recipe): key = self._recipe_key(recipe) self._mc.delete(key) self.cached_store.delete(recipe) def recipe_get(self, recipe): key = self._recipe_key(recipe) cached_recipe = self._get(key) if cached_recipe: recipe = cached_recipe else: recipe = self.cached_store.get(recipe) del recipe.store self._mc.set(key, recipe) return recipe def recipe_put(self, recipe): key = self._recipe_key(recipe) self.cached_store.put(recipe) self._mc.delete(key) def bag_delete(self, bag): key = self._bag_key(bag) if self._mc.delete(key): tiddlers_in_bag = bag.list_tiddlers() for tiddler in tiddlers_in_bag: self._mc.delete_multi([ self._tiddler_revision_key( self._create_tiddler_revision(tiddler, revision_id)) for revision_id in self.list_tiddler_revisions(tiddler) ]) self._mc.delete_multi( [self._tiddler_key(tiddler) for tiddler in tiddlers_in_bag]) self.cached_store.delete(bag) def bag_get(self, bag): if (hasattr(bag, 'skinny') and bag.skinny): key = self._bag_key(bag) cached_bag = self._get(key) if cached_bag: bag = cached_bag else: bag = self.cached_store.get(bag) del bag.store self._mc.set(key, bag) else: bag = self.cached_store.get(bag) del bag.store return bag def bag_put(self, bag): key = self._bag_key(bag) self.cached_store.put(bag) self._mc.delete(key) def tiddler_delete(self, tiddler): key = self._tiddler_key(tiddler) if self._mc.delete(key): self._mc.delete(self._bag_key(Bag(tiddler.bag))) self._mc.delete_multi([ self._tiddler_revision_key( self._create_tiddler_revision(tiddler, revision_id)) for revision_id in self.list_tiddler_revisions(tiddler) ]) self.cached_store.delete(tiddler) def tiddler_get(self, tiddler): if not tiddler.revision or tiddler.revision == 0: key = self._tiddler_key(tiddler) else: key = self._tiddler_revision_key(tiddler) cached_tiddler = self._get(key) if cached_tiddler: cached_tiddler.recipe = tiddler.recipe tiddler = cached_tiddler else: tiddler = self.cached_store.get(tiddler) del tiddler.store self._mc.set(key, tiddler) return tiddler def tiddler_put(self, tiddler): key = self._tiddler_key(tiddler) self.cached_store.put(tiddler) self._mc.delete(self._bag_key(Bag(tiddler.bag))) self._mc.delete(key) def user_delete(self, user): key = self._user_key(user) self._mc.delete(key) self.cached_store.delete(user) def user_get(self, user): key = self._user_key(user) cached_user = self._get(key) if cached_user: user = cached_user else: user = self.cached_store.get(user) del user.store self._mc.set(key, user) return user def user_put(self, user): key = self._user_key(user) self.cached_store.put(user) self._mc.delete(key) def list_recipes(self): return self.cached_store.list_recipes() def list_bags(self): return self.cached_store.list_bags() def list_users(self): return self.cached_store.list_users() def list_tiddler_revisions(self, tiddler): return self.cached_store.list_tiddler_revisions(tiddler) def search(self, search_query): return self.cached_store.search(search_query) def _create_tiddler_revision(self, tiddler, revision_id): revision = Tiddler(tiddler.title, tiddler.bag) revision.revision = revision_id return revision def _tiddler_key(self, tiddler): key = 'tiddler:%s/%s' % (tiddler.bag, tiddler.title) return self._mangle(key) def _tiddler_revision_key(self, tiddler): key = 'tiddler:%s/%s/%s' % (tiddler.bag, tiddler.title, tiddler.revision) return self._mangle(key) def _user_key(self, user): key = 'user:%s' % user.usersign return self._mangle(key) def _bag_key(self, bag): key = 'bag:%s' % bag.name return self._mangle(key) def _recipe_key(self, recipe): key = 'recipe:%s' % recipe.name return self._mangle(key) def _mangle(self, key): key = '%s:%s:%s' % (self.host, self.prefix, key) return quote(key.encode('UTF-8'), safe='') def _get(self, key): object = self._mc.get(key) if object: logging.debug('cache hit for %s' % key) else: logging.debug('cache miss for %s' % key) return object