# -*- coding: utf-8 -*- """ TokyoTyrantをモデルっぽく使う class Soldier(TokyoTyrantStorage): hp = TokyoTyrantStorage.Field(default=0) mp = TokyoTyrantStorage.Field(default=0) cain = Soldier('Cain') cain.hp = 100 cain.mp = 50 cain.save() abel = Soldier('Abel') abel.hp = 50 abel.mp = 100 abel.save() cain = Soldier('Cain') cain.hp -= 80 cain.save() abel = Soldier('Abel') abel.mp -= 20 abel.save() cain = Soldier('Cain') cain.hp = min(cain.hp + 50, 100) cain.save() cain = Soldier('Cain') cain.hp Out: 70 """ import logging from tokyotyrant import get_client import msgpack class TokyoTyrantStorage(object): """ TokyoTyrantをディクショナリとして使う基底クラス 継承して使ってください """ packer = msgpack.Packer() tt_client = get_client() def __new__(cls, *args, **kwargs): for k, v in vars(cls).iteritems(): if isinstance(v, TokyoTyrantStorage.Field): v.set_field_name(k) return object.__new__(cls) def __init__(self, key_object): """ @param key_object djangoのモデルインスタンスなど。player や osuser オーバーライドして、superの__init__を呼びたくないときは そのまま self.after_init(key_part) する """ self.key_object = key_object key_part = getattr(key_object, 'pk', str(key_object)) self.after_init(key_part) def after_init(self, key_part): """ 初期化処理の後半 @param (str)key_part キー生成の元となるユニークな文字列 """ self.kvs_key = '%s::%s' % (self.__class__.__name__, key_part) bulk_storage = self.tt_client.get(self.kvs_key, None) if bulk_storage: self.storage = msgpack.unpackb(bulk_storage) else: self.storage = {} def get(self, k, default=None): return self.storage.get(k,default) def set(self, k, value): self.storage[k] = value def save(self): """ storageを保存 """ self.tt_client.set(self.kvs_key, self.packer.pack(self.storage)) def delete(self): """ storageを削除 """ self.tt_client.out(self.kvs_key) self.storage = {} def dump(self): logging.debug("[TokyoTyrantStorage] dump: kvs_key=%s, storage=%r" % (self.kvs_key, self.storage)) class Field(object): """ TokyoTyrantStorage に使えるフィールド score = TokyoTyrantStorage.Field(default=0) みたいに使う。 """ def __init__(self, key_name=None, default=None): self._key_name = key_name self.default = default def __get__(self, inst, type=None): assert isinstance(inst, TokyoTyrantStorage), '%s use only TokyoTyrantStorage class.' % self.__class__.__name__ return inst.get(self.key_name, self.default) def __set__(self, inst, value): assert isinstance(inst, TokyoTyrantStorage), '%s use only TokyoTyrantStorage class.' % self.__class__.__name__ inst.set(self.key_name, value) def set_field_name(self, field_name): #TokyoTyrantStorage.__new__ から呼ばれる self.field_name = field_name @property def key_name(self): return self._key_name or self.field_name
コメント