Ejemplo n.º 1
0
    def __init__(self, source_path=None):
        self.context = Context()
        self.promise_type = self.context.glob.Promise
        self.cache = None

        try:
            script = Script(source=stdlib.source, filename=stdlib.name)
            self.context.eval(script)
        except Exception as e:
            raise JSBuildError(500, 'Error while compiling stdlib.js') from e

        if source_path:
            for file_name in os.listdir(source_path):
                if not file_name.endswith('.js'):
                    continue

                logger.info('Compiling file {0}.'.format(os.path.join(source_path, file_name)))

                try:
                    with open(os.path.join(source_path, file_name), encoding='utf8') as f:
                        script = Script(source=f.read(), filename=file_name)
                        self.context.eval(script)
                except Exception as e:
                    raise JSBuildError(500, 'Error while compiling.') from e

        session_api.expose(self.context)
Ejemplo n.º 2
0
def test_script():
    c1 = Context()
    c1.kappa = 'pride'
    c2 = Context()
    s = Script('kappa')
    assert c1.eval(s) == 'pride'
    with pytest.raises(JSException):
        c2.eval(s)
Ejemplo n.º 3
0
    def __init__(self, build_id=None, model=None, source_path=None, autorelease_time=30000, is_server=False):
        self.build_id = build_id
        self.model = model
        self.context = Context()
        self.promise_type = self.context.glob.Promise
        self.build_cache = ExpiringDict(2048, 60)

        # this variable holds amount of users of this build. once this variable hits back to zero,
        # eventually the build will be released
        self.refs = 0
        self._check_refs = PeriodicCallback(self.__check_build_refs__, autorelease_time)
        self.released = False

        try:
            script = Script(source=stdlib.source, filename=stdlib.name)
            self.context.eval(script)
        except Exception as e:
            logging.exception("Error while compiling stdlib.js")
            raise JavascriptBuildError(500, str(e))

        if source_path:
            for file_name in os.listdir(source_path):
                if not file_name.endswith(".js"):
                    continue

                logging.info("Compiling file {0}".format(os.path.join(source_path, file_name)))

                try:
                    with open(os.path.join(source_path, file_name), 'r') as f:
                        script = Script(source=f.read(), filename=str(file_name))
                        self.context.eval(script)
                except Exception as e:
                    logging.exception("Error while compiling")
                    raise JavascriptBuildError(500, str(e))

        expose(self.context, is_server=is_server)
        if self.build_id:
            logging.info("Created new build {0}".format(self.build_id))

        self._check_refs.start()
Ejemplo n.º 4
0
 def green_func(next_green):
     def swg():
         try: # Kappa
             next_green.switch()
         except GreenletExit: # Kappa
             pass # Kappa
     c = Context()
     c.expose(swg)
     c.eval('swg()')
Ejemplo n.º 5
0
def test_cross_context_exception_value(context):
    def call_context():
        context.eval('throw {foo: "bar"}')

    context2 = Context()
    context2.expose(call_context)
    try:
        context2.eval('call_context()')
    except JSException as e:
        assert e.value['foo'] == 'bar'
Ejemplo n.º 6
0
class JSBuild:
    def __init__(self, source_path=None):
        self.context = Context()
        self.promise_type = self.context.glob.Promise
        self.cache = None

        try:
            script = Script(source=stdlib.source, filename=stdlib.name)
            self.context.eval(script)
        except Exception as e:
            raise JSBuildError('Error while compiling stdlib.js') from e

        if source_path:
            for file_name in os.listdir(source_path):
                if not file_name.endswith('.js'):
                    continue

                logger.info('Compiling file {0}.'.format(os.path.join(source_path, file_name)))

                try:
                    with open(os.path.join(source_path, file_name), encoding='utf8') as f:
                        script = Script(source=f.read(), filename=file_name)
                        self.context.eval(script)
                except Exception as e:
                    raise JSBuildError('Error while compiling') from e

        session_api.expose(self.context)

    def add_source(self, source_code, filename=None):
        script = Script(source=source_code, filename=filename)
        try:
            self.context.eval(script)
        except JSException as e:
            raise JSBuildError('Error while adding source') from e

    def create_session(self, handler, class_name, args, **env):
        if class_name not in self.context.glob:
            raise ClassDoesNotExist

        clazz = getattr(self.context.glob, class_name)

        if not getattr(clazz, 'allow_session', False):
            raise ClassDoesNotExist

        try:
            instance = new(clazz, args, env)
        except (TypeError, JSException) as e:
            raise JSSessionError('Failed to build session') from e

        js_session = JSSession(handler, self, instance, self.promise_type, **env)
        return js_session
Ejemplo n.º 7
0
def context():
    return Context()
Ejemplo n.º 8
0
 def expose(self, context: Context) -> None:
     context.expose_readonly(**dict(self.items))
Ejemplo n.º 9
0
def context_with_timeout():
    return Context(timeout=0.1)
Ejemplo n.º 10
0
def context(Global):
    return Context(Global)
Ejemplo n.º 11
0
class JavascriptBuild(object):
    def __init__(self, build_id=None, model=None, source_path=None, autorelease_time=30000, is_server=False):
        self.build_id = build_id
        self.model = model
        self.context = Context()
        self.promise_type = self.context.glob.Promise
        self.build_cache = ExpiringDict(2048, 60)

        # this variable holds amount of users of this build. once this variable hits back to zero,
        # eventually the build will be released
        self.refs = 0
        self._check_refs = PeriodicCallback(self.__check_build_refs__, autorelease_time)
        self.released = False

        try:
            script = Script(source=stdlib.source, filename=stdlib.name)
            self.context.eval(script)
        except Exception as e:
            logging.exception("Error while compiling stdlib.js")
            raise JavascriptBuildError(500, str(e))

        if source_path:
            for file_name in os.listdir(source_path):
                if not file_name.endswith(".js"):
                    continue

                logging.info("Compiling file {0}".format(os.path.join(source_path, file_name)))

                try:
                    with open(os.path.join(source_path, file_name), 'r') as f:
                        script = Script(source=f.read(), filename=str(file_name))
                        self.context.eval(script)
                except Exception as e:
                    logging.exception("Error while compiling")
                    raise JavascriptBuildError(500, str(e))

        expose(self.context, is_server=is_server)
        if self.build_id:
            logging.info("Created new build {0}".format(self.build_id))

        self._check_refs.start()

    def __check_build_refs__(self):
        if self.refs > 0:
            return

        if self.build_id:
            logging.info("Build {0} is being released because no usages left.".format(self.build_id))

        self._remove_timeout = None
        IOLoop.current().add_callback(self.release)

    @validate(source_code="str", filename="str")
    def add_source(self, source_code, filename=None):
        script = Script(source=str(source_code), filename=str(filename))
        try:
            self.context.eval(script)
        except JSException as e:
            raise JavascriptBuildError(500, e.message)

    @validate(class_name="str_name", args="json_dict")
    def session(self, class_name, args, log=None, debug=None, **env):
        if class_name not in self.context.glob:
            raise NoSuchClass()
        clazz = getattr(self.context.glob, class_name)

        # each 'session' class should have 'SessionClass.allow_session = true' defined
        if not getattr(clazz, "allow_session", False):
            raise NoSuchClass()

        handler = JavascriptCallHandler(self.build_cache, env, self.context,
                                        debug=debug, promise_type=self.promise_type)
        if log:
            handler.log = log
        PromiseContext.current = handler

        try:
            instance = new(clazz, args, env)
        except TypeError:
            raise JavascriptSessionError(500, "Failed to open session: TypeError while construction")
        except JSException as e:
            raise JavascriptSessionError(500, "Failed to open session: " + str(e))

        # declare some usage, session will release it using 'session_released' call
        self.add_ref()
        return JavascriptSession(self, instance, env, log=log, debug=debug,
                                 cache=self.build_cache, promise_type=self.promise_type)

    @validate(method_name="str_name", args="json_dict")
    async def call(self, method_name, args, call_timeout=10, **env):

        if method_name.startswith("_"):
            raise NoSuchMethod()

        if method_name in JavascriptSession.CALL_BLACKLIST:
            raise NoSuchMethod()

        instance = self.context.glob

        if not hasattr(instance, method_name):
            raise NoSuchMethod()

        method = getattr(instance, method_name)

        # each plain function should have 'function.allow_call = true' defined
        if not getattr(method, "allow_call", False):
            raise NoSuchMethod()

        handler = JavascriptCallHandler(None, env, self.context, promise_type=self.promise_type)
        PromiseContext.current = handler

        # declare some usage until this call is finished
        self.add_ref()

        try:
            try:
                future = self.context.async_call(method, (args,), JSFuture)
            except JSException as e:
                value = e.value
                if hasattr(value, "code"):
                    if hasattr(value, "stack"):
                        raise JavascriptExecutionError(value.code, value.message, stack=str(value.stack))
                    else:
                        raise JavascriptExecutionError(value.code, value.message)
                if hasattr(e, "stack"):
                    raise JavascriptExecutionError(500, str(e), stack=str(e.stack))
                raise JavascriptExecutionError(500, str(e))
            except APIError as e:
                raise JavascriptExecutionError(e.code, e.message)
            except InternalError as e:
                raise JavascriptExecutionError(
                    e.code, "Internal error: " + e.body)
            except JavaScriptTerminated:
                raise JavascriptExecutionError(
                    408, "Evaluation process timeout: function shouldn't be "
                         "blocking and should rely on async methods instead.")
            except Exception as e:
                raise JavascriptExecutionError(500, str(e))

            if future.done():
                return future.result()

            try:
                result = await with_timeout(datetime.timedelta(seconds=call_timeout), future)
            except TimeoutError:
                raise APIError(408, "Total function '{0}' call timeout ({1})".format(
                    method_name, call_timeout))
            else:
                return result

        finally:
            del handler.context
            del handler
            self.remove_ref()

    def add_ref(self):
        self.refs += 1

    def remove_ref(self):
        self.refs -= 1

    async def session_released(self, session):
        self.remove_ref()

    async def release(self):
        if self.released:
            return

        self._check_refs.stop()
        self._check_refs = None

        if hasattr(self, "context"):
            del self.context

        if self.build_id:
            logging.info("Build released {0}".format(self.build_id))

        if self.model:
            await self.model.build_released(self)

        self.released = True