def __init__(self, observableName, proxyToVortexName: str,
                 additionalFilt=None, subscriptionsEnabled=True,
                 observerName="default") -> None:
        """ Constructor

        :param observableName: The name of this and the other observable
        :param proxyToVortexName: The vortex dest name to proxy requests to
        :param additionalFilt: Any additional filter keys that are required
        :param subscriptionsEnabled: Should subscriptions be enabled (default)
        :param observerName: We can clash with other observers, so where there are
        multiple observers on the one vortex, they should use different names.
        """
        TupleDataObservableCache.__init__(self)

        self._proxyToVortexName = proxyToVortexName
        self._subscriptionsEnabled = subscriptionsEnabled
        self._observerName = observerName
        self._filt = dict(name=observableName,
                          key="tupleDataObservable")
        if additionalFilt:
            self._filt.update(additionalFilt)

        # Create the local observable, this allows local tuple providers
        # The rest are proxied on to the backend
        self._localObservableHandler = TupleDataObservableHandler(
            observableName,
            additionalFilt=additionalFilt,
            subscriptionsEnabled=subscriptionsEnabled)
        # Shutdown the local observables endpoint, we don't want it listening it's self
        self._localObservableHandler.shutdown()

        # Finally, Setup our endpoint
        self._endpoint = PayloadEndpoint(self._filt, self._process)

        TupleDataObservableCache.start(self)
예제 #2
0
def makeTupleDataObservableHandler(dbSessionCreator: DbSessionCreator,
                                   statusController: StatusController):
    """" Make Tuple Data Observable Handler

    This method creates the observable object, registers the tuple providers and then
    returns it.

    :param statusController: The search status controller.
    :param dbSessionCreator: A function that returns a SQLAlchemy session when called

    :return: An instance of :code:`TupleDataObservableHandler`

    """
    tupleObservable = TupleDataObservableHandler(
        observableName=searchObservableName, additionalFilt=searchFilt)

    # Search Property
    tupleObservable.addTupleProvider(
        SearchPropertyTuple.tupleName(),
        SearchPropertyTupleProvider(dbSessionCreator))

    # Search Object Type
    tupleObservable.addTupleProvider(
        SearchObjectTypeTuple.tupleName(),
        SearchObjectTypeTupleProvider(dbSessionCreator))

    # Admin status tuple
    tupleObservable.addTupleProvider(
        AdminStatusTuple.tupleName(),
        AdminStatusTupleProvider(statusController))

    return tupleObservable
def makeTupleDataObservableHandler(ormSessionCreator):
    """" Make Tuple Data Observable Handler

    This method creates the observable object, registers the tuple providers and then
    returns it.

    :param ormSessionCreator: A function that returns a SQLAlchemy session when called

    :return: An instance of :code:`TupleDataObservableHandler`

    """
    tupleObservable = TupleDataObservableHandler(
        observableName=branchObservableName, additionalFilt=branchFilt)

    # Register TupleProviders here
    tupleObservable.addTupleProvider(
        BranchDetailTuple.tupleName(),
        BranchDetailTupleProvider(ormSessionCreator))
    return tupleObservable
예제 #4
0
def makeAdminTupleDataObservableHandler(dbSessionCreator, deviceApi: DeviceApiABC, ourApi):
    observable = TupleDataObservableHandler(observableName=userPluginObservableName,
                                            additionalFilt=userPluginFilt,
                                            acceptOnlyFromVortex=peekAdminName)

    observable.addTupleProvider(
        LoggedInUserStatusTuple.tupleName(),
        LoggedInUserStatusTupleProvider(dbSessionCreator, deviceApi)
    )

    observable.addTupleProvider(GroupDetailTuple.tupleName(),
                                GroupDetailTupleProvider(ourApi))

    observable.addTupleProvider(UserListItemTuple.tupleName(),
                                UserListItemTupleProvider(dbSessionCreator, ourApi))

    observable.addTupleProvider(UserLoggedInTuple.tupleType(),
                                UserLoggedInTupleProvider(dbSessionCreator, ourApi))

    return observable
def makeTupleDataObservableHandler(ormSessionCreator):
    """" Make Tuple Data Observable Handler

    This method creates the observable object, registers the tuple providers and then
    returns it.

    :param ormSessionCreator: A function that returns a SQLAlchemy session when called

    :return: An instance of :code:`TupleDataObservableHandler`

    """
    tupleObservable = TupleDataObservableHandler(
        observableName=diagramTraceObservableName,
        additionalFilt=diagramTraceFilt)

    tupleObservable.addTupleProvider(
        SettingProperty.tupleName(),
        SettingPropertyTupleProvider(ormSessionCreator))

    return tupleObservable
예제 #6
0
def makeTupleDataObservableHandler(ormSessionCreator,
                                   adminStatusController: AdminStatusController):
    """" Make Tuple Data Observable Handler

    This method creates the observable object, registers the tuple providers and then
    returns it.

    :param adminStatusController:
    :param ormSessionCreator: A function that returns a SQLAlchemy session when called

    :return: An instance of :code:`TupleDataObservableHandler`

    """
    tupleObservable = TupleDataObservableHandler(
        observableName=livedbObservableName,
        additionalFilt=livedbFilt)

    # # Register TupleProviders here
    tupleObservable.addTupleProvider(AdminStatusTuple.tupleName(),
                                     AdminStatusTupleProvider(adminStatusController))
    return tupleObservable
def makeTupleDataObservableHandler(dbSessionCreator, ourApi):
    observable = TupleDataObservableHandler(
        observableName=userPluginObservableName,
        additionalFilt=userPluginFilt,
        acceptOnlyFromVortex=peekClientName)

    observable.addTupleProvider(GroupDetailTuple.tupleName(),
                                GroupDetailTupleProvider(ourApi))

    observable.addTupleProvider(
        UserListItemTuple.tupleName(),
        UserListItemTupleProvider(dbSessionCreator, ourApi))

    observable.addTupleProvider(
        UserLoggedInTuple.tupleType(),
        UserLoggedInTupleProvider(dbSessionCreator, ourApi))

    observable.addTupleProvider(
        UserLoginUiSettingTuple.tupleType(),
        UserLoginUiSettingTupleProvider(dbSessionCreator))

    return observable
def makeTupleDataObservableHandler(ormSessionCreator):
    observable = TupleDataObservableHandler(observableName=inboxObservableName,
                                            additionalFilt=inboxFilt)

    observable.addTupleProvider(Task.tupleName(),
                                TaskTupleProvider(ormSessionCreator))

    observable.addTupleProvider(Activity.tupleName(),
                                ActivityTupleProvider(ormSessionCreator))
    return observable
class TupleDataObservableProxyHandler(TupleDataObservableCache):
    __CHECK_PERIOD = 30  # seconds

    def __init__(self, observableName, proxyToVortexName: str,
                 additionalFilt=None, subscriptionsEnabled=True,
                 observerName="default") -> None:
        """ Constructor

        :param observableName: The name of this and the other observable
        :param proxyToVortexName: The vortex dest name to proxy requests to
        :param additionalFilt: Any additional filter keys that are required
        :param subscriptionsEnabled: Should subscriptions be enabled (default)
        :param observerName: We can clash with other observers, so where there are
        multiple observers on the one vortex, they should use different names.
        """
        TupleDataObservableCache.__init__(self)

        self._proxyToVortexName = proxyToVortexName
        self._subscriptionsEnabled = subscriptionsEnabled
        self._observerName = observerName
        self._filt = dict(name=observableName,
                          key="tupleDataObservable")
        if additionalFilt:
            self._filt.update(additionalFilt)

        # Create the local observable, this allows local tuple providers
        # The rest are proxied on to the backend
        self._localObservableHandler = TupleDataObservableHandler(
            observableName,
            additionalFilt=additionalFilt,
            subscriptionsEnabled=subscriptionsEnabled)
        # Shutdown the local observables endpoint, we don't want it listening it's self
        self._localObservableHandler.shutdown()

        # Finally, Setup our endpoint
        self._endpoint = PayloadEndpoint(self._filt, self._process)

        TupleDataObservableCache.start(self)

    def shutdown(self):
        self._endpoint.shutdown()
        TupleDataObservableCache.shutdown(self)

    ## ----- Implement local observable

    def addTupleProvider(self, tupleName, provider: TuplesProviderABC):
        """ Add Tuple Provider

        Adds a tuple provider to the local observable.

        All other requests are proxied on

        """
        self._localObservableHandler.addTupleProvider(tupleName, provider=provider)

    def notifyOfTupleUpdate(self, tupleSelector: TupleSelector) -> None:
        """ Notify of Tuple Update

        Notifies the local observable that tuples have been updated

        """
        if not self._localObservableHandler.hasTupleProvider(tupleSelector.name):
            raise Exception("Local observable doesn't have tuple provider for %s"
                            " registered, Proxy is : %s" % (
                                tupleSelector.name, self._filt
                            ))

        self._localObservableHandler.notifyOfTupleUpdate(tupleSelector)

    ## ----- Implement proxy from here on in

    @inlineCallbacks
    def _process(self, payloadEnvelope: PayloadEnvelope, vortexUuid: str, vortexName: str,
                 sendResponse: SendVortexMsgResponseCallable, **kwargs):
        if vortexName == self._proxyToVortexName:
            yield self._processUpdateFromBackend(payloadEnvelope)

        else:
            yield self._processSubscribeFromFrontend(payloadEnvelope, vortexUuid,
                                                     sendResponse)

    def _processSubscribeFromFrontend(self, payloadEnvelope: PayloadEnvelope,
                                      vortexUuid: str,
                                      sendResponse: SendVortexMsgResponseCallable):
        tupleSelector: TupleSelector = payloadEnvelope.filt["tupleSelector"]

        # If the local observable provides this tuple, then use that instead
        if self._localObservableHandler.hasTupleProvider(tupleSelector.name):
            return self._localObservableHandler._process(payloadEnvelope=payloadEnvelope,
                                                         vortexUuid=vortexUuid,
                                                         sendResponse=sendResponse)

        # Add support for just getting data, no subscription.
        if payloadEnvelope.filt.get("unsubscribe", True):
            return self._handleUnsubscribe(tupleSelector, vortexUuid)

        elif payloadEnvelope.filt.get("subscribe", True) and self._subscriptionsEnabled:
            return self._handleSubscribe(payloadEnvelope, tupleSelector, sendResponse,
                                         vortexUuid)

        else:
            return self._handlePoll(payloadEnvelope, tupleSelector, sendResponse)

    def _handleUnsubscribe(self, tupleSelector: TupleSelector, vortexUuid: str):

        if not self._hasTupleSelector(tupleSelector):
            return

        cache = self._getCache(tupleSelector)
        try:
            cache.vortexUuids.remove(vortexUuid)
        except KeyError:
            pass

    def _handleSubscribe(self, payloadEnvelope: PayloadEnvelope,
                         tupleSelector: TupleSelector,
                         sendResponse: SendVortexMsgResponseCallable,
                         vortexUuid: str):

        # Add support for just getting data, no subscription.
        cache = self._getCache(tupleSelector)
        if cache and cache.lastServerPayloadDate is not None and cache.cacheEnabled:
            respPayloadEnvelope = PayloadEnvelope(filt=payloadEnvelope.filt,
                                                  encodedPayload=cache.encodedPayload,
                                                  date=cache.lastServerPayloadDate)

            d = respPayloadEnvelope.toVortexMsgDefer()
            d.addCallback(sendResponse)
            d.addErrback(vortexLogFailure, logger, consumeError=True)

        elif cache:
            self._sendRequestToServer(payloadEnvelope)

        else:
            cache = self._makeCache(tupleSelector)
            self._sendRequestToServer(payloadEnvelope)

        cache.vortexUuids.add(vortexUuid)
        # Allow the cache to be disabled
        cache.cacheEnabled = (
                cache.cacheEnabled
                and not payloadEnvelope.filt.get("disableCache", False)
        )

    def _sendRequestToServer(self, payloadEnvelope: PayloadEnvelope):
        payloadEnvelope.filt["observerName"] = self._observerName
        d = VortexFactory.sendVortexMsg(vortexMsgs=payloadEnvelope.toVortexMsg(),
                                        destVortexName=self._proxyToVortexName)
        d.addErrback(vortexLogFailure, logger, consumeError=True)

    def _sendUnsubscribeToServer(self, tupleSelector: TupleSelector):
        payloadEnvelope = PayloadEnvelope()
        payloadEnvelope.filt["tupleSelector"] = tupleSelector
        payloadEnvelope.filt["unsubscribe"] = True
        self._sendRequestToServer(payloadEnvelope)

    def _handlePoll(self, payloadEnvelope: PayloadEnvelope,
                    tupleSelector: TupleSelector,
                    sendResponse: SendVortexMsgResponseCallable):

        useCache = payloadEnvelope.filt.get('useCache', True)

        # Keep a copy of the incoming filt, in case they are using PayloadResponse
        responseFilt = copy(payloadEnvelope.filt)

        # Restore the original payload filt (PayloadResponse) and send it back
        def reply(payload):
            payload.filt = responseFilt
            d = payload.toVortexMsgDefer()
            d.addCallback(sendResponse)
            d.addErrback(vortexLogFailure, logger, consumeError=True)
            # logger.debug("Received response from observable")

        if useCache:
            cache = self._getCache(tupleSelector)
            if cache and cache.lastServerPayloadDate is not None and cache.cacheEnabled:
                payloadEnvelope.encodedPayload = cache.encodedPayload
                payloadEnvelope.date = cache.lastServerPayloadDate
                reply(payloadEnvelope)
                return

        # Track the response, log an error if it fails
        # 5 Seconds is long enough
        pr = PayloadResponse(
            payloadEnvelope,
            timeout=PayloadResponse.TIMEOUT - 5,  # 5 seconds less
            logTimeoutError=False
        )

        pr.addErrback(self._handlePrFailure, tupleSelector)
        pr.addErrback(vortexLogFailure, logger, consumeError=True)
        pr.addCallback(reply)

        self._sendRequestToServer(payloadEnvelope)

    def _handlePrFailure(self, f: Failure, tupleSelector):
        if f.check(TimeoutError):
            logger.error(
                "Received no response from\nobservable %s\ntuple selector %s",
                self._filt,
                tupleSelector.toJsonStr()
            )
        else:
            logger.error(
                "Unexpected error, %s\nobservable %s\ntuple selector %s",
                f,
                self._filt,
                tupleSelector.toJsonStr()
            )

    @deferToThreadWrapWithLogger(logger)
    def _processUpdateFromBackend(self, payloadEnvelope: PayloadEnvelope):

        tupleSelector: TupleSelector = payloadEnvelope.filt["tupleSelector"]

        if not self._hasTupleSelector(tupleSelector):
            return

        cache, requiredUpdate = self._updateCache(payloadEnvelope)
        if not requiredUpdate:
            return

        # Get / update the list of observing UUIDs
        observingUuids = cache.vortexUuids & set(VortexFactory.getRemoteVortexUuids())

        if not observingUuids:
            return

        # Create the vortexMsg
        vortexMsg = payloadEnvelope.toVortexMsg()

        # Send the vortex messages
        for vortexUuid in observingUuids:
            d = VortexFactory.sendVortexMsg(vortexMsgs=vortexMsg,
                                            destVortexUuid=vortexUuid)
            d.addErrback(vortexLogFailure, logger, consumeError=True)
def makeTupleDataObservableHandler(ormSessionCreator,
                                   statusController: StatusController,
                                   branchLiveEditController: BranchLiveEditController):
    """" Make Tuple Data Observable Handler

    This method creates the observable object, registers the tuple providers and then
    returns it.

    :param branchLiveEditController:
    :param ormSessionCreator: A callable that returns an SQLAlchemy session
    :param statusController: The status controller
    :return: An instance of :code:`TupleDataObservableHandler`

    """
    tupleObservable = TupleDataObservableHandler(
        observableName=diagramObservableName,
        additionalFilt=diagramFilt)

    # Register TupleProviders here
    tupleObservable.addTupleProvider(DiagramImporterStatusTuple.tupleName(),
                                     DiagramLoaderStatusTupleProvider(statusController))

    # Register TupleProviders here
    tupleObservable.addTupleProvider(ModelSet.tupleName(),
                                     ServerModelSetTupleProvider(ormSessionCreator))

    # Register TupleProviders here
    tupleObservable.addTupleProvider(ModelCoordSet.tupleName(),
                                     ServerCoordSetTupleProvider(ormSessionCreator))

    # Register TupleProviders here
    tupleObservable.addTupleProvider(BranchKeyToIdMapTuple.tupleName(),
                                     BranchKeyToIdMapTupleProvider(ormSessionCreator))

    # Register TupleProviders here
    lookupTupleProvider = ServerLookupTupleProvider(ormSessionCreator)
    tupleObservable.addTupleProvider(DispLevel.tupleName(), lookupTupleProvider)
    tupleObservable.addTupleProvider(DispLayer.tupleName(), lookupTupleProvider)
    tupleObservable.addTupleProvider(DispColor.tupleName(), lookupTupleProvider)
    tupleObservable.addTupleProvider(DispLineStyle.tupleName(), lookupTupleProvider)
    tupleObservable.addTupleProvider(DispTextStyle.tupleName(), lookupTupleProvider)

    tupleObservable.addTupleProvider(
        BranchLiveEditTuple.tupleName(),
        BranchLiveEditTupleProvider(branchLiveEditController)
    )

    return tupleObservable
예제 #11
0
def makeTupleDataObservableHandler(dbSessionCreator: DbSessionCreator,
                                   statusController: StatusController):
    """" Make Tuple Data Observable Handler

    This method creates the observable object, registers the tuple providers and then
    returns it.

    :param dbSessionCreator: A function that returns a SQLAlchemy session when called
    :param statusController:

    :return: An instance of :code:`TupleDataObservableHandler`

    """
    tupleObservable = TupleDataObservableHandler(
        observableName=docDbObservableName, additionalFilt=docDbFilt)

    # Register TupleProviders here
    tupleObservable.addTupleProvider(DocDbDocument.tupleName(),
                                     DocumentTupleProvider(dbSessionCreator))

    # Admin status tuple
    tupleObservable.addTupleProvider(
        AdminStatusTuple.tupleName(),
        AdminStatusTupleProvider(statusController))

    # Document Type Tuple
    tupleObservable.addTupleProvider(
        DocDbDocumentTypeTuple.tupleName(),
        DocumentTypeTupleProvider(dbSessionCreator))

    # Document Property Tuple
    tupleObservable.addTupleProvider(
        DocDbPropertyTuple.tupleName(),
        DocumentPropertyTupleProvider(dbSessionCreator))

    # Model Set Tuple
    tupleObservable.addTupleProvider(DocDbModelSet.tupleName(),
                                     ModelSetTupleProvider(dbSessionCreator))

    return tupleObservable
예제 #12
0
def makeTupleDataObservableHandler(
        ormSessionCreator: DbSessionCreator,
        adminStatusController: AdminStatusController):
    """" Make Tuple Data Observable Handler

    This method creates the observable object, registers the tuple providers and then
    returns it.

    :param adminStatusController:
    :param ormSessionCreator: A function that returns a SQLAlchemy session when called

    :return: An instance of :code:`TupleDataObservableHandler`

    """
    tupleObservable = TupleDataObservableHandler(
        observableName=eventdbObservableName, additionalFilt=eventdbFilt)

    # Add the tuple selector update mappers
    tupleObservable.addTupleSelectorUpdateMapper(NewEventTSUpdateMapper())

    # Admin Tuple Observers
    tupleObservable.addTupleProvider(
        AdminStatusTuple.tupleName(),
        AdminStatusTupleProvider(adminStatusController))

    tupleObservable.addTupleProvider(
        EventDBModelSetTable.tupleName(),
        EventDBModelSetTableTupleProvider(ormSessionCreator))

    # UI Tuple Observers
    tupleObservable.addTupleProvider(
        EventDBEventTuple.tupleName(),
        EventDBEventTupleProvider(ormSessionCreator))

    tupleObservable.addTupleProvider(
        EventDBPropertyTuple.tupleName(),
        EventDBPropertyTupleProvider(ormSessionCreator))
    return tupleObservable
        tuples = makeTestTupleData(count)

        for t in tuples:
            t.aDate = datetime.now(pytz.utc)
            t.aDict = tupleSelector.selector
            t.aString = tupleSelector.name

        return Payload(filt=filt,
                       tuples=tuples).makePayloadEnvelope().toVortexMsg()


class NotifyTestTimer:
    @classmethod
    def __notify(cls):
        observableHandler.notifyOfTupleUpdate(testTuples1Selector)
        observableHandler.notifyOfTupleUpdate(testTuples2Selector)

    @classmethod
    def startTupleUpdateNotifyer(cls):
        cls.__loopingCall = task.LoopingCall(cls.__notify)
        d = cls.__loopingCall.start(2)
        d.addErrback(lambda f: logger.exception(f.value))
        d.addCallback(
            lambda _: logger.debug("Observable tuple updates started"))


observableHandler = TupleDataObservableHandler("vortexTestObservable")
observableHandler.addTupleProvider(TestTuple.tupleName(), TestTupleProvider())
observableHandler.addTupleProvider("testTuples1", TestTupleProvider())
observableHandler.addTupleProvider("testTuples2", TestTupleProvider())