Browse Source

Start the new fully modelled SCCD Mv client

Yentl Van Tendeloo 8 years ago
parent
commit
e677faef89

+ 192 - 0
wrappers/classes/http_client.xml

@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<diagram author="Yentl Van Tendeloo" name="HTTP client">
+    <description>
+        HTTP client.
+    </description>
+    <top>
+        import uuid
+    </top>
+
+    <inport name="socket_in"/>
+    <outport name="socket_out"/>
+
+    <inport name="request_in"/>
+    <outport name="request_out"/>
+
+    <class name="HTTPClient">
+        <constructor>
+            <body>
+                <![CDATA[
+                self.socket = None
+                self.received_data = ""
+                self.send_data = ""
+                self.queue = []
+                self.IDs = []
+                ]]>
+            </body>
+        </constructor>
+        <scxml initial="init">
+            <state id="init">
+                <onentry>
+                    <script>
+                        self.ID = str(uuid.uuid4())
+                    </script>
+                    <raise scope="output" event="create_socket" port="socket_out">
+                        <parameter expr="self.ID"/>
+                    </raise>
+                </onentry>
+
+                <transition port="socket_in" event="created_socket" cond="self.ID == ID" target="../waiting">
+                    <parameter name="socket"/>
+                    <parameter name="ID"/>
+                    <script>
+                        self.socket = socket
+                    </script>
+                </transition>
+            </state>
+
+            <state id="waiting">
+                <onentry>
+                    <raise scope="output" port="request_out" event="http_client_initialized"/>
+                </onentry>
+
+                <transition port="request_in" event="connect" target="../connecting">
+                    <parameter name="address"/>
+                    <parameter name="timeout"/>
+
+                    <script>
+                        self.address = address
+                        self.timeout = timeout
+                    </script>
+                </transition>
+            </state>
+
+            <state id="connecting" initial="connecting">
+                <state id="connecting">
+                    <onentry>
+                        <raise scope="output" event="connect_socket" port="socket_out">
+                            <parameter expr="self.socket"/>
+                            <parameter expr="self.address"/>
+                        </raise>
+                    </onentry>
+
+                    <transition port="socket_in" event="error_socket" target="../cooldown"/>
+
+                    <transition port="socket_in" event="connected_socket" cond="self.socket == socket" target="../../connected">
+                        <parameter name="socket"/>
+                        <raise scope="output" port="request_out" event="http_client_ready"/>
+                    </transition>
+                </state>
+
+                <state id="cooldown">
+                    <transition after="0.1" target="../connecting"/>
+                </state>
+
+                <transition after="self.timeout" target="../waiting">
+                    <raise scope="output" port="request_out" event="http_client_timeout"/>
+                </transition>
+            </state>
+
+            <parallel id="connected">
+                <state id="listening" initial="listen">
+                    <state id="listen">
+                        <onentry>
+                            <raise scope="output" port="socket_out" event="recv_socket">
+                                <parameter expr="self.socket"/>
+                            </raise>
+                        </onentry>
+                        <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) > 0)" target=".">
+                            <parameter name="socket"/>
+                            <parameter name="data"/>
+                            <script>
+                                self.received_data += data
+                            </script>
+                        </transition>
+                        <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) == 0)" target="../close">
+                            <parameter name="socket"/>
+                            <parameter name="data"/>
+                        </transition>
+                    </state>
+                    <state id="close">
+                    </state>
+                </state>
+
+                <state id="sending" initial="waiting_for_data">
+                    <state id="waiting_for_data">
+                        <transition cond="len(self.send_data) > 0" target="../transferring">
+                            <raise scope="output" port="socket_out" event="send_socket">
+                                <parameter expr="self.socket"/>
+                                <parameter expr="self.send_data"/>
+                            </raise>
+                        </transition>
+                    </state>
+                    <state id="transferring">
+                        <transition event="sent_socket" port="socket_in" cond="self.socket == socket" target="../waiting_for_data">
+                            <parameter name="socket"/>
+                            <parameter name="sent_bytes"/>
+                            <script>
+                                self.send_data = self.send_data[sent_bytes:]
+                            </script>
+                        </transition>
+                    </state>
+                </state>
+
+                <state id="queueing">
+                    <state id="queueing">
+                        <onentry>
+                        </onentry>
+                        <transition port="request_in" event="HTTP_input" target=".">
+                            <parameter name="data"/>
+                            <parameter name="ID"/>
+                            <script>
+                                self.send_data += "POST / HTTP/1.0\r\n"
+                                self.send_data += "Content-Length: %i\r\n" % len(str(data))
+                                self.send_data += "\r\n"
+                                self.send_data += data
+                                self.IDs.append(ID)
+                            </script>
+                        </transition>
+                    </state>
+                </state>
+
+                <state id="parsing" initial="wait_for_header">
+                    <state id="wait_for_header">
+                        <transition cond="'\r\n\r\n' in self.received_data" target="../wait_for_payload">
+                            <script>
+                                header, self.received_data = self.received_data.split("\r\n\r\n", 1)
+                                header = header.lower()
+                                if "content-length" in header:
+                                    _, after = header.split("content-length:", 1)
+                                    after, _ = after.split("\r\n", 1)
+                                    after = after.strip()
+                                    self.length = int(after)
+                                else:
+                                    self.length = float('inf')
+                            </script>
+                        </transition>
+                    </state>
+                    <state id="wait_for_payload">
+                        <transition cond="len(self.received_data) >= self.length and self.IDs[0] is not None" target="../wait_for_header">
+                            <script>
+                                data = self.received_data[:self.length]
+                                self.received_data = self.received_data[self.length:]
+                            </script>
+                            <raise event="HTTP_output" scope="output" port="request_out">
+                                <parameter expr="data"/>
+                                <parameter expr="self.IDs.pop(0)"/>
+                            </raise>
+                        </transition>
+
+                        <transition cond="len(self.received_data) >= self.length and self.IDs[0] is None" target="../wait_for_header">
+                            <script>
+                                # Drop data
+                                self.received_data = self.received_data[self.length:]
+                                self.IDs.pop(0)
+                            </script>
+                        </transition>
+                    </state>
+                </state>
+            </parallel>
+        </scxml>
+    </class>
+</diagram>

+ 342 - 0
wrappers/classes/modelverse.xml

@@ -0,0 +1,342 @@
+<class name="Modelverse">
+    <relationships>
+        <association name="http_client" class="HTTPClient" min="2" max="2"/>
+    </relationships>
+
+    <method name="load_action">
+        <parameter name="context"/>
+        <body>
+            action = self.actions[None].pop(0)
+            self.parameters = action["parameters"]
+            self.current_ID = action["ID"]
+        </body>
+    </method>
+
+    <method name="expect_response">
+        <parameter name="expected"/>
+        <parameter name="pop" default="False"/>
+        <body>
+            if self.responses and self.responses[0] == expected:
+                if pop:
+                    del self.responses[0]
+                return True
+            else:
+                return False
+        </body>
+    </method>
+
+    <method name="expect_action">
+        <parameter name="context"/>
+        <parameter name="expected"/>
+        <body>
+            return self.actions[context] and self.actions[context][0]["name"] == expected
+        </body>
+    </method>
+
+    <constructor>
+        <body>
+            self.actions = {None: []}
+            self.responses = []
+            self.http_clients = []
+        </body>
+    </constructor>
+
+    <scxml initial="init">
+        <state id="init">
+            <onentry>
+                <raise scope="cd" event="create_instance">
+                    <parameter expr="'http_client'"/>
+                    <parameter expr="'HTTPClient'"/>
+                </raise>
+
+                <raise scope="cd" event="create_instance">
+                    <parameter expr="'http_client'"/>
+                    <parameter expr="'HTTPClient'"/>
+                </raise>
+            </onentry>
+
+            <transition event="instance_created" target=".">
+                <parameter name="instance"/>
+                <script>
+                    self.http_clients.append(instance)
+                </script>
+                <raise scope="cd" event="start_instance">
+                    <parameter expr="instance"/>
+                </raise>
+            </transition>
+
+            <transition cond="len(self.http_clients) == 2" target="../waiting"/>
+        </state>
+
+        <state id="waiting">
+            <transition event="http_client_initialized" target="../initialized"/>
+        </state>
+
+        <parallel id="initialized">
+            <onentry>
+                <raise scope="output" port="ready" event="ready"/>
+            </onentry>
+
+            <state id="http_mapper" initial="init">
+                <state id="init">
+                    <transition event="request" cond="isinstance(value, type([]))" target=".">
+                        <parameter name="value"/>
+                        <raise event="HTTP_input" target="self.http_clients[0]">
+                            <parameter expr='urllib.urlencode({"op": "set_input", "data": json.dumps(value), "taskname": self.taskname})'/>
+                            <parameter expr='None'/>
+                        </raise>
+                    </transition>
+
+                    <transition event="request" cond="not isinstance(value, type([]))" target=".">
+                        <parameter name="value"/>
+                        <raise event="HTTP_input" target="self.http_clients[0]">
+                            <parameter expr='urllib.urlencode({"op": "set_input", "value": json.dumps(value), "taskname": self.taskname})'/>
+                            <parameter expr='None'/>
+                        </raise>
+                    </transition>
+
+                    <transition event="request_raw" target=".">
+                        <parameter name="value"/>
+                        <parameter name="taskname"/>
+                        <parameter name="http_client"/>
+                        <raise event="HTTP_input" target="self.http_clients[http_client]">
+                            <parameter expr='urllib.urlencode({"op": "set_input", "value": json.dumps(value), "taskname": taskname})'/>
+                            <parameter expr='"parent"'/>
+                        </raise>
+                    </transition>
+
+                    <transition event="HTTP_output" target=".">
+                        <parameter name="data"/>
+                        <raise event="HTTP_input" target="self.http_clients[1]">
+                            <parameter expr='urllib.urlencode({"op": "get_output", "taskname": self.taskname})'/>
+                            <parameter expr='"parent"'/>
+                        </raise>
+                        <script>
+                            print("Got output " + str(data))
+                            self.responses.append(json.loads(data))
+                        </script>
+                    </transition>
+                </state>
+            </state>
+
+            <state id="behaviour" initial="wait_for_action">
+                <state id="connecting" initial="connect_http_client">
+                    <onentry>
+                        <script>
+                            self.address, self.timeout = self.parameters
+                            self.address = self.address.rsplit(":", 1)
+                            self.address = (self.address[0], int(self.address[1]))
+
+                            self.i = 0
+                            self.taskname = str(uuid.uuid4())
+                        </script>
+                    </onentry>
+
+                    <state id="connect_http_client">
+                        <transition cond="self.i &lt; 2" target="../waiting_http_client">
+                            <raise scope="narrow" target="self.http_clients[self.i]" event="connect">
+                                <parameter expr="self.address"/>
+                                <parameter expr="self.timeout"/>
+                            </raise>
+                        </transition>
+
+                        <transition cond="self.i == 2" target="../../wait_for_action/connected">
+                            <!-- Start polling for output -->
+                            <raise event="HTTP_input" target="self.http_clients[1]">
+                                <parameter expr='urllib.urlencode({"op": "get_output", "taskname": self.taskname})'/>
+                                <parameter expr='"parent"'/>
+                            </raise>
+
+                            <!-- Sent out completion -->
+                            <raise event="result">
+                                <parameter expr="[]"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="waiting_http_client">
+                        <transition event="http_client_ready" target="../wait_for_taskname_ack">
+                            <!-- Request the task to be created -->
+                            <raise event="request_raw">
+                                <parameter expr="self.taskname"/>
+                                <parameter expr="'task_manager'"/>
+                                <parameter expr="self.i"/>
+                            </raise>
+
+                            <script>
+                                self.i += 1
+                            </script>
+                        </transition>
+
+                        <transition event="http_client_timeout" target="../../wait_for_action/disconnected">
+                            <raise scope="broad" event="exception">
+                                <parameter expr="self.current_ID"/>
+                                <parameter expr="'Connection timeout'"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="wait_for_taskname_ack">
+                        <transition cond="self.expect_response('OK', pop=True)" target="../connect_http_client"/>
+                    </state>
+                </state>
+
+                <state id="logging_in" initial="wait_prompt_1">
+                    <state id="wait_prompt_1">
+                        <transition cond="self.expect_response('Log on as which user?', pop=True)" target="../wait_prompt_2">
+                            <raise event="request">
+                                <parameter expr="self.parameters[0]"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="wait_prompt_2">
+                        <transition cond="self.expect_response('Password for existing user?', pop=True)" target="../wait_prompt_existing">
+                            <raise event="request">
+                                <parameter expr="self.parameters[1]"/>
+                            </raise>
+                        </transition>
+
+                        <transition cond="self.expect_response('This is a new user: please give password!', pop=True)" target="../wait_prompt_existing">
+                            <raise event="request">
+                                <parameter expr="self.parameters[1]"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="wait_prompt_existing">
+                        <transition cond="self.expect_response('Welcome to the Model Management Interface v2.0!', pop=True)" target="../login_ok"/>
+                        <transition cond="self.expect_response('Wrong password!', pop=True)" target="../../wait_for_action/connected">
+                            <raise event="exception">
+                                <parameter expr="{'name': 'PermissionDenied'}"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="login_ok">
+                        <transition cond="self.expect_response('Use the \'help\' command for a list of possible commands', pop=True)" target="../../wait_for_action/megamodelling">
+                            <raise event="request">
+                                <parameter expr="'quiet'"/>
+                            </raise>
+                            <raise event="result">
+                                <parameter expr="[]"/>
+                            </raise>
+                        </transition>
+                    </state>
+                </state>
+
+                <state id="model_add" initial="init">
+                    <state id="init">
+                        <transition cond="self.parameters[2] is not None" target="../compiled">
+                            <script>
+                                try:
+                                    self.compiled = _compile_model(model_code)
+                                    self.exception = None
+                                except Exception as e:
+                                    self.compiled = None
+                                    self.exception = e
+                            </script>
+                        </transition>
+                        <transition cond="self.parameters[2] is None" target="../compiled">
+                            <script>
+                                self.compiled = [0]
+                                self.exception = None
+                            </script>
+                        </transition>
+                    </state>
+
+                    <state id="compiled">
+                        <transition cond="self.compiled is None" target="../../wait_for_action/history">
+                            <raise event="exception">
+                                <parameter expr="self.exception"/>
+                            </raise>
+                        </transition>
+
+                        <transition cond="self.compiled is not None" target="../sent_commands">
+                            <raise event="request">
+                                <parameter expr="['model_add', self.parameters[1], self.parameters[0]]"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="sent_commands">
+                        <transition cond="self.expect_response('Waiting for model constructors')">
+                    </state>
+                </state>
+
+                <state id="wait_for_action" initial="disconnected">
+                    <state id="disconnected">
+                        <transition cond="self.expect_action(None, 'init')" target="../../connecting">
+                            <script>
+                                self.load_action(None)
+                            </script>
+                        </transition>
+                    </state>
+
+                    <state id="connected">
+                        <transition cond="self.expect_action(None, 'login')" target="../../logging_in">
+                            <script>
+                                self.load_action(None)
+                            </script>
+                        </transition>
+                    </state>
+
+                    <state id="megamodelling">
+                        <transition cond="self.expect_action(None, 'model_add')" target="../../model_add">
+                            <script>
+                                self.load_action(None)
+                            </script>
+                    </state>
+
+                    <state id="modelling" initial="manual">
+                        <state id="manual">
+                        </state>
+
+                        <state id="scripted">
+                        </state>
+                    </state>
+
+                    <history id="history" type="deep"/>
+                </state>
+            </state>
+
+            <state id="queue">
+                <state id="queue">
+                    <transition port="action_in" event="action" target=".">
+                        <parameter name="action_name"/>
+                        <parameter name="ID"/>
+                        <parameter name="context_ID"/>
+                        <parameter name="parameters"/>
+                        <script>
+                            self.actions[context_ID].append({"name": action_name, "ID": ID, "parameters": parameters})
+                        </script>
+                    </transition>
+
+                    <transition event="result" target=".">
+                        <parameter name="parameters"/>
+                        <raise scope="output" event="result" port="action_out">
+                            <parameter expr="self.current_ID"/>
+                            <parameter expr="parameters"/>
+                        </raise>
+                    </transition>
+
+                    <transition event="exception" target=".">
+                        <parameter name="parameters"/>
+                        <raise scope="output" event="exception" port="action_out">
+                            <parameter expr="self.current_ID"/>
+                            <parameter expr="parameters"/>
+                        </raise>
+                    </transition>
+
+                    <transition port="input_in" event="input" target=".">
+                        <parameter name="value"/>
+                        <parameter name="context_ID"/>
+                        <script>
+                            self.inputs[context_ID].append(value)
+                        </script>
+                    </transition>
+                </state>
+            </state>
+        </parallel>
+    </scxml>
+</class>

File diff suppressed because it is too large
+ 32 - 1007
wrappers/modelverse.py


+ 25 - 0
wrappers/modelverse_SCCD.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<diagram author="Yentl Van Tendeloo" name="MvK Server">
+    <description>
+        Modelverse Kernel client.
+    </description>
+    <top>
+        import sccd.runtime.accurate_time as accurate_time
+        import time
+        import os
+        import sys
+        import uuid
+        import urllib
+        import json
+        import sys
+    </top>
+
+    <inport name="socket_in"/>
+    <outport name="socket_out"/>
+    <inport name="action_in"/>
+    <outport name="action_out"/>
+    <outport name="ready"/>
+
+    <class src="classes/modelverse.xml" default="true"/>
+    <class src="classes/http_client.xml"/>
+</diagram>

File diff suppressed because it is too large
+ 1022 - 0
wrappers/modelverse_coded.py