from dataclasses import dataclass from typing import List from cache.Cache import Cache from core.builtin_concepts import BuiltinConcepts from core.global_symbols import NotFound from core.sheerka.services.sheerka_service import ServiceObj, BaseService @dataclass class Variable(ServiceObj): """ Variable to store """ who: str # who is the modifier key: str # key of the variable value: object # value parents: List[str] # previous references of the variable (Note that there should be only one parent) def get_key(self): return f"{self.who}|{self.key}" def __str__(self): return f"({self.who}){self.key}={self.value}" @dataclass class InternalObj: obj: object def __deepcopy__(self, memodict={}): return self def __copy__(self): return self class SheerkaVariableManager(BaseService): NAME = "VariableManager" VARIABLES_ENTRY = "VariableManager:Variables" # entry for variables which will be copied in sdp INTERNAL_VARIABLES_ENTRY = "VariableManager:InternalVariables" # internal to current process (can store lambda) def __init__(self, sheerka): super().__init__(sheerka) self.bound_variables = { self.sheerka.name: {"enable_process_return_values", "save_execution_context"} } def initialize(self): self.sheerka.bind_service_method(self.record_var, True, visible=False) self.sheerka.bind_service_method(self.load_var, False, visible=False) self.sheerka.bind_service_method(self.record_internal_var, True, visible=False) self.sheerka.bind_service_method(self.load_internal_var, False, visible=False) self.sheerka.bind_service_method(self.delete_var, True, visible=False) self.sheerka.bind_service_method(self.set_var, True) self.sheerka.bind_service_method(self.get_var, False) self.sheerka.bind_service_method(self.list_vars, False) cache = Cache().auto_configure(self.VARIABLES_ENTRY) self.sheerka.om.register_cache(self.VARIABLES_ENTRY, cache, True, True) cache.populate(lambda sdp: sdp.list(self.VARIABLES_ENTRY), lambda var: var.get_key()) internal_vars = Cache().auto_configure(self.INTERNAL_VARIABLES_ENTRY) self.sheerka.om.register_cache(self.INTERNAL_VARIABLES_ENTRY, internal_vars, False, False) def initialize_deferred(self, context, first_time): # update bound variables for who, keys in self.bound_variables.items(): for key in keys: if (variable := self.sheerka.om.get(self.VARIABLES_ENTRY, f"{who}|{key}")) is not NotFound: service = self.sheerka if who == self.sheerka.name else self.sheerka.services[who] setattr(service, key, variable.value) def record_var(self, context, who, key, value): """ :param context: :param who: entity that owns the key (acts as a namespace) :param key: :param value: :return: """ variable = Variable(context.event.get_digest(), who, key, value, None) self.sheerka.om.put(self.VARIABLES_ENTRY, variable.get_key(), variable) # TODO: manage credentials if who in self.bound_variables and key in self.bound_variables[who]: service = self.sheerka if who == self.sheerka.name else self.sheerka.services[who] setattr(service, key, value) def load_var(self, who, key): variable = self.sheerka.om.get(self.VARIABLES_ENTRY, who + "|" + key) if variable is NotFound: return NotFound return variable.value def record_internal_var(self, context, who, key, value): """ Stores the value in the internal cache This cache is not pushed to the remote repository :param context: :param who: entity that owns the key (acts as a namespace) :param key: :param value: """ self.sheerka.om.put(self.INTERNAL_VARIABLES_ENTRY, f"{who}|{key}", InternalObj(value)) def load_internal_var(self, who, key): value = self.sheerka.om.get(self.INTERNAL_VARIABLES_ENTRY, f"{who}|{key}") return NotFound if value is NotFound else value.obj def delete_var(self, context, who, key): self.sheerka.om.delete(self.VARIABLES_ENTRY, who + "|" + key) def set_var(self, context, key, value): self.record_var(context, context.event.user_id, key, value) return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS)) def get_var(self, context, key): return self.load_var(context.event.user_id, key) def list_vars(self, context, all_vars=False): if all_vars: res = [str(v) for v in self.sheerka.om.copy(self.VARIABLES_ENTRY).values()] else: res = [str(v) for v in self.sheerka.om.copy(self.VARIABLES_ENTRY).values() if v.who == context.event.user_id] return res