示例#1
0
文件: main.py 项目: Godhart/fvf
    def calculate(self, expression):
        """
        :param expression: string with expression to send to Calc App
        :return: ProtocolReply
        """
        start_time = time.time()
        if self._mock:
            try:
                result = evaluate(expression)
            except ZeroDivisionError:
                result = None
            except Exception as e:
                result = "Platform {}: exception occurred on calculate: {}".format(
                    self.name, e)
                exprint()
                tprint("calculate (with fail) elapsed {}".format(time.time() -
                                                                 start_time))
                return proto_failure(result, -2)
            tprint("calculate elapsed {}".format(time.time() - start_time))
            return proto_success(result)

        # NOTE: mock code just ended here. To avoid nesting there is no else, just flat code

        # TODO: optimize code - now it's way to hard (just send/receive and so much code!!!)
        c = self.request(new_message(self._io_interface, "send", expression),
                         None, [], {},
                         timeout=2.0)  # TODO: decrease timeout
        c_state = self._pop_request_state(c)
        if not self._request_state_is_success(c_state):
            tprint(
                "calculate (with fail result) elapsed {}".format(time.time() -
                                                                 start_time))
            return proto_failure("IO failed to send data")

        c = self.request(new_message(self._io_interface, "receive"),
                         None, [], {},
                         timeout=2.0)  # TODO: decrease timeout
        c_state = self._pop_request_state(c)
        if not self._request_state_is_success(c_state):
            tprint(
                "calculate (with fail result) elapsed {}".format(time.time() -
                                                                 start_time))
            return proto_failure("IO failed to receive response")
        # TODO: convert from string to number
        tprint("calculate elapsed {}".format(time.time() - start_time))
        result = PM.parse(c_state["__message__"]).reply_data["value"]
        if isinstance(
                result, (list, tuple)
        ):  # NOTE: softwarerunner returns list but stream_io returns single item
            result = result[0]
        if result.strip() == 'None':
            result = None
        else:
            try:
                result = int(result)
            except ValueError:
                result = float(result)
        return proto_success(result)
示例#2
0
文件: main.py 项目: Godhart/fvf
 def rpyc_send(self, data):
     """
     Sends data to app via stdin
     :param data: Data to send over stdin. Could be an item like str, bytearray or list/tuple of items
     :return: True if data were sent successfully, otherwise - False
     """
     start_time = time.time()
     if (self._mock is None or data == 'exit') and self._connection is None:
         return proto_failure("No connection. Ensure start is complete")
     try:
         if not isinstance(data, (list, tuple)):
             data = data,
         for m in data:
             if self._mock is None or data == 'exit':  # TODO: why data=='exit' overrides self._mock?
                 self._connection.root.send(m)
             else:
                 try:
                     if self._mock_eval:
                         r = evaluate(m)
                     else:
                         r = m
                 except Exception as e:
                     r = None
                 self._mock.append(str(r))
         if self._mock is None or data == 'exit':  # TODO: why data=='exit' overrides self._mock?
             self._connection.root.flush()
     except Exception as e:
         eprint("Platform {}: exception occurred during send: {}".format(
             self.name, e))
         exprint()
         return proto_failure(
             "Failed to send due to exception {}".format(e), -2)
     tprint("rpyc_send elapsed {}".format(time.time() - start_time))
     return proto_success(None)
示例#3
0
文件: main.py 项目: Godhart/fvf
 def _run(self, context, runs=None):  # TODO: threaded arg
     if runs is None:
         runs = self._runs
     if runs <= 0:
         runs = 0
     self._complete = 0
     self._remaining = runs
     if self._remaining > 0:
         self._reply(context, PM.notify("started sequence"))
     while self._remaining > 0:
         assert self._expr is not None, "Sequencer {} wasn't started!".format(self.name)
         start_time = time.time()
         expr_result = next(self._expr)
         # TODO: replace assertions with proto_fails?
         assert isinstance(expr_result, (list, tuple)), "Expression should return list or tuple"
         assert len(expr_result) > 0, "Expression should return list or tuple with length at least" \
                                      "3 if there is no channel specification and " \
                                      "4 if there is channel specification"
         if isinstance(expr_result[0], str) and expr_result[0][0] in ('@', '#'):
             channel = expr_result.pop(0)
         else:
             channel = None
         assert len(expr_result) >= 3, "Expression should return list or tupple with length at least" \
                                       "3 if there is no channel specification and " \
                                       "4 if there is channel specification"
         request_message = new_message(*expr_result)
         c = self.request(request_message,
                          None, [], {}, channel=channel, store_state=False)
         # NOTE: used default request handler (which just waits for success or failure reply)
         tprint("sequencer {} request elapsed {}".format(self.name, time.time()-start_time))
         # TODO: option to treat request completed when specific message is passed by over special interface
         self._complete += 1
         self._remaining -= 1
     return proto_success({"breaked": runs != self._complete, "runs_completed": self._complete}, None)
示例#4
0
文件: platformix.py 项目: Godhart/fvf
 def _stop(self, reply_contexts):
     """
     Stopping worker method. Does all necessary actions to stop platform after all stop conditions were met
     Derrived classes should call this in the end when overriding _stop method
     :return: True if successfully stopped - subject were stopped (whatever that means) and disconnected,
              otherwise - False
     """
     self._running = False
     self._stopping = False
     vprint("platform {} has been stopped".format(self.name))
     return proto_success(None)
示例#5
0
文件: platformix.py 项目: Godhart/fvf
 def _start(self, reply_contexts):
     """
     Startup worker method. Does all necessary actions to start platform instance after all start conditions were met
     Derrived classes should call this in the end when overriding _start method
     :return: True if successfully started (binded to subject and subject is in operational state), otherwise - False
     """
     self._running = True
     self._start_in_progress = False
     self._starting = False
     vprint("platform {} just started".format(self.name))
     return proto_success(None)
示例#6
0
文件: main.py 项目: Godhart/fvf
 def rpyc_log(self):
     if self._connection is None:
         return proto_failure("No connection. Ensure start is complete")
     try:
         data = self._connection.root.log
     except Exception as e:
         eprint(
             "Platform {}: exception occurred while getting log: {}".format(
                 self.name, e))
         exprint()
         return proto_failure(
             "Failed to get log due to exception {}".format(e), -2)
     return proto_success(data)
示例#7
0
 def _platformix_report(self, context, fake_reply, kind):
     """
     Reports about platform's state
     Currently only running and is_running supported
     * running - replies with retval True if platform is running, and False otherwise
     * is_running - successful reply if platform is running, and failure otherwise
     :param context:
     :param kind:
     :return:
     """
     if kind == "running":
         self._reply(context,
                     proto_success(["False", "True"][self._worker.running]),
                     fake_reply)
         return
     elif kind == "is_running":
         if self._worker.running:
             self._reply(context, proto_success("True", "state"),
                         fake_reply)
         else:
             self._reply(context, proto_failure("False"), fake_reply)
     else:
         self._reply(context, proto_failure("Unknown report request"),
                     fake_reply)
示例#8
0
 def _platformix_get(self, context, fake_reply, prop):
     """
     Get host's property.
     Value is returned in a success message as item with index same as property name
     :param context: messaging context
     :param prop: property symbolic name
     :return: None
     """
     if hasattr(self.host, prop):
         self._reply(context, proto_success(getattr(self.host, prop), prop),
                     fake_reply)
     else:
         self._reply(
             context,
             proto_failure("Property {} not found on {}".format(
                 prop, self.host.name)), fake_reply)
示例#9
0
文件: main.py 项目: Godhart/fvf
 def rpyc_receive(self, count=1, timeout=1.0):
     """
     Get's data that were sent by app via stdout
     :param count: Amount of lines to receive.
             set count to 0 to receive as much as possible, and at least one message
             set count to -1 to receive as much as possible, but nothing is acceptable too
     :param timeout: Time in seconds to wait for data
     :return: True if successfully received Data, otherwise - False. Data itself is contained in a reply to channel
              and Data is list of strings
     """
     start_time = time.time()
     if not isinstance(count, int) or count < -1:
         raise ValueError(
             "Count should be an integer in a range from -1 and up to +infinity"
         )
     if self._mock is None and self._connection is None:
         return proto_failure("No connection. Ensure start is complete")
     try:
         data = []
         if self._mock is not None:
             data = self._mock[:count]
             self._mock = self._mock[count:]
         else:
             while len(data) < count or count == 0 or count == -1:
                 received = self._connection.root.receive(timeout)
                 if received is None or len(received) == 0:
                     break
                 if isinstance(received, (list, tuple)):
                     data += received
                 else:
                     data.append(received)
     except Exception as e:
         eprint("Platform {}: exception occurred during receive: {}".format(
             self.name, e))
         exprint()
         return proto_failure(
             "Failed to receive due to exception {}".format(e), -2)
     tprint("rpyc_receive elapsed {}".format(time.time() - start_time))
     if 0 < count != len(data):
         return proto_failure("Not all requested data were received")
         # TODO: need a way to return partially received data
     elif count == 0 and len(data) == 0:
         return proto_failure("No data were received")
     else:
         return proto_success(data)
示例#10
0
 def _platformix_call(self, context, fake_reply, method, *args, **kwargs):
     """
     Calls host's method
     Call result is returned in a success message as value item
     :param context: messaging context
     :param method: method symbolic name
     :param args: args to method call
     :param kwargs: kwargs to method call
     :return: None
     """
     if hasattr(self.host, method):
         if not callable(getattr(self.host, method)):
             self._reply(
                 context,
                 proto_failure("Attribute {} of {} is a property".format(
                     property, self.host.name)), fake_reply)
             return
         try:
             result = getattr(self.host, method)(*args, **kwargs)
         except Exception as e:
             eprint(
                 "Platformix protocol: failed to call method {} of {} with args {}, kwargs {} "
                 "due to exception {}".format(method, self.host.name, args,
                                              kwargs, e))
             exprint()
             self._reply(
                 context,
                 proto_failure(
                     "Failed to call method {} of {} with args {}, kwargs {} "
                     "due to exception {}".format(method, self.host.name,
                                                  args, kwargs, e)),
                 fake_reply)
             return
         self._reply(context, proto_success(result), fake_reply)
     else:
         self._reply(
             context,
             proto_failure("Method {} not found on {}".format(
                 property, self.host.name)), fake_reply)
示例#11
0
 def _platformix_set(self, context, fake_reply, prop, value):
     """
     Set host's property to a value
     :param context: messaging context
     :param prop: property symbolic name
     :param value: value to set
     :return: None
     """
     if hasattr(self.host, prop):
         if not callable(getattr(self.host, prop)):
             try:
                 setattr(self.host, prop, value)
             except Exception as e:
                 eprint(
                     "Platformix protocol: failed to set attribute {} of {} to value {} "
                     "due to exception {}".format(prop, self.host.name,
                                                  value, e))
                 exprint()
                 self._reply(
                     context,
                     proto_failure(
                         "Failed to set attribute {} of {} to value {} "
                         "due to exception {}".format(
                             prop, self.host.name, value, e)), fake_reply)
                 return
             self._reply(context,
                         proto_success(getattr(self.host, prop), prop),
                         fake_reply)
         else:
             self._reply(
                 context,
                 proto_failure("Attribute {} of {} is a method".format(
                     prop, self.host.name)), fake_reply)
     else:
         self._reply(
             context,
             proto_failure("Property {} not found on {}".format(
                 prop, self.host.name)), fake_reply)
示例#12
0
文件: main.py 项目: Godhart/fvf
 def tcp_send(self, data):
     """
     Sends data to app via stdin
     :param data: Data to send over stdin. Could be an item like str, bytearray or list/tuple of items
     :return: True if data were sent successfully, otherwise - False
     """
     start_time = time.time()
     if self._mock is None and self._sock is None:
         return proto_failure("No connection. Ensure start is complete")
     try:
         if not isinstance(data, (list, tuple)):
             data = data,
         for m in data:
             if self._mock is None:
                 if not isinstance(m, bytearray):
                     if isinstance(m, str):
                         m = m.encode('UTF-8')
                     else:
                         return proto_failure("Send data is expected to be a string, bytearray or "
                                              "list/tuple of strings and bytearrays")
                 self._sock.sendall(m)
             else:
                 try:
                     if self._mock_eval and isinstance(m, str):
                         r = evaluate(m)
                     else:
                         r = m
                 except Exception as e:
                     r = None
                 self._mock.append(str(r))
     except Exception as e:
         eprint("Platform {} failed to send due to exception {}".format(self.name, e))
         exprint()
         return proto_failure("Failed to send due to exception {}".format(e), -2)
     tprint("tcp_send elapsed {}".format(time.time() - start_time))
     return proto_success(None)
示例#13
0
文件: main.py 项目: Godhart/fvf
 def _do_break(self, context):
     # NOTE: make's sense only in threaded run or if among reactions to sequencer request would be sequencer break
     # NOTE: just for LOL - try to use sequencer to test sequencer
     self._remaining = 0
     return proto_success("Breaked sequence. After last issued request is complete sequencer would stop",
                          retval_name="state")
示例#14
0
文件: main.py 项目: Godhart/fvf
    def tcp_receive(self, count=0, timeout=None, decode='UTF-8'):
        """
        Get's data that were sent by app via stdout
        :param count: Amount of bytes to receive.
                set count to 0 to receive as much as possible, at least something
                set count to -1 to receive as much as possible, but nothing is acceptable too
        :param timeout: Time in seconds to wait for data. If None then TCP socket timeout is used
        :param deoode: If not None then received data is decoded into string using specified decoder. Default: 'UTF-8'
        :return: True if successfully received Data, otherwise - False. Data itself is contained in a reply to channel
                 and Data is list of strings
        """
        start_time = time.time()
        if not isinstance(count, int) or count < -1:
            raise ValueError("Count should be an integer in a range from -1 and up to +infinity")
        if self._mock is None and self._sock is None:
            return proto_failure("No connection. Ensure start is complete")
        try:
            if self._mock is not None:
                data = self._mock.pop(0)
            else:
                data = bytearray()
                if count < 1:
                    recv_size = 1024
                else:
                    recv_size = count
                if timeout is not None:
                    timeout = time.time() + timeout
                while len(data) < count or count == 0 or count == -1:
                    try:
                        received = self._sock.recv(recv_size)
                    except TimeoutError:
                        received = None
                    except socket.timeout:
                        received = None

                    if received is None:
                        if count < 0:
                            break
                        if count == 0 and len(data) > 0:
                            break
                    else:
                        data += received

                    if timeout is not None and time.time() > timeout:
                        break

                    if count > 0:
                        recv_size = count - len(data)

                if decode is not None:
                    data = data.decode(decode)

        except Exception as e:
            eprint("Platform {} failed to receive due to exception {}".format(self.name, e))
            exprint()
            return proto_failure("Failed to receive due to exception {}".format(e), -2)
        tprint("rpyc_receive elapsed {}".format(time.time() - start_time))
        if 0 < count != len(data):
            return proto_failure("Not all requested data were received")
            # TODO: need a way to return partially received data
        elif count == 0 and len(data) == 0:
            return proto_failure("No data were received")
        else:
            return proto_success(data)
示例#15
0
    def _platformix_stop(self, context, fake_reply):  # TODO: Force parameter
        """
        Stops platform instance
        Breaks startup process if the platform is in middle of startup
        Waits before nested platforms are stopped before actually do stop
        # TODO: also should wait platforms which are waiting for this one on start
        If parent platform or platforms in wait list are not running yet - will wait for them
        If stop were deferred due to waiting of other platforms then stop method should be called again later
        Usually it happens automatically after other platforms are replying on their's stopping end
        :param context: messaging context
        :return: None
        """
        assert fake_reply is None, "platformix_stop replies shouldn't be faked!"

        stopping = self._worker.stopping  # Store current stopping state
        need_stop = self._worker.stopping = self._worker.running or self._worker.starting
        self._worker.stopping = True  # Set _stopping right in the beginning

        new_thread = False
        if not stopping and self._context is not None:  # Break startup process if necessary
            self._reply_all(self._context["reply_to"],
                            proto_failure("interrupted by stop"), None)
            if self._worker.starting:
                self._worker.starting = False
                self._worker.start_in_progress = False
            self._context = None
        if not stopping and not need_stop:  # If not running and not starting - do nothing more
            self._worker.stopping = False
            self._reply(context, proto_success("already stopped", "state"),
                        None)
            return
        if stopping:  # If were already stopping - update reply list
            if context not in self._context["reply_to"]:
                new_thread = True
                self._context["reply_to"].append(context)
        else:  # Otherwise initiate context
            new_thread = True
            self._context = {
                "action": "stop",
                "reply_to": [context],
                "waiting_for": [],
                "wait_ignore": []
            }
            self._notify(context, "received stop signal")
            # TODO: do recursive stop? parent->childs? and call only root platforms stop?
        assert self._worker.stopping, "At this point stopping should be True"
        # Update waiting list
        # TODO: also wait those that are depends on this one
        self._context["waiting_for"] = [
            w.name for w in self.host.subplatforms + self.host.depended
            if w.running is True or w.stopping is True
            and w.name not in self._context["wait_ignore"]
        ]

        # If there is some platforms to wait - notify about this
        if self.waiting_count > 0 and new_thread:
            self._worker.register_reply_handler(
                context,
                self._platformix_stop_reply_handler, [], {},
                timeout=self._worker.stop_max_wait,
                force=True)
            self._notify_all(self._context["reply_to"], "waiting")
        # If no one left to wait for - do stop at last
        elif not self._worker.stop_in_progress and self.waiting_count == 0:
            for c in self._context["reply_to"]:
                self._worker.unregister_reply_handler(c,
                                                      True, {},
                                                      dont_check=True)
            self._worker.running = False
            self._worker.stop_in_progress = True
            self._notify_all(self._context["reply_to"], "stopping")
            result = self._worker.stop(self._context["reply_to"])
            reply_to = self._context["reply_to"]
            self._context = None
            assert isinstance(
                result, ProtocolReply
            ), "Worker should return result as ProtocolReply instance"
            if result.success:
                self._reply_all(reply_to, proto_success(None), None)
            else:
                self._reply_all(reply_to, result, None)
示例#16
0
 def _platformix_start(
         self, context,
         fake_reply):  # TODO: Recursive option to start nested platforms
     """
     Starts platform instance (actually checks that necessary conditions are met and calls startup worker method)
     If parent platform or platforms in wait list are not running yet - will wait for them
     If start were deferred due to waiting of other platforms then start method should be called again later
     Usually it happens automatically after other platforms are replying on their's startup end
     :param context: messaging context
     :return: None
     """
     assert fake_reply is None, "platformix_start replies shouldn't be faked!"
     if self._worker.running:  # If already running - just do nothing
         self._reply(context, proto_success("already running", "state"),
                     None)
         return
     if self._worker.stopping:  # If in the middle of stop - do nothing
         self._reply(context, proto_failure("stop is in progress"), None)
         return
     new_thread = False
     if self._worker.starting:  # If were already starting - update reply list
         if context not in self._context["reply_to"]:
             new_thread = True
             self._context["reply_to"].append(context)
             self._notify(context, "waiting")
     else:
         new_thread = True
         self._worker.starting = True
         self._context = {
             "action": "start",
             "reply_to": [context],
             "waiting_for": [],
             "wait_ignore": []
         }
         self._notify(context, "received start signal")
         # TODO: do recursive start? parent->childs? and call only root platforms to get up and running?
     # TODO: lock as validation can intersect with stop action since stop can be called from different threads
     if not self._validate_context({"action": "start"}):
         return
     if not self._worker.starting:  # NOTE: in case if starting were interrupted by stop - just return
         return
     # Update waiting list
     self._context["waiting_for"] = [
         w for w in self._worker.wait
         if self._worker.farm.is_running(w) is False
     ]
     # If there is some platforms to wait - notify about this
     if self.waiting_count > 0 and new_thread:
         self._worker.register_reply_handler(
             context,
             self._platformix_start_reply_handler, [], {},
             timeout=self._worker.start_max_wait,
             force=True)
         self._notify(context, "waiting")
     # If no one left to wait for - do stop at last
     elif not self._worker.start_in_progress and self.waiting_count == 0:
         for c in self._context["reply_to"]:
             try:
                 self._worker.unregister_reply_handler(c,
                                                       True, {},
                                                       dont_check=True)
             except AssertionError:
                 pass
         self._worker.start_in_progress = True
         self._notify_all(self._context["reply_to"], "launching")
         if self._validate_context({"action": "start"}):
             result = self._worker.start(self._context["reply_to"])
             result_error = not isinstance(result, ProtocolReply)
         else:
             result = None
             result_error = False
         if self._validate_context({"action": "start"}):
             reply_to = self._context["reply_to"]
             self._context = None
         else:
             return  # TODO: probably need to fid a way to reply failure in that case
         assert result_error is False, "Worker should return result as ProtocolReply instance"
         if result is not None:
             if result.success:
                 self._reply_all(reply_to, result, None)
             else:
                 self._reply_all(reply_to, result, None)