示例#1
0
    def test_heartbeat_failure(self):
        self.patch_cfg('pyon.ion.process.CFG', {'cc':{'timeout':{'heartbeat_proc_count_threshold':2, 'heartbeat':1.0}}})

        svc = self.container.proc_manager.procs[self.pid]
        ip = svc._process
        stopar = AsyncResult()
        self.container.proc_manager.add_proc_state_changed_callback(lambda *args: stopar.set(args))

        noticear = AsyncResult()        # notify us when the call has been made
        ar = ip._routing_call(svc.takes_too_long, None, noticear=noticear)

        noticear.get(timeout=10)        # wait for the call to be made

        # heartbeat a few times so we trigger the failure soon
        for x in xrange(2):
            ip.heartbeat()

        # wait for ip thread to kick over
        ip._ctrl_thread.join(timeout=5)

        # now wait for notice proc got canned
        stopargs = stopar.get(timeout=5)

        self.assertEquals(stopargs, (svc, ProcessStateEnum.FAILED, self.container))

        # should've shut down, no longer in container's process list
        self.assertEquals(len(self.container.proc_manager.procs), 0)
示例#2
0
    def test_zero_max_size(self):
        q = queue.Channel()

        def sender(evt, q):
            q.put('hi')
            evt.set('done')

        def receiver(evt, q):
            x = q.get()
            evt.set(x)

        e1 = AsyncResult()
        e2 = AsyncResult()

        p1 = gevent.spawn(sender, e1, q)
        gevent.sleep(0.001)
        self.assert_(not e1.ready())
        p2 = gevent.spawn(receiver, e2, q)
        self.assertEquals(e2.get(), 'hi')
        self.assertEquals(e1.get(), 'done')
        timeout = gevent.Timeout.start_new(0)
        try:
            gevent.joinall([p1, p2])
        finally:
            timeout.cancel()
示例#3
0
    def test__control_flow_cancelled_call(self):
        svc = self._make_service()
        p = IonProcessThread(name=sentinel.name, listeners=[], service=svc)
        p.start()
        p.get_ready_event().wait(timeout=5)
        self.addCleanup(p.stop)

        # put a call in that will never finish
        waitar = AsyncResult()      # test specific, wait for this to indicate we're being processed/hung
        callar = AsyncResult()      # test specific, an ar that is just waited on by the spin call (eventually set in this test)
        def spin(inar, outar):
            outar.set(True)
            inar.wait()

        ar = p._routing_call(spin, MagicMock(), callar, waitar)

        # schedule a second call that we're going to cancel
        futurear = AsyncResult()
        ar2 = p._routing_call(futurear.set, MagicMock(), sentinel.val)

        # wait until we get notice we're being processed
        waitar.get(timeout=2)

        # cancel the SECOND call
        p.cancel_or_abort_call(ar2)

        # prove we didn't interrupt the current proc by allowing it to continue
        callar.set()
        ar.get(timeout=2)

        # now the second proc will get queued and never called because it is cancelled
        self.assertRaises(Timeout, futurear.get, timeout=2)
        self.assertTrue(ar2.ready())
示例#4
0
    def test__control_flow_expired_call(self):
        svc = self._make_service()
        p = IonProcessThread(name=sentinel.name, listeners=[], service=svc)
        p.start()
        p.get_ready_event().wait(timeout=5)
        self.addCleanup(p.stop)

        def make_call(call, ctx, val):
            ar = p._routing_call(call, ctx, val)
            return ar.get(timeout=10)

        ctx = { 'reply-by' : 0 }        # no need for real time, as it compares by CURRENT >= this value
        futurear = AsyncResult()
        with patch('pyon.ion.process.greenlet') as gcm:
            waitar = AsyncResult()
            gcm.getcurrent().kill.side_effect = lambda *a, **k: waitar.set()

            ar = p._routing_call(futurear.set, ctx, sentinel.val)

            waitar.get(timeout=10)

            # futurear is not set
            self.assertFalse(futurear.ready())

            # neither is the ar we got back from routing_call
            self.assertFalse(ar.ready())

            # we should've been killed, though
            self.assertEquals(gcm.getcurrent().kill.call_count, 1)
            self.assertIsInstance(gcm.getcurrent().kill.call_args[1]['exception'], IonTimeout)

        # put a new call through (to show unblocked)
        futurear2 = AsyncResult()
        ar2 = p._routing_call(futurear2.set, MagicMock(), sentinel.val2)
        ar2.get(timeout=2)
示例#5
0
    def test__interrupt_control_thread(self):
        svc = self._make_service()
        p = IonProcessThread(name=sentinel.name, listeners=[], service=svc)
        p.start()
        p.get_ready_event().wait(timeout=5)
        self.addCleanup(p.stop)

        # put a call in that will never finish
        waitar = AsyncResult()      # test specific, wait for this to indicate we're being processed/hung
        callar = AsyncResult()      # test specific, an ar that is just waited on by the spin call
        def spin(inar, outar):
            outar.set(True)
            inar.wait()

        ar = p._routing_call(spin, MagicMock(), callar, waitar)

        # wait until we get notice we're being processed
        waitar.get(timeout=2)

        # interrupt it
        p._interrupt_control_thread()

        # the ar we got back from routing_call will not be set, it never finished the call
        self.assertFalse(ar.ready())

        # to prove we're unblocked, run another call through the control thread
        ar2 = p._routing_call(callar.set, MagicMock(), sentinel.val)
        ar2.get(timeout=2)
        self.assertTrue(callar.ready())
        self.assertEquals(callar.get(), sentinel.val)
    def test_quit_stops_timers(self):

        ar = AsyncResult()
        def cb(*args, **kwargs):
            ar.set(args)

            self.interval_timer_count += 1

        event_origin = "test_quitter"
        sub = EventSubscriber(event_type="TimerEvent", callback=cb, origin=event_origin)
        sub.start()
        self.addCleanup(sub.stop)

        tid = self.ssclient.create_interval_timer(start_time="now",
                                                  interval=1,
                                                  event_origin=event_origin)

        # wait until at least one scheduled message
        ar.get(timeout=5)

        # shut it down!
        p = self.container.proc_manager.procs_by_name['scheduler']
        self.container.terminate_process(p.id)

        # assert empty
        self.assertEquals(p.schedule_entries, {})
 def test_result_cb_error(self):
     result = AsyncResult()
     DNSResolver._result_cb(result, 13, pycares.errno.ARES_ENOTFOUND)
     with self.assertRaises(DNSError) as cm:
         result.get()
     self.assertEqual('Domain name not found [ARES_ENOTFOUND]',
                      str(cm.exception))
示例#8
0
    def test_two_waiters_one_dies(self):

        def waiter(q, evt):
            evt.set(q.get())

        def do_receive(q, evt):
            timeout = gevent.Timeout.start_new(0, RuntimeError())
            try:
                try:
                    result = q.get()
                    evt.set(result)
                except RuntimeError:
                    evt.set('timed out')
            finally:
                timeout.cancel()

        q = queue.Queue()
        dying_evt = AsyncResult()
        waiting_evt = AsyncResult()
        gevent.spawn(do_receive, q, dying_evt)
        gevent.spawn(waiter, q, waiting_evt)
        gevent.sleep(0.01)
        q.put('hi')
        self.assertEquals(dying_evt.get(), 'timed out')
        self.assertEquals(waiting_evt.get(), 'hi')
class GConnection(Async):
    def __init__(self, *args, **kwargs):
        """
        This class is a 'GEvent'-optimized subclass of libcouchbase
        which utilizes the underlying IOPS structures and the gevent
        event primitives to efficiently utilize couroutine switching.
        """
        experimental.enabled_or_raise()
        super(GConnection, self).__init__(IOPS(), *args, **kwargs)

    def _do_ctor_connect(self):
        if self.connected:
            return

        self._connect()
        self._evconn = AsyncResult()
        self._conncb = self._on_connected
        self._evconn.get()
        self._evconn = None

    def _on_connected(self, err):
        if err:
            self._evconn.set_exception(err)
        else:
            self._evconn.set(None)

    def _waitwrap(self, cbasync):
        cur_thread = getcurrent()
        cbasync.callback = cur_thread.switch
        cbasync.errback = lambda r, x, y, z: cur_thread.throw(x, y, z)

        return get_hub().switch()

    def _meth_factory(meth, name):
        def ret(self, *args, **kwargs):
            return self._waitwrap(meth(self, *args, **kwargs))
        return ret

    def _http_request(self, **kwargs):
        res = super(GConnection, self)._http_request(**kwargs)
        if kwargs.get('chunked', False):
            return res #views

        e = Event()
        res._callback = lambda x, y: e.set()

        e.wait()

        res._maybe_raise()
        return res

    def query(self, *args, **kwargs):
        kwargs['itercls'] = GView
        ret = super(GConnection, self).query(*args, **kwargs)
        ret.start()
        return ret

    locals().update(Async._gen_memd_wrappers(_meth_factory))
示例#10
0
    def test_link_to_asyncresult(self):
        p = gevent.spawn(lambda: 100)
        event = AsyncResult()
        p.link(event)
        self.assertEqual(event.get(), 100)

        for i in range(3):
            event2 = AsyncResult()
            p.link(event2)
            self.assertEqual(event2.get(), 100)
    def _start_platform(self):
        """
        Starts the given platform waiting for it to transition to the
        UNINITIALIZED state (note that the agent starts in the LAUNCHING state).

        More in concrete the sequence of steps here are:
        - prepares subscriber to receive the UNINITIALIZED state transition
        - launches the platform process
        - waits for the start of the process
        - waits for the transition to the UNINITIALIZED state
        """
        ##############################################################
        # prepare to receive the UNINITIALIZED state transition:
        async_res = AsyncResult()

        def consume_event(evt, *args, **kwargs):
            log.debug("Got ResourceAgentStateEvent %s from origin %r", evt.state, evt.origin)
            if evt.state == PlatformAgentState.UNINITIALIZED:
                async_res.set(evt)

        # start subscriber:
        sub = EventSubscriber(event_type="ResourceAgentStateEvent",
                              origin=self.platform_device_id,
                              callback=consume_event)
        sub.start()
        log.info("registered event subscriber to wait for state=%r from origin %r",
                 PlatformAgentState.UNINITIALIZED, self.platform_device_id)
        #self._event_subscribers.append(sub)
        sub._ready_event.wait(timeout=EVENT_TIMEOUT)

        ##############################################################
        # now start the platform:
        agent_instance_id = self.platform_agent_instance_id
        log.debug("about to call start_platform_agent_instance with id=%s", agent_instance_id)
        pid = self.imsclient.start_platform_agent_instance(platform_agent_instance_id=agent_instance_id)
        log.debug("start_platform_agent_instance returned pid=%s", pid)

        #wait for start
        agent_instance_obj = self.imsclient.read_platform_agent_instance(agent_instance_id)
        gate = AgentProcessStateGate(self.processdispatchclient.read_process,
                                     self.platform_device_id,
                                     ProcessStateEnum.RUNNING)
        self.assertTrue(gate.await(90), "The platform agent instance did not spawn in 90 seconds")

        # Start a resource agent client to talk with the agent.
        self._pa_client = ResourceAgentClient(self.platform_device_id,
                                              name=gate.process_id,
                                              process=FakeProcess())
        log.debug("got platform agent client %s", str(self._pa_client))

        ##############################################################
        # wait for the UNINITIALIZED event:
        async_res.get(timeout=self._receive_timeout)
示例#12
0
 def test_wait_noerrors(self):
     x = gevent.spawn(lambda: 1)
     y = gevent.spawn(lambda: 2)
     z = gevent.spawn(lambda: 3)
     gevent.joinall([x, y, z], raise_error=True)
     self.assertEqual([x.value, y.value, z.value], [1, 2, 3])
     e = AsyncResult()
     x.link(e)
     self.assertEqual(e.get(), 1)
     x.unlink(e)
     e = AsyncResult()
     x.link(e)
     self.assertEqual(e.get(), 1)
示例#13
0
    def test_set(self):
        event1 = AsyncResult()
        timer_exc = MyException('interrupted')

        # Notice that this test is racy:
        # After DELAY, we set the event. We also try to immediately
        # raise the exception with a timer of 0 --- but that depends
        # on cycling the loop. Hence the fairly large value for DELAY.
        g = gevent.spawn_later(DELAY, event1.set, 'hello event1')
        self._close_on_teardown(g.kill)
        with gevent.Timeout.start_new(0, timer_exc):
            with self.assertRaises(MyException) as exc:
                event1.get()
            self.assertIs(timer_exc, exc.exception)
示例#14
0
class Future:
    def __init__(self):
        self.result = AsyncResult()

    def set(self, value):
        self.result.set(value)

    def get(self):
        return self.result.get()

    def on_ready(self, func):
        while self.result.ready() != False:
            gevent.sleep(0)
        func(self.result.get())
示例#15
0
 def request(self, service_name, data=""):
     """
     这里将数据写到缓冲队列,然后让当前请求协程在event上等待
     """
     if self._is_closed:
         logging.error("request in a close cliet")
         raise Exception("connection closed")
     rid = self.rid
     req = (service_name, data, rid)
     req_data = cp_dumps(req)
     req_data_len = len(req_data)
     head = s_pack("i", req_data_len)
     self._send_data.extend((head, req_data))
     if not self._write_open:
         self._write()                                          # 立即尝试写一下,可以降低延迟
         self._start_write()
     event = AsyncResult()
     self._events[rid] = event
     try:
         out = event.get(timeout=DEFAULT_REQUEST_TIMEOUT)       # 在这个event上面等待,阻塞当前协程
         if self._is_closed:
             raise Exception("connection disconnected")
         return out
     finally:
         del self._events[rid]
示例#16
0
 def call(self, protoname, msg):
     session = self._get_session()
     pack = proto.request(protoname, msg, session)
     ev = AsyncResult()
     self._sessions[session] = ev
     self._send(pack)
     return ev.get()
示例#17
0
        def rpc(request=None, conn=None, connections=None, timeout=None,
                **kwargs):
            request = request or request_class(**kwargs)

            meta = self.meta
            meta.Clear()
            meta.service_method = service_method
            meta.packet_type = packet_type
            if connections is not None:
                for conn in connections:
                    conn.send(conn.pack_meta(meta, request))
            else:
                conn = conn or self.conn or \
                    self.connection_pool.get_connection()
                assert conn, conn
                if require_response:
                    meta.transmission_id = conn.transmission_id
                conn.transmission_id += 1
                conn.send(conn.pack_meta(meta, request))

                if hasattr(conn, 'release'):
                    conn.release()
                if not require_response:
                    return

                async_result = AsyncResult()
                conn.transmissions[meta.transmission_id] = async_result
                return async_result.get(timeout=timeout or self.timeout)
示例#18
0
文件: producer.py 项目: wtolson/gnsq
    def multipublish(self, topic, messages, block=True, timeout=None,
                     raise_error=True):
        """Publish an iterable of messages to the given topic.

        :param topic: the topic to publish to

        :param messages: iterable of bytestrings to publish

        :param block: wait for a connection to become available before
            publishing the message. If block is `False` and no connections
            are available, :class:`~gnsq.errors.NSQNoConnections` is raised

        :param timeout: if timeout is a positive number, it blocks at most
            ``timeout`` seconds before raising
            :class:`~gnsq.errors.NSQNoConnections`

        :param raise_error: if ``True``, it blocks until a response is received
            from the nsqd server, and any error response is raised. Otherwise
            an :class:`~gevent.event.AsyncResult` is returned
        """
        result = AsyncResult()
        conn = self._get_connection(block=block, timeout=timeout)

        try:
            self._response_queues[conn].append(result)
            conn.multipublish(topic, messages)
        finally:
            self._put_connection(conn)

        if raise_error:
            return result.get()

        return result
示例#19
0
文件: tests.py 项目: cordis/spinoff
def actor_exec(node, fn, *args, **kwargs):
    class ExecActor(Actor):
        def run(self):
            ret.set(fn(*args, **kwargs))
    ret = AsyncResult()
    node.spawn(ExecActor)
    return ret.get()
示例#20
0
    def request_many(self, reqs):
        """
        salvo simultaneous query many service and get result
        """
        local_quests = {}
        idx = 0
        while idx < len(reqs):
            req = reqs[idx]
            ar = AsyncResult()
            qid = self.next_qid()
            self.emit_query(qid, *req)
            self._query_list[qid] = ar
            local_quests[qid] = (idx, ar)
            idx += 1

        for qid, it in local_quests.items():
            idx, ar = it
            """
            async result will always get a response even if other query
            reply soon

            """
            msg = ar.get()
            if msg:
                if msg.status:
                    yield ProxyError(qid, msg.status, msg.params), idx
                else:
                    yield msg.data, idx
示例#21
0
文件: channel.py 项目: swarbhanu/pyon
    def _sync_call(self, func, cb_arg, *args, **kwargs):
        """
        Functionally similar to the generic blocking_cb but with error support that's Channel specific.
        """
        ar = AsyncResult()

        def cb(*args, **kwargs):
            ret = list(args)
            if len(kwargs): ret.append(kwargs)
            ar.set(ret)

        def eb(ch, code, text):
            ar.set(ChannelError("_sync_call could not complete due to an error (%d): %s" % (code, text)))

        kwargs[cb_arg] = cb
        with self.push_closed_error_callback(eb):
            func(*args, **kwargs)
            ret_vals = ar.get(timeout=10)

        if isinstance(ret_vals, ChannelError):
            raise ret_vals

        if len(ret_vals) == 0:
            return None
        elif len(ret_vals) == 1:
            return ret_vals[0]
        return tuple(ret_vals)
示例#22
0
文件: twist.py 项目: smurfix/HomEvenT
def sleepUntil(force,delta):
	from homevent.times import unixdelta,now

	if isinstance(delta,dt.datetime):
		delta = delta - now()
	if isinstance(delta,dt.timedelta):
		delta = unixdelta(delta)
	if delta < 0: # we're late
		delta = 0 # but let's hope not too late

	if "HOMEVENT_TEST" in os.environ:
		ev = AsyncResult()
		callLater(force,delta, ev.set,None)
		ev.get(block=True)
	else:
		gevent.sleep(delta)
示例#23
0
    def test_known_error(self):

        # IonExceptions and TypeErrors get forwarded back intact
        svc = self._make_service()
        p = IonProcessThread(name=sentinel.name, listeners=[], service=svc)
        p.start()
        p.get_ready_event().wait(timeout=5)
        self.addCleanup(p.stop)

        def proc_call():
            raise NotFound("didn't find it")

        def client_call(p=None, ar=None):
            try:
                ca = p._routing_call(proc_call, None)
                ca.get(timeout=5)

            except IonException as e:
                ar.set(e)

        ar = AsyncResult()
        gl_call = spawn(client_call, p=p, ar=ar)

        e = ar.get(timeout=5)

        self.assertIsInstance(e, NotFound)
示例#24
0
def test_watching_new_actor(defer):
    class Watcher(Actor):
        def pre_start(self):
            a = self.spawn(Actor)
            a.stop()
            watchee.set(a)
            self.watch(a)

        def receive(self, message):
            message_receieved.set((self.sender, message))

    node = DummyNode()
    defer(node.stop)
    watchee, message_receieved = AsyncResult(), AsyncResult()
    node.spawn(Watcher)
    eq_(message_receieved.get(), (watchee.get(), ('terminated', watchee.get())))
    def wait_event(self, event, timeout=None, raises=False):
        """
        Blocks until an event and returns the results

        :param event: event identifier
        :param timeout: (optional)(default:None) seconds to wait
        :type timeout: :class:`int`
        :param raises: (optional)(default:False) On timeout if ``False`` return ``None``, else raise ``gevent.Timeout``
        :type raises: :class:`bool`
        :return: returns event arguments in tuple
        :rtype: :class:`None`, or :class:`tuple`
        :raises: ``gevent.Timeout``

        Handling timeout

        .. code:: python

            args = ee.wait_event('my event', timeout=5)
            if args is None:
                print "Timeout!"

        """
        result = AsyncResult()
        self.once(event, result)

        try:
            return result.get(True, timeout)
        except gevent.Timeout:
            self.remove_listener(event, result)

            if raises:
                raise
            else:
                return None
示例#26
0
    def test_link_to_asyncresult_exception(self):
        err = ExpectedError('test_link_to_asyncresult_exception')
        p = gevent.spawn(lambda: getcurrent().throw(err))
        event = AsyncResult()
        p.link(event)
        with self.assertRaises(ExpectedError) as exc:
            event.get()

        self.assertIs(exc.exception, err)

        for _ in range(3):
            event2 = AsyncResult()
            p.link(event2)
            with self.assertRaises(ExpectedError) as exc:
                event2.get()
            self.assertIs(exc.exception, err)
示例#27
0
    def test_unknown_error(self):

        # Unhandled exceptions get handled and then converted to ContainerErrors
        svc = self._make_service()
        p = IonProcessThread(name=sentinel.name, listeners=[], service=svc)
        p.start()
        p.get_ready_event().wait(timeout=5)
        self.addCleanup(p.stop)

        def proc_call():
            raise self.ExpectedError("didn't find it")

        def client_call(p=None, ar=None):
            try:
                ca = p._routing_call(proc_call, None)
                ca.get(timeout=5)

            except IonException as e:
                ar.set(e)

        ar = AsyncResult()
        gl_call = spawn(client_call, p=p, ar=ar)

        e = ar.get(timeout=5)

        self.assertIsInstance(e, ContainerError)
        self.assertEquals(len(p._errors), 1)
示例#28
0
    def _sync_call(self, func, cb_arg, *args, **kwargs):
        """
        Functionally similar to the generic blocking_cb but with error support that's Channel specific.
        """
        ar = AsyncResult()

        def cb(*args, **kwargs):
            ret = list(args)
            if len(kwargs): ret.append(kwargs)
            ar.set(ret)

        eb = lambda ch, *args: ar.set(TransportError("_sync_call could not complete due to an error (%s)" % args))

        kwargs[cb_arg] = cb
        with self._push_close_cb(eb):
            func(*args, **kwargs)
            ret_vals = ar.get(timeout=10)

        if isinstance(ret_vals, TransportError):

            # mark this channel as poison, do not use again!
            # don't test for type here, we don't want to have to import PyonSelectConnection
            if hasattr(self._client.transport, 'connection') and hasattr(self._client.transport.connection, 'mark_bad_channel'):
                self._client.transport.connection.mark_bad_channel(self._client.channel_number)
            else:
                log.warn("Could not mark channel # (%s) as bad, Pika could be corrupt", self._client.channel_number)

            raise ret_vals

        if len(ret_vals) == 0:
            return None
        elif len(ret_vals) == 1:
            return ret_vals[0]
        return tuple(ret_vals)
示例#29
0
    def fetch_hashchain(self):
        log_st.debug('fetching hashchain')
        blockhashes_chain = [self.blockhash]  # youngest to oldest

        blockhash = self.blockhash
        assert blockhash not in self.chain

        # get block hashes until we found a known one
        max_blockhashes_per_request = self.initial_blockhashes_per_request
        while blockhash not in self.chain:
            # proto with highest_difficulty should be the proto we got the newblock from
            blockhashes_batch = []

            # try with protos
            protocols = self.synchronizer.protocols
            if not protocols:
                log_st.warn('no protocols available')
                return self.exit(success=False)

            for proto in protocols:
                if proto.is_stopped:
                    continue

                # request
                assert proto not in self.requests
                deferred = AsyncResult()
                self.requests[proto] = deferred
                proto.send_getblockhashes(blockhash, max_blockhashes_per_request)
                try:
                    blockhashes_batch = deferred.get(block=True,
                                                     timeout=self.blockhashes_request_timeout)
                except gevent.Timeout:
                    log_st.warn('syncing timed out')
                    continue
                finally:
                    # is also executed 'on the way out' when any other clause of the try statement
                    # is left via a break, continue or return statement.
                    del self.requests[proto]

                if not blockhashes_batch:
                    log_st.warn('empty getblockhashes result')
                    continue
                if not all(isinstance(bh, bytes) for bh in blockhashes_batch):
                    log_st.warn('got wrong data type', expected='bytes',
                                received=type(blockhashes_batch[0]))
                    continue
                break

            for blockhash in blockhashes_batch:  # youngest to oldest
                assert isinstance(blockhash, bytes)
                if blockhash not in self.chain:
                    blockhashes_chain.append(blockhash)
                else:
                    log_st.debug('found known blockhash', blockhash=blockhash.encode('hex'),
                                 is_genesis=bool(blockhash == self.chain.genesis.hash))
                    break
            max_blockhashes_per_request = self.max_blockhashes_per_request

        self.fetch_blocks(blockhashes_chain)
示例#30
0
    def execution_result(executor):
        result = AsyncResult()
        deferred = executor()
        assert isinstance(deferred, Deferred), 'Another middleware has converted the execution result ' \
                                               'away from a Deferred.'

        deferred.add_callbacks(result.set, lambda e: result.set_exception(e.value, (e.type, e.value, e.traceback)))
        return result.get()
示例#31
0
    def test_set(self):
        event1 = AsyncResult()
        event2 = AsyncResult()

        g = gevent.spawn_later(DELAY / 2.0, event1.set, 'hello event1')
        t = gevent.Timeout.start_new(0, ValueError('interrupted'))
        try:
            try:
                result = event1.get()
            except ValueError as ex:
                X = object()
                result = gevent.with_timeout(DELAY,
                                             event2.get,
                                             timeout_value=X)
                assert result is X, 'Nobody sent anything to event2 yet it received %r' % (
                    result, )
                if PY3:
                    ex.__traceback__ = None
        finally:
            t.cancel()
            g.kill()
示例#32
0
def test_watching_running_remote_actor_that_stops_causes_termination_message(
        defer):
    class Watcher(Actor):
        def pre_start(self):
            self.watch(
                self.root.node.lookup_str('localhost:20002/remote-watchee'))

        def receive(self, msg):
            received.set(msg)

    received = AsyncResult()
    node1, node2 = Node('localhost:20001',
                        enable_remoting=True), Node('localhost:20002',
                                                    enable_remoting=True)
    defer(node1.stop, node2.stop)

    remote_watchee = node2.spawn(Actor, name='remote-watchee')
    node1.spawn(Watcher)
    remote_watchee.stop()

    eq_(received.get(), ('terminated', remote_watchee))
示例#33
0
    def send(self, destination, command, payload, allowed_replies):
        result = AsyncResult()

        def callback(reply):
            result.set(reply)

        def error_callback(reply):
            result.set(reply)

        defer = new_defer(
            callback, error_callback, self.verify(allowed_replies),
            allowed_replies,
            new_message(destination, command,
                        self.getNextSequenceNumberAsPrefixPayload() + payload),
            int(round(time.time() * 1000)) + 10000)
        tasks.put_nowait(defer)

        message = result.get()  # blocking

        # received ack from Agent
        return message
示例#34
0
    def stop_tcp_server(self, data, reply_address):
        DBG("NetoolCommandServer stop_tcp_server %r" % data)
        try:
            conn_greenlets[data['name']]['greenlet'].kill(exception=StopServer,
                                                          block=False)

            result = AsyncResult()
            conn_greenlets[data['name']]['result'] = result
            re = result.get()
            value = re['result']
            if value != 'ok':
                del (conn_greenlets[data['name']])
            re = self.socket.sendto(json.dumps(re), reply_address)
            DBG("sent %d" % re)
        except:
            DBG_TRACE()
            self.socket.sendto(
                json.dumps({
                    'result': 'error',
                    'msg': base64.b64encode(sys.exc_info()[1])
                }), reply_address)
示例#35
0
def receive():
    """Generator that yields a message at least every KEEP_ALIVE_DELAY seconds.

    yields messages sent by `broadcast`.

    """
    now = time.time()
    end = now + MAX_DURATION
    tmp = None
    # Heroku doesn't notify when clients disconnect so we have to impose a
    # maximum connection duration.
    while now < end:
        if not tmp:
            tmp = AsyncResult()
            BROADCAST_QUEUE.put(tmp)
        try:
            yield tmp.get(timeout=KEEP_ALIVE_DELAY)
            tmp = None
        except Timeout:
            yield ''
        now = time.time()
示例#36
0
def waitForDeferred(d, result=None):
    """Block current greenlet for Deferred, waiting until result is not a Deferred or a failure is encountered"""
    from twisted.internet import reactor
    assert reactor.greenlet != getcurrent(), "can't invoke this in the reactor greenlet"
    if result is None:
        result = AsyncResult()

    def cb(res):
        if isinstance(res, defer.Deferred):
            waitForDeferred(res, result)
        else:
            result.set(res)

    def eb(res):
        result.set_exception(res)

    d.addCallbacks(cb, eb)
    try:
        return result.get()
    except failure.Failure, ex:
        ex.raiseException()
示例#37
0
    def _sync_call(self, func, cb_arg, *args, **kwargs):
        """
        Functionally similar to the generic blocking_cb but with error support that's Channel specific.
        """
        ar = AsyncResult()

        def cb(*args, **kwargs):
            ret = list(args)
            if len(kwargs): ret.append(kwargs)
            ar.set(ret)

        eb = lambda ch, *args: ar.set(
            TransportError("_sync_call could not complete due to an error (%s)"
                           % args))

        kwargs[cb_arg] = cb
        with self._push_close_cb(eb):
            func(*args, **kwargs)
            ret_vals = ar.get(timeout=10)

        if isinstance(ret_vals, TransportError):

            # mark this channel as poison, do not use again!
            # don't test for type here, we don't want to have to import PyonSelectConnection
            if hasattr(self._client.transport, 'connection') and hasattr(
                    self._client.transport.connection, 'mark_bad_channel'):
                self._client.transport.connection.mark_bad_channel(
                    self._client.channel_number)
            else:
                log.warn(
                    "Could not mark channel # (%s) as bad, Pika could be corrupt",
                    self._client.channel_number)

            raise ret_vals

        if len(ret_vals) == 0:
            return None
        elif len(ret_vals) == 1:
            return ret_vals[0]
        return tuple(ret_vals)
示例#38
0
    def get(self):
        def watcher(event):
            if event.type in (EventType.CREATED, EventType.CHANGED):
                _data, _stats = zk.get(job_status_path)
                async_result.set((_data, _stats))

        tid = self.get_argument("tid")
        version = int(self.get_argument("version", -1))
        job_status_path = os.path.join(ZK_JOB_STATUS_PATH, tid)
        try:
            raw_data, stats = zk.get(job_status_path)
        except NoNodeError:
            raise DoesNotExist("job status doesn't exists")

        if version > stats.version:
            raise ValidationError("job status version too large")
        elif version == stats.version:
            async_result = AsyncResult()
            zk.exists(job_status_path, watch=watcher)
            raw_data, stats = async_result.get()

        try:
            data = json.loads(raw_data)
            # for compatible with 'undo' status set by GANGR
            # regard this as common unfinished status like 'unknown','doing' and ignore it
            if data['status'] == 'undo':
                pass
            elif Status[data['status']] in finished_statuses:
                Deployment.set_status(tid, Status[data['status']])
        except Exception as e:
            Deployment.set_status(tid, Status.error)
            raise TemporaryServerError("fetched status illegal: %s" % e)

        ret = {
            "version": stats.version,
            "data": data,
        }
        self.write_json(ret)
示例#39
0
    def disconnect_accepted(self, data, reply_address):
        DBG("NetoolCommandServer disconnect_accepted %r" % data)
        try:
            if not data['accepted_name'] in conn_greenlets:  # already closed
                self.socket.sendto(json.dumps({'result': 'ok'}), reply_address)
                return
            conn_greenlets[data['accepted_name']]['greenlet'].kill(
                exception=CloseSocket, block=False)

            result = AsyncResult()
            conn_greenlets[data['accepted_name']]['result'] = result
            value = result.get()
            conn_greenlets[data['accepted_name']]['greenlet'].join()
            del conn_greenlets[data['accepted_name']]
            re = self.socket.sendto(json.dumps(value), reply_address)
            DBG("sent %d" % re)
        except:
            DBG_TRACE()
            self.socket.sendto(
                json.dumps({
                    'result': 'error',
                    'msg': base64.b64encode(sys.exc_info()[1])
                }), reply_address)
示例#40
0
    def multipublish(self,
                     topic,
                     messages,
                     block=True,
                     timeout=None,
                     raise_error=True):
        """Publish an iterable of messages to the given topic.

        :param topic: the topic to publish to

        :param messages: iterable of bytestrings to publish

        :param block: wait for a connection to become available before
            publishing the message. If block is `False` and no connections
            are available, :class:`~gnsq.errors.NSQNoConnections` is raised

        :param timeout: if timeout is a positive number, it blocks at most
            ``timeout`` seconds before raising
            :class:`~gnsq.errors.NSQNoConnections`

        :param raise_error: if ``True``, it blocks until a response is received
            from the nsqd server, and any error response is raised. Otherwise
            an :class:`~gevent.event.AsyncResult` is returned
        """
        result = AsyncResult()
        conn = self._get_connection(block=block, timeout=timeout)

        try:
            self._response_queues[conn].append(result)
            conn.multipublish(topic, messages)
        finally:
            self._put_connection(conn)

        if raise_error:
            return result.get()

        return result
示例#41
0
    def test_competing__routing_call(self):
        svc = self._make_service()
        p = IonProcessThread(name=sentinel.name, listeners=[], service=svc)
        p.start()
        p.get_ready_event().wait(timeout=5)

        sem = Semaphore()

        # define a callable method that tries to grab a shared semaphore
        def thecall(ar=None):

            semres = sem.acquire(blocking=False)
            if not semres:
                raise StandardError(
                    "Could not get semaphore, routing_call/control flow is broken!"
                )

            # make this take a sec
            time.sleep(1)

            # make sure we release
            sem.release()

            # set the ar
            ar.set(True)

        # schedule some calls (in whatever order)
        ar1 = AsyncResult()
        ar2 = AsyncResult()
        ar3 = AsyncResult()

        p._routing_call(thecall, None, ar=ar3)
        p._routing_call(thecall, None, ar=ar1)
        p._routing_call(thecall, None, ar=ar2)

        # wait on all the ARs to be set
        ar1.get(timeout=5)
        ar2.get(timeout=5)
        ar3.get(timeout=5)

        # just getting here without throwing an exception is the true test!

        p._notify_stop()
        p.stop()
示例#42
0
                def subprocess_stopped(result: AsyncResult) -> None:
                    if janitor._exit_in_progress:
                        # During __exit__ we expect processes to stop, since
                        # they are killed by the janitor.
                        return

                    with janitor._processes_lock:
                        # Processes are expected to quit while the nursery is
                        # active, remove them from the track list to clear memory
                        janitor._processes.remove(process)

                        # if the subprocess error'ed propagate the error.
                        try:
                            exit_code = result.get()
                            if exit_code != STATUS_CODE_FOR_SUCCESS:
                                log.error(
                                    "Process died! Bailing out.",
                                    args=process.args,
                                    exit_code=exit_code,
                                )
                                exception = SystemExit(exit_code)
                                janitor._stop.set_exception(exception)
                        except Exception as exception:
                            janitor._stop.set_exception(exception)
示例#43
0
def wait_for_events(events, timeout=None):
    def _remove():
        for event in events:
            remove(event, on_event)

    def on_event(*args, **kwargs):
        _remove()
        result.set([args, kwargs])

    if timeout:
        timeout = gevent.Timeout(
            timeout,
            RuntimeError('timeout while waiting for events: {}'.format(
                ', '.join(events))))
        timeout.start()
    try:
        result = AsyncResult()
        for event in events:
            add(event, on_event)
        return result.get()
    finally:
        if timeout:
            timeout.cancel()
        _remove()
class Qt4_DiffractometerMockup(HardwareObject):
    """
    Descript. :
    """
    MANUAL3CLICK_MODE = "Manual 3-click"
    C3D_MODE = "Computer automatic"
    MOVE_TO_BEAM_MODE = "Move to Beam"

    def __init__(self, *args):
        """
        Descript. :
        """
        HardwareObject.__init__(self, *args)

        qmo.CentredPosition.set_diffractometer_motor_names(\
            "phi", "focus", "phiz", "phiy", "zoom",
            "sampx", "sampy", "kappa", "kappa_phi")
        self.phiMotor = None
        self.phizMotor = None
        self.phiyMotor = None
        self.lightMotor = None
        self.zoomMotor = None
        self.sampleXMotor = None
        self.sampleYMotor = None
        self.camera = None

        self.beam_position = None
        self.x_calib = None
        self.y_calib = None
        self.pixels_per_mm_x = None
        self.pixels_per_mm_y = None
        self.image_width = None
        self.image_height = None
        self.current_sample_info = None
        self.cancel_centring_methods = None
        self.current_centring_procedure = None
        self.current_centring_method = None
        self.current_positions_dict = None
        self.centring_methods = None
        self.centring_status = None
        self.centring_time = None
        self.user_confirms_centring = None
        self.user_clicked_event = None
        self.phase_list = None

        self.connect(self, 'equipmentReady', self.equipmentReady)
        self.connect(self, 'equipmentNotReady', self.equipmentNotReady)

        #IK - this will be sorted out
        self.startCentringMethod = self.start_centring_method
        self.cancelCentringMethod = self.cancel_centring_method
        self.imageClicked = self.image_clicked
        self.acceptCentring = self.accept_centring
        self.rejectCentring = self.reject_centring
        self.getCentringStatus = self.get_centring_status
        self.takeSnapshots = self.take_snapshots
        self.moveMotors = self.move_motors

    def init(self):
        """
        Descript. :
        """
        self.x_calib = 0.000444
        self.y_calib = 0.000446
         
        self.pixels_per_mm_x = 1.0 / self.x_calib
        self.pixels_per_mm_y = 1.0 / self.y_calib
        self.beam_position = [200, 200]
        
        self.centring_methods = {
             Qt4_DiffractometerMockup.MANUAL3CLICK_MODE: self.start_3Click_centring,
             Qt4_DiffractometerMockup.C3D_MODE: self.start_automatic_centring}
        self.cancel_centring_methods = {}
        self.current_positions_dict = {'phiy'  : 0, 'phiz' : 0, 'sampx' : 0,
                                       'sampy' : 0, 'zoom' : 0, 'phi' : 17.6,
                                       'focus' : 0, 'kappa': 0, 'kappa_phi': 0,
                                       'beam_x': 0, 'beam_y': 0} 
        self.current_state_dict = {}
        self.centring_status = {"valid": False}
        self.centring_time = 0
        self.user_confirms_centring = True
        self.user_clicked_event = AsyncResult()

        self.image_width = 400
        self.image_height = 400

        self.equipmentReady()
        self.user_clicked_event = AsyncResult()

        self.phi_motor_hwobj = self.getObjectByRole('phi')
        if self.phi_motor_hwobj is not None:
            self.connect(self.phi_motor_hwobj, 'stateChanged', self.phi_motor_state_changed)
            self.connect(self.phi_motor_hwobj, "positionChanged", self.phi_motor_moved)

        self.reversing_rotation = self.getProperty("reversingRotation")
        try:
            self.grid_direction = eval(self.getProperty("gridDirection"))
        except:
            self.grid_direction = {"fast": (0, 1), "slow": (1, 0)}

        try:
            self.phase_list = eval(self.getProperty("phaseList"))
        except:
            self.phase_list = ['demo']


    def getStatus(self):
        """
        Descript. :
        """
        return "ready"

    def in_plate_mode(self):
        return True

    def is_reversing_rotation(self):
        return True

    def get_grid_direction(self):
        """
        Descript. :
        """
        return self.grid_direction

    def manual_centring(self):
        """
        Descript. :
        """
        self.user_clicked_event = AsyncResult()
        x, y = self.user_clicked_event.get()
        last_centred_position[0] = x
        last_centred_position[1] = y
        random_num = random.random()
        centred_pos_dir = {'phiy': random_num * 10, 'phiz': random_num, 
                         'sampx': 0.0, 'sampy': 9.3, 'zoom': 8.53,
                         'phi': 311.1, 'focus': -0.42, 'kappa': 0.0009, 
                         ' kappa_phi': 311.0}
        return centred_pos_dir 		

    def set_sample_info(self, sample_info):
        """
        Descript. :
        """
        self.current_sample_info = sample_info
	
    def emit_diffractometer_moved(self, *args):
        """
        Descript. :
        """
        self.emit("diffractometerMoved", ())
	
    def isReady(self):
        """
        Descript. :
        """ 
        return True

    def isValid(self):
        """
        Descript. :
        """
        return True

    def equipmentReady(self):
        """
        Descript. :
        """
        self.emit('minidiffReady', ())

    def equipmentNotReady(self):
        """
        Descript. :
        """
        self.emit('minidiffNotReady', ())

    def phi_motor_moved(self, pos):
        """
        Descript. :
        """
        self.current_positions_dict["phi"] = pos
        self.emit_diffractometer_moved()
        self.emit("phiMotorMoved", pos)
        #self.emit('stateChanged', (self.current_state_dict["phi"], ))

    def phi_motor_state_changed(self, state):
        """
        Descript. :
        """
        self.current_state_dict["phi"] = state
        self.emit('stateChanged', (state, ))

    def invalidate_centring(self):
        """
        Descript. :
        """
        if self.current_centring_procedure is None and self.centring_status["valid"]:
            self.centring_status = {"valid":False}
            self.emitProgressMessage("")
            self.emit('centringInvalid', ())

    def get_centred_point_from_coord(self, x, y, return_by_names=None):
        """
        Descript. :
        """
        random_num = random.random() 
        centred_pos_dir = {'phiy': random_num * 10, 'phiz': random_num,
                          'sampx': 0.0, 'sampy': 9.3, 'zoom': 8.53,
                          'phi': 311.1, 'focus': -0.42, 'kappa': 0.0009,
                          'kappa_phi': 311.0}
        return centred_pos_dir

    def get_available_centring_methods(self):
        """
        Descript. :
        """
        return self.centring_methods.keys()

    def get_calibration_data(self, offset):
        """
        Descript. :
        """
        #return (1.0 / self.x_calib, 1.0 / self.y_calib)
        return (1.0 / self.x_calib, 1.0 / self.y_calib)

    def get_pixels_per_mm(self):
        """
        Descript. :
        """
        return (self.pixels_per_mm_x, self.pixels_per_mm_y)

    def refresh_omega_reference_position(self):
        """
        Descript. :
        """
        return

    def get_omega_axis_position(self):	
        """
        Descript. :
        """
        return self.current_positions_dict.get("phi")     

    def get_positions(self):
        """
        Descript. :
        """
        return self.current_positions_dict

    def get_current_positions_dict(self):
        """
        Descript. :
        """
        return self.current_positions_dict

    def beam_position_changed(self, value):
        """
        Descript. :
        """
        self.beam_position = value
  
    def start_centring_method(self, method, sample_info = None):
        """
        Descript. :
        """
        if self.current_centring_method is not None:
            logging.getLogger("HWR").error("already in centring method %s" %\
                    self.current_centring_method)
            return
        curr_time = time.strftime("%Y-%m-%d %H:%M:%S")
        self.centring_status = {"valid": False, "startTime": curr_time}
        self.emit_centring_started(method)
        try:
            fun = self.centring_methods[method]
        except KeyError, diag:
            logging.getLogger("HWR").error("unknown centring method (%s)" % \
                    str(diag))
            self.emit_centring_failed()
        else:
示例#45
0
class _Socket(_original_Socket):
    """Green version of :class:`zmj.core.socket.Socket`

    The following methods are overridden:

        * send
        * recv

    To ensure that the ``zmq.NOBLOCK`` flag is set and that sending or recieving
    is deferred to the hub if a ``zmq.EAGAIN`` (retry) error is raised.

    The `__state_changed` method is triggered when the zmq.FD for the socket is
    marked as readable and triggers the necessary read and write events (which
    are waited for in the recv and send methods).

    Some double underscore prefixes are used to minimize pollution of
    :class:`zmj.core.socket.Socket`'s namespace.
    """
    def __init__(self, context, socket_type):
        self.__setup_events()

    def close(self):
        # close the _state_event event, keeps the number of active file descriptors down
        if not self._closed and getattr(self, '_state_event', None):
            try:
                self._state_event.stop()
            except AttributeError as e:
                # gevent<1.0 compat
                self._state_event.cancel()
        super(_Socket, self).close()

    def __setup_events(self):
        self.__readable = AsyncResult()
        self.__writable = AsyncResult()
        try:
            self._state_event = get_hub().loop.io(self.getsockopt(FD),
                                                  1)  # read state watcher
            self._state_event.start(self.__state_changed)
        except AttributeError:
            # for gevent<1.0 compatibility
            from gevent.core import read_event
            self._state_event = read_event(self.getsockopt(FD),
                                           self.__state_changed,
                                           persist=True)

    def __state_changed(self, event=None, _evtype=None):
        try:
            if self.closed:
                # if the socket has entered a close state resume any waiting greenlets
                self.__writable.set()
                self.__readable.set()
                return
            events = self.getsockopt(zmq.EVENTS)
        except ZMQError as exc:
            self.__writable.set_exception(exc)
            self.__readable.set_exception(exc)
        else:
            if events & zmq.POLLOUT:
                self.__writable.set()
            if events & zmq.POLLIN:
                self.__readable.set()

    def _wait_write(self):
        self.__writable = AsyncResult()
        self.__writable.get()

    def _wait_read(self):
        self.__readable = AsyncResult()
        self.__readable.get()

    def send(self, data, flags=0, copy=True, track=False):
        # if we're given the NOBLOCK flag act as normal and let the EAGAIN get raised
        if flags & zmq.NOBLOCK:
            return super(_Socket, self).send(data, flags, copy, track)
        # ensure the zmq.NOBLOCK flag is part of flags
        flags |= zmq.NOBLOCK
        while True:  # Attempt to complete this operation indefinitely, blocking the current greenlet
            try:
                # attempt the actual call
                return super(_Socket, self).send(data, flags, copy, track)
            except zmq.ZMQError as e:
                # if the raised ZMQError is not EAGAIN, reraise
                if e.errno != zmq.EAGAIN:
                    raise
            # defer to the event loop until we're notified the socket is writable
            self._wait_write()

    def recv(self, flags=0, copy=True, track=False):
        if flags & zmq.NOBLOCK:
            return super(_Socket, self).recv(flags, copy, track)
        flags |= zmq.NOBLOCK
        while True:
            try:
                return super(_Socket, self).recv(flags, copy, track)
            except zmq.ZMQError as e:
                if e.errno != zmq.EAGAIN:
                    raise
            self._wait_read()
示例#46
0
 def run_watcher(self):
     res = AsyncResult()
     self.watch_q.put(res)
     return res.get()
示例#47
0
class _Socket(_original_Socket):
    """Green version of :class:`zmq.core.socket.Socket`

    The following methods are overridden:

        * send
        * recv

    To ensure that the ``zmq.NOBLOCK`` flag is set and that sending or recieving
    is deferred to the hub if a ``zmq.EAGAIN`` (retry) error is raised.
    
    The `__state_changed` method is triggered when the zmq.FD for the socket is
    marked as readable and triggers the necessary read and write events (which
    are waited for in the recv and send methods).

    Some double underscore prefixes are used to minimize pollution of
    :class:`zmq.core.socket.Socket`'s namespace.
    """
    def __init__(self, context, socket_type):
        self.__in_send_multipart = False
        self.__in_recv_multipart = False
        self.__setup_events()

    def __del__(self):
        self.close()

    def close(self, linger=None):
        super(_Socket, self).close(linger)
        self.__cleanup_events()

    def __cleanup_events(self):
        # close the _state_event event, keeps the number of active file descriptors down
        if getattr(self, '_state_event', None):
            _stop(self._state_event)
            self._state_event = None
        # if the socket has entered a close state resume any waiting greenlets
        self.__writable.set()
        self.__readable.set()

    def __setup_events(self):
        self.__readable = AsyncResult()
        self.__writable = AsyncResult()
        self.__readable.set()
        self.__writable.set()

        try:
            self._state_event = get_hub().loop.io(self.getsockopt(zmq.FD),
                                                  1)  # read state watcher
            self._state_event.start(self.__state_changed)
        except AttributeError:
            # for gevent<1.0 compatibility
            from gevent.core import read_event
            self._state_event = read_event(self.getsockopt(zmq.FD),
                                           self.__state_changed,
                                           persist=True)

    def __state_changed(self, event=None, _evtype=None):
        if self.closed:
            self.__cleanup_events()
            return
        try:
            # avoid triggering __state_changed from inside __state_changed
            events = super(_Socket, self).getsockopt(zmq.EVENTS)
        except zmq.ZMQError as exc:
            self.__writable.set_exception(exc)
            self.__readable.set_exception(exc)
        else:
            if events & zmq.POLLOUT:
                self.__writable.set()
            if events & zmq.POLLIN:
                self.__readable.set()

    def _wait_write(self):
        assert self.__writable.ready(
        ), "Only one greenlet can be waiting on this event"
        self.__writable = AsyncResult()
        # timeout is because libzmq cannot be trusted to properly signal a new send event:
        # this is effectively a maximum poll interval of 1s
        tic = time.time()
        timeout = gevent.Timeout(seconds=1)
        try:
            timeout.start()
            self.__writable.get(block=True)
        except gevent.Timeout as t:
            if t is not timeout:
                raise
            toc = time.time()
            # gevent bug: get can raise timeout even on clean return
            # don't display zmq bug warning for gevent bug (this is getting ridiculous)
            if toc - tic > 0.9 and self.getsockopt(zmq.EVENTS) & zmq.POLLOUT:
                print("BUG: gevent missed a libzmq send event on %i!" %
                      self.FD,
                      file=sys.stderr)
        finally:
            timeout.cancel()
            self.__writable.set()

    def _wait_read(self):
        assert self.__readable.ready(
        ), "Only one greenlet can be waiting on this event"
        self.__readable = AsyncResult()
        # timeout is because libzmq cannot always be trusted to play nice with libevent.
        # I can only confirm that this actually happens for send, but lets be symmetrical
        # with our dirty hacks.
        # this is effectively a maximum poll interval of 1s
        tic = time.time()
        timeout = gevent.Timeout(seconds=1)
        try:
            timeout.start()
            self.__readable.get(block=True)
        except gevent.Timeout as t:
            if t is not timeout:
                raise
            toc = time.time()
            # gevent bug: get can raise timeout even on clean return
            # don't display zmq bug warning for gevent bug (this is getting ridiculous)
            if toc - tic > 0.9 and self.getsockopt(zmq.EVENTS) & zmq.POLLIN:
                print("BUG: gevent missed a libzmq recv event on %i!" %
                      self.FD,
                      file=sys.stderr)
        finally:
            timeout.cancel()
            self.__readable.set()

    def send(self, data, flags=0, copy=True, track=False):
        """send, which will only block current greenlet
        
        state_changed always fires exactly once (success or fail) at the
        end of this method.
        """

        # if we're given the NOBLOCK flag act as normal and let the EAGAIN get raised
        if flags & zmq.NOBLOCK:
            try:
                msg = super(_Socket, self).send(data, flags, copy, track)
            finally:
                if not self.__in_send_multipart:
                    self.__state_changed()
            return msg
        # ensure the zmq.NOBLOCK flag is part of flags
        flags |= zmq.NOBLOCK
        while True:  # Attempt to complete this operation indefinitely, blocking the current greenlet
            try:
                # attempt the actual call
                msg = super(_Socket, self).send(data, flags, copy, track)
            except zmq.ZMQError as e:
                # if the raised ZMQError is not EAGAIN, reraise
                if e.errno != zmq.EAGAIN:
                    if not self.__in_send_multipart:
                        self.__state_changed()
                    raise
            else:
                if not self.__in_send_multipart:
                    self.__state_changed()
                return msg
            # defer to the event loop until we're notified the socket is writable
            self._wait_write()

    def recv(self, flags=0, copy=True, track=False):
        """recv, which will only block current greenlet
        
        state_changed always fires exactly once (success or fail) at the
        end of this method.
        """
        if flags & zmq.NOBLOCK:
            try:
                msg = super(_Socket, self).recv(flags, copy, track)
            finally:
                if not self.__in_recv_multipart:
                    self.__state_changed()
            return msg

        flags |= zmq.NOBLOCK
        while True:
            try:
                msg = super(_Socket, self).recv(flags, copy, track)
            except zmq.ZMQError as e:
                if e.errno != zmq.EAGAIN:
                    if not self.__in_recv_multipart:
                        self.__state_changed()
                    raise
            else:
                if not self.__in_recv_multipart:
                    self.__state_changed()
                return msg
            self._wait_read()

    def send_multipart(self, *args, **kwargs):
        """wrap send_multipart to prevent state_changed on each partial send"""
        self.__in_send_multipart = True
        try:
            msg = super(_Socket, self).send_multipart(*args, **kwargs)
        finally:
            self.__in_send_multipart = False
            self.__state_changed()
        return msg

    def recv_multipart(self, *args, **kwargs):
        """wrap recv_multipart to prevent state_changed on each partial recv"""
        self.__in_recv_multipart = True
        try:
            msg = super(_Socket, self).recv_multipart(*args, **kwargs)
        finally:
            self.__in_recv_multipart = False
            self.__state_changed()
        return msg

    def getsockopt(self, opt):
        """trigger state_changed on getsockopt(EVENTS)"""
        optval = super(_Socket, self).getsockopt(opt)
        if opt == zmq.EVENTS:
            self.__state_changed()
        return optval
示例#48
0
class AceClient(object):
    def __init__(self, acehostslist, connect_timeout=5, result_timeout=10):
        # Receive buffer
        self._recvbuffer = None
        # Ace stream socket
        self._socket = None
        # Result timeout
        self._resulttimeout = float(result_timeout)
        # Shutting down flag
        self._shuttingDown = Event()
        # Product key
        self._product_key = None
        # Current STATUS
        self._status = None
        # Current EVENT
        self._event = None
        # Current STATE
        self._state = None
        # Current AUTH
        self._gender = None
        self._age = None
        # Result (Created with AsyncResult() on call)
        self._result = AsyncResult()
        # Seekback seconds.
        self._seekback = None
        # Did we get START command again? For seekback.
        self._started_again = Event()

        self._idleSince = time.time()
        self._streamReaderConnection = None
        self._streamReaderState = Event()
        self._streamReaderQueue = gevent.queue.Queue(
            maxsize=1024)  # Ring buffer with max number of chunks in queue
        self._engine_version_code = None

        # Logger
        logger = logging.getLogger('AceClient')
        # Try to connect AceStream engine
        for AceEngine in acehostslist:
            try:
                self._socket = Telnet(AceEngine[0], AceEngine[1],
                                      connect_timeout)
                AceConfig.acehost, AceConfig.aceAPIport, AceConfig.aceHTTPport = AceEngine[
                    0], AceEngine[1], AceEngine[2]
                logger.debug('Successfully connected to AceStream on %s:%d' %
                             (AceEngine[0], AceEngine[1]))
                break
            except:
                logger.debug('The are no alive AceStream on %s:%d' %
                             (AceEngine[0], AceEngine[1]))
                pass
        # Spawning recvData greenlet
        if self._socket: gevent.spawn(self._recvData)
        else:
            logger.error('The are no alive AceStream Engines found')
            return

    def destroy(self):
        '''
        AceClient Destructor
        '''
        logger = logging.getLogger('AceClient_destroy')  # Logger
        if self._shuttingDown.ready():
            return  # Already in the middle of destroying
        self._result.set()
        # Trying to disconnect
        try:
            logger.debug('Destroying AceStream client.....')
            self._shuttingDown.set()
            self._write(AceMessage.request.SHUTDOWN)
        except:
            pass  # Ignore exceptions on destroy
        finally:
            self._shuttingDown.set()

    def reset(self):
        self._idleSince = time.time()
        self._started_again.clear()
        self._streamReaderState.clear()
        self._result.set()

    def _write(self, message):
        try:
            logger = logging.getLogger('AceClient_write')
            logger.debug('>>> %s' % message)
            self._socket.write('%s\r\n' % message)
        except EOFError as e:
            raise AceException('Write error! %s' % repr(e))

    def aceInit(self,
                gender=AceConst.SEX_MALE,
                age=AceConst.AGE_25_34,
                product_key=AceConfig.acekey):
        self._product_key = product_key
        self._gender = gender
        self._age = age
        self._seekback = AceConfig.videoseekback
        self._started_again.clear()

        logger = logging.getLogger('AceClient_aceInit')

        self._result = AsyncResult()
        self._write(AceMessage.request.HELLO)  # Sending HELLOBG
        try:
            params = self._getResult(timeout=self._resulttimeout)
        except:
            errmsg = 'HELLOTS not resived from engine!'
            raise AceException(errmsg)
            return
        self._engine_version_code = int(params.get('version_code', 0))

        self._result = AsyncResult()
        self._write(
            AceMessage.request.READY(params.get('key', ''), self._product_key))
        if not self._getResult(timeout=self._resulttimeout
                               ):  # Get NOTREADY instead AUTH user_auth_level
            errmsg = 'NOTREADY recived from AceEngine! Wrong acekey?'
            raise AceException(errmsg)
            return

        if self._engine_version_code >= 3003600:  # Display download_stopped massage
            params_dict = {'use_stop_notifications': '1'}
            self._write(AceMessage.request.SETOPTIONS(params_dict))

    def _getResult(self, timeout=10.0):
        logger = logging.getLogger('AceClient_getResult')  # Logger
        try:
            return self._result.get(timeout=timeout)
        except gevent.Timeout:
            errmsg = 'Engine response time exceeded. getResult timeout from %s:%s' % (
                AceConfig.acehost, AceConfig.aceAPIport)
            raise AceException(errmsg)

    def START(self, datatype, value, stream_type):
        '''
        Start video method
        Returns the url provided by AceEngine
        '''
        if stream_type == 'hls' and self._engine_version_code >= 3010500:
            params_dict = {
                'output_format': stream_type,
                'transcode_audio': AceConfig.transcode_audio,
                'transcode_mp3': AceConfig.transcode_mp3,
                'transcode_ac3': AceConfig.transcode_ac3,
                'preferred_audio_language': AceConfig.preferred_audio_language
            }
        else:
            params_dict = {'output_format': 'http'}
        self._result = AsyncResult()
        self._write(
            AceMessage.request.START(
                datatype.upper(), value, ' '.join(
                    ['{}={}'.format(k, v) for k, v in params_dict.items()])))
        return self._getResult(timeout=float(
            AceConfig.videotimeout))  # Get url for play from AceEngine

    def STOP(self):
        '''
        Stop video method
        '''
        self._result = AsyncResult()
        self._write(AceMessage.request.STOP)
        self._getResult(timeout=self._resulttimeout
                        )  # Get STATE 0(IDLE) after sendig STOP to AceEngine

    def LOADASYNC(self, datatype, params):
        self._result = AsyncResult()
        self._write(
            AceMessage.request.LOADASYNC(
                datatype.upper(),
                random.randint(1, AceConfig.maxconns * 10000), params))
        return self._getResult(timeout=self._resulttimeout
                               )  # Get _contentinfo json from AceEngine

    def GETCONTENTINFO(self, datatype, value):
        params_dict = {
            datatype: value,
            'developer_id': '0',
            'affiliate_id': '0',
            'zone_id': '0'
        }
        return self.LOADASYNC(datatype, params_dict)

    def GETCID(self, datatype, url):
        contentinfo = self.GETCONTENTINFO(datatype, url)
        if contentinfo['status'] in (1, 2):
            params_dict = {
                'checksum': contentinfo['checksum'],
                'infohash': contentinfo['infohash'],
                'developer_id': '0',
                'affiliate_id': '0',
                'zone_id': '0'
            }
            self._result = AsyncResult()
            self._write(AceMessage.request.GETCID(params_dict))
            cid = self._result.get(timeout=5.0)
        else:
            cid = None
            errmsg = 'LOADASYNC returned error with message: %s' % contentinfo[
                'message']
            raise AceException(errmsg)
        return '' if cid is None or cid == '' else cid[2:]

    def GETINFOHASH(self, datatype, url, idx=0):
        contentinfo = self.GETCONTENTINFO(datatype, url)
        if contentinfo['status'] in (1, 2):
            return contentinfo['infohash'], [
                x[0] for x in contentinfo['files'] if x[1] == int(idx)
            ][0]
        elif contentinfo['status'] == 0:
            errmsg = 'LOADASYNC returned status 0: The transport file does not contain audio/video files'
            raise AceException(errmsg)
        else:
            errmsg = 'LOADASYNC returned error with message: %s' % contentinfo[
                'message']
            raise AceException(errmsg)
        return None, None

    def startStreamReader(self, url, cid, counter, req_headers=None):
        logger = logging.getLogger('StreamReader')
        logger.debug('Open video stream: %s' % url)
        transcoder = None

        logger.debug('Get headers from client: %s' % req_headers)

        try:
            if url.endswith('.m3u8'):
                logger.warning(
                    'HLS stream detected. Ffmpeg transcoding started')
                popen_params = {
                    'bufsize': requests.models.CONTENT_CHUNK_SIZE,
                    'stdout': gevent.subprocess.PIPE,
                    'stderr': None,
                    'shell': False
                }

                if AceConfig.osplatform == 'Windows':
                    ffmpeg_cmd = 'ffmpeg.exe '
                    CREATE_NO_WINDOW = 0x08000000
                    CREATE_NEW_PROCESS_GROUP = 0x00000200
                    DETACHED_PROCESS = 0x00000008
                    popen_params.update(creationflags=CREATE_NO_WINDOW
                                        | DETACHED_PROCESS
                                        | CREATE_NEW_PROCESS_GROUP)
                else:
                    ffmpeg_cmd = 'ffmpeg '

                ffmpeg_cmd += '-hwaccel auto -hide_banner -loglevel fatal -re -i %s -c copy -f mpegts -' % url
                transcoder = gevent.subprocess.Popen(ffmpeg_cmd.split(),
                                                     **popen_params)
                out = transcoder.stdout
            else:
                self._streamReaderConnection = requests.get(
                    url,
                    headers=req_headers,
                    stream=True,
                    timeout=(5, AceConfig.videotimeout))
                self._streamReaderConnection.raise_for_status(
                )  # raise an exception for error codes (4xx or 5xx)
                out = self._streamReaderConnection.raw

            self._streamReaderState.set()
            self._write(AceMessage.request.EVENT('play'))

            while 1:
                gevent.sleep()
                clients = counter.getClients(cid)
                if clients:
                    try:
                        chunk = out.read(requests.models.CONTENT_CHUNK_SIZE)
                        try:
                            self._streamReaderQueue.put_nowait(chunk)
                        except gevent.queue.Full:
                            self._streamReaderQueue.get_nowait()
                            self._streamReaderQueue.put_nowait(chunk)
                    except requests.packages.urllib3.exceptions.ReadTimeoutError:
                        logger.warning(
                            'No data received from AceEngine for %ssec - broadcast stoped'
                            % AceConfig.videotimeout)
                        break
                    except:
                        break
                    else:
                        for c in clients:
                            try:
                                c.queue.put(chunk, timeout=5)
                            except gevent.queue.Full:
                                if len(clients) > 1:
                                    logger.warning(
                                        'Client %s does not read data from buffer until 5sec - disconnect it'
                                        % c.handler.clientip)
                                    c.destroy()
                            except gevent.GreenletExit:
                                pass

                else:
                    logger.debug('All clients disconnected - broadcast stoped')
                    break

        except requests.exceptions.HTTPError as err:
            logger.error(
                'An http error occurred while connecting to aceengine: %s' %
                repr(err))
        except requests.exceptions.RequestException:
            logger.error(
                'There was an ambiguous exception that occurred while handling request'
            )
        except Exception as err:
            logger.error('Unexpected error in streamreader %s' % repr(err))
        finally:
            self.closeStreamReader()
            if transcoder is not None:
                try:
                    transcoder.kill()
                    logger.warning('Ffmpeg transcoding stoped')
                except:
                    pass
            counter.deleteAll(cid)

    def closeStreamReader(self):
        logger = logging.getLogger('StreamReader')
        self._streamReaderState.clear()
        if self._streamReaderConnection:
            logger.debug('Close video stream: %s' %
                         self._streamReaderConnection.url)
            self._streamReaderConnection.close()
        self._streamReaderQueue.queue.clear()

    def _recvData(self):
        '''
        Data receiver method for greenlet
        '''
        logger = logging.getLogger('AceClient_recvdata')

        while 1:
            gevent.sleep()
            try:
                self._recvbuffer = self._socket.read_until('\r\n').strip()
                logger.debug('<<< %s' %
                             requests.compat.unquote(self._recvbuffer))
            except:
                # If something happened during read, abandon reader.
                logger.error('Exception at socket read. AceClient destroyed')
                if not self._shuttingDown.ready(): self._shuttingDown.set()
                return
            else:  # Parsing everything only if the string is not empty
                # HELLOTS
                if self._recvbuffer.startswith('HELLOTS'):
                    # version=engine_version version_code=version_code key=request_key http_port=http_port
                    self._result.set({
                        k: v
                        for k, v in (x.split('=')
                                     for x in self._recvbuffer.split()
                                     if '=' in x)
                    })
                # NOTREADY
                elif self._recvbuffer.startswith('NOTREADY'):
                    self._result.set(False)
                    # AUTH
                elif self._recvbuffer.startswith('AUTH'):
                    self._result.set(
                        self._recvbuffer.split()[1])  # user_auth_level
                    # START
                elif self._recvbuffer.startswith('START'):
                    # url [ad=1 [interruptable=1]] [stream=1] [pos=position]
                    params = {
                        k: v
                        for k, v in (x.split('=')
                                     for x in self._recvbuffer.split()
                                     if '=' in x)
                    }
                    if not self._seekback or self._started_again.ready(
                    ) or params.get('stream', '') is not '1':
                        # If seekback is disabled, we use link in first START command.
                        # If seekback is enabled, we wait for first START command and
                        # ignore it, then do seekback in first EVENT position command
                        # AceStream sends us STOP and START again with new link.
                        # We use only second link then.
                        self._result.set(
                            self._recvbuffer.split()[1])  # url for play
                # LOADRESP
                elif self._recvbuffer.startswith('LOADRESP'):
                    self._result.set(
                        requests.compat.json.loads(
                            requests.compat.unquote(' '.join(
                                self._recvbuffer.split()[2:]))))
                # STATE
                elif self._recvbuffer.startswith('STATE'):
                    self._state = self._recvbuffer.split()[1]  # state_id
                    if self._state == '0':  # 0(IDLE)
                        self._result.set(
                            self._write(AceMessage.request.EVENT('stop')))
                    elif self._state == '1':
                        pass  # 1 (PREBUFFERING)
                    elif self._state == '2':
                        pass  # 2 (DOWNLOADING)
                    elif self._state == '3':
                        pass  # 3 (BUFFERING)
                    elif self._state == '4':
                        pass  # 4 (COMPLETED)
                    elif self._state == '5':
                        pass  # 5 (CHECKING)
                    elif self._state == '6':
                        pass  # 6 (ERROR)
                # STATUS
                elif self._recvbuffer.startswith('STATUS'):
                    pass
                    # CID
                elif self._recvbuffer.startswith('##'):
                    self._result.set(self._recvbuffer)
                    # INFO
                elif self._recvbuffer.startswith('INFO'):
                    pass
                    # EVENT
                elif self._recvbuffer.startswith('EVENT'):
                    self._event = self._recvbuffer.split()
                    if 'livepos' in self._event:
                        if self._seekback and not self._started_again.ready(
                        ):  # if seekback
                            params = {
                                k: v
                                for k, v in (x.split('=') for x in self._event
                                             if '=' in x)
                            }
                            self._write(
                                AceMessage.request.LIVESEEK(
                                    int(params['last']) - self._seekback))
                            self._started_again.set()
                    elif 'getuserdata' in self._event:
                        self._write(
                            AceMessage.request.USERDATA(
                                self._gender, self._age))
                    elif 'cansave' in self._event:
                        pass
                    elif 'showurl' in self._event:
                        pass
                    elif 'download_stopped' in self._event:
                        pass
                # PAUSE
                elif self._recvbuffer.startswith('PAUSE'):
                    self._write(AceMessage.request.EVENT('pause'))
                    # RESUME
                elif self._recvbuffer.startswith('RESUME'):
                    self._write(AceMessage.request.EVENT('play'))
                    # STOP
                elif self._recvbuffer.startswith('STOP'):
                    pass
                    # SHUTDOWN
                elif self._recvbuffer.startswith('SHUTDOWN'):
                    self._socket.close()
                    logger.debug('AceClient destroyed')
                    return
示例#49
0
class Step(ExecutionElement):
    _templatable = True

    def __init__(self,
                 app,
                 action,
                 name='',
                 device='',
                 inputs=None,
                 triggers=None,
                 next_steps=None,
                 position=None,
                 widgets=None,
                 risk=0,
                 uid=None,
                 templated=False,
                 raw_representation=None):
        """Initializes a new Step object. A Workflow has many steps that it executes.

        Args:
            app (str): The name of the app associated with the Step
            action (str): The name of the action associated with a Step
            name (str, optional): The name of the Step object. Defaults to an empty string.
            device (str, optional): The name of the device associated with the app associated with the Step. Defaults
                to an empty string.
            inputs (dict, optional): A dictionary of Argument objects that are input to the step execution. Defaults
                to None.
            triggers (list[Flag], optional): A list of Flag objects for the Step. If a Step should wait for data
                before continuing, then include these Trigger objects in the Step init. Defaults to None.
            next_steps (list[NextStep], optional): A list of NextStep objects for the Step object. Defaults to None.
            position (dict, optional): A dictionary with the x and y coordinates of the Step object. This is used
                for UI display purposes. Defaults to None.
            widgets (list[tuple(str, str)], optional): A list of widget tuples, which holds the app and the
                corresponding widget. Defaults to None.
            risk (int, optional): The risk associated with the Step. Defaults to 0.
            uid (str, optional): A universally unique identifier for this object.
                Created from uuid.uuid4().hex in Python
            templated (bool, optional): Whether or not the Step is templated. Used for Jinja templating.
            raw_representation (dict, optional): JSON representation of this object. Used for Jinja templating.
        """
        ExecutionElement.__init__(self, uid)

        self.triggers = triggers if triggers is not None else []
        self._incoming_data = AsyncResult()

        self.name = name
        self.app = app
        self.action = action
        self._run, self._input_api = get_app_action_api(self.app, self.action)
        get_app_action(self.app, self._run)
        if isinstance(inputs, list):
            inputs = {arg['name']: arg['value'] for arg in inputs}
        elif isinstance(inputs, dict):
            inputs = inputs
        else:
            inputs = {}
        self.templated = templated
        if not self.templated:
            self.inputs = validate_app_action_parameters(
                self._input_api, inputs, self.app, self.action)
        else:
            self.inputs = inputs
        self.device = device if (device is not None
                                 and device != 'None') else ''
        self.risk = risk
        self.next_steps = next_steps if next_steps is not None else []
        self.position = position if position is not None else {}
        self.widgets = [
            widget if isinstance(widget, Widget) else Widget(**widget)
            for widget in widgets
        ] if widgets is not None else []

        self._output = None
        self._next_up = None
        self._raw_representation = raw_representation if raw_representation is not None else {}
        self._execution_uid = 'default'

    def get_output(self):
        """Gets the output of a Step (the result)

        Returns:
            The result of the Step
        """
        return self._output

    def get_next_up(self):
        """Gets the next step to be executed

        Returns:
            The next step to be executed
        """
        return self._next_up

    def set_next_up(self, next_up):
        """Sets the next step to be executed

        Returns:
            The next step to be executed
        """
        self._next_up = next_up

    def get_execution_uid(self):
        """Gets the execution UID of the Step

        Returns:
            The execution UID
        """
        return self._execution_uid

    def send_data_to_trigger(self, data):
        """Sends data to the Step if it has triggers associated with it, and is currently awaiting data

        Args:
            data (dict): The data to send to the triggers. This dict has two keys: 'data_in' which is the data
                to be sent to the triggers, and 'inputs', which is an optional parameter to change the inputs to the
                current Step
        """
        self._incoming_data.set(data)

    def _update_json(self, updated_json):
        self.action = updated_json['action']
        self.app = updated_json['app']
        self.device = updated_json['device'] if 'device' in updated_json else ''
        self.risk = updated_json['risk'] if 'risk' in updated_json else 0
        inputs = {arg['name']: arg['value']
                  for arg in updated_json['inputs']
                  } if 'inputs' in updated_json else {}
        if inputs is not None:
            if not self.templated:
                self.inputs = validate_app_action_parameters(
                    self._input_api, inputs, self.app, self.action)
            else:
                self.inputs = inputs
        else:
            self.inputs = validate_app_action_parameters(
                self._input_api, {}, self.app, self.action)
        self.next_steps = [
            NextStep.create(cond_json)
            for cond_json in updated_json['next_steps']
        ]

    @contextdecorator.context
    def render_step(self, **kwargs):
        """Uses JINJA templating to render a Step object.

        Args:
            kwargs (dict[str]): Arguments to use in the JINJA templating.
        """
        if self.templated:
            from jinja2 import Environment
            env = Environment().from_string(
                json.dumps(self._raw_representation)).render(
                    core.config.config.JINJA_GLOBALS, **kwargs)
            self._update_json(updated_json=json.loads(env))

    def set_input(self, new_input):
        """Updates the input for a Step object.

        Args:
            new_input (dict): The new inputs for the Step object.
        """
        self.inputs = validate_app_action_parameters(self._input_api,
                                                     new_input, self.app,
                                                     self.action)

    def execute(self, instance, accumulator):
        """Executes a Step by calling the associated app function.

        Args:
            instance (App): The instance of an App object to be used to execute the associated function.
            accumulator (dict): Dict containing the results of the previous steps

        Returns:
            The result of the executed function.
        """
        self._execution_uid = uuid.uuid4().hex
        data_sent.send(self, callback_name="Step Started", object_type="Step")

        if self.triggers:
            data_sent.send(self,
                           callback_name="Trigger Step Awaiting Data",
                           object_type="Step")
            logger.debug('Trigger Step {} is awaiting data'.format(self.name))

            while True:
                try:
                    data = self._incoming_data.get(timeout=1)
                    self._incoming_data = AsyncResult()
                except gevent.Timeout:
                    gevent.sleep(0.1)
                    continue
                data_in = data['data_in']
                inputs = data['inputs'] if 'inputs' in data else {}

                if all(
                        flag.execute(data_in=data_in, accumulator=accumulator)
                        for flag in self.triggers):
                    data_sent.send(self,
                                   callback_name="Trigger Step Taken",
                                   object_type="Step")
                    logger.debug(
                        'Trigger is valid for input {0}'.format(data_in))
                    accumulator[self.name] = data_in

                    if inputs:
                        self.inputs.update(inputs)
                    break
                else:
                    logger.debug(
                        'Trigger is not valid for input {0}'.format(data_in))
                    data_sent.send(self,
                                   callback_name="Trigger Step Not Taken",
                                   object_type="Step")

                gevent.sleep(0.1)

        try:
            args = dereference_step_routing(self.inputs, accumulator,
                                            'In step {0}'.format(self.name))
            args = validate_app_action_parameters(self._input_api, args,
                                                  self.app, self.action)
            action = get_app_action(self.app, self._run)
            if is_app_action_bound(self.app, self._run):
                result = action(instance, **args)
            else:
                result = action(**args)

            data_sent.send(self,
                           callback_name="Function Execution Success",
                           object_type="Step",
                           data=json.dumps({"result": result.as_json()}))
        except InvalidInput as e:
            formatted_error = format_exception_message(e)
            logger.error('Error calling step {0}. Error: {1}'.format(
                self.name, formatted_error))
            data_sent.send(self,
                           callback_name="Step Input Invalid",
                           object_type="Step")
            self._output = ActionResult('error: {0}'.format(formatted_error),
                                        'InvalidInput')
            raise
        except Exception as e:
            formatted_error = format_exception_message(e)
            logger.error('Error calling step {0}. Error: {1}'.format(
                self.name, formatted_error))
            self._output = ActionResult('error: {0}'.format(formatted_error),
                                        'UnhandledException')
            raise
        else:
            self._output = result
            for widget in self.widgets:
                get_widget_signal(widget.app, widget.name).send(
                    self, data=json.dumps({"result": result.as_json()}))
            logger.debug('Step {0}-{1} (uid {2}) executed successfully'.format(
                self.app, self.action, self.uid))
            return result

    def get_next_step(self, accumulator):
        """Gets the NextStep object to be executed after the current Step.

        Args:
            accumulator (dict): A record of teh previously-executed steps. Of form {step_name: result}

        Returns:
            The NextStep object to be executed.
        """

        for next_step in self.next_steps:
            next_step = next_step.execute(self._output, accumulator)
            if next_step is not None:
                self._next_up = next_step
                data_sent.send(self,
                               callback_name="Conditionals Executed",
                               object_type="Step")
                return next_step
示例#50
0
class DiffractometerMockup(Equipment):
    """
    Descript. :
    """
    MANUAL3CLICK_MODE = "Manual 3-click"
    C3D_MODE = "Computer automatic"
    MOVE_TO_BEAM_MODE = "Move to Beam"

    MINIKAPPA = "MiniKappa"
    PLATE = "Plate"
    SC = "SC"

    def __init__(self, *args):
        """
        Descript. :
        """
        Equipment.__init__(self, *args)

        queue_model_objects.CentredPosition.set_diffractometer_motor_names(\
                "phi", "focus", "phiz", "phiy", "zoom",
                "sampx", "sampy", "kappa", "kappa_phi")


        self.phiMotor = None
        self.phizMotor = None
        self.phiyMotor = None
        self.lightMotor = None
        self.zoomMotor = None
        self.sampleXMotor = None
        self.sampleYMotor = None
        self.camera_hwobj = None
        self.beam_info_hwobj = None

        self.beam_position = None
        self.x_calib = None
        self.y_calib = None
        self.pixels_per_mm_x = None
        self.pixels_per_mm_y = None
        self.image_width = None
        self.image_height = None
        self.current_sample_info = None
        self.cancel_centring_methods = None
        self.current_centring_procedure = None
        self.current_centring_method = None
        self.current_positions_dict = None
        self.current_phase = None
        self.centring_methods = None
        self.centring_status = None
        self.centring_time = None
        self.user_confirms_centring = None
        self.user_clicked_event = None
        self.phase_list = None
        self.head_type = None
        self._drawing = None

        self.connect(self, 'equipmentReady', self.equipmentReady)
        self.connect(self, 'equipmentNotReady', self.equipmentNotReady)

        self.startCentringMethod = self.start_centring_method
        self.cancelCentringMethod = self.cancel_centring_method
        self.imageClicked = self.image_clicked
        self.acceptCentring = self.accept_centring
        self.rejectCentring = self.reject_centring
        self.getCentringStatus = self.get_centring_status
        self.takeSnapshots = self.take_snapshots
        self.moveMotors = self.move_motors

    def init(self):
        """
        Descript. :
        """
        self.x_calib = 0.000444
        self.y_calib = 0.000446
         
        self.pixels_per_mm_x = 1.0 / self.x_calib
        self.pixels_per_mm_y = 1.0 / self.y_calib
        self.beam_position = [200, 200]
        
        self.centring_methods = {
             DiffractometerMockup.MANUAL3CLICK_MODE: self.start_3Click_centring,
             DiffractometerMockup.C3D_MODE: self.start_automatic_centring}
        self.cancel_centring_methods = {}
        self.current_positions_dict = {'phiy'  : 0, 'phiz' : 0, 'sampx' : 0,
                                       'sampy' : 0, 'zoom' : 0, 'phi' : 17.6,
                                       'focus' : 0, 'kappa': 0, 'kappa_phi': 0,
                                       'beam_x': 0, 'beam_y': 0} 
        self.centring_status = {"valid": False}
        self.centring_time = 0
        self.user_confirms_centring = True
        self.fast_shutter_is_open = False
        self.user_clicked_event = AsyncResult()

        self.image_width = 400
        self.image_height = 400

        self.equipmentReady()
        self.user_clicked_event = AsyncResult()

        self.phiMotor = self.getDeviceByRole('phi')
        self.sampleXMotor = self.getDeviceByRole('sampx')
        self.sampleYMotor = self.getDeviceByRole('sampy')
        self.camera_hwobj = self.getDeviceByRole('camera')

        if self.phiMotor is not None:
            self.connect(self.phiMotor, 'stateChanged', self.phiMotorStateChanged)
            self.connect(self.phiMotor, "positionChanged", self.phi_motor_position_changed)
        else:
            logging.getLogger("HWR").error('MiniDiff: phi motor is not defined in minidiff equipment %s', str(self.name()))

        if self.sampleXMotor is not None:
            self.connect(self.sampleXMotor, 'stateChanged', self.sampleX_motor_state_changed)
            self.connect(self.sampleXMotor, 'positionChanged', self.sampleX_motor_moved)
            self.connect(self.sampleXMotor, "positionChanged", self.emit_diffractometer_moved)
        else:
            logging.getLogger("HWR").error('MiniDiff: Sampx motor is not defined')

        if self.sampleYMotor is not None:
            self.connect(self.sampleYMotor, 'stateChanged', self.sampleY_motor_state_changed)
            self.connect(self.sampleYMotor, 'positionChanged', self.sampleY_motor_moved)
            self.connect(self.sampleYMotor, "positionChanged", self.emit_diffractometer_moved)
        else:
            logging.getLogger("HWR").error('MiniDiff: Sampx motor is not defined')

        self.beam_info_hwobj = HardwareRepository.HardwareRepository().\
                                getHardwareObject(self.getProperty("beam_info"))
        if self.beam_info_hwobj is not None:
            self.connect(self.beam_info_hwobj, 'beamPosChanged', self.beam_position_changed)
        else:
            logging.getLogger("HWR").debug('Minidiff: Beaminfo is not defined')

        takeSnapshots = self.take_snapshots
        self.getCentringStatus = self.get_centring_status

        self.reversing_rotation = self.getProperty("reversingRotation")
        try:
            self.grid_direction = eval(self.getProperty("gridDirection"))
        except:
            self.grid_direction = {"fast": (0, 1), "slow": (1, 0)}
            logging.getLogger("HWR").warning('MiniDiff: Grid direction is not defined. Using default.')

        try:
            self.current_phase = "Transfer"
            self.phase_list = eval(self.getProperty("phaseList"))
            self.head_type = self.getProperty("headType")
        except:
            self.phase_list = []

    def set_drawing(self, drawing):
	self._drawing = drawing

    def use_sample_changer(self):
        return True

    def in_plate_mode(self):
        #TODO head detection should be used to detect if in plate mode 
	return False

    def toggle_fast_shutter(self):
        self.fast_shutter_is_open = not self.fast_shutter_is_open
        self.emit('minidiffShutterStateChanged', (self.fast_shutter_is_open, ))

    def get_head_type(self):
        return self.head_type
         
    def get_grid_direction(self):
        return self.grid_direction

    def is_reversing_rotation(self):
        return self.reversing_rotation == True

    def phiMotorStateChanged(self,state):
        self.emit('phiMotorStateChanged', (state, ))
        self.emit('minidiffStateChanged', (state,))

    def phi_motor_position_changed(self, position):
        self.current_positions_dict["phi"] = position
        self.emit('minidiffStateChanged', ("ready",)) 

    def sampleX_motor_state_changed(self, state):
        """
        Descript. :
        """
        self.emit('sampxMotorStateChanged', (state, ))
        self.emit('minidiffStateChanged', (state, ))

    def sampleY_motor_state_changed(self, state):
        """
        Descript. :
        """
        self.emit('sampyMotorStateChanged', (state, ))
        self.emit('minidiffStateChanged', (state, ))

    def sampleX_motor_moved(self, pos):
        """
        Descript. :
        """
        self.current_positions_dict["sampx"] = pos
        if time.time() - self.centring_time > 1.0:
            self.invalidate_centring()

    def sampleY_motor_moved(self, pos):
        """
        Descript. :
        """
        self.current_positions_dict["sampy"] = pos
        if time.time() - self.centring_time > 1.0:
            self.invalidate_centring()

    def getStatus(self):
        """
        Descript. :
        """
        return "ready"

    def manual_centring(self):
        """
        Descript. :
        """
        self.user_clicked_event = AsyncResult()
        x, y = self.user_clicked_event.get()
        last_centred_position[0] = x
        last_centred_position[1] = y
        random_num = random.random()
        centred_pos_dir = {'phiy': random_num, 'phiz': random_num * 2, 
                           'sampx': random_num * 3, 'sampy': random_num * 4, 
                           'zoom': 8.53, 'phi': 311.1, 'focus': -0.42, 
                           'kappa': 0.0, 'kappa_phi': 0.0}
        return centred_pos_dir 		

    def set_sample_info(self, sample_info):
        """
        Descript. :
        """
        self.current_sample_info = sample_info
	
    def emit_diffractometer_moved(self, *args):
        """
        Descript. :
        """
        self.emit("diffractometerMoved", ())
	
    def isReady(self):
        """
        Descript. :
        """ 
        return True

    def isValid(self):
        """
        Descript. :
        """
        return True

    def equipmentReady(self):
        """
        Descript. :
        """
        self.emit('minidiffReady', ())

    def equipmentNotReady(self):
        """
        Descript. :
        """
        self.emit('minidiffNotReady', ())

    def invalidate_centring(self):
        """
        Descript. :
        """
        if self.current_centring_procedure is None and self.centring_status["valid"]:
            self.centring_status = {"valid":False}
            self.emitProgressMessage("")
            self.emit('centringInvalid', ())

    def get_available_centring_methods(self):
        """
        Descript. :
        """
        return self.centring_methods.keys()

    def get_calibration_data(self, offset):
        """
        Descript. :
        """
        #return (1.0 / self.x_calib, 1.0 / self.y_calib)
        return (1.0 / self.x_calib, 1.0 / self.y_calib)

    def get_pixels_per_mm(self):
        """
        Descript. :
        """
        return (self.pixels_per_mm_x, self.pixels_per_mm_y)

    def refresh_omega_reference_position(self):
        """
        Descript. :
        """
        return

    def get_omega_axis_position(self):	
        """
        Descript. :
        """
        return self.current_positions_dict.get("phi")     

    def get_positions(self):
        """
        Descript. :
        """
        return self.current_positions_dict

    def get_current_positions_dict(self):
        """
        Descript. :
        """
        return self.current_positions_dict

    def beam_position_changed(self, value):
        """
        Descript. :
        """
        self.beam_position = value
  
    def start_centring_method(self, method, sample_info = None):
        """
        Descript. :
        """
        if self.current_centring_method is not None:
            logging.getLogger("HWR").error("already in centring method %s" %\
                    self.current_centring_method)
            return
        curr_time = time.strftime("%Y-%m-%d %H:%M:%S")
        self.centring_status = {"valid": False, "startTime": curr_time}
        self.emit_centring_started(method)
        try:
            fun = self.centring_methods[method]
        except KeyError, diag:
            logging.getLogger("HWR").error("unknown centring method (%s)" % \
                    str(diag))
            self.emit_centring_failed()
        else:
示例#51
0
def listen():
    waiter = AsyncResult()
    waiters.append(waiter)
    return "($('body').html('%s'));" % waiter.get()
示例#52
0
class TestRemoteEndpoint(IonIntegrationTestCase):
    """
    Test cases for 2CAA terrestrial endpoint.
    """
    def setUp(self):
        """
        Start fake terrestrial components and add cleanup.
        Start terrestrial server and retrieve port.
        Set internal variables.
        Start container.
        Start deployment.
        Start container agent.
        Spawn remote endpoint process.
        Create remote endpoint client and retrieve remote server port.
        Create event publisher.
        """
        
        self._terrestrial_server = R3PCServer(self.consume_req, self.terrestrial_server_close)
        self._terrestrial_client = R3PCClient(self.consume_ack, self.terrestrial_client_close)
        self.addCleanup(self._terrestrial_server.stop)
        self.addCleanup(self._terrestrial_client.stop)
        self._other_port = self._terrestrial_server.start('*', 0)
        log.debug('Terrestrial server binding to *:%i', self._other_port)
        
        self._other_host = 'localhost'
        self._platform_resource_id = 'abc123'
        self._resource_id = 'fake_id'
        self._no_requests = 10
        self._requests_sent = {}
        self._results_recv = {}
        self._no_telem_events = 0
        self._done_evt = AsyncResult()
        self._done_telem_evts = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        
        # Start container.
        log.debug('Staring capability container.')
        self._start_container()
        
        # Bring up services in a deploy file (no need to message).
        log.info('Staring deploy services.')
        self.container.start_rel_from_url('res/deploy/r2deploy.yml')

        # Create a container client.
        log.debug('Creating container client.')
        container_client = ContainerAgentClient(node=self.container.node,
            name=self.container.name)

        # Create agent config.
        endpoint_config = {
            'other_host' : self._other_host,
            'other_port' : self._other_port,
            'this_port' : 0,
            'platform_resource_id' : self._platform_resource_id
        }
        
        # Spawn the remote enpoint process.
        log.debug('Spawning remote endpoint process.')
        re_pid = container_client.spawn_process(
            name='remote_endpoint_1',
            module='ion.services.sa.tcaa.remote_endpoint',
            cls='RemoteEndpoint',
            config=endpoint_config)
        log.debug('Endpoint pid=%s.', str(re_pid))

        # Create an endpoint client.
        self.re_client = RemoteEndpointClient(
            process=FakeProcess(),
            to_name=re_pid)
        log.debug('Got re client %s.', str(self.re_client))
        
        # Remember the remote port.
        self._this_port = self.re_client.get_port()
        log.debug('The remote port is: %i.', self._this_port)
        
        # Start the event publisher.
        self._event_publisher = EventPublisher()
      
    ######################################################################    
    # Helpers.
    ######################################################################    

    def on_link_up(self):
        """
        Called by a test to simulate turning the link on.
        """
        log.debug('Terrestrial client connecting to localhost:%i.',
                 self._this_port)
        self._terrestrial_client.start('localhost', self._this_port)
        # Publish a link up event to be caught by the endpoint.
        log.debug('Publishing telemetry event.')
        self._event_publisher.publish_event(
                            event_type='PlatformTelemetryEvent',
                            origin=self._platform_resource_id,
                            status = TelemetryStatusType.AVAILABLE)
    
    def on_link_down(self):
        """
        Called by a test to simulate turning the link off.
        """
        self._terrestrial_client.stop()
        # Publish a link down event to be caught by the endpoint.
        log.debug('Publishing telemetry event.')
        self._event_publisher.publish_event(
                            event_type='PlatformTelemetryEvent',
                            origin=self._platform_resource_id,
                            status = TelemetryStatusType.UNAVAILABLE)    
    
    def consume_req(self, res):
        """
        Consume a terrestrial request setting async event when necessary.
        """
        command_id = res['command_id']
        self._results_recv[command_id] = res
        if len(self._results_recv) == self._no_requests:
            self._done_evt.set()
    
    def consume_ack(self, cmd):
        """
        Consume terrestrial ack setting async event when necessary.
        """
        self._requests_sent[cmd.command_id] = cmd
        if len(self._requests_sent) == self._no_requests:
            self._cmd_tx_evt.set()
        
    def terrestrial_server_close(self):
        """
        Callback when terrestrial server closes.
        """
        pass
    
    def terrestrial_client_close(self):
        """
        Callback when terrestrial client closes.
        """
        pass
    
    def make_fake_command(self, no):
        """
        Build a fake command for use in tests.
        """
            
        cmdstr = 'fake_cmd_%i' % no
        cmd = IonObject('RemoteCommand',
                             resource_id=self._resource_id,
                             command=cmdstr,
                             args=['arg1', 23],
                             kwargs={'worktime':3},
                             command_id = str(uuid.uuid4()))
        return cmd

    def start_agent(self):
        """
        Start an instrument agent and client.
        """
        
        log.info('Creating driver integration test support:')
        log.info('driver module: %s', DRV_MOD)
        log.info('driver class: %s', DRV_CLS)
        log.info('device address: %s', DEV_ADDR)
        log.info('device port: %s', DEV_PORT)
        log.info('log delimiter: %s', DELIM)
        log.info('work dir: %s', WORK_DIR)        
        self._support = DriverIntegrationTestSupport(DRV_MOD,
                                                     DRV_CLS,
                                                     DEV_ADDR,
                                                     DEV_PORT,
                                                     DATA_PORT,
                                                     CMD_PORT,
                                                     PA_BINARY,
                                                     DELIM,
                                                     WORK_DIR)
        
        # Start port agent, add stop to cleanup.
        port = self._support.start_pagent()
        log.info('Port agent started at port %i',port)
        
        # Configure driver to use port agent port number.
        DVR_CONFIG['comms_config'] = {
            'addr' : 'localhost',
            'port' : port,
            'cmd_port' : CMD_PORT
        }
        self.addCleanup(self._support.stop_pagent)    
                        
        # Create agent config.
        agent_config = {
            'driver_config' : DVR_CONFIG,
            'stream_config' : {},
            'agent'         : {'resource_id': IA_RESOURCE_ID},
            'test_mode' : True
        }
    
        # Start instrument agent.
        log.debug("Starting IA.")
        container_client = ContainerAgentClient(node=self.container.node,
            name=self.container.name)
    
        ia_pid = container_client.spawn_process(name=IA_NAME,
            module=IA_MOD,
            cls=IA_CLS,
            config=agent_config)
    
        log.info('Agent pid=%s.', str(ia_pid))
    
        # Start a resource agent client to talk with the instrument agent.
    
        self._ia_client = ResourceAgentClient(IA_RESOURCE_ID, process=FakeProcess())
        log.info('Got ia client %s.', str(self._ia_client))                
                
    ######################################################################    
    # Tests.
    ######################################################################    

    def test_process_queued(self):
        """
        test_process_queued
        Test that queued commands are forwarded to and handled by
        remote endpoint when link comes up.
        """        
        
        # Create and enqueue some requests.
        for i in range(self._no_requests):
            cmd = self.make_fake_command(i)
            self._terrestrial_client.enqueue(cmd)

        # Publish a telemetry available event.
        # This will cause the endpoint clients to wake up and connect.
        self.on_link_up()

        # Wait for all the enqueued commands to be acked.
        # Wait for all the responses to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)

        # Publish a telemetry unavailable event.
        # This will cause the endpoint clients to disconnect and go to sleep.
        self.on_link_down()

        # Confirm the results match the commands sent.
        self.assertItemsEqual(self._requests_sent.keys(),
                                  self._results_recv.keys())
    
    def test_process_online(self):
        """
        test_process_online
        Test commands are forwarded and handled while link is up.
        """        
        
        # Publish a telemetry available event.
        # This will cause the endpoint clients to wake up and connect.
        self.on_link_up()

        # Wait for the link to be up.
        # The remote side does not publish public telemetry events
        # so we can't wait for that.
        gevent.sleep(1)

        # Create and enqueue some requests.
        for i in range(self._no_requests):
            cmd = self.make_fake_command(i)
            self._terrestrial_client.enqueue(cmd)

        # Wait for all the enqueued commands to be acked.
        # Wait for all the responses to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)

        # Publish a telemetry unavailable event.
        # This will cause the endpoint clients to disconnect and go to sleep.
        self.on_link_down()

        # Confirm the results match the commands sent.
        self.assertItemsEqual(self._requests_sent.keys(),
                                  self._results_recv.keys())

    def test_terrestrial_late(self):
        """
        test_terrestrial_late
        Test queued commands are forwarded and handled by remote endpoint
        when terrestrial side is late to come up.
        """        
        
        # Publish a telemetry available event.
        # This will cause the endpoint clients to wake up and connect.
        self.on_link_up()

        # Wait for the link to be up.
        # The remote side does not publish public telemetry events
        # so we can't wait for that.
        gevent.sleep(1)

        # Manually stop the terrestrial endpoint.
        # This will cause it to be unavailable when commands are queued
        # to simulate stability during asynchronous wake ups.
        self._terrestrial_server.stop()
        self._terrestrial_client.stop()

        # Create and enqueue some requests.
        for i in range(self._no_requests):
            cmd = self.make_fake_command(i)
            self._terrestrial_client.enqueue(cmd)

        # Remote side awaits the terrestrial waking up.
        gevent.sleep(3)

        # Terrestrail endpoint eventually wakes up and starts transmitting.        
        self._terrestrial_client.start('localhost', self._this_port)
        self._terrestrial_server.start('*', self._other_port)
    
        # Wait for all the enqueued commands to be acked.
        # Wait for all the responses to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)

        # Publish a telemetry unavailable event.
        # This will cause the endpoint clients to disconnect and go to sleep.
        self.on_link_down()

        # Confirm the results match the commands sent.
        self.assertItemsEqual(self._requests_sent.keys(),
                                  self._results_recv.keys())

    def test_service_commands(self):
        """
        test_service_commands
        Test that real service commands are handled by the remote endpoint.
        """
        
        # Publish a telemetry available event.
        # This will cause the endpoint clients to wake up and connect.
        self.on_link_up()

        # Send commands one at a time.
        # Reset queues and events.
        self._no_requests = 1
        self._done_evt = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        self._requests_sent = {}
        self._results_recv = {}
        
        # Create user object.
        obj = IonObject("UserInfo", name="some_name")
        cmd = IonObject('RemoteCommand',
                             resource_id='',
                             svc_name='resource_registry',
                             command='create',
                             args=[obj],
                             kwargs='',
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd)
        
        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)
        
        # Returns obj_id, obj_rev.
        obj_id, obj_rev = self._results_recv[cmd.command_id]['result']
        
        # Confirm the results are valid.
        """
        Result is a tuple of strings.
        {'result': ['ad183ff26bae4f329ddd85fd69d160a9',
        '1-00a308c45fff459c7cda1db9a7314de6'],
        'command_id': 'cc2ae00d-40b0-47d2-af61-8ffb87f1aca2'}
        """
        self.assertIsInstance(obj_id, str)
        self.assertNotEqual(obj_id, '')
        self.assertIsInstance(obj_rev, str)
        self.assertNotEqual(obj_rev, '')
        
        # Send commands one at a time.
        # Reset queues and events.
        self._no_requests = 1
        self._done_evt = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        self._requests_sent = {}
        self._results_recv = {}

        # Read user object.
        cmd = IonObject('RemoteCommand',
                             resource_id='',
                             svc_name='resource_registry',
                             command='read',
                             args=[obj_id],
                             kwargs='',
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd)

        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)

        # Returns read_obj.
        read_obj = self._results_recv[cmd.command_id]['result']
        
        # Confirm the results are valid.
        """
        Result is a user info object with the name set.
        {'lcstate': 'DEPLOYED_AVAILABLE',
        '_rev': '1-851f067bac3c34b2238c0188b3340d0f',
        'description': '',
        'ts_updated': '1349213207638',
        'type_': 'UserInfo',
        'contact': <interface.objects.ContactInformation object at 0x10d7df590>,
        '_id': '27832d93f4cd4535a75ac75c06e00a7e',
        'ts_created': '1349213207638',
        'variables': [{'name': '', 'value': ''}],
        'name': 'some_name'}
        """
        self.assertIsInstance(read_obj, UserInfo)
        self.assertEquals(read_obj.name, 'some_name')
        
        # Send commands one at a time.
        # Reset queues and events.
        self._no_requests = 1
        self._done_evt = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        self._requests_sent = {}
        self._results_recv = {}

        # Update user object.
        read_obj.name = 'some_other_name'
        cmd = IonObject('RemoteCommand',
                             resource_id='',
                             svc_name='resource_registry',
                             command='update',
                             args=[read_obj],
                             kwargs='',
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd)

        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)

        # Returns nothing.
        
        # Send commands one at a time.
        # Reset queues and events.
        self._no_requests = 1
        self._done_evt = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        self._requests_sent = {}
        self._results_recv = {}

        # Read user object.
        cmd = IonObject('RemoteCommand',
                             resource_id='',
                             svc_name='resource_registry',
                             command='read',
                             args=[obj_id],
                             kwargs='',
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd)        

        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)

        # Returns read_obj.
        read_obj = self._results_recv[cmd.command_id]['result']
        
        self.assertIsInstance(read_obj, UserInfo)
        self.assertEquals(read_obj.name, 'some_other_name')
        
        # Send commands one at a time.
        # Reset queues and events.
        self._no_requests = 1
        self._done_evt = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        self._requests_sent = {}
        self._results_recv = {}
        
        # Delete user object.
        cmd = IonObject('RemoteCommand',
                             resource_id='',
                             svc_name='resource_registry',
                             command='delete',
                             args=[obj_id],
                             kwargs='',
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd)        

        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)

        # Returns nothing.
            
        # Publish a telemetry unavailable event.
        # This will cause the endpoint clients to disconnect and go to sleep.
        self.on_link_down()

        gevent.sleep(1)
        
    def test_resource_commands(self):
        """
        test_resource_commands
        Test that real resource commands are handled by the remote endpoint.
        """
        
        # Start the IA and check it's out there and behaving.
        self.start_agent()
        
        state = self._ia_client.get_agent_state()
        log.debug('Agent state is: %s', state)
        self.assertEqual(state, ResourceAgentState.UNINITIALIZED)

        retval = self._ia_client.ping_agent()
        log.debug('Agent ping is: %s', str(retval))
        self.assertIn('ping from InstrumentAgent', retval)

        # Publish a telemetry available event.
        # This will cause the endpoint clients to wake up and connect.
        self.on_link_up()

        # Wait for the link to be up.
        # The remote side does not publish public telemetry events
        # so we can't wait for that.
        gevent.sleep(1)

        # Send commands one at a time.
        # Reset queues and events.
        self._no_requests = 1
        self._done_evt = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        self._requests_sent = {}
        self._results_recv = {}

        # Get agent state via remote endpoint.        
        cmd = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='get_agent_state',
                             args=[],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd)
        
        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)
        
        # Returns agent state.
        state = self._results_recv[cmd.command_id]['result']
        self.assertEqual(state, ResourceAgentState.UNINITIALIZED)

        # Send commands one at a time.
        # Reset queues and events.
        self._no_requests = 1
        self._done_evt = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        self._requests_sent = {}
        self._results_recv = {}

        # Ping agent via remote endpoint. 
        cmd = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='ping_agent',
                             args=[],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd)
        
        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)
        
        # Returns agent state.
        ping = self._results_recv[cmd.command_id]['result']
        self.assertIn('ping from InstrumentAgent', ping)
        
        # Publish a telemetry unavailable event.
        # This will cause the endpoint clients to disconnect and go to sleep.
        self.on_link_down()

        gevent.sleep(1)

    def test_bad_service_name_resource_id(self):
        """
        test_bad_service_name_resource_id
        Test for proper exception behavior when a bad service name or
        resource id is used in a command forwarded to the remote endpoint.
        """
        
        # Publish a telemetry available event.
        # This will cause the endpoint clients to wake up and connect.
        self.on_link_up()

        # Wait for the link to be up.
        # The remote side does not publish public telemetry events
        # so we can't wait for that.
        gevent.sleep(1)

        # Send commands one at a time.
        # Reset queues and events.
        self._no_requests = 1
        self._done_evt = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        self._requests_sent = {}
        self._results_recv = {}
        
        # Create user object.
        obj = IonObject("UserInfo", name="some_name")
        cmd = IonObject('RemoteCommand',
                             resource_id='',
                             svc_name='bogus_service',
                             command='create',
                             args=[obj],
                             kwargs='',
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd)
        
        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)
        
        # Returns NotFound.
        result = self._results_recv[cmd.command_id]['result']
        self.assertIsInstance(result, NotFound)

        # Send commands one at a time.
        # Reset queues and events.
        self._no_requests = 1
        self._done_evt = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        self._requests_sent = {}
        self._results_recv = {}

        # Get agent state via remote endpoint.        
        cmd = IonObject('RemoteCommand',
                             resource_id='bogus_resource_id',
                             svc_name='',
                             command='get_agent_state',
                             args=[],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd)
        
        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)

        # Returns NotFound.
        result = self._results_recv[cmd.command_id]['result']
        self.assertIsInstance(result, NotFound)

        # Publish a telemetry unavailable event.
        # This will cause the endpoint clients to disconnect and go to sleep.
        self.on_link_down()

        gevent.sleep(1)

    def test_bad_commands(self):
        """
        test_bad_commands
        Test for correct exception behavior if a bad command name is forwarded
        to a remote service or resource.
        """
        
        # Start the IA and check it's out there and behaving.
        self.start_agent()
        
        state = self._ia_client.get_agent_state()
        log.debug('Agent state is: %s', state)
        self.assertEqual(state, ResourceAgentState.UNINITIALIZED)

        retval = self._ia_client.ping_agent()
        log.debug('Agent ping is: %s', str(retval))
        self.assertIn('ping from InstrumentAgent', retval)
        
        # Publish a telemetry available event.
        # This will cause the endpoint clients to wake up and connect.
        self.on_link_up()

        # Wait for the link to be up.
        # The remote side does not publish public telemetry events
        # so we can't wait for that.
        gevent.sleep(1)

        # Send commands one at a time.
        # Reset queues and events.
        self._no_requests = 1
        self._done_evt = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        self._requests_sent = {}
        self._results_recv = {}
        
        # Create user object.
        obj = IonObject("UserInfo", name="some_name")
        cmd = IonObject('RemoteCommand',
                             resource_id='',
                             svc_name='resource_registry',
                             command='what_the_flunk',
                             args=[obj],
                             kwargs='',
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd)
        
        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)
        
        # Returns BadRequest.
        result = self._results_recv[cmd.command_id]['result']
        self.assertIsInstance(result, BadRequest)

        # Send commands one at a time.
        # Reset queues and events.
        self._no_requests = 1
        self._done_evt = AsyncResult()
        self._cmd_tx_evt = AsyncResult()
        self._requests_sent = {}
        self._results_recv = {}

        # Get agent state via remote endpoint.        
        cmd = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='what_the_flunk',
                             args=[],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd)
        
        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)

        # Returns NotFound.
        result = self._results_recv[cmd.command_id]['result']
        self.assertIsInstance(result, BadRequest)
        
        # Publish a telemetry unavailable event.
        # This will cause the endpoint clients to disconnect and go to sleep.
        self.on_link_down()

        gevent.sleep(1)

    def test_resource_command_sequence(self):
        """
        test_resource_command_sequence
        Test for successful completion of a properly ordered sequence of
        resource commands queued for forwarding to the remote endpoint.
        """
        # Start the IA and check it's out there and behaving.
        self.start_agent()
        
        state = self._ia_client.get_agent_state()
        log.debug('Agent state is: %s', state)
        self.assertEqual(state, ResourceAgentState.UNINITIALIZED)

        retval = self._ia_client.ping_agent()
        log.debug('Agent ping is: %s', str(retval))
        self.assertIn('ping from InstrumentAgent', retval)

        # We execute a sequence of twelve consecutive events.
        self._no_requests = 12

        # Get agent state.
        cmd1 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='get_agent_state',
                             args=[],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd1)
        
        # Initialize agent.
        cmd2 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='execute_agent',
                             args=[AgentCommand(command=ResourceAgentEvent.INITIALIZE)],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd2)
        
        # Get agent state.
        cmd3 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='get_agent_state',
                             args=[],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd3)
        
        # Go active.
        cmd4 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='execute_agent',
                             args=[AgentCommand(command=ResourceAgentEvent.GO_ACTIVE)],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd4)
        
        # Get agent state.
        cmd5 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='get_agent_state',
                             args=[],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd5)
        
        # Run.
        cmd6 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='execute_agent',
                             args=[AgentCommand(command=ResourceAgentEvent.RUN)],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd6)
        
        # Get agent state.
        cmd7 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='get_agent_state',
                             args=[],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd7)
        
        # Acquire sample.
        cmd8 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='execute_resource',
                             args=[AgentCommand(command=SBE37ProtocolEvent.ACQUIRE_SAMPLE)],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd8)
        
        # Acquire sample
        cmd9 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='execute_resource',
                             args=[AgentCommand(command=SBE37ProtocolEvent.ACQUIRE_SAMPLE)],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd9)
        
        # Acquire sample.
        cmd10 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='execute_resource',
                             args=[AgentCommand(command=SBE37ProtocolEvent.ACQUIRE_SAMPLE)],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd10)
        
        # Reset.
        cmd11 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='execute_agent',
                             args=[AgentCommand(command=ResourceAgentEvent.RESET)],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd11)
        
        # Get agent state.
        cmd12 = IonObject('RemoteCommand',
                             resource_id=IA_RESOURCE_ID,
                             svc_name='',
                             command='get_agent_state',
                             args=[],
                             kwargs={},
                             command_id = str(uuid.uuid4()))
        self._terrestrial_client.enqueue(cmd12)

        
        # Publish a telemetry available event.
        # This will cause the endpoint clients to wake up and connect.
        self.on_link_up()
        
        # Wait for command request to be acked.
        # Wait for response to arrive.
        self._cmd_tx_evt.get(timeout=CFG.endpoint.receive.timeout)
        self._done_evt.get(timeout=CFG.endpoint.receive.timeout)

        # Check results of command sequence.
        """
        0ccf1e10-eeca-400d-aefe-f9d6888ec963   {'result': 'RESOURCE_AGENT_STATE_INACTIVE', 'command_id': '0ccf1e10-eeca-400d-aefe-f9d6888ec963'}
        92531bdf-c2c8-4aa8-817d-5107c7311b37   {'result': <interface.objects.AgentCommandResult object at 0x10d7f11d0>, 'command_id': '92531bdf-c2c8-4aa8-817d-5107c7311b37'}
        509934a1-5038-40d8-8014-591e2d8042b6   {'result': 'RESOURCE_AGENT_STATE_COMMAND', 'command_id': '509934a1-5038-40d8-8014-591e2d8042b6'}
        88bacbb7-5366-4d27-9ecf-fff2bec34b2c   {'result': <interface.objects.AgentCommandResult object at 0x10d389190>, 'command_id': '88bacbb7-5366-4d27-9ecf-fff2bec34b2c'}
        f8b4d3fa-a249-439b-8bd4-ac212b6100aa   {'result': <interface.objects.AgentCommandResult object at 0x10d3893d0>, 'command_id': 'f8b4d3fa-a249-439b-8bd4-ac212b6100aa'}
        8ae98e39-fdb3-4218-ad8f-584620397d9f   {'result': <interface.objects.AgentCommandResult object at 0x10d739990>, 'command_id': '8ae98e39-fdb3-4218-ad8f-584620397d9f'}
        746364a1-c4c7-400f-96d4-ee36df5dc1a4   {'result': BadRequest('Execute argument "command" not set.',), 'command_id': '746364a1-c4c7-400f-96d4-ee36df5dc1a4'}
        d516d3d9-e4f9-4ea5-80e0-34639a6377b5   {'result': <interface.objects.AgentCommandResult object at 0x10d3b2350>, 'command_id': 'd516d3d9-e4f9-4ea5-80e0-34639a6377b5'}
        c7da03f5-59bc-420a-9e10-0a7794266599   {'result': 'RESOURCE_AGENT_STATE_IDLE', 'command_id': 'c7da03f5-59bc-420a-9e10-0a7794266599'}
        678d870a-bf18-424a-afb0-f80ecf3277e2   {'result': <interface.objects.AgentCommandResult object at 0x10d739590>, 'command_id': '678d870a-bf18-424a-afb0-f80ecf3277e2'}
        750c6a30-56eb-4535-99c2-a81fefab1b1f   {'result': 'RESOURCE_AGENT_STATE_COMMAND', 'command_id': '750c6a30-56eb-4535-99c2-a81fefab1b1f'}
        c17bd658-3775-4aa3-8844-02df70a0e3c0   {'result': 'RESOURCE_AGENT_STATE_UNINITIALIZED', 'command_id': 'c17bd658-3775-4aa3-8844-02df70a0e3c0'}
        """        
        
        # First result is a state string.
        result1 = self._results_recv[cmd1.command_id]['result']
        self.assertEqual(result1, ResourceAgentState.UNINITIALIZED)
        
        # Second result is an empty AgentCommandResult.
        result2 = self._results_recv[cmd2.command_id]['result']

        # Third result is a state string.
        result3 = self._results_recv[cmd3.command_id]['result']
        self.assertEqual(result3, ResourceAgentState.INACTIVE)
        
        # Fourth result is an empty AgentCommandResult.
        result4 = self._results_recv[cmd4.command_id]['result']

        # Fifth result is a state string.
        result5 = self._results_recv[cmd5.command_id]['result']
        self.assertEqual(result5, ResourceAgentState.IDLE)

        # Sixth result is an empty AgentCommandResult.
        result6 = self._results_recv[cmd6.command_id]['result']

        # Seventh result is a state string.
        result7 = self._results_recv[cmd7.command_id]['result']
        self.assertEqual(result7, ResourceAgentState.COMMAND)
        
        """
        {'raw': {'quality_flag': 'ok', 'preferred_timestamp': 'driver_timestamp',
        'stream_name': 'raw', 'pkt_format_id': 'JSON_Data',
        'pkt_version': 1, '
        values': [{'binary': True, 'value_id': 'raw',
        'value': 'NzkuNDM3MywxNy4yMDU2NCwgNzYxLjg4NSwgICA2LjIxOTgsIDE1MDYuMzk3LCAwMSBGZWIgMjAwMSwgMDE6MDE6MDA='}],
        'driver_timestamp': 3558286748.8039923},
        'parsed': {'quality_flag': 'ok', 'preferred_timestamp': 'driver_timestamp',
        'stream_name': 'parsed', 'pkt_format_id': 'JSON_Data', 'pkt_version': 1,
        'values': [{'value_id': 'temp', 'value': 79.4373},
        {'value_id': 'conductivity', 'value': 17.20564},
        {'value_id': 'pressure', 'value': 761.885}],
        'driver_timestamp': 3558286748.8039923}}
        """
        
        # Eigth result is an AgentCommandResult containing a sample.
        result8 = self._results_recv[cmd8.command_id]['result']
        self.assertTrue('parsed',result8.result )
        
        # Ninth result is an AgentCommandResult containing a sample.
        result9 = self._results_recv[cmd9.command_id]['result']
        self.assertTrue('parsed',result9.result )

        # Tenth result is an AgentCommandResult containing a sample.
        result10 = self._results_recv[cmd10.command_id]['result']
        self.assertTrue('parsed',result10.result )

        # Eleventh result is an empty AgentCommandResult.
        result11 = self._results_recv[cmd11.command_id]['result']

        # Twelth result is a state string.
        result12 = self._results_recv[cmd12.command_id]['result']
        self.assertEqual(result1, ResourceAgentState.UNINITIALIZED)
        
        # Publish a telemetry unavailable event.
        # This will cause the endpoint clients to disconnect and go to sleep.
        self.on_link_down()

        gevent.sleep(1)
示例#53
0
class AceClient(object):
    def __init__(self,
                 clientcounter,
                 ace,
                 connect_timeout=5,
                 result_timeout=10):
        # Telnet socket response buffer
        self._recvbuffer = None
        # AceEngine socket
        self._socket = None
        # AceEngine read result timeout
        self._resulttimeout = result_timeout
        # AceEngine product key
        self._product_key = None
        # Result (Created with AsyncResult() on call)
        self._auth = AsyncResult()
        # Result for START URL
        self._url = AsyncResult()
        # Response time from AceEngine to get URL or DATA
        self._videotimeout = None
        # Result for CID
        self._cid = AsyncResult()
        # Result fo LOADASYNC
        self._loadasync = AsyncResult()
        # Current STATUS
        self._status = AsyncResult()
        # Current EVENT
        self._event = AsyncResult()
        # Current STATE
        self._state = AsyncResult()
        # Current AUTH
        self._gender = self._age = None
        # Seekback seconds.
        self._seekback = None
        # Did we get START command again? For seekback.
        self._started_again = Event()
        # ClientCounter
        self._clientcounter = clientcounter
        # AceConfig.ace
        self._ace = ace

        try:
            self._socket = Telnet(self._ace['aceHostIP'],
                                  self._ace['aceAPIport'], connect_timeout)
            logging.debug(
                'Successfully connected to AceStream on {aceHostIP}:{aceAPIport}'
                .format(**self._ace))
        except:
            errmsg = 'The are no alive AceStream Engines found!'
            raise AceException(errmsg)

    def destroy(self):
        '''
        AceClient Destructor
        '''
        # Send SHUTDOWN to AceEngine
        try:
            self._write(AceMessage.request.SHUTDOWN)
        except:
            pass  # Ignore exceptions on destroy
        finally:
            self._clientcounter.idleAce = None

    def reset(self):
        '''
        Reset initial values
        '''
        self._started_again.clear()
        self._url.set()
        self._loadasync.set()
        self._cid.set()
        self._status.set()
        self._event.set()
        self._state.set()

    def _write(self, message):
        try:
            self._socket.write('%s\r\n' % message)
            logging.debug('>>> %s' % message)
        except gevent.socket.error:
            raise AceException('Error writing data to AceEngine API port')

    def aceInit(self,
                gender=AceConst.SEX_MALE,
                age=AceConst.AGE_25_34,
                product_key=None,
                videoseekback=0,
                videotimeout=30):
        self._gender = gender
        self._age = age
        self._product_key = product_key
        self._seekback = videoseekback
        self._videotimeout = videotimeout
        self._started_again.clear()
        # Spawning telnet data reader with recvbuffer read timeout (allowable STATE 0 (IDLE) time)
        gevent.spawn(
            wrap_errors((EOFError, gevent.socket.error), self._recvData),
            self._videotimeout).link_exception(lambda x: logging.error(
                'Error reading data from AceEngine API port'))

        self._auth = AsyncResult()
        self._write(AceMessage.request.HELLO)  # Sending HELLOBG
        try:
            params = self._auth.get(timeout=self._resulttimeout)
        except gevent.Timeout as t:
            errmsg = 'Engine response time %s exceeded. HELLOTS not resived!' % t
            raise AceException(errmsg)

        if isinstance(params, dict):
            self._write(
                AceMessage.request.READY(params.get('key', ''),
                                         self._product_key))
        else:
            self._auth.set(params)

        try:
            if self._auth.get(
                    timeout=self._resulttimeout
            ) == 'NOTREADY':  # Get NOTREADY instead AUTH user_auth_level
                errmsg = 'NOTREADY recived from AceEngine! Wrong acekey?'
                raise AceException(errmsg)
        except gevent.Timeout as t:
            errmsg = 'Engine response time %s exceeded. AUTH not resived!' % t
            raise AceException(errmsg)

        if int(params.get('version_code',
                          0)) >= 3003600:  # Display download_stopped massage
            params_dict = {'use_stop_notifications': '1'}
            self._write(AceMessage.request.SETOPTIONS(params_dict))

    def START(self, command, paramsdict, acestreamtype):
        '''
        Start video method. Get url for play from AceEngine
        '''
        paramsdict['stream_type'] = ' '.join(
            ['{}={}'.format(k, v) for k, v in acestreamtype.items()])
        self._url = AsyncResult()
        self._write(AceMessage.request.START(command.upper(), paramsdict))
        try:
            return self._url.get(timeout=self._videotimeout)
        except gevent.Timeout as t:
            errmsg = 'START URL not received! Engine response time %s exceeded' % t
            raise AceException(errmsg)

    def STOP(self):
        '''
        Stop video method
        '''
        if self._state:
            self._write(AceMessage.request.STOP)

    def LOADASYNC(self, command, params, sessionid='0'):
        self._loadasync = AsyncResult()
        self._write(
            AceMessage.request.LOADASYNC(command.upper(), sessionid, params))
        try:
            return self._loadasync.get(
                timeout=self._resulttimeout)  # Get _contentinfo json
        except gevent.Timeout as t:
            errmsg = 'Engine response %s time exceeded. LOADARESP not resived!' % t
            raise AceException(errmsg)

    def GETCONTENTINFO(self, command, value, sessionid='0'):
        paramsdict = {
            command: value,
            'developer_id': '0',
            'affiliate_id': '0',
            'zone_id': '0'
        }
        return self.LOADASYNC(command, paramsdict, sessionid)

    def GETCID(self, command, value):
        contentinfo = self.GETCONTENTINFO(command, value)
        if contentinfo['status'] in (1, 2):
            paramsdict = {
                'checksum': contentinfo['checksum'],
                'infohash': contentinfo['infohash'],
                'developer_id': '0',
                'affiliate_id': '0',
                'zone_id': '0'
            }
            self._cid = AsyncResult()
            self._write(AceMessage.request.GETCID(paramsdict))
            try:
                return self._cid.get(timeout=self._resulttimeout)[2:]  # ##CID
            except gevent.Timeout as t:
                errmsg = 'Engine response time %s exceeded. CID not resived!' % t
                raise AceException(errmsg)
        else:
            errmsg = 'LOADASYNC returned error with message: %s' % contentinfo[
                'message']
            raise AceException(errmsg)

    def GETINFOHASH(self, command, value, sessionid='0', idx=0):
        contentinfo = self.GETCONTENTINFO(command, value, sessionid)
        if contentinfo['status'] in (1, 2):
            return contentinfo['infohash'], next(
                iter([x[0] for x in contentinfo['files'] if x[1] == int(idx)]),
                None)
        elif contentinfo['status'] == 0:
            errmsg = 'LOADASYNC returned status 0: The transport file does not contain audio/video files'
            raise AceException(errmsg)
        else:
            errmsg = 'LOADASYNC returned error with message: %s' % contentinfo[
                'message']
            raise AceException(errmsg)

    def _recvData(self, timeout=30):
        '''
        Data receiver method for greenlet
        '''
        while 1:
            # Destroy socket connection if AceEngine STATE 0 (IDLE) and we didn't read anything from socket until Nsec
            with gevent.Timeout(timeout, False):
                try:
                    self._recvbuffer = self._socket.read_until('\r\n',
                                                               None).strip()
                except gevent.Timeout:
                    self.destroy()
                except gevent.socket.timeout:
                    pass
                except:
                    raise
                else:
                    logging.debug('<<< %s' % unquote(self._recvbuffer))
                    # Parsing everything only if the string is not empty
                    # HELLOTS
                    if self._recvbuffer.startswith('HELLOTS'):
                        #version=engine_version version_code=version_code key=request_key http_port=http_port
                        self._auth.set({
                            k: v
                            for k, v in (x.split('=')
                                         for x in self._recvbuffer.split()
                                         if '=' in x)
                        })
                    # NOTREADY
                    elif self._recvbuffer.startswith('NOTREADY'):
                        self._auth.set('NOTREADY')
                        # AUTH
                    elif self._recvbuffer.startswith('AUTH'):
                        self._auth.set(
                            self._recvbuffer.split()[1])  # user_auth_level
                        # START
                    elif self._recvbuffer.startswith('START'):
                        # url [ad=1 [interruptable=1]] [stream=1] [pos=position]
                        params = {
                            k: v
                            for k, v in (x.split('=')
                                         for x in self._recvbuffer.split()
                                         if '=' in x)
                        }
                        if not self._seekback or self._started_again.ready(
                        ) or params.get('stream', '') is not '1':
                            # If seekback is disabled, we use link in first START command.
                            # If seekback is enabled, we wait for first START command and
                            # ignore it, then do seekback in first EVENT position command
                            # AceStream sends us STOP and START again with new link.
                            # We use only second link then.
                            self._url.set(
                                self._recvbuffer.split()[1])  # url for play
                    # LOADRESP
                    elif self._recvbuffer.startswith('LOADRESP'):
                        self._loadasync.set(
                            json.loads(
                                unquote(''.join(
                                    self._recvbuffer.split()[2:]))))
                    # STATE
                    elif self._recvbuffer.startswith('STATE'):
                        self._state.set(self._recvbuffer.split()
                                        [1])  # STATE state_id -> STATE_NAME
                    # STATUS
                    elif self._recvbuffer.startswith('STATUS'):
                        self._tempstatus = self._recvbuffer.split()[1]
                        stat = [self._tempstatus.split(';')[0].split(':')[1]
                                ]  # main:????
                        if self._tempstatus.startswith('main:idle'): pass
                        elif self._tempstatus.startswith('main:loading'): pass
                        elif self._tempstatus.startswith('main:starting'): pass
                        elif self._tempstatus.startswith('main:check'): pass
                        elif self._tempstatus.startswith('main:err'):
                            pass  # err;error_id;error_message
                        elif self._tempstatus.startswith('main:dl'):  #dl;
                            stat.extend(
                                map(int,
                                    self._tempstatus.split(';')[1:]))
                        elif self._tempstatus.startswith(
                                'main:wait'):  #wait;time;
                            stat.extend(
                                map(int,
                                    self._tempstatus.split(';')[2:]))
                        elif self._tempstatus.startswith(
                            ('main:prebuf', 'main:buf')):  #buf;progress;time;
                            stat.extend(
                                map(int,
                                    self._tempstatus.split(';')[3:]))
                        try:
                            self._status.set({
                                k: v
                                for k, v in zip(AceConst.STATUS, stat)
                            })  # dl, wait, buf, prebuf
                        except:
                            self._status.set(
                                {'status':
                                 stat[0]})  # idle, loading, starting, check
                    # CID
                    elif self._recvbuffer.startswith('##'):
                        self._cid.set(self._recvbuffer)
                        # INFO
                    elif self._recvbuffer.startswith('INFO'):
                        pass
                        # EVENT
                    elif self._recvbuffer.startswith('EVENT'):
                        self._tempevent = self._recvbuffer.split()
                        if self._seekback and not self._started_again.ready(
                        ) and 'livepos' in self._tempevent:
                            params = {
                                k: v
                                for k, v in (x.split('=')
                                             for x in self._tempevent
                                             if '=' in x)
                            }
                            self._write(
                                AceMessage.request.LIVESEEK(
                                    int(params['last']) - self._seekback))
                            self._started_again.set()
                        elif 'getuserdata' in self._tempevent:
                            self._write(
                                AceMessage.request.USERDATA(
                                    self._gender, self._age))
                        elif 'cansave' in self._tempevent:
                            pass
                        elif 'showurl' in self._tempevent:
                            pass
                        elif 'download_stopped' in self._tempevent:
                            pass
                    # PAUSE
                    elif self._recvbuffer.startswith('PAUSE'):
                        pass  #self._write(AceMessage.request.EVENT('pause'))
                        # RESUME
                    elif self._recvbuffer.startswith('RESUME'):
                        pass  #self._write(AceMessage.request.EVENT('play'))
                        # STOP
                    elif self._recvbuffer.startswith('STOP'):
                        pass  #self._write(AceMessage.request.EVENT('stop'))
                        # SHUTDOWN
                    elif self._recvbuffer.startswith('SHUTDOWN'):
                        self._socket.close()
                        break
示例#54
0
class Bucket(AsyncBucket):
    def __init__(self, *args, **kwargs):
        """
        This class is a 'GEvent'-optimized subclass of libcouchbase
        which utilizes the underlying IOPS structures and the gevent
        event primitives to efficiently utilize couroutine switching.
        """
        super(Bucket, self).__init__(IOPS(), *args, **kwargs)

    def _do_ctor_connect(self):
        if self.connected:
            return

        self._connect()
        self._evconn = AsyncResult()
        self._conncb = self._on_connected
        self._evconn.get()
        self._evconn = None

    def _on_connected(self, err):
        if err:
            self._evconn.set_exception(err)
        else:
            self._evconn.set(None)

    def _waitwrap(self, cbasync):
        cur_thread = getcurrent()
        errback = lambda r, x, y, z: cur_thread.throw(x, y, z)
        cbasync.set_callbacks(cur_thread.switch, errback)
        try:
            return get_hub().switch()
        finally:
            # Deregister callbacks to prevent another request on the same
            # greenlet to get the result from this context.
            cbasync.set_callbacks(dummy_callback, dummy_callback)

    def _meth_factory(meth, name):
        def ret(self, *args, **kwargs):
            return self._waitwrap(meth(self, *args, **kwargs))

        return ret

    def _http_request(self, **kwargs):
        res = super(Bucket, self)._http_request(**kwargs)

        w = Waiter()
        res.callback = lambda x: w.switch(x)
        res.errback = lambda x, c, o, b: w.throw(c, o, b)
        return w.get()

    def query(self, *args, **kwargs):
        kwargs['itercls'] = GView
        return super(Bucket, self).query(*args, **kwargs)

    def n1ql_query(self, query, *args, **kwargs):
        kwargs['itercls'] = GN1QLRequest
        return super(Bucket, self).n1ql_query(query, *args, **kwargs)

    def _get_close_future(self):
        ev = Event()

        def _dtor_cb(*args):
            ev.set()

        self._dtorcb = _dtor_cb
        return ev

    locals().update(AsyncBucket._gen_memd_wrappers(_meth_factory))
class TransactionDummy(ATransaction):
    ping_timeout = 5  # sec
    result_timeout = 20  # sec

    def __init__(self,
                 callback_url: str,
                 local_timeout: float,
                 ping_timeout=None,
                 result_timeout=None):
        super().__init__(ObjectId())
        self.callback_url = callback_url
        self.local_timeout = local_timeout
        self.ping_timeout = ping_timeout if ping_timeout is not None else TransactionDummy.ping_timeout  # type: float
        self.result_timeout = result_timeout if result_timeout is not None else TransactionDummy.result_timeout  # type: float

        self.key = sha256(
            bytes(str(self.id) +
                  str(int(time.time() * 10**6) ^ randint(0, 2**20)),
                  encoding="utf-8")).hexdigest()

        debug_SSE.event({
            "event": "init",
            "t": datetime.now(),
            "data": {
                "callback_url": self.callback_url,
                "local_timeout": self.local_timeout * 1000,
                "result_timeout": self.result_timeout * 1000,
                "ping_timeout": self.ping_timeout * 1000,
                "key": self.key,
                "_id": self.id
            }
        })  # DEBUG init

        self._ping = Event()
        self.result = AsyncResult()
        self.ping_timeout_thread_obj = None  # type: Greenlet
        self.result_thread_obj = None  # type: Greenlet

    @g_async
    def _spawn(self):
        self.ping_timeout_thread_obj = self.ping_timeout_thread(
        )  # THREAD:1, loop

    # wait((self.ready_commit, self.fail), timeout=self.local_timeout)  # BLOCK, timeout
    # wait((self.commit, self.fail))  # BLOCK

    @g_async
    def ping_timeout_thread(self):
        while not (self.done.ready() or self.fail.ready()):
            debug_SSE.event({
                "event": "wait_ping",
                "t": datetime.now(),
                "data": None
            })  # DEBUG wait_ping
            w = wait((self._ping, self.done, self.fail),
                     count=1,
                     timeout=self.ping_timeout * 2)  # BLOCK, timeout
            if not len(w):
                debug_SSE.event({
                    "event": "fail",
                    "t": datetime.now(),
                    "data": "ping timeout"
                })  # DEBUG ping timeout
                self.fail.set()  # EMIT(fail)
                break

            if self._ping.ready():
                debug_SSE.event({
                    "event": "ping",
                    "t": datetime.now(),
                    "data": None
                })  # DEBUG ping
                self._ping.clear()  # EMIT(-ping)
                sleep()

    def do_work(self, resource):
        self.result_thread_obj = self.result_thread(resource)  # THREAD:1

    @g_async
    def result_thread(self, resource):
        sleep(self.result_timeout)  # BLOCK, sleep
        if not (self.ready_commit.ready() or self.fail.ready()):
            self.result.set(resource)  # EMIT(result)
            self.ready_commit.set()  # EMIT(ready_commit)
            debug_SSE.event({
                "event": "ready_commit",
                "t": datetime.now(),
                "data": None
            })  # DEBUG ready_commit
            data = {"key": self.key, "response": {"data": self.result.get()}}
            rp = requests.put(self.callback_url,
                              headers={"Connection": "close"},
                              json=data,
                              timeout=5)

    # else:
    # 	raise Exception("error during work")

    def ping(self) -> bool:
        if not (self.fail.ready() or self.done.ready()):
            self._ping.set()  # EMIT(ping)
            return True
        return False

    @g_async
    def do_commit(self):
        if not self.fail.ready():
            if self.ready_commit.ready() and self.result.ready():
                self.commit.set()  # EMIT(ping)
                debug_SSE.event({
                    "event": "commit",
                    "t": datetime.now(),
                    "data": None
                })  # DEBUG commit
            else:
                raise Exception("Error during commit")

            sleep(randint(self.ping_timeout - 2, self.ping_timeout + 2))

            data = {"key": self.key, "done": True}
            rp = requests.put(self.callback_url,
                              headers={"Connection": "close"},
                              json=data)
            debug_SSE.event({
                "event": "done",
                "t": datetime.now(),
                "data": None
            })  # DEBUG done

    @g_async
    def do_rollback(self):
        self.fail.set()  # EMIT(fail)
        debug_SSE.event({
            "event": "rollback",
            "t": datetime.now(),
            "data": None
        })  # DEBUG rollback
示例#56
0
 def _read_piece(self, fd, offset):
     event = AsyncResult()
     callback = partial(self._read_callback, event)
     aio_read(fd, offset, self.chunk_size, callback)
     return event.get()
示例#57
0
class AceClient(object):
    def __init__(self,
                 clientcounter,
                 ace,
                 connect_timeout=5,
                 result_timeout=10):
        # Telnet socket response buffer
        self._recvbuffer = None
        # Telnet socket response buffer read timeout
        self._recvbuffertimeout = 30
        # AceEngine socket
        self._socket = None
        # ClientCounter
        self._clientcounter = clientcounter
        # AceEngine read result timeout
        self._resulttimeout = float(result_timeout)
        # AceEngine product key
        self._product_key = None
        # Result (Created with AsyncResult() on call)
        self._auth = AsyncResult()
        # Result for START URL
        self._url = AsyncResult()
        # Response time from AceEngine to get URL or DATA
        self._videotimeout = None
        # Result for CID
        self._cid = AsyncResult()
        # Result fo LOADASYNC
        self._loadasync = AsyncResult()
        # Current STATUS
        self._status = AsyncResult()
        # Current EVENT
        self._event = AsyncResult()
        # Current STATE
        self._state = AsyncResult()
        # Current AUTH
        self._gender = None
        self._age = None
        # Seekback seconds.
        self._seekback = None
        # Did we get START command again? For seekback.
        self._started_again = Event()

        try:
            self._socket = Telnet(ace['aceHostIP'], ace['aceAPIport'],
                                  connect_timeout)
            logging.debug('Successfully connected to AceStream on %s:%s' %
                          (ace['aceHostIP'], ace['aceAPIport']))
        except:
            errmsg = 'The are no alive AceStream Engines found!'
            raise AceException(errmsg)
        else:
            gevent.spawn(self._recvData)  # Spawning telnet data reader

    def destroy(self):
        '''
        AceClient Destructor
        '''
        # Trying to disconnect
        logging.debug('Destroying AceStream client.....')
        try:
            self._write(AceMessage.request.SHUTDOWN)
        except:
            pass  # Ignore exceptions on destroy

    def reset(self):
        '''
        Reset initial values
        '''
        self._started_again.clear()
        self._url.set()
        self._loadasync.set()
        self._cid.set()

    def _write(self, message):
        try:
            logging.debug('>>> %s' % message)
            self._socket.write('%s\r\n' % message)
        except gevent.socket.error as e:
            raise AceException('Telnet exception at socket write %s' % repr(e))

    def aceInit(self,
                gender=AceConst.SEX_MALE,
                age=AceConst.AGE_25_34,
                product_key=None,
                videoseekback=0,
                videotimeout=30):
        self._gender = gender
        self._age = age
        self._product_key = product_key
        self._seekback = videoseekback
        self._videotimeout = float(videotimeout)
        self._started_again.clear()

        self._auth = AsyncResult()
        self._write(AceMessage.request.HELLO)  # Sending HELLOBG
        try:
            params = self._auth.get(timeout=self._resulttimeout)
        except gevent.Timeout:
            errmsg = 'Engine response time %ssec exceeded. HELLOTS not resived!' % self._resulttimeout
            raise AceException(errmsg)
            return

        self._auth = AsyncResult()
        self._write(
            AceMessage.request.READY(params.get('key', ''), self._product_key))
        try:
            if self._auth.get(
                    timeout=self._resulttimeout
            ) == 'NOTREADY':  # Get NOTREADY instead AUTH user_auth_level
                errmsg = 'NOTREADY recived from AceEngine! Wrong acekey?'
                raise AceException(errmsg)
                return
        except gevent.Timeout:
            errmsg = 'Engine response time %ssec exceeded. AUTH not resived!' % self._resulttimeout
            raise AceException(errmsg)

        if int(params.get('version_code',
                          0)) >= 3003600:  # Display download_stopped massage
            params_dict = {'use_stop_notifications': '1'}
            self._write(AceMessage.request.SETOPTIONS(params_dict))

    def START(self, command, paramsdict, acestreamtype):
        '''
        Start video method
        Return the url provided by AceEngine
        '''
        paramsdict['stream_type'] = ' '.join(
            ['{}={}'.format(k, v) for k, v in acestreamtype.items()])
        self._url = AsyncResult()
        self._write(AceMessage.request.START(command.upper(), paramsdict))
        try:
            return self._url.get(
                timeout=self._videotimeout)  # Get url for play from AceEngine
        except gevent.Timeout:
            errmsg = 'Engine response time %ssec exceeded. START URL not resived!' % self._videotimeout
            raise AceException(errmsg)

    def STOP(self):
        '''
        Stop video method
        '''
        self._state = AsyncResult()
        self._write(AceMessage.request.STOP)
        try:
            self._state.get(timeout=self._resulttimeout)
            self._started_again.clear()
        except gevent.Timeout:
            errmsg = 'Engine response time %ssec exceeded. STATE 0 (IDLE) not resived!' % self._resulttimeout
            raise AceException(errmsg)

    def LOADASYNC(self, command, params):
        self._loadasync = AsyncResult()
        self._write(
            AceMessage.request.LOADASYNC(command.upper(),
                                         random.randint(1, 100000), params))
        try:
            return self._loadasync.get(
                timeout=self._resulttimeout)  # Get _contentinfo json
        except gevent.Timeout:
            errmsg = 'Engine response %ssec time exceeded. LOADARESP not resived!' % self._resulttimeout
            raise AceException(errmsg)

    def GETCONTENTINFO(self, command, value):
        paramsdict = {
            command: value,
            'developer_id': '0',
            'affiliate_id': '0',
            'zone_id': '0'
        }
        return self.LOADASYNC(command, paramsdict)

    def GETCID(self, command, value):
        contentinfo = self.GETCONTENTINFO(command, value)
        if contentinfo['status'] in (1, 2):
            paramsdict = {
                'checksum': contentinfo['checksum'],
                'infohash': contentinfo['infohash'],
                'developer_id': '0',
                'affiliate_id': '0',
                'zone_id': '0'
            }
            self._cid = AsyncResult()
            self._write(AceMessage.request.GETCID(paramsdict))
            try:
                return self._cid.get(timeout=self._resulttimeout)[2:]  # ##CID
            except gevent.Timeout:
                errmsg = 'Engine response time %ssec exceeded. CID not resived!' % self._resulttimeout
                raise AceException(errmsg)
        else:
            errmsg = 'LOADASYNC returned error with message: %s' % contentinfo[
                'message']
            raise AceException(errmsg)

    def GETINFOHASH(self, command, value, idx=0):
        contentinfo = self.GETCONTENTINFO(command, value)
        if contentinfo['status'] in (1, 2):
            return contentinfo['infohash'], [
                x[0] for x in contentinfo['files'] if x[1] == int(idx)
            ][0]
        elif contentinfo['status'] == 0:
            errmsg = 'LOADASYNC returned status 0: The transport file does not contain audio/video files'
            raise AceException(errmsg)
        else:
            errmsg = 'LOADASYNC returned error with message: %s' % contentinfo[
                'message']
            raise AceException(errmsg)

    def AceStreamReader(self, url, cid, req_headers=None):
        '''
        Get stream from AceEngine url and write it to client(s)
        '''
        logging.debug('Start StreamReader for url: %s' % url)
        with requests.Session() as session:
            if req_headers:
                session.headers.update(req_headers)
                logging.debug('Sending headers from client to AceEngine: %s' %
                              session.headers)
            try:
                self._write(AceMessage.request.EVENT('play'))
                # AceEngine return link for HLS stream
                if url.endswith('.m3u8'):
                    _used_chunks = []
                    while self._state.get(
                            timeout=self._resulttimeout)[0] in ('2', '3'):
                        for line in session.get(
                                url, stream=True,
                                timeout=(5, self._videotimeout)).iter_lines():
                            if line.startswith(b'download not found'): return
                            if line.startswith(
                                    b'http://') and line not in _used_chunks:
                                self.RAWDataReader(
                                    session.get(line,
                                                stream=True,
                                                timeout=(5,
                                                         self._videotimeout)),
                                    self._clientcounter.getClientsList(cid))
                                _used_chunks.append(line)
                                if len(_used_chunks) > 15: _used_chunks.pop(0)
                # AceStream return link for HTTP stream
                else:
                    self.RAWDataReader(
                        session.get(url,
                                    stream=True,
                                    timeout=(5, self._videotimeout)),
                        self._clientcounter.getClientsList(cid))

            except Exception as err:
                clients = self._clientcounter.getClientsList(cid)
                if clients:
                    logging.error('"%s" StreamReader error: %s' %
                                  (clients[0].channelName, repr(err)))
                    gevent.wait([
                        gevent.spawn(self.write_chunk, c, b'', True)
                        for c in clients
                    ])  #b'0\r\n\r\n' - send the chunked trailer
            finally:
                _used_chunks = None

    def RAWDataReader(self, stream, clients):
        for chunk in stream.iter_content(
                chunk_size=1048576 if 'Content-Length' in
                stream.headers else None):
            if chunk:
                gevent.wait([
                    gevent.spawn(self.write_chunk, c, chunk) for c in clients
                ])

    def write_chunk(self, client, chunk, chunk_trailer=None):
        try:
            client.out.write(
                b'%X\r\n%s\r\n' %
                (len(chunk),
                 chunk)) if not client.transcoder else client.out.write(chunk)
        except:
            client.destroy()  # Client disconected
        if chunk_trailer: client.destroy()

    def _recvData(self):
        '''
        Data receiver method for greenlet
        '''
        while 1:
            try:
                with gevent.timeout.Timeout(self._recvbuffertimeout):
                    self._recvbuffer = self._socket.read_until(
                        '\r\n', timeout=None).strip()
            except EOFError as e:
                # if the connection is closed and no cooked data is available.
                raise AceException(
                    'Telnet exception at socket read. AceClient destroyed %s' %
                    repr(e))
                return
            # Ignore error occurs while reading blank lines from socket in STATE 0 (IDLE)
            except gevent.socket.timeout:
                pass
                # SHUTDOWN socket connection if AceEngine STATE 0 (IDLE) and we didn't read anything from socket until Nsec
            except gevent.timeout.Timeout:
                self.destroy()
                self._clientcounter.idleAce = None

            else:  # Parsing everything only if the string is not empty
                logging.debug('<<< %s' %
                              requests.compat.unquote(self._recvbuffer))
                # HELLOTS
                if self._recvbuffer.startswith('HELLOTS'):
                    # version=engine_version version_code=version_code key=request_key http_port=http_port
                    self._auth.set({
                        k: v
                        for k, v in (x.split('=')
                                     for x in self._recvbuffer.split()
                                     if '=' in x)
                    })
                # NOTREADY
                elif self._recvbuffer.startswith('NOTREADY'):
                    self._auth.set('NOTREADY')
                    # AUTH
                elif self._recvbuffer.startswith('AUTH'):
                    self._auth.set(
                        self._recvbuffer.split()[1])  # user_auth_level
                    # START
                elif self._recvbuffer.startswith('START'):
                    # url [ad=1 [interruptable=1]] [stream=1] [pos=position]
                    params = {
                        k: v
                        for k, v in (x.split('=')
                                     for x in self._recvbuffer.split()
                                     if '=' in x)
                    }
                    if not self._seekback or self._started_again.ready(
                    ) or params.get('stream', '') is not '1':
                        # If seekback is disabled, we use link in first START command.
                        # If seekback is enabled, we wait for first START command and
                        # ignore it, then do seekback in first EVENT position command
                        # AceStream sends us STOP and START again with new link.
                        # We use only second link then.
                        self._url.set(
                            self._recvbuffer.split()[1])  # url for play
                # LOADRESP
                elif self._recvbuffer.startswith('LOADRESP'):
                    self._loadasync.set(
                        requests.compat.json.loads(
                            requests.compat.unquote(''.join(
                                self._recvbuffer.split()[2:]))))
                # STATE
                elif self._recvbuffer.startswith(
                        'STATE'):  # tuple of (state_id, time of appearance)
                    self._state.set(
                        (self._recvbuffer.split()[1], gevent.time.time()))
                # STATUS
                elif self._recvbuffer.startswith('STATUS'):
                    self._tempstatus = self._recvbuffer.split()[1]
                    if self._tempstatus.startswith('main:idle'): pass
                    elif self._tempstatus.startswith('main:loading'): pass
                    elif self._tempstatus.startswith('main:starting'): pass
                    elif self._tempstatus.startswith('main:check'): pass
                    elif self._tempstatus.startswith('main:wait'): pass
                    elif self._tempstatus.startswith(
                        ('main:prebuf', 'main:buf')):
                        pass  #progress;time
                        #values = list(map(int, self._tempstatus.split(';')[3:]))
                        #self._status.set({k: v for k, v in zip(AceConst.STATUS, values)})
                    elif self._tempstatus.startswith('main:dl'):
                        pass
                        #values = list(map(int, self._tempstatus.split(';')[1:]))
                        #self._status.set({k: v for k, v in zip(AceConst.STATUS, values)})
                    elif self._tempstatus.startswith(
                            'main:err'):  # err;error_id;error_message
                        self._status.set_exception(
                            AceException('%s with message %s' %
                                         (self._tempstatus.split(';')[0],
                                          self._tempstatus.split(';')[2])))
                # CID
                elif self._recvbuffer.startswith('##'):
                    self._cid.set(self._recvbuffer)
                    # INFO
                elif self._recvbuffer.startswith('INFO'):
                    pass
                    # EVENT
                elif self._recvbuffer.startswith('EVENT'):
                    self._tempevent = self._recvbuffer.split()
                    if self._seekback and not self._started_again.ready(
                    ) and 'livepos' in self._tempevent:
                        params = {
                            k: v
                            for k, v in (x.split('=') for x in self._tempevent
                                         if '=' in x)
                        }
                        self._write(
                            AceMessage.request.LIVESEEK(
                                int(params['last']) - self._seekback))
                        self._started_again.set()
                    elif 'getuserdata' in self._tempevent:
                        self._write(
                            AceMessage.request.USERDATA(
                                self._gender, self._age))
                    elif 'cansave' in self._tempevent:
                        pass
                    elif 'showurl' in self._tempevent:
                        pass
                    elif 'download_stopped' in self._tempevent:
                        pass
                # PAUSE
                elif self._recvbuffer.startswith('PAUSE'):
                    self._write(AceMessage.request.EVENT('pause'))
                    # RESUME
                elif self._recvbuffer.startswith('RESUME'):
                    self._write(AceMessage.request.EVENT('play'))
                    # STOP
                elif self._recvbuffer.startswith('STOP'):
                    pass
                    # SHUTDOWN
                elif self._recvbuffer.startswith('SHUTDOWN'):
                    self._socket.close()
                    logging.debug('AceClient destroyed')
                    return

            finally:
                gevent.sleep()
示例#58
0
class AceClient(object):
    def __init__(self, acehostslist, connect_timeout=5, result_timeout=10):
        # Receive buffer
        self._recvbuffer = None
        # Stream URL
        self._url = None
        # Ace stream socket
        self._socket = None
        # Result timeout
        self._resulttimeout = result_timeout
        # Shutting down flag
        self._shuttingDown = Event()
        # Product key
        self._product_key = None
        # Current STATUS
        self._status = None
        # Current STATE
        self._state = None
        # Current video position
        self._position = None
        # Available video position (loaded data)
        self._position_last = None
        # Buffered video pieces
        self._position_buf = None
        # Current AUTH
        self._auth = None
        self._gender = None
        self._age = None
        # Result (Created with AsyncResult() on call)
        self._result = AsyncResult()
        self._authevent = Event()
        # Result for getURL()
        self._urlresult = AsyncResult()
        # Result for GETCID()
        self._cidresult = AsyncResult()
        # Event for resuming from PAUSE
        self._resumeevent = Event()
        # Seekback seconds.
        self._seekback = AceConfig.videoseekback
        # Did we get START command again? For seekback.
        self._started_again = False

        self._idleSince = time.time()
        self._streamReaderConnection = None
        self._streamReaderState = None
        self._lock = threading.Condition(threading.Lock())
        self._streamReaderQueue = gevent.queue.Queue(
            maxsize=AceConfig.readcachesize)  # Ring buffer
        self._engine_version_code = 0

        # Logger
        logger = logging.getLogger('AceClientimport tracebacknt_init')
        # Try to connect AceStream engine
        for AceEngine in acehostslist:
            try:
                self._socket = telnetlib.Telnet(AceEngine[0], AceEngine[1],
                                                connect_timeout)
                AceConfig.acehost, AceConfig.aceAPIport, AceConfig.aceHTTPport = AceEngine[
                    0], AceEngine[1], AceEngine[2]
                logger.debug('Successfully connected to AceStream on %s:%d' %
                             (AceEngine[0], AceEngine[1]))
                break
            except:
                logger.debug('The are no alive AceStream on %s:%d' %
                             (AceEngine[0], AceEngine[1]))
                pass
        # Spawning recvData greenlet
        if self._socket:
            gevent.spawn(self._recvData)
            gevent.sleep()
        else:
            logger.error('The are no alive AceStream Engines found')
            return

    def destroy(self):
        '''
        AceClient Destructor
        '''
        logger = logging.getLogger('AceClient_destroy')  # Logger

        if self._shuttingDown.isSet():
            return  # Already in the middle of destroying

        self._resumeevent.set(
        )  # We should resume video to prevent read greenlet deadlock
        self._urlresult.set()  # And to prevent getUrl deadlock

        # Trying to disconnect
        try:
            logger.debug('Destroying AceStream client.....')
            self._shuttingDown.set()
            self._write(AceMessage.request.SHUTDOWN)
        except:
            pass  # Ignore exceptions on destroy
        finally:
            self._shuttingDown.set()

    def reset(self):
        self._started_again = False
        self._idleSince = time.time()
        self._streamReaderState = None

    def _write(self, message):
        try:
            logger = logging.getLogger('AceClient_write')
            logger.debug('>>> %s' % message)
            self._socket.write('%s\r\n' % message)
        except EOFError as e:
            raise AceException('Write error! %s' % repr(e))

    def aceInit(self,
                gender=AceConst.SEX_MALE,
                age=AceConst.AGE_25_34,
                product_key=AceConfig.acekey):
        self._product_key = product_key
        self._gender = gender
        self._age = age
        self._seekback = AceConfig.videoseekback
        self._started_again = False

        logger = logging.getLogger('AceClient_aceInit')
        self._write(AceMessage.request.HELLO)  # Sending HELLOBG

        if not self._authevent.wait(self._resulttimeout):
            errmsg = 'Authentication timeout during AceEngine init. Wrong key?'  # HELLOTS not resived from engine
            logger.error(errmsg)
            raise AceException(errmsg)
            return

        if not self._auth:
            errmsg = 'Authentication error during AceEngine init. Wrong key?'
            logger.error(errmsg)
            raise AceException(errmsg)
            return
        # Display download_stopped massage
        if self._engine_version_code >= 3003600:
            self._write(AceMessage.request.SETOPTIONS)

    def _getResult(self):
        try:
            result = self._result.get(timeout=self._resulttimeout)
            if not result:
                raise AceException('Result not received from %s:%s' %
                                   (AceConfig.acehost, AceConfig.aceAPIport))
        except gevent.Timeout:
            raise AceException('gevent_Timeout')
        return result

    def START(self, datatype, value, stream_type):
        '''
        Start video method
        '''
        if stream_type == 'hls' and self._engine_version_code >= 3010500:
            stream_type = 'output_format=hls' + ' transcode_audio=' + str(AceConfig.transcode_audio) \
                                              + ' transcode_mp3=' + str(AceConfig.transcode_mp3) \
                                              + ' transcode_ac3=' + str(AceConfig.transcode_ac3) \
                                              + ' preferred_audio_language=' + AceConfig.preferred_audio_language
        else:
            stream_type = 'output_format=http'

        self._urlresult = AsyncResult()
        self._write(
            AceMessage.request.START(datatype.upper(), value, stream_type))
        self._getResult()

    def STOP(self):
        '''
        Stop video method
        '''
        if self._state and self._state != '0':
            self._result = AsyncResult()
            self._write(AceMessage.request.STOP)
            self._getResult()

    def LOADASYNC(self, datatype, params):
        self._result = AsyncResult()
        self._write(
            AceMessage.request.LOADASYNC(
                datatype.upper(),
                random.randint(1, AceConfig.maxconns * 10000), params))
        return self._getResult()

    def GETCONTENTINFO(self, datatype, value):
        paramsdict = {
            datatype: value,
            'developer_id': '0',
            'affiliate_id': '0',
            'zone_id': '0'
        }
        return self.LOADASYNC(datatype, paramsdict)

    def GETCID(self, datatype, url):
        contentinfo = self.GETCONTENTINFO(datatype, url)
        self._cidresult = AsyncResult()
        self._write(
            AceMessage.request.GETCID(contentinfo.get('checksum'),
                                      contentinfo.get('infohash'), 0, 0, 0))
        cid = self._cidresult.get(True, 5)
        return '' if not cid or cid == '' else cid[2:]

    def getUrl(self, timeout=30):
        logger = logging.getLogger('AceClient_getURL')  # Logger
        try:
            res = self._urlresult.get(timeout=timeout)
            return res
        except gevent.Timeout:
            errmsg = 'Engine response time exceeded. GetURL timeout!'
            logger.error(errmsg)
            raise AceException(errmsg)

    def startStreamReader(self, url, cid, counter, req_headers=None):
        logger = logging.getLogger('StreamReader')
        logger.debug('Open video stream: %s' % url)
        self._streamReaderState = 1
        transcoder = None

        if 'range' in req_headers: del req_headers['range']
        logger.debug('Get headers from client: %s' % req_headers)

        with requests.get(url,
                          headers=req_headers,
                          stream=True,
                          timeout=(5, None)) as self._streamReaderConnection:
            try:
                if self._streamReaderConnection.status_code not in (200, 206):
                    logger.error('Failed to open video stream %s' % url)
                    return None

                if url.endswith('.m3u8'):
                    self._streamReaderConnection.headers = {
                        'Content-Type': 'application/octet-stream',
                        'Connection': 'Keep-Alive',
                        'Keep-Alive': 'timeout=15, max=100'
                    }
                    popen_params = {
                        "bufsize": AceConfig.readchunksize,
                        "stdout": PIPE,
                        "stderr": None,
                        "shell": False
                    }

                    if AceConfig.osplatform == 'Windows':
                        ffmpeg_cmd = 'ffmpeg.exe '
                        CREATE_NO_WINDOW = 0x08000000
                        CREATE_NEW_PROCESS_GROUP = 0x00000200
                        DETACHED_PROCESS = 0x00000008
                        popen_params.update(creationflags=CREATE_NO_WINDOW
                                            | DETACHED_PROCESS
                                            | CREATE_NEW_PROCESS_GROUP)
                    else:
                        ffmpeg_cmd = 'ffmpeg '

                    ffmpeg_cmd += '-hwaccel auto -hide_banner -loglevel fatal -re -i %s -c copy -f mpegts -' % url
                    transcoder = Popen(ffmpeg_cmd.split(), **popen_params)
                    out = transcoder.stdout
                    logger.warning(
                        'HLS stream detected. Ffmpeg transcoding started')
                else:
                    out = self._streamReaderConnection.raw

            except requests.exceptions.RequestException:
                logger.error('Failed to open video stream %s' % url)
                logger.error(traceback.format_exc())
            except:
                logger.error(traceback.format_exc())

            else:
                with self._lock:
                    self._streamReaderState = 2
                    self._lock.notifyAll()
                self.play_event()
                while 1:
                    self.getPlayEvent(
                    )  # Wait for PlayEvent (stop/resume sending data from AceEngine to streamReaderQueue)
                    clients = counter.getClients(cid)
                    try:
                        data = out.read(AceConfig.readchunksize)
                    except:
                        data = None
                    if data is not None and clients:
                        if self._streamReaderQueue.full():
                            self._streamReaderQueue.get()
                        self._streamReaderQueue.put(data)
                        for c in clients:
                            try:
                                c.queue.put(data, timeout=5)
                            except gevent.queue.Full:  #Queue.Full client does not read data from buffer until 5sec - disconnect it
                                if len(clients) > 1:
                                    logger.debug('Disconnecting client: %s' %
                                                 c.handler.clientip)
                                    c.destroy()
                    elif counter.count(cid) == 0:
                        logger.debug(
                            'All clients disconnected - broadcast stoped')
                        break
                    else:
                        logger.warning('No data received - broadcast stoped')
                        counter.deleteAll(cid)
                        break
            finally:
                with self._lock:
                    self._streamReaderState = None
                    self._lock.notifyAll()
                if transcoder:
                    try:
                        transcoder.kill()
                        logger.warning('Ffmpeg transcoding stoped')
                    except:
                        pass

    def closeStreamReader(self):
        logger = logging.getLogger('StreamReader')
        c = self._streamReaderConnection
        if c:
            logger.debug('Close video stream: %s' % c.url)
            c.close()
            self._streamReaderConnection = None
        self._streamReaderQueue.queue.clear()

    def getPlayEvent(self, timeout=None):
        '''
        Blocking while in PAUSE, non-blocking while in RESUME
        '''
        return self._resumeevent.wait(timeout=timeout)

    # EVENTS from client to AceEngine
    def play_event(self):
        self._write(AceMessage.request.PLAYEVENT)

    def pause_event(self):
        self._write(AceMessage.request.PAUSEEVENT)

    def stop_event(self):
        self._write(AceMessage.request.STOPEVENT)

    # END EVENTS

    def _recvData(self):
        '''
        Data receiver method for greenlet
        '''
        logger = logging.getLogger('AceClient_recvdata')

        while 1:
            gevent.sleep()
            try:
                self._recvbuffer = self._socket.read_until('\r\n').strip()
                logger.debug(
                    '<<< %s' %
                    requests.compat.unquote(self._recvbuffer).decode('utf8'))
            except:
                # If something happened during read, abandon reader.
                logger.error('Exception at socket read. AceClient destroyed')
                if not self._shuttingDown.isSet(): self._shuttingDown.set()
                return
            else:
                # Parsing everything only if the string is not empty

                # HELLOTS
                if self._recvbuffer.startswith(AceMessage.response.HELLO):
                    try:
                        params = {
                            k: v
                            for k, v in (x.split('=')
                                         for x in self._recvbuffer.split()
                                         if '=' in x)
                        }
                    except:
                        logger.error("Can't parse HELLOTS")
                        params = {}
                    if 'version_code' in params:
                        self._engine_version_code = params['version_code']
                    if 'key' in params:
                        self._write(
                            AceMessage.request.READY_key(
                                params['key'], self._product_key))
                        self._request_key = None
                    else:
                        self._write(AceMessage.request.READY_nokey)
                # NOTREADY
                elif self._recvbuffer.startswith(AceMessage.response.NOTREADY):
                    self._auth = None
                    self._authevent.set()
                    logger.error('AceEngine is not ready. Wrong auth?')
                # AUTH
                elif self._recvbuffer.startswith(AceMessage.response.AUTH):
                    try:
                        self._auth = self._recvbuffer.split()[1]
                        self._write(
                            AceMessage.request.USERDATA(
                                self._gender, self._age))
                    except:
                        pass
                    self._authevent.set()
                # GETUSERDATA
                elif self._recvbuffer.startswith(
                        AceMessage.response.GETUSERDATA):
                    raise AceException('You should init me first!')
                # LOADRESP
                elif self._recvbuffer.startswith(AceMessage.response.LOADRESP):
                    _contentinfo = json.loads(
                        requests.compat.unquote(' '.join(
                            self._recvbuffer.split()[2:])).decode('utf8'))
                    if _contentinfo.get('status') == 100:
                        logger.error(
                            'LOADASYNC returned error with message: %s' %
                            _contentinfo.get('message'))
                        self._result.set(False)
                    else:
                        self._result.set(_contentinfo)
                # START
                elif self._recvbuffer.startswith(AceMessage.response.START):
                    if not self._seekback or self._started_again or not self._recvbuffer.endswith(
                            ' stream=1'):
                        # If seekback is disabled, we use link in first START command.
                        # If seekback is enabled, we wait for first START command and
                        # ignore it, then do seekback in first EVENT position command
                        # AceStream sends us STOP and START again with new link.
                        # We use only second link then.
                        try:
                            self._urlresult.set(self._recvbuffer.split()[1])
                            self._resumeevent.set()
                        except IndexError as e:
                            self._url = None
                    else:
                        logger.debug('START received. Waiting for %s.' %
                                     AceMessage.response.LIVEPOS)
                # STATE
                elif self._recvbuffer.startswith(AceMessage.response.STATE):
                    self._state = self._recvbuffer.split()[1]
                    if self._state in ('0', '1'):
                        self._result.set(True)  #idle, starting
                    elif self._state == '6':
                        self._result.set(False)  # error
                # STATUS
                elif self._recvbuffer.startswith(AceMessage.response.STATUS):
                    self._status = self._recvbuffer.split()[1].split(';')
                    if 'main:err' in set(
                            self._status):  # main:err;error_id;error_message
                        logger.error('%s with message %s' %
                                     (self._status[0], self._status[2]))
                        self._result.set_exception(
                            AceException('%s with message %s' %
                                         (self._status[0], self._status[2])))
                        self._urlresult.set_exception(
                            AceException('%s with message %s' %
                                         (self._status[0], self._status[2])))
                # LIVEPOS
                elif self._recvbuffer.startswith(AceMessage.response.LIVEPOS):
                    if self._seekback and not self._started_again:
                        try:
                            params = {
                                k: v
                                for k, v in (x.split('=')
                                             for x in self._recvbuffer.split()
                                             if '=' in x)
                            }
                            self._write(
                                AceMessage.request.LIVESEEK(
                                    int(params['last']) - self._seekback))
                            logger.debug('Seeking back.....')
                            self._started_again = True
                        except:
                            logger.error("Can't parse %s" %
                                         AceMessage.response.LIVEPOS)
                # CID
                elif self._recvbuffer.startswith('##') or len(
                        self._recvbuffer) == 0:
                    self._cidresult.set(self._recvbuffer)
                    #DOWNLOADSTOP
                elif self._recvbuffer.startswith(
                        AceMessage.response.DOWNLOADSTOP):
                    pass
                    # INFO
                elif self._recvbuffer.startswith(AceMessage.response.INFO):
                    pass
                    # SHOWURL
                elif self._recvbuffer.startswith(AceMessage.response.SHOWURL):
                    pass
                    # CANSAVE
                elif self._recvbuffer.startswith(AceMessage.response.CANSAVE):
                    pass
                    # PAUSE
                elif self._recvbuffer.startswith(AceMessage.response.PAUSE):
                    self.pause_event()
                    self._resumeevent.clear()
                    # RESUME
                elif self._recvbuffer.startswith(AceMessage.response.RESUME):
                    self.play_event()
                    self._resumeevent.set()
                    # STOP
                elif self._recvbuffer.startswith(AceMessage.response.STOP):
                    pass
                    # SHUTDOWN
                elif self._recvbuffer.startswith(AceMessage.response.SHUTDOWN):
                    self._socket.get_socket().shutdown(SHUT_WR)
                    self._recvbuffer = self._socket.read_all()
                    self._socket.close()
                    logger.debug('AceClient destroyed')
                    return
示例#59
0
    def fetch_blocks(self, blockhashes_chain):
        # fetch blocks (no parallelism here)
        log_st.debug('fetching blocks', num=len(blockhashes_chain))
        assert blockhashes_chain
        blockhashes_chain.reverse()  # oldest to youngest
        num_blocks = len(blockhashes_chain)
        num_fetched = 0

        while blockhashes_chain:
            blockhashes_batch = blockhashes_chain[:self.max_blocks_per_request]
            t_blocks = []

            # try with protos
            protocols = self.synchronizer.protocols
            if not protocols:
                log_st.warn('no protocols available')
                return self.exit(success=False)

            for proto in protocols:
                if proto.is_stopped:
                    continue
                assert proto not in self.requests
                # request
                log_st.debug('requesting blocks', num=len(blockhashes_batch))
                deferred = AsyncResult()
                self.requests[proto] = deferred
                proto.send_getblocks(*blockhashes_batch)
                try:
                    t_blocks = deferred.get(
                        block=True, timeout=self.blocks_request_timeout)
                except gevent.Timeout:
                    log_st.warn('getblocks timed out, trying next proto')
                    continue
                finally:
                    del self.requests[proto]
                if not t_blocks:
                    log_st.warn('empty getblocks reply, trying next proto')
                    continue
                elif not isinstance(t_blocks[0], TransientBlock):
                    log_st.warn('received unexpected data',
                                data=repr(t_blocks))
                    t_blocks = []
                    continue
                # we have results
                if not [b.header.hash for b in t_blocks
                        ] == blockhashes_batch[:len(t_blocks)]:
                    log_st.warn('received wrong blocks, should ban peer')
                    t_blocks = []
                    continue
                break

            # add received t_blocks
            num_fetched += len(t_blocks)
            log_st.debug('received blocks',
                         num=len(t_blocks),
                         num_fetched=num_fetched,
                         total=num_blocks,
                         missing=num_blocks - num_fetched)

            if not t_blocks:
                log_st.warn('failed to fetch blocks',
                            missing=len(blockhashes_chain))
                return self.exit(success=False)

            ts = time.time()
            log_st.debug('adding blocks',
                         qsize=self.chainservice.block_queue.qsize())
            for t_block in t_blocks:
                assert t_block.header.hash == blockhashes_chain.pop(0)
                self.chainservice.add_block(
                    t_block, proto)  # this blocks if the queue is full
            log_st.debug('adding blocks done', took=time.time() - ts)

        # done
        last_block = t_block
        assert not len(blockhashes_chain)
        assert last_block.header.hash == self.blockhash
        log_st.debug('syncing finished')
        # at this point blocks are not in the chain yet, but in the add_block queue
        if self.chain_difficulty >= self.chain.head.chain_difficulty():
            self.chainservice.broadcast_newblock(last_block,
                                                 self.chain_difficulty,
                                                 origin=proto)

        self.exit(success=True)
示例#60
0
    def forward(self, *args, **kwargs):
        """
        Forward a service method to the terrestrial endpoint
        through the service interface.
        """
        func_name = kwargs.pop('func_name')
        try:
            link = kwargs.pop('link')
        except KeyError:
            link = True
        cid = ''
        try:
            remote_timeout = kwargs.pop('remote_timeout')
            if not isinstance(remote_timeout, int):
                remote_timeout = 0
            elif remote_timeout < 0:
                remote_timeout = 0
            elif remote_timeout == 0:
                pass
            else:
                cid = str(uuid.uuid4())

        except KeyError:
            remote_timeout = 0

        cmd = IonObject('RemoteCommand',
                        resource_id=self._resource_id,
                        svc_name=self._svc_name,
                        command=func_name,
                        command_id=cid,
                        args=args,
                        kwargs=kwargs)

        if remote_timeout == 0:
            return self._te_client.enqueue_command(cmd, link)

        else:

            if self._resource_id:
                origin = self._resource_id
            elif self._svc_name:
                origin = self._svc_name + self._xs_name

            pending_cmd = cmd
            async_result_evt = AsyncResult()

            def result_callback(evt, *args, **kwargs):
                """
                Callback for subscriber retrive blocking results.
                """
                #global async_result_evt
                if evt.type_ == 'RemoteCommandResult':
                    cmd = evt.command
                    if cmd.command_id == pending_cmd.command_id:
                        async_result_evt.set(cmd)

            sub = EventSubscriber(event_type='RemoteCommandResult',
                                  origin=origin,
                                  callback=result_callback)

            sub.start()
            #self._pending_cmd = cmd
            cmd = self._te_client.enqueue_command(cmd, link)
            try:
                result = async_result_evt.get(timeout=remote_timeout)
                #self._pending_cmd = None
                sub.stop()
            except gevent.Timeout:
                #self._pending_cmd = None
                sub.stop()
                raise Timeout('Timed out waiting for remote result.')

            return result