Skip to content

Commit

Permalink
0.0.9
Browse files Browse the repository at this point in the history
- Fixed js exceptions not getting caught properly
  • Loading branch information
Osiris-Team committed Sep 30, 2021
1 parent 20e7937 commit 3664b70
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 33 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.osiris.headlessbrowser</groupId>
<artifactId>Headless-Browser</artifactId>
<version>0.0.7</version>
<version>0.0.9</version>
<repositories>
<repository>
<id>jitpack</id>
Expand Down
61 changes: 32 additions & 29 deletions src/main/java/com/osiris/headlessbrowser/NodeContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public class NodeContext implements AutoCloseable {
private final OutputStream processOutput;
private final PrintStream debugOutput;
private final File lastJsCodeExecutionResultFile;
private File executableFile;
private final int timeout;
private File executableFile;

public NodeContext() {
this(null, 30);
Expand Down Expand Up @@ -133,17 +133,6 @@ public NodeContext(OutputStream debugOutput, int timeout) {
"var fs = require('fs');\n" +
"var data = fs.writeFileSync('" + resultFilePath + "', result);\n" +
"};\n" +
"// Ensures that all errors get catched:\n" +
"// Note that process.exit() must be called explicitly because by adding the below we are in an inconsistent state\n" +
"// Source: https://stackoverflow.com/questions/19909904/how-to-handle-all-exceptions-in-node-js\n" +
"process.on('uncaughtException', function(err) {\n" +
" console.error('Caught exception: ' + err.name);\n" +
" console.error(\"with message: \"+err.message);\n" +
"try {\n" +
" console.error(\"at line: \" + err.lineNumber);\n" +
" console.error(\"with stack: \" + err.stack);\n" +
"} catch (e) {}\n" +
"});\n" +
"console.log('Context initialised!');\n");

} catch (Exception e) {
Expand Down Expand Up @@ -196,10 +185,10 @@ public synchronized NodeContext writeLine(String line) throws IOException {
}

/**
* See {@link #executeJavaScript(String, int)} for details.
* See {@link #executeJavaScript(String, int, boolean)} for details.
*/
public NodeContext executeJavaScript(String jsCode) throws NodeJsCodeException {
return executeJavaScript(jsCode, timeout);
return executeJavaScript(jsCode, timeout, true);
}

/**
Expand All @@ -208,10 +197,24 @@ public NodeContext executeJavaScript(String jsCode) throws NodeJsCodeException {
* Note that everything related to JavaScript gets printed/written to the {@link #debugOutput}, which <br>
* means that you must have provided this {@link NodeContext} a {@link #debugOutput} at initialisation to see your codes output. <br>
*/
public synchronized NodeContext executeJavaScript(String jsCode, int timeout) throws NodeJsCodeException {
public synchronized NodeContext executeJavaScript(String jsCode, int timeout, boolean wrapInTryCatch) throws NodeJsCodeException {
try {
jsCode = jsCode + "\n" +
"console.log('Done!');\n";
if (wrapInTryCatch) {
jsCode = "try{\n" + // Just to make sure that errors get definitively caught
jsCode + "\n" +
"console.log('Done!');\n" +
"} catch (e){\n" +
" console.error('CAUGHT JS-EXCEPTION: ' + e.name + '\\n'" +
" + 'MESSAGE: ' + e.message + '\\n'" +
" + 'LINE: ' + e.lineNumber + '\\n'" +
" + 'STACK: ' + e.stack+'\\n');\n" +
"}\n"
;
} else {
jsCode = jsCode + "\n" +
"console.log('Done!');\n";
}

if (jsCode.contains("\n")) {
debugOutput.println("Executing following JS-Code: ");
debugOutput.println("JS-CODE START >");
Expand All @@ -227,7 +230,7 @@ public synchronized NodeContext executeJavaScript(String jsCode, int timeout) th
}

AtomicBoolean wasExecuted = new AtomicBoolean();
List<String> errors = new ArrayList<>();
List<String> errors = new ArrayList<>(2);
Consumer<String> consoleLogListener = line -> wasExecuted.set(true);
processInput.listeners.add(consoleLogListener);

Expand All @@ -245,26 +248,26 @@ public synchronized NodeContext executeJavaScript(String jsCode, int timeout) th
// Wait until we receive a response, like undefined

for (int i = 0; i < timeout * 10; i++) { // Example timeout = 30s * 10 = 300loops * 100ms = 30000ms = 30s
if (wasExecuted.get())
if (wasExecuted.get() || !errors.isEmpty())
break;
else
Thread.sleep(100); // Total of 30 seconds
}

if (timeout == 0) {
while (!wasExecuted.get()) {
if (timeout == 0) { // Since the timeout is 0 we wait indefinitely for the script to finish
while (!wasExecuted.get() && errors.isEmpty()) {
Thread.sleep(100);
}
}

if (!errors.isEmpty()) {
throw new NodeJsCodeException("Error during JavaScript code execution! Details: ", errors);
}

if (!wasExecuted.get())
throw new NodeJsCodeException("Script execution timeout of 30 seconds reached! This means that the script didn't finish within the last 30 seconds.", null);


if (!errors.isEmpty()) {
throw new NodeJsCodeException("Error during JavaScript code execution!", errors);
}

processErrorInput.listeners.remove(consoleErrorLogListener);
processInput.listeners.remove(consoleLogListener);
tmpJs.delete();
Expand All @@ -277,10 +280,10 @@ public synchronized NodeContext executeJavaScript(String jsCode, int timeout) th
}

/**
* See {@link #executeJavaScript(String, int)} for details.
* See {@link #executeJavaScript(String, int, boolean)} for details.
*/
public synchronized String executeJavaScriptAndGetResult(String jsCode) {
return executeJavaScriptAndGetResult(jsCode, timeout);
return executeJavaScriptAndGetResult(jsCode, timeout, true);
}

/**
Expand All @@ -293,10 +296,10 @@ public synchronized String executeJavaScriptAndGetResult(String jsCode) {
*
* @param timeout 30 seconds is the default, set to 0 to disable.
*/
public synchronized String executeJavaScriptAndGetResult(String jsCode, int timeout) {
public synchronized String executeJavaScriptAndGetResult(String jsCode, int timeout, boolean wrapInTryCatch) {
try {
executeJavaScript(jsCode + "\n"
+ "writeToJava(result);\n", timeout);
+ "writeToJava(result);\n", timeout, wrapInTryCatch);

StringBuilder result = new StringBuilder();
String line = null;
Expand Down
50 changes: 47 additions & 3 deletions src/main/java/com/osiris/headlessbrowser/NodeWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class NodeWindow implements AutoCloseable {
private final OutputStream debugOutput;
private HBrowser parentBrowser;
private boolean enableJavaScript;
private String url;

public NodeWindow(HBrowser parentBrowser, boolean enableJavaScript, OutputStream debugOutput, int jsTimeout) {
this.parentBrowser = parentBrowser;
Expand All @@ -35,7 +36,19 @@ public NodeWindow(HBrowser parentBrowser, boolean enableJavaScript, OutputStream
jsContext.npmInstall("puppeteer");
jsContext.executeJavaScript("const puppeteer = require('puppeteer');\n" +
"const browser = await puppeteer.launch();\n" +
"const page = await browser.newPage();\n");
"const page = await browser.newPage();\n" +
"var downloadFile = null;\n", 30, false);
jsContext.executeJavaScript("" +
"await page.setRequestInterception(true);\n" +
"page.on('request', (request) => {\n" +
"if (downloadFile!=null){" +
" // Override headers\n" +
" var content = await request.frame().content()\n" +
" console.log('FRAME: '+content);\n" +
"} else{" +
"request.continue();" +
"}" +
"});");
setEnableJavaScript(enableJavaScript);
} catch (Exception e) {
throw new RuntimeException(e);
Expand All @@ -60,7 +73,9 @@ public NodeWindow load(String url) throws IOException, NodeJsCodeException {
if (!url.startsWith("http"))
url = "https://" + url;

jsContext.executeJavaScript("var currentPageResponse = await page.goto('" + url + "');");
jsContext.executeJavaScript("" +
"var response = await page.goto('" + url + "');\n");
this.url = url;
return this;
}

Expand All @@ -84,7 +99,7 @@ public String getTitle() {
* Note that the current {@link NodeContext} must have been initialised with a debugOutputStream to see JavaScript console output. <br>
*/
public NodeWindow executeJS(String jsCode) throws NodeJsCodeException {
jsContext.executeJavaScript("page.evaluate(() => {\n" +
jsContext.executeJavaScript("await page.evaluate(() => {\n" +
jsCode +
"});\n");
return this;
Expand Down Expand Up @@ -322,6 +337,35 @@ public int getStatusCode() throws NodeJsCodeException {
}
*/

/** TODO
* Downloads the currently loaded page/resource to the specified file. <br>
* Creates the file if not existing. <br>
public NodeWindow download(File downloadedFile) throws NodeJsCodeException, IOException {
return download(url, downloadedFile);
}
*/

/**
* TODO
* Note that the url won't get loaded into the current window.
* <p>
* public NodeWindow download(String url, File downloadedFile) throws NodeJsCodeException, IOException {
* String filePath = downloadedFile.getAbsolutePath().replace("\\", "/");
* jsContext.executeJavaScript("downloadFile = '"+filePath+"';");
* load(url);
* jsContext.executeJavaScript("downloadFile = null;");
* <p>
* jsContext.executeJavaScript("" +
* "" +
* "var buffer = await response.buffer();\n" +
* "fs.writeFileSync(\""+filePath+"\", buffer);");
* <p>
* <p>
* return this;
* }
*/

public HBrowser getParentBrowser() {
return parentBrowser;
Expand Down
2 changes: 2 additions & 0 deletions src/test/java/com/osiris/headlessbrowser/NodeWindowTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public static void main(String[] args) throws Exception {
window.load("https://github.com/Osiris-Team");
System.out.println(window.getBrowserType());
window.printCookiesAsJsonArray();
//TODO window.download("https://github.com/Osiris-Team/AutoPlug-Releases/raw/master/stable-builds/AutoPlug-Client.jar",
// new File("AutoPlug-Client.jar"));
}
}

Expand Down

0 comments on commit 3664b70

Please sign in to comment.