Пример #1
0
class DummyTransport(object):

    def __init__(self):
        self.lose_connection_called = Deferred()

    def loseConnection(self):
        self.lose_connection_called.callback(None)
Пример #2
0
    def put(self, router_type="", router_token="", uaid="", chid=""):
        """HTTP PUT

        Update router type/data for a UAID.

        """
        self.start_time = time.time()

        if not self._validate_auth(uaid):
            return self._write_response(
                401, 109, message="Invalid Authentication")

        params = self._load_params()
        self.uaid = uaid
        router_data = params
        if router_type not in self.ap_settings.routers or not router_data:
            log.msg("Invalid parameters", **self._client_info())
            return self._write_response(
                400, 108, message="Invalid arguments")
        router = self.ap_settings.routers[router_type]
        valid, router_token = router.check_token(router_token)
        if not valid:
            newUrl = self._relocate(router_type, router_token, uaid, chid)
            return self._write_response(
                301, 0, "Location: %s" % newUrl,
                headers={"Location": newUrl})

        self.add_header("Content-Type", "application/json")
        d = Deferred()
        d.addCallback(router.register, router_data)
        d.addCallback(self._save_router_data, router_type)
        d.addCallback(self._success)
        d.addErrback(self._router_fail_err)
        d.addErrback(self._response_err)
        d.callback(uaid)
Пример #3
0
    def cachedZipResource(self, request, name, url, segments):
        archivePath = self.config.CachedResources.child("{0}.zip".format(name))

        if archivePath.exists():
            d = Deferred()
            d.callback(None)
        else:
            d = http_download(archivePath, url)

        def readFromArchive(_):
            filePath = ZipArchive(archivePath.path)
            for segment in segments:
                filePath = filePath.child(segment)
            return filePath.getContent()

        def notFoundHandler(f):
            f.trap(KeyError)
            request.setResponseCode(http.NOT_FOUND)
            set_response_header(
                request, HeaderName.contentType, ContentType.plain
            )
            return b"Not found."

        d.addCallback(readFromArchive)
        d.addErrback(notFoundHandler)
        return d
Пример #4
0
    def create_keychain(self):
        """
        The guid generation can take a while. While it's doing that we will
        open a port to allow a UI to connect and listen for generation to
        complete.
        """
        print "Generating GUID, this may take a few minutes..."
        d = Deferred()
        api = GUIDGenerationListener(d)
        site = Site(api, timeout=None)
        connector = reactor.listenTCP(18470, site, interface="127.0.0.1")
        start = time.time()
        g = GUID()
        d.callback((round(time.time() - start, 2), connector))

        self.guid = g.guid
        self.guid_privkey = g.privkey
        self.signing_key = nacl.signing.SigningKey(self.guid_privkey)
        self.guid_signed_pubkey = g.signed_pubkey
        self.db.set_key("guid", self.guid_privkey, self.guid_signed_pubkey)

        self.bitcoin_master_privkey = bitcointools.bip32_master_key(bitcointools.sha256(self.guid_privkey))
        self.bitcoin_master_pubkey = bitcointools.bip32_privtopub(self.bitcoin_master_privkey)
        self.db.set_key("bitcoin", self.bitcoin_master_privkey, self.bitcoin_master_pubkey)

        self.encryption_key = PrivateKey(self.guid_privkey)
        self.encryption_pubkey = self.encryption_key.public_key.encode()
Пример #5
0
class _Producer(object):
    implements(IPullProducer)

    deferred = None

    def __init__(self, body, consumer):
        """:param body: an iterable of strings"""

        # check to see if we can determine the length
        try:
            len(body) # iterator?
            self.length = sum([len(fragment) for fragment in body])
            self.body = iter(body)

        except TypeError:
            self.length = UNKNOWN_LENGTH
            self.body = body

        self.deferred = Deferred()

        self.consumer = consumer

    def resumeProducing(self):
        try:
            chunk = self.body.next()

        except StopIteration, e:
            self.consumer.unregisterProducer()
            if self.deferred is not None:
                self.deferred.callback(self.consumer)
                self.deferred = None
            return

        self.consumer.write(chunk)
Пример #6
0
def noop(id, data, config, runsettings):
    """
    Do nothing
    """
    d = Deferred()
    d.callback(True)
    return d
Пример #7
0
class SubprocessProtocol(protocol.ProcessProtocol):
    """Twisted-friendly subprocess."""
    
    def __init__(self, args, environment):
        self.deferred = Deferred()
        self.buffer = StringIO()
        
        reactor.spawnProcess(self, args[0], args, self.clean_environ(environment))
    
    def outReceived(self, data):
        self.buffer.write(data)
    
    def errReceived(self, data):
        self.outReceived(data)
    
    def processEnded(self, status):
        self.deferred.callback(self.buffer.getvalue())
    
    @staticmethod
    def clean_environ(environ):
        """Filter non-string items from environ, as reactor.spawnProcess cannot handle them."""
        
        for k, v in environ.items():
            if type(v) not in [str, unicode]:
                environ.pop(k)
        
        return environ
Пример #8
0
class WebSocketConnection(WebSocketProtocol):
	def __init__(self, stateObject):
		self.state = stateObject
		self.opcode = TEXT
		WebSocketProtocol.__init__(self, WebSocketReceiver(self))
		self.finished = Deferred()
		self.pingLoop = LoopingCall(self.doPing)

	def doPing(self):
		self.receiver.transport.sendFrame(PING, '')

	def write(self, data):
		self.receiver.transport.sendFrame(self.opcode, data)

	def sendFrame(self, opcode, data):
		self.receiver.transport.sendFrame(opcode, data)

	def writeSequence(self, data):
		for chunk in data:
			self.write(chunk)

	def connectionLost(self, reason):
		if self.pingLoop.running:
			self.pingLoop.stop()
		self.finished.callback(self)
Пример #9
0
    def test_producer_send_messages_no_acks(self):
        first_part = 19
        client = Mock()
        ret = Deferred()
        client.send_produce_request.return_value = ret
        client.topic_partitions = {self.topic: [first_part, 101, 102, 103]}
        client.metadata_error_for_topic.return_value = False
        msgs = [self.msg("one"), self.msg("two")]
        ack_timeout = 5

        producer = Producer(client, ack_timeout=ack_timeout,
                            req_acks=PRODUCER_ACK_NOT_REQUIRED)
        d = producer.send_messages(self.topic, msgs=msgs)
        # Check the expected request was sent
        msgSet = create_message_set(
            make_send_requests(msgs), producer.codec)
        req = ProduceRequest(self.topic, first_part, msgSet)
        client.send_produce_request.assert_called_once_with(
            [req], acks=producer.req_acks, timeout=ack_timeout,
            fail_on_error=False)
        # Check results when "response" fires
        self.assertNoResult(d)
        ret.callback([])
        result = self.successResultOf(d)
        self.assertEqual(result, None)
        producer.stop()
Пример #10
0
    def test_producer_cancel_one_request_getting_topic(self):
        # Test cancelling a request after it's begun to be processed
        client = Mock()
        client.topic_partitions = {}
        ret = Deferred()
        client.load_metadata_for_topics.return_value = ret
        msgs = [self.msg("one"), self.msg("two")]
        msgs2 = [self.msg("three"), self.msg("four")]
        batch_n = 4

        producer = Producer(client, batch_every_n=batch_n, batch_send=True)
        d1 = producer.send_messages(self.topic, msgs=msgs)
        # Check that no request was sent
        self.assertFalse(client.send_produce_request.called)
        # This will trigger the metadata lookup
        d2 = producer.send_messages(self.topic, msgs=msgs2)
        d1.cancel()
        self.failureResultOf(d1, CancelledError)
        # Check that still no request was sent
        self.assertFalse(client.send_produce_request.called)
        self.assertNoResult(d2)
        # Setup the client's topics and trigger the metadata deferred
        client.topic_partitions = {self.topic: [0, 1, 2, 3]}
        client.metadata_error_for_topic.return_value = False
        ret.callback(None)
        # Expect that only the msgs2 messages were sent
        msgSet = create_message_set(
            make_send_requests(msgs2), producer.codec)
        req = ProduceRequest(self.topic, 1, msgSet)
        client.send_produce_request.assert_called_once_with(
            [req], acks=producer.req_acks, timeout=producer.ack_timeout,
            fail_on_error=False)

        producer.stop()
Пример #11
0
    def sync_box(self, root_box):
        """ Start syncing the named box. """
        logging.debug("WebServer, sync_box for root_box {0}".format(root_box))
        return_d = Deferred()

        if root_box in self.syncs:
            logging.error("sync_box: returning from cache")
            indxsync = self.syncs[root_box]
            return_d.callback(indxsync)
        else:
            def err_cb(failure):
                logging.error("WebServer, sync_box error getting token: {0} {1}".format(failure, failure.value))
                # FIXME do something with the error?
                return_d.errback(failure)

            self.syncs[root_box] = None # reserve the slot

            def store_cb(root_store):
                indxsync = IndxSync(root_store, self.database, self.server_url, self.keystore, self)
                self.syncs[root_box] = indxsync
                return_d.callback(indxsync)

            # assign ourselves a new token to access the root box using the @indx user
            # this only works because the "create_root_box" function gave this user read permission
            # this doesn't work in the general case.
            def token_cb(token):
                token.get_store().addCallbacks(store_cb, err_cb)

            self.tokens.new("@indx","",root_box,"IndxSync","/","::1", self.server_id).addCallbacks(token_cb, return_d.errback)

        return return_d 
Пример #12
0
class Engine:
    def __init__(self, controller):
        self._ctrl = controller
        self._ctrl.add_engine(self)
        self.deferred = Deferred()

    def _signal(self, name, *args, **keywords):
        self._ctrl.signal(name, *args, **keywords)

    def __stop(self):
        self._ctrl.remove_engine(self)

    def _success(self, result=None):
        self.__stop()
        self.deferred.callback(result)

    def _failure(self, fail='Engine failed'):
        self.__stop()
        self.deferred.errback(fail)

    def abort(self):
        """Aborts this engine, does not emit a signal."""
        self.__stop()

    def send(self, something):
        return self._ctrl.send(something)

    def sendall(self, something):
        return self._ctrl.sendall(something)
Пример #13
0
class SpoolingSignalProtocol(Protocol):
    def __init__(self, *args, **kwargs):
        self.spooling = SpoolingProtocol()
        self.signaling = SignalProtocol(*args, **kwargs)
        self.finished = None

    def connectionMade(self):
        self.finished = Deferred()

    def connectionLost(self, reason):
        if reason.type is ProcessTerminated:
            self.finished.errback(reason.value)
        else:
            self.finished.callback(reason.value)

    def dataReceived(self, data):
        self.signaling.dataReceived(data)
        self.spooling.dataReceived(data)

    def extReceived(self, fd, data):
        self.signaling.extReceived(fd, data)
        self.spooling.extReceived(fd, data)

    def flush(self):
        return self.spooling.flush()
Пример #14
0
    def start(self):
        # We need to run 4 commands in a row, and each of them can fail
        d = Deferred()

        def chain(args, description, failMessage):
            d.addCallback(self._spawnProcess, args, description, failMessage)

        for serviceName in ['manager', 'worker']:
            chain(["flumotion",
                   "-C", self._confDir,
                   "-L", self._logDir,
                   "-R", self._runDir,
                   "create", serviceName,
                   "admin", str(self._port)],
                  _('Creating %s ...') % serviceName,
                  _("Could not create %s." % serviceName))
            chain(["flumotion",
                   "-C", self._confDir,
                   "-L", self._logDir,
                   "-R", self._runDir,
                   "start", serviceName, "admin"],
                  _('Starting %s ...' % serviceName),
                  _("Could not start %s." % serviceName))

        d.addErrback(lambda f: None)

        def done(result):
            self._finished()
        d.addCallback(done)

        # start chain
        d.callback(None)

        return d
Пример #15
0
    def put(self, uaid=""):
        """HTTP PUT

        Update router type/data for a UAID.

        """
        self.start_time = time.time()

        if not self._validate_auth(uaid):
            return self._write_response(
                401, 109, message="Invalid Authentication")

        params = self._load_params()
        self.uaid = uaid
        router_type = params.get("type")
        router_data = params.get("data")
        if router_type not in self.ap_settings.routers or not router_data:
            log.msg("Invalid parameters", **self._client_info())
            return self._write_response(
                400, 108, message="Invalid arguments")

        self.add_header("Content-Type", "application/json")
        router = self.ap_settings.routers[router_type]

        d = Deferred()
        d.addCallback(router.register, router_data)
        d.addCallback(self._save_router_data, router_type)
        d.addCallback(self._success)
        d.addErrback(self._router_fail_err)
        d.addErrback(self._response_err)
        d.callback(uaid)
Пример #16
0
    def test_log_while_connecting(self):
        connect_d = Deferred()
        real_connect = self.endpoint.connect.side_effect

        def _delay_connect(factory):
            d = real_connect(factory)
            connect_d.addCallback(lambda _: d)

            return connect_d

        self.endpoint.connect.side_effect = _delay_connect
        client = ScribeClient(self.endpoint)

        d = client.log('category', 'message')
        self.assertEqual(self.client_proto.client.Log.call_count, 0)

        d2 = client.log('category', 'message')
        self.assertEqual(self.client_proto.client.Log.call_count, 0)

        connect_d.callback(None)

        self.assertEqual(self.assertFired(d), ttypes.ResultCode.OK)
        self.assertEqual(self.assertFired(d2), ttypes.ResultCode.OK)

        self.assertEqual(self.client_proto.client.Log.call_count, 2)
Пример #17
0
    def test_rewind_blocks_on_deferreds_returned_by_ops(self):
        """
        rewind will serialize operations waiting on any deferreds returned
        before running the next operation.
        """
        called = [0]

        def op(op_d):
            called[0] += 1
            return op_d

        op_d1 = Deferred()
        self.undo.push(op, op_d1)
        op_d2 = Deferred()
        self.undo.push(op, op_d2)

        d = self.undo.rewind()
        self.assertEqual(called[0], 1)
        self.assertNoResult(d)

        op_d2.callback(None)
        self.assertEqual(called[0], 2)
        self.assertNoResult(d)

        op_d1.callback(None)
        self.successResultOf(d)
Пример #18
0
    def get_package(self, request, from_ip=None):
        commands = self._parse_request(request)

        d = Deferred()

        d.callback(commands)
        return d
Пример #19
0
    def stop_daemon(self, host_id):
        """
        Stops a running daemon.

        :param host_id: the hash id of the host
        :type host_id: string
        """
        main_deferred = Deferred()
        host = self.get_host(host_id)
        if not host:
            main_deferred.callback((False, _("Daemon doesn't exist")))
            return main_deferred

        try:
            def on_connect(connected, c):
                if not connected:
                    main_deferred.callback((False, _("Daemon not running")))
                    return
                c.daemon.shutdown()
                main_deferred.callback((True, ))

            def on_connect_failed(reason):
                main_deferred.callback((False, reason))

            host, port, user, password = host[1:5]
            c = Client()
            d = c.connect(host, port, user, password)
            d.addCallback(on_connect, c)
            d.addErrback(on_connect_failed)
        except:
            main_deferred.callback((False, "An error occurred"))
        return main_deferred
Пример #20
0
class TestBase(object):
    def __init__(self, conn, iTag, testType):
        self._conn = conn
        self._iTag = iTag
        self._testType = testType

        self._data = []

    def _activate(self):
        pass

    def _deactivate(self):
        pass

    def _run(self):
        raise NotImplementedError

    def run(self, _):
        self._deferred = Deferred()
        self._conn.reactor.callLater(1, self._activate)
        self._conn.reactor.callLater(2, self._run)
        return self._deferred

    def _done(self):
        self._deactivate()
        self._deferred.callback(None)

    def __str__(self):
        return json.dumps({'type' : self._testType, 'data' : self._data})
Пример #21
0
 def scale_down(self):
     global overlay
     n_workers = len(overlay.aws.workers)
     d = Deferred()
     for i in range(1, 1 + n_workers / 2):
         d.addCallback(overlay.aws.term_worker(overlay.aws.workers[i]))
     d.callback(0);
Пример #22
0
        def test_double_subscribe(self):
            handler = ApplicationSession()
            MockTransport(handler)

            event0 = Deferred()
            event1 = Deferred()

            subscription0 = yield handler.subscribe(
                lambda: event0.callback(42), u'com.myapp.topic1')
            subscription1 = yield handler.subscribe(
                lambda: event1.callback('foo'), u'com.myapp.topic1')
            # same topic, same ID
            self.assertTrue(subscription0.id == subscription1.id)

            # do a publish (MockTransport fakes the acknowledgement
            # message) and then do an actual publish event. The IDs
            # are the same, so we just do one Event.
            publish = yield handler.publish(
                u'com.myapp.topic1',
                options=types.PublishOptions(acknowledge=True, exclude_me=False),
            )
            handler.onMessage(message.Event(subscription0.id, publish.id))

            # ensure we actually got both callbacks
            self.assertTrue(event0.called, "Missing callback")
            self.assertTrue(event1.called, "Missing callback")
Пример #23
0
class DummyClient(DatagramProtocol):

    def __init__(self, *args, **kwargs):
        self.ready = Deferred()

    def startProtocol(self):
        self.ready.callback(None)
Пример #24
0
 def test_deferPreCommit(self):
     """
     If callables passed to L{IAsyncTransaction.preCommit} return
     L{Deferred}s, they will defer the actual commit operation until it has
     fired.
     """
     txn = self.createTransaction()
     d = Deferred()
     def wait():
         wait.started = True
         def executed(it):
             wait.sqlResult = it
         # To make sure the _underlying_ commit operation was Deferred, we
         # have to execute some SQL to make sure it happens.
         return (d.addCallback(lambda ignored: txn.execSQL("some test sql"))
                  .addCallback(executed))
     wait.started = False
     wait.sqlResult = None
     txn.preCommit(wait)
     result = self.resultOf(txn.commit())
     self.flushHolders()
     self.assertEquals(wait.started, True)
     self.assertEquals(wait.sqlResult, None)
     self.assertEquals(result, [])
     d.callback(None)
     # allow network I/O for pooled / networked implementation; there should
     # be the commit message now.
     self.flushHolders()
     self.assertEquals(len(result), 1)
     self.assertEquals(wait.sqlResult, [[1, "some test sql"]])
Пример #25
0
 def testTriggerSystemEvent4(self):
     # make sure interleaved event types do not interfere with each other.
     # Old cReactor code had a single defer_list for all event types.
     l = []
     l2 = []
     d = Deferred()
     d2 = Deferred()
     def _returnDeferred(d=d):
         return d
     def _returnDeferred2(d2=d2):
         return d2
     def _appendToList(l=l):
         l.append(1)
     def _appendToList2(l2=l2):
         l2.append(1)
     r = reactor
     self.addTrigger("before", "event1", _returnDeferred)
     self.addTrigger("after", "event1", _appendToList)
     self.addTrigger("before", "event2", _returnDeferred2)
     self.addTrigger("after", "event2", _appendToList2)
     r.fireSystemEvent("event1")
     # event1 should be waiting on deferred 'd'
     r.fireSystemEvent("event2")
     # event2 should be waiting on deferred 'd2'
     self.assertEquals(len(l), 0, "Event should not have fired yet.")
     self.assertEquals(len(l2), 0, "Event should not have fired yet.")
     d.callback(None)
     # event1 should run "during" and "after" stages
     # event2 should still be waiting on d2
     self.assertEquals(len(l), 1)
     self.assertEquals(len(l2), 0)
     d2.callback(None)
     # event2 should run "during" and "after" stages
     self.assertEquals(len(l), 1)
     self.assertEquals(len(l2), 1)
Пример #26
0
 def testTriggerSystemEvent2(self):
     # one of the "before" trigger functions returns a deferred. A later
     # "before" trigger fires the deferred. A third before runs. Then a
     # "during" should be run. One of the failure modes for the old
     # cReactor code is to start the "during" as soon as the deferred
     # fires, rather than waiting for the "before" phase to be finished
     l = []
     d = Deferred()
     d2 = Deferred()
     def _returnDeferred(d=d):
         return d
     def _fireDeferred(d=d):
         d.callback(None)
     def _returnDeferred2(d2=d2):
         return d2
     def _appendToList(l=l):
         l.append(1)
     r = reactor
     # to test this properly, the triggers must fire in this sequence:
     # _returnDeferred, _fireDeferred, _returnDeferred2 . cReactor happens
     # to run triggers in the order in which they were added.
     self.addTrigger("before", "defer2", _returnDeferred)
     self.addTrigger("before", "defer2", _fireDeferred)
     self.addTrigger("before", "defer2", _returnDeferred2)
     self.addTrigger("during", "defer2", _appendToList)
     self.addTrigger("after", "defer2", _appendToList)
     r.fireSystemEvent("defer2")
     self.assertEquals(len(l), 0, "Event should not have fired yet.")
     d2.callback(None)
     self.assertEquals(len(l), 2)
Пример #27
0
 def testTriggerSystemEvent3(self):
     # make sure reactor can survive the loss of an event type while
     # waiting for a before-trigger's Deferred to fire
     l = []
     d = Deferred()
     d2 = Deferred()
     def _returnDeferred(d=d):
         return d
     def _appendToList(l=l):
         l.append(1)
     def _ignore(failure):
         return None
     r = reactor
     b1 = self.addTrigger("before", "defer3", _returnDeferred)
     b2 = self.addTrigger("after", "defer3", _appendToList)
     r.fireSystemEvent("defer3")
     self.assertEquals(len(l), 0, "Event should not have fired yet.")
     self.removeTrigger(b1)
     self.removeTrigger(b2)
     try:
         d.callback(None) # cReactor gives errback to deferred
     except ValueError:
         pass
     self.assertEquals(len(l), 0)
     d.addErrback(_ignore)
Пример #28
0
    def get(self, tid):
        """ Used to get a token by the BaseHandler, and whenever a
            handler needs to token (usually because it wants to access
            the store object).

            tid -- The ID of the Token to get, it must have already been
                created, usually by the get_token call to the AuthHandler.
        """
        return_d = Deferred()

        if self.tokens.get(tid) is not None:
            # already in cache, return existing
            return_d.callback(self.tokens.get(tid))
            return return_d

        # otherwise check the db
        def token_cb(token_tuple):
            if token_tuple is None:
                return_d.callback(None)
                return

            username, password, boxid, appid, origin, clientip, server_id = token_tuple
            token = Token(self.db, username, password, boxid, appid, origin, clientip, server_id)

            self.add(token)
            return_d.callback(token)
            return

        self.db.get_token(tid).addCallbacks(token_cb, return_d.errback)
        return return_d
Пример #29
0
 def test_subsequentBeforeTriggerFiresPriorBeforeDeferred(self):
     """
     If a trigger added to the C{'before'} phase of an event calls back a
     L{Deferred} returned by an earlier trigger in the C{'before'} phase of
     the same event, the remaining C{'before'} triggers for that event
     should be run and any further L{Deferred}s waited on before proceeding
     to the C{'during'} events.
     """
     eventType = 'test'
     events = []
     firstDeferred = Deferred()
     secondDeferred = Deferred()
     def firstBeforeTrigger():
         return firstDeferred
     def secondBeforeTrigger():
         firstDeferred.callback(None)
     def thirdBeforeTrigger():
         events.append('before')
         return secondDeferred
     def duringTrigger():
         events.append('during')
     self.addTrigger('before', eventType, firstBeforeTrigger)
     self.addTrigger('before', eventType, secondBeforeTrigger)
     self.addTrigger('before', eventType, thirdBeforeTrigger)
     self.addTrigger('during', eventType, duringTrigger)
     self.assertEqual(events, [])
     reactor.fireSystemEvent(eventType)
     self.assertEqual(events, ['before'])
     secondDeferred.callback(None)
     self.assertEqual(events, ['before', 'during'])
Пример #30
0
 def test_multipleBeforeReturnDeferred(self):
     """
     If more than one trigger added to the C{'before'} phase of an event
     return L{Deferred}s, the C{'during'} phase should be delayed until they
     are all called back.
     """
     firstDeferred = Deferred()
     secondDeferred = Deferred()
     eventType = 'test'
     events = []
     def firstBeforeTrigger():
         return firstDeferred
     def secondBeforeTrigger():
         return secondDeferred
     def duringTrigger():
         events.append('during')
     self.addTrigger('before', eventType, firstBeforeTrigger)
     self.addTrigger('before', eventType, secondBeforeTrigger)
     self.addTrigger('during', eventType, duringTrigger)
     self.assertEqual(events, [])
     reactor.fireSystemEvent(eventType)
     self.assertEqual(events, [])
     firstDeferred.callback(None)
     self.assertEqual(events, [])
     secondDeferred.callback(None)
     self.assertEqual(events, ['during'])
Пример #31
0
class Locations(YomboLibrary):
    """
    Manages locations for a gateway.
    """
    @property
    def locations_sorted(self):
        return OrderedDict(
            sorted(self.locations.items(), key=lambda x: x[1].label))

    def __contains__(self, location_requested):
        """
        Checks to if a provided location ID or machine_label exists.

            >>> if '0kas02j1zss349k1' in self._Locations:

        or:

            >>> if 'some_location_name' in self.Locations:

        :raises YomboWarning: Raised when request is malformed.
        :raises KeyError: Raised when request is not found.
        :param location_requested: The location id or machine_label to search for.
        :type location_requested: string
        :return: Returns true if exists, otherwise false.
        :rtype: bool
        """
        try:
            self.get_meta(location_requested)
            return True
        except:
            return False

    def __getitem__(self, location_requested):
        """
        Attempts to find the location requested using a couple of methods.

            >>> location = self.Locations['0kas02j1zss349k1']  #by uuid

        or:

            >>> location = self.Locations['alpnum']  #by name

        :raises YomboWarning: Raised when request is malformed.
        :raises KeyError: Raised when request is not found.
        :param location_requested: The location ID or machine_label to search for.
        :type location_requested: string
        :return: A pointer to the location type instance.
        :rtype: instance
        """
        return self.get_meta(location_requested)

    def __setitem__(self, **kwargs):
        """
        Sets are not allowed. Raises exception.

        :raises Exception: Always raised.
        """
        raise Exception("Not allowed.")

    def __delitem__(self, **kwargs):
        """
        Deletes are not allowed. Raises exception.

        :raises Exception: Always raised.
        """
        raise Exception("Not allowed.")

    def __iter__(self):
        """ iter locations. """
        return self.locations.__iter__()

    def __len__(self):
        """
        Returns an int of the number of locations configured.

        :return: The number of locations configured.
        :rtype: int
        """
        return len(self.locations)

    def __str__(self):
        """
        Returns the name of the library.
        :return: Name of the library
        :rtype: string
        """
        return self.locations.__str__()

    def keys(self):
        """
        Returns the keys (location ID's) that are configured.

        :return: A list of location IDs.
        :rtype: list
        """
        return list(self.locations.keys())

    def items(self):
        """
        Gets a list of tuples representing the locations configured.

        :return: A list of tuples.
        :rtype: list
        """
        return list(self.locations.items())

    def values(self):
        return list(self.locations.values())

    def _init_(self, **kwargs):
        """
        Setups up the basic framework. Nothing is loaded in here until the
        Load() stage.
        """
        self.load_deferred = None  # Prevents loader from moving on past _load_ until we are done.
        self.locations = {}
        self.location_search_attributes = [
            'location_id', 'gateway_id', 'location', 'machine_label',
            'destination', 'data_type', 'status'
        ]
        self.load_deferred = Deferred()
        self._load_locations_from_database()
        return self.load_deferred

    # def _load_(self):
    #     """
    #     Loads all locations from DB to various arrays for quick lookup.
    #     """

    def _stop_(self, **kwargs):
        """
        Cleans up any pending deferreds.
        """
        if hasattr(self, 'load_deferred'):
            if self.load_deferred is not None and self.load_deferred.called is False:
                self.load_deferred.callback(
                    1)  # if we don't check for this, we can't stop!

    @inlineCallbacks
    def _load_locations_from_database(self):
        """
        Loads locations from database and sends them to
        :py:meth:`import_location <Locations.import_location>`

        This can be triggered either on system startup or when new/updated locations have been saved to the
        database and we need to refresh existing locations.
        """
        locations = yield self._LocalDB.get_locations()
        for location in locations:
            self.import_location(location.__dict__)
        self.load_deferred.callback(10)

    def import_location(self, location, test_location=False):
        """
        Add a new locations to memory or update an existing locations.

        **Hooks called**:

        * _location_before_load_ : If added, sends location dictionary as 'location'
        * _location_before_update_ : If updated, sends location dictionary as 'location'
        * _location_loaded_ : If added, send the location instance as 'location'
        * _location_updated_ : If updated, send the location instance as 'location'

        :param location: A dictionary of items required to either setup a new location or update an existing one.
        :type input: dict
        :param test_location: Used for unit testing.
        :type test_location: bool
        :returns: Pointer to new input. Only used during unittest
        """
        # logger.debug("location: {location}", location=location)

        global_invoke_all('_locations_before_import_',
                          called_by=self,
                          **{'location': location})
        location_id = location["id"]
        if location_id not in self.locations:
            global_invoke_all('_location_before_load_',
                              called_by=self,
                              **{'location': location})
            self.locations[location_id] = Location(self, location)
            global_invoke_all('_location_loaded_',
                              called_by=self,
                              **{'location': self.locations[location_id]})
        elif location_id not in self.locations:
            global_invoke_all('_location_before_update_',
                              called_by=self,
                              **{'location': location})
            self.locations[location_id].update_attributes(location)
            global_invoke_all('_location_updated_',
                              called_by=self,
                              **{'location': self.locations[location_id]})

    def remove_location(self, location_id):
        """
        Remove a location from memory.
        
        :param location_id: 
        :return: 
        """
        if location_id in self.locations:
            del self.locations[location_id]

    def area_label(
        self, area_id: dict(
            type=str,
            help="Area ID (location) to use for prepending to label"),
        label: dict(type=str, help="Label to prepend Area to.")
    ) -> dict(type=str, help="The result of:  area + label"):
        """
        Adds an area label to a provided string (label).
        """
        if area_id in self.locations:
            area_label = self.locations[area_id].label
            if area_label.lower() != "none" and area_label is not None:
                return "%s %s" % (area_label, label)
        return label

    def full_label(
        self,
        location_id: dict(type=str,
                          help="Location ID to use for prepending to label"),
        area_id: dict(
            type=str,
            help="Area ID (location) to use for prepending to label"),
        label: dict(type=str, help="Label to prepend Location and Area to.")
    ) -> dict(type=str, help="The result of:  location + area + label"):
        """
        Adds location and area to a provided string (label).
        """
        output = ""
        if location_id in self.locations:
            location_label = self.locations[location_id].label
            if location_label.lower() != "none" and location_label is not None:
                output = location_label

        if area_id in self.locations:
            area_label = self.locations[area_id].label
            if area_label.lower() != "none" and area_label is not None:
                return "%s %s %s" % (output, area_label, label)
        return "%s %s" % (output, label)

    def get_all(self):
        """
        Returns a copy of the locations list.
        :return:
        """
        return self.locations.copy()

    def get(self,
            location_requested,
            location_type=None,
            limiter=None,
            status=None):
        """
        Performs the actual search.

        .. note::

           Can use the built in methods below or use get_meta/get to include 'location_type' limiter:

            >>> self.Locations['13ase45']

        or:

            >>> self.Locations['numeric']

        :raises YomboWarning: For invalid requests.
        :raises KeyError: When item requested cannot be found.
        :param location_requested: The location ID or location label to search for.
        :type location_requested: string
        :param limiter_override: Default: .89 - A value between .5 and .99. Sets how close of a match it the search should be.
        :type limiter_override: float
        :param status: Deafult: 1 - The status of the location to check for.
        :type status: int
        :return: Pointer to requested location.
        :rtype: dict
        """
        if limiter is None:
            limiter = .89

        if limiter > .99999999:
            limiter = .99
        elif limiter < .10:
            limiter = .10

        if status is None:
            status = 1

        if location_requested in self.locations:
            item = self.locations[location_requested]
            if item.status != status:
                raise KeyError(
                    "Requested location found, but has invalid status: %s" %
                    item.status)
            return item
        else:
            attrs = [{
                'field': 'location_id',
                'value': location_requested,
                'limiter': limiter,
            }, {
                'field': 'machine_label',
                'value': location_requested,
                'limiter': limiter,
            }, {
                'field': 'label',
                'value': location_requested,
                'limiter': limiter,
            }]
            try:
                # logger.debug("Get is about to call search...: %s" % location_requested)
                # found, key, item, ratio, others = self._search(attrs, operation="highest")
                found, key, item, ratio, others = do_search_instance(
                    attrs,
                    self.locations,
                    self.location_search_attributes,
                    limiter=limiter,
                    operation="highest")
                # logger.debug("found location by search: others: {others}", others=others)
                if location_type is not None:
                    for other in others:
                        if other[
                                'value'].location_type == location_type and other[
                                    'ratio'] > limiter:
                            return other['value']
                else:
                    if found:
                        return item
                raise KeyError("Location not found: %s" % location_requested)
            except YomboWarning as e:
                raise KeyError('Searched for %s, but had problems: %s' %
                               (location_requested, e))

    def search(self, _limiter=None, _operation=None, **kwargs):
        """
        Search for location based on attributes for all locations.

        :param limiter_override: Default: .89 - A value between .5 and .99. Sets how close of a match it the search should be.
        :type limiter_override: float
        :param status: Deafult: 1 - The status of the location to check for.
        :return: 
        """
        return search_instance(kwargs, self.locations,
                               self.location_search_attributes, _limiter,
                               _operation)

    @inlineCallbacks
    def add_location(self, data, **kwargs):
        """
        Add a location at the Yombo server level, not at the local gateway level.

        :param data:
        :param kwargs:
        :return:
        """
        location_results = yield self._YomboAPI.request(
            'POST', '/v1/location', data)

        if location_results['code'] > 299:
            results = {
                'status': 'failed',
                'msg': "Couldn't add location",
                'apimsg': location_results['content']['message'],
                'apimsghtml': location_results['content']['html_message'],
            }
            return results

        results = {
            'status': 'success',
            'msg': "Location type added.",
            'location_id': location_results['data']['id'],
        }
        data['id'] = location_results['data']['id']
        data['updated_at'] = time()
        data['created_at'] = time()
        self._LocalDB.insert_locations(data)
        self.import_location(data)
        return results

    @inlineCallbacks
    def edit_location(self, location_id, data, **kwargs):
        """
        Edit a location at the Yombo server level, not at the local gateway level.

        :param data:
        :param kwargs:
        :return:
        """

        location_results = yield self._YomboAPI.request(
            'PATCH', '/v1/location/%s' % (location_id), data)

        if location_results['code'] > 299:
            results = {
                'status': 'failed',
                'msg': "Couldn't edit location",
                'apimsg': location_results['content']['message'],
                'apimsghtml': location_results['content']['html_message'],
            }
            return results

        results = {
            'status': 'success',
            'msg': "Device type edited.",
            'location_id': location_results['data']['id'],
        }

        if location_id in self.locations:
            self.locations[location_id].update_attributes(data)
            self.locations[location_id].save_to_db(data)

        return results

    @inlineCallbacks
    def delete_location(self, location_id, **kwargs):
        """
        Delete a location at the Yombo server level, not at the local gateway level.

        :param location_id: The location ID to delete.
        :param kwargs:
        :return:
        """
        location_results = yield self._YomboAPI.request(
            'DELETE', '/v1/location/%s' % location_id)

        if location_results['code'] > 299:
            results = {
                'status': 'failed',
                'msg': "Couldn't delete location",
                'apimsg': location_results['content']['message'],
                'apimsghtml': location_results['content']['html_message'],
            }
            return results

        results = {
            'status': 'success',
            'msg': "Location deleted.",
            'location_id': location_id,
        }

        self.remove_location(location_id)
        self._LocalDB.delete_locations(location_id)
        return results
Пример #32
0
 def closure(future, adapt):
     if isinstance(future, Deferred):
         d = Deferred()
         future.addCallback(lambda r: d.callback(adapt(r)))
         return d
     return adapt(future)