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 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
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
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
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
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())