123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- import urllib
- import urllib2
- import json
- import random
- from urllib2 import URLError
- import sys
- import time
- import threading
- COMPILER_PATH = "interface/HUTN"
- MODE_UNCONNECTED = 0
- MODE_UNAUTHORIZED = 1
- MODE_MODELLING = 2
- MODE_SERVICE = 6
- # Bind to the compiler (might have to update path manually!)
- sys.path.append(COMPILER_PATH)
- from hutn_compiler.compiler import main as do_compile
- # Exceptions
- class ModelverseException(Exception):
- pass
- class UnknownError(ModelverseException):
- pass
- class UnknownIdentifier(ModelverseException):
- pass
- class CompilationError(ModelverseException):
- pass
- class NoSuchAttribute(ModelverseException):
- pass
- class UnknownModel(ModelverseException):
- pass
- class ConnectionError(ModelverseException):
- pass
- class ModelExists(ModelverseException):
- pass
- class PermissionDenied(ModelverseException):
- pass
- class InvalidMode(ModelverseException):
- pass
- class InterfaceMismatch(ModelverseException):
- pass
- class UnknownMetamodellingHierarchy(ModelverseException):
- pass
- # Helper functions and configuration: do not use yourself!
- taskname = None
- address = None
- last_output = None
- mode = MODE_UNCONNECTED
- prev_mode = None
- current_model = None
- registered_metamodels = {}
- def _check_type(value):
- if not isinstance(value, (int, long, float, str, unicode, bool)):
- raise UnsupportedValue("%s : %s" % (value, str(type(value))))
- def _check_type_list(value):
- if isinstance(value, list):
- [_check_type(i) for i in value]
- else:
- _check_type(value)
- def _goto_mode(new_mode, model_name=None):
- global mode
- if mode == new_mode:
- return
- else:
- # Go to a mode that we have no automatic transfer to: raise exception
- raise InvalidMode("Required mode: %s, current mode: %s" % (new_mode, mode))
- def _input(value, port=None):
- # Ugly json encoding of primitives
- if port is None:
- port = taskname
- if isinstance(value, type([])):
- value = json.dumps(value)
- urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "data": value, "taskname": port}))).read()
- else:
- value = json.dumps(value)
- #print("Set input: " + str(value))
- urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": value, "taskname": port}))).read()
- def _input_raw(value, taskname):
- # Ugly json encoding of primitives
- urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": value, "taskname": taskname}))).read()
- def _compile_AL(code):
- # Compile an action language file and send the compiled code
- code_fragments = code.split("\n")
- code_fragments = [i for i in code_fragments if i.strip() != ""]
- code_fragments = [i.replace(" ", "\t") for i in code_fragments]
- initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
- code_fragments = [i[initial_tabs:] for i in code_fragments]
- code_fragments.append("")
- code = "\n".join(code_fragments)
- with open(".code.alc", "w") as f:
- f.write(code)
- f.flush()
- compiled = do_compile(".code.alc", COMPILER_PATH + "/grammars/actionlanguage.g", "CS")
- return compiled
- def _compile_model(code):
- # Compile a model and send the compiled graph
- # First change multiple spaces to a tab
- code_fragments = code.split("\n")
- code_fragments = [i for i in code_fragments if i.strip() != ""]
- code_fragments = [i.replace(" ", "\t") for i in code_fragments]
- initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
- code_fragments = [i[initial_tabs:] for i in code_fragments]
- code_fragments.append("")
- code = "\n".join(code_fragments)
- with open(".model.mvc", "w") as f:
- f.write(code)
- f.flush()
- return do_compile(".model.mvc", COMPILER_PATH + "/grammars/modelling.g", "M")
- def _output(expected=None,port=None):
- if port is None:
- port = taskname
- try:
- global last_output
- last_output = json.loads(urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "taskname": port}))).read())
- #print("[OUT] %s" % last_output)
- except:
- raise UnknownError()
- if expected is not None and last_output != expected:
- raise InterfaceMismatch(_last_output(), expected)
- return last_output
- def _last_output():
- return last_output
- # Raise common exceptions
- def _handle_output(requested=None, split=None):
- value = _output()
- if value.startswith("Model exists: "):
- raise ModelExists(value.split(": ", 1)[1])
- elif value.startswith("Permission denied"):
- raise PermissionDenied(value.split(": ", 1)[1])
- elif value.startswith("Model not found: "):
- raise UnknownModel(value.split(": ", 1)[1])
- elif value.startswith("Element not found: "):
- raise UnknownIdentifier(value.split(": ", 1)[1])
- elif value.startswith("Element exists: "):
- raise ElementExists(value.split(": ", 1)[1])
- elif value.startswith("Attribute not found: "):
- raise NoSuchAttribute(value.split(": ", 1)[1])
- elif requested is not None and value.startswith(requested):
- if split is None:
- return value
- else:
- splitted = value.strip().split(split, 1)
- if len(splitted) == 1:
- return ""
- else:
- return splitted[1].rstrip()
- else:
- raise InterfaceMismatch(value)
-
- def _model_modify(model_name, metamodel_name):
- """Modify an existing model."""
- global mode
- global prev_mode
- if mode == MODE_MANUAL:
- prev_mode = MODE_MANUAL
- mode = MODE_MODIFY
- return None
- _goto_mode(MODE_MODELLING)
- prev_mode = MODE_MODELLING
- _input(["model_modify", model_name, metamodel_name])
- _handle_output("Success")
- global current_model
- current_model = model_name
- # Mode has changed
- mode = MODE_MODIFY
- _output("Model loaded, ready for commands!")
- def _model_exit():
- """Leave model modify mode."""
- global mode
- global prev_mode
- if prev_mode == MODE_MANUAL:
- mode = MODE_MANUAL
- return
- if mode != MODE_MODIFY:
- raise InvalidMode()
- _input("exit")
- _output("Success")
- mode = MODE_MODELLING
- def alter_context(model_name, metamodel_name):
- global registered_metamodels
- registered_metamodels[model_name] = metamodel_name
- # Main MvC operations
- def init(address_param="127.0.0.1:8001", timeout=20.0):
- """Starts up the connection to the Modelverse."""
- global mode
- global address
- global taskname
- address = "http://%s" % address_param
- start_time = time.time()
- taskname = random.random()
- while 1:
- try:
- _input_raw('"%s"' % taskname, "task_manager")
- mode = MODE_UNAUTHORIZED
- break
- except URLError as e:
- if time.time() - start_time > timeout:
- raise ConnectionError(e.reason)
- else:
- time.sleep(0.1)
- def login(username, password):
- """Log in a user, if user doesn't exist, it is created."""
- global mode
- _goto_mode(MODE_UNAUTHORIZED)
- _output("Log on as which user?")
- _input(username)
- if _output() == "Password for existing user?":
- _input(password)
- if _output() == "Welcome to the Model Management Interface v2.0!":
- _output("Use the 'help' command for a list of possible commands")
- _input("quiet")
- mode = MODE_MODELLING
- elif _last_output() == "Wrong password!":
- raise PermissionDenied()
- else:
- raise InterfaceMismatch(_last_output())
- elif _last_output() == "This is a new user: please give password!":
- _input(password)
- _output("Please repeat the password")
- _input(password)
- if _output() == "Passwords match!":
- _output("Welcome to the Model Management Interface v2.0!")
- _output("Use the 'help' command for a list of possible commands")
- _input("quiet")
- mode = MODE_MODELLING
- elif _last_output() == "Not the same password!":
- # We just sent the same password, so it should be identical, unless the interface changed
- raise InterfaceMismatch(_last_output())
- else:
- raise InterfaceMismatch(_last_output())
- else:
- raise InterfaceMismatch(_last_output())
- def service_register(name, function):
- """Register a function as a service with a specific name."""
- def service_process(port):
- while 1:
- thrd = threading.Thread(target=function, args=[service_get(port)])
- thrd.daemon = True
- thrd.start()
- global mode
- _goto_mode(MODE_MODELLING)
- _input(["service_register", name])
- # Now we are in service-mode
- mode = MODE_SERVICE
- port = _handle_output("Success: ", split=" ")
- # Process events in the background!
- threading.Thread(target=service_process, args=[port]).start()
- def service_stop():
- """Stop the currently executing process."""
- _goto_mode(MODE_SERVICE)
- _input("service_stop")
- _handle_output("Success")
- global mode
- mode = MODE_MODELLING
- def service_get(port):
- """Get the values on the specified port."""
- _goto_mode(MODE_SERVICE)
- return _output(port=port)
- def service_set(port, value):
- """Set a value on a specified port."""
- _check_type_list(value)
- _goto_mode(MODE_SERVICE)
- _input(value, port=port)
- def service_poll(port):
- """Checks whether or not the Modelverse side has any input ready to be processed."""
- raise NotImplementedError()
|