add function to call a function with a timeout

This commit is contained in:
Mariano Guerra 2013-02-08 17:23:34 +01:00
parent 0439990ed6
commit a122aa704e
4 changed files with 47 additions and 8 deletions

View file

@ -145,6 +145,14 @@
(.evaluateString ctx scope code filename line-number sec-domain)
(finally (Context/exit)))))
(defn call-timeout [scope fun timeout-ms & args]
(let [factory (TimedContextFactory. timeout-ms)
ctx (.enterContext factory)
args (into-array Object (map #(to-js % scope ctx) args))]
(try
(.call fun ctx scope nil args)
(finally (Context/exit)))))
(defn undefined? [value]
"return true if value is undefined"
(= value (. UniqueTag NOT_FOUND)))
@ -225,10 +233,12 @@
"create a new scope using a safe root scope as parent"
(new-scope ctx (new-safe-root-scope ctx)))
(defn compile-function [scope code & {:keys [ctx filename line-number sec-domain]}]
(defn compile-function [scope code & {:keys [filename line-number sec-domain]}]
"compile and return function defined in code"
(with-context-if-nil ctx (fn [ctx]
(let [ctx (.enterContext (TimedContextFactory. 0))]
(try
(.compileFunction ctx scope code
(or filename "<eval>")
(or line-number 1) sec-domain))))
(or line-number 1) sec-domain)
(finally (Context/exit)))))

View file

@ -0,0 +1,9 @@
package org.marianoguerra.rhino;
public class TimeOutError extends Error {
public final long timeoutMillis;
public TimeOutError(long timeoutMillis) {
this.timeoutMillis = timeoutMillis;
}
}

View file

@ -44,7 +44,7 @@ public class TimedContextFactory extends ContextFactory {
// it is time to stop the script.
// Throw Error instance to ensure that script will never
// get control back through catch or finally.
throw new Error();
throw new TimeOutError(this.timeoutMillis);
}
}

View file

@ -1,5 +1,6 @@
(ns clj-rhino.core-test
(:import [org.mozilla.javascript Context UniqueTag EvaluatorException NativeArray])
(:import [org.mozilla.javascript Context UniqueTag EvaluatorException NativeArray]
[org.marianoguerra.rhino TimeOutError])
(:use clojure.test)
(:require [clj-rhino :as js]))
@ -197,7 +198,26 @@
(testing "eval-timeout times out on infinite loop"
(let [scope (js/new-safe-scope)]
(is (thrown? Error (js/eval-timeout scope "while (true);" 1000)))))
(is (thrown? TimeOutError (js/eval-timeout scope "while (true);" 1000)))))
(testing "call-timeout works"
(let [scope (js/new-safe-scope)
fun-code "function (a, b) { return a + b; }"
compiled-fun (js/compile-function scope fun-code)
result (js/call-timeout scope compiled-fun 1000 2 3)]
(is (= result 5.0))))
(testing "call-timeout timeouts correctly"
(let [scope (js/new-safe-scope)
fun-code "function (a, b) { while(true); }"
compiled-fun (js/compile-function scope fun-code)]
(try
(js/call-timeout scope compiled-fun 1000 2 3)
(throw (Exception. "shouldn't reach this point, should timeout"))
(catch TimeOutError error
(is (= (.-timeoutMillis error) 1000))))))
(testing "native clojure functions can be added"
(js/with-context