From 6dec2146ceec410c6a5da6938e592a11b3830470 Mon Sep 17 00:00:00 2001 From: teo Date: Wed, 7 Feb 2024 18:13:41 +0200 Subject: [PATCH] added initial event service implementation --- packages/syft/src/syft/service/event/event.py | 67 +++++++++++++++++++ .../src/syft/service/event/event_service.py | 65 ++++++++++++++++++ .../src/syft/service/event/event_stash.py | 30 +++++++++ 3 files changed, 162 insertions(+) create mode 100644 packages/syft/src/syft/service/event/event.py create mode 100644 packages/syft/src/syft/service/event/event_service.py create mode 100644 packages/syft/src/syft/service/event/event_stash.py diff --git a/packages/syft/src/syft/service/event/event.py b/packages/syft/src/syft/service/event/event.py new file mode 100644 index 00000000000..8a7bd8df494 --- /dev/null +++ b/packages/syft/src/syft/service/event/event.py @@ -0,0 +1,67 @@ +from typing import Any, ClassVar, Dict, List, Type + +from syft.service.dataset.dataset import Asset, Dataset +from syft.store.linked_obj import LinkedObject +from ...types.syft_object import SyftObject +from ...types.uid import UID +from datetime import datetime +from pydantic import Field + +event_handler_registry = {} + +def register_event_handler(event_type): + def inner(method): + event_handler_registry[event_type.__name__] = method.__name__ + return method + + return inner + +class Event(SyftObject): + creator_user: UID + creation_date: datetime = Field(default_factory=lambda: datetime.now()) + + def handler(self, node): + method_name = event_handler_registry[self.__class__.__name__] + return getattr(node, method_name) + +class CRUDEvent(Event): + object_type: ClassVar[Type] = Type + object_id: UID + + @property + def merge_updates_repr(self): + return f"{self.updates} for object {self.object_id} by {self.creator}" + +class CreateObjectEvent(CRUDEvent): + @property + def updated_properties(self): + return list(self.object_type.__annotations__.keys()) + + @property + def updates(self): + return {p: getattr(self, p) for p in self.updated_properties} + + @property + def update_tuples(self): + return list(self.updates.items()) + + +class UpdateObjectEvent(CRUDEvent): + updates: Dict[str, Any] + + @property + def updated_properties(self): + return list(self.updates.keys()) + + @property + def update_tuples(self): + return list(self.updates.items()) + +class CreateDatasetEvent(CRUDEvent): + object_type: ClassVar[Type] = Dataset + + def execute(self, node): + handler = self.handler(node) + handler( + object_id=self.real.obj_id, + ) \ No newline at end of file diff --git a/packages/syft/src/syft/service/event/event_service.py b/packages/syft/src/syft/service/event/event_service.py new file mode 100644 index 00000000000..6819d389253 --- /dev/null +++ b/packages/syft/src/syft/service/event/event_service.py @@ -0,0 +1,65 @@ +from syft.serde.serializable import serializable +from syft.service.context import AuthedServiceContext +from syft.service.event.event_stash import EventStash +from syft.service.response import SyftError, SyftSuccess +from syft.service.service import AbstractService, service_method +from syft.service.user.user_roles import DATA_OWNER_ROLE_LEVEL +from syft.store.document_store import DocumentStore +from syft.types.uid import UID +from syft.util.trace_decorator import instrument +from .event import Event + +@instrument +@serializable() +class EventService(AbstractService): + store: DocumentStore + stash: EventStash + + def __init__(self, store: DocumentStore) -> None: + self.store = store + self.stash = EventStash(store=store) + + @service_method( + path="event.add", + name="add", + roles=DATA_OWNER_ROLE_LEVEL, + ) + def add( + self, context: AuthedServiceContext, event: Event, + ): + result = self.stash.set(context.credentials, event) + if result.is_err(): + return SyftError(message=str(result.err())) + + return SyftSuccess(message=f'Great Success!') + + + @service_method( + path="event.get_by_uid", + name="get_by_uid", + roles=DATA_OWNER_ROLE_LEVEL, + ) + def get_by_uid( + self, context: AuthedServiceContext, uid: UID, + ): + result = self.stash.get_by_uid(context.credentials, uid=uid) + if result.is_err(): + return SyftError(message=str(result.err())) + return result.ok() + + + @service_method( + path="event.get_all", + name="get_all", + roles=DATA_OWNER_ROLE_LEVEL, + ) + def get_all( + self, context: AuthedServiceContext + ): + result = self.stash.get_all(context.credentials) + if result.is_err(): + return SyftError(message=str(result.err())) + + return result.ok() + + \ No newline at end of file diff --git a/packages/syft/src/syft/service/event/event_stash.py b/packages/syft/src/syft/service/event/event_stash.py new file mode 100644 index 00000000000..25478c504b1 --- /dev/null +++ b/packages/syft/src/syft/service/event/event_stash.py @@ -0,0 +1,30 @@ +# stdlib +from typing import List +from typing import Optional + +# third party +from result import Result + +# relative +from ...node.credentials import SyftVerifyKey +from ...serde.serializable import serializable +from ...store.document_store import BaseUIDStoreStash +from ...store.document_store import DocumentStore +from ...store.document_store import PartitionKey +from ...store.document_store import PartitionSettings +from ...store.document_store import QueryKeys +from ...types.uid import UID +from ...util.telemetry import instrument +from .event import Event + + +@instrument +@serializable() +class EventStash(BaseUIDStoreStash): + object_type = Event + settings: PartitionSettings = PartitionSettings( + name=Event.__canonical_name__, object_type=Event + ) + + def __init__(self, store: DocumentStore) -> None: + super().__init__(store=store) \ No newline at end of file