Skip to content

Commit

Permalink
inwc3#62: instrument retry policy
Browse files Browse the repository at this point in the history
  • Loading branch information
Cokemonkey11 committed Mar 28, 2021
1 parent 251638c commit 3bfdb3d
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 37 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies {
implementation group: 'com.dorkbox', name: 'PeParser-Dorkbox-Util', version: '2.7'
implementation group: 'com.twelvemonkeys.imageio', name: 'imageio-jpeg', version: '3.6.4'
implementation 'com.jcraft:jzlib:1.1.3'
implementation 'net.jodah:failsafe:2.4.0'

// TestNG
testImplementation 'org.testng:testng:6.14.3'
Expand Down
104 changes: 67 additions & 37 deletions src/main/java/net/moonlightflower/wc3libs/bin/GameExe.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package net.moonlightflower.wc3libs.bin;

import dorkbox.peParser.PE;
import net.jodah.failsafe.Failsafe;
import net.jodah.failsafe.RetryPolicy;
import net.jodah.failsafe.event.ExecutionCompletedEvent;
import net.moonlightflower.wc3libs.misc.ProcCaller;
import net.moonlightflower.wc3libs.port.GameVersion;

Expand All @@ -12,17 +15,37 @@
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class GameExe {
private static final Logger log = LoggerFactory.getLogger(GameExe.class.getName());

@Nonnull
public static String getVersionString(@Nonnull File file) throws IOException {
return Failsafe.with(
new RetryPolicy<String>()
.handle(IOException.class)
.withBackoff(500, 10_000, ChronoUnit.MILLIS)
.withMaxRetries(3)
.onRetriesExceeded(GameExe::logRetriesExceededGettingVersion)
).get(() -> GameExe.getVersionStringInternal(file));
}

private static void logRetriesExceededGettingVersion(ExecutionCompletedEvent<String> event) {
log.warn("Failed to get version string from either dorkbox PE or WMIC. Last event was {}", event);
}

/**
* Attempts to read windows exe metadata to obtain version string. Uses dorkbox PE, and falls back to WMIC if there
* is an exception.
* @param file location of exe
* @return version string, e.g. `1.32.9.16589`
* @throws IOException if dorkbox PE encounters an exception and then WMIC subsequently fails to emit a version.
*/
@Nonnull
private static String getVersionStringInternal(@Nonnull File file) throws IOException {
try {
String s = file.getAbsolutePath();
log.info("Querying {} with dorkbox PE", s);
Expand All @@ -31,59 +54,66 @@ public static String getVersionString(@Nonnull File file) throws IOException {
} catch (Exception e) {
log.info("Falling back to WMIC due to {}", e);

File tmpBat = File.createTempFile("getVersionString", "tmp_proxy.bat");
return getVersionStringInternalWmic(file);
}
}

tmpBat.deleteOnExit();
@Nonnull
private static String getVersionStringInternalWmic(@Nonnull File file) throws IOException {
File tmpBat = File.createTempFile("getVersionString", "tmp_proxy.bat");

File tmpOut = File.createTempFile("getVersionString", "tmp_out.txt");
tmpBat.deleteOnExit();

tmpOut.deleteOnExit();
File tmpOut = File.createTempFile("getVersionString", "tmp_out.txt");

String query = "\"%SystemRoot%\\System32\\Wbem\\wmic.exe\""+
" datafile"+
" where"+
String.format(" name=\"%s\"", file.getAbsolutePath().replaceAll("\\\\", "\\\\\\\\"))+
" get"+
" Version"+
" /value"+
String.format(" 1>\"%s\"", tmpOut.getAbsolutePath().replaceAll("\\\\", "\\\\\\\\"));
tmpOut.deleteOnExit();

//System.out.println("load " + query);
String query = "\"%SystemRoot%\\System32\\Wbem\\wmic.exe\""+
" datafile"+
" where"+
String.format(" name=\"%s\"", file.getAbsolutePath().replaceAll("\\\\", "\\\\\\\\"))+
" get"+
" Version"+
" /value"+
String.format(" 1>\"%s\"", tmpOut.getAbsolutePath().replaceAll("\\\\", "\\\\\\\\"));

Files.write(tmpBat.toPath(), Arrays.asList("chcp 65001", query, "EXIT /B %ERRORLEVEL%"));
//System.out.println("load " + query);

ProcCaller proc = new ProcCaller(tmpBat.getAbsolutePath());
Files.write(tmpBat.toPath(), Arrays.asList("chcp 65001", query, "EXIT /B %ERRORLEVEL%"));

proc.exec();
ProcCaller proc = new ProcCaller(tmpBat.getAbsolutePath());

if (proc.exitVal() != 0) {
throw new IOException(proc.getErrString());
}
proc.exec();

if (proc.exitVal() != 0) {
throw new IOException(proc.getErrString());
}

BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(tmpOut), StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
InputStreamReader inputStream = new InputStreamReader(new FileInputStream(tmpOut), StandardCharsets.UTF_8);

StringBuilder sb = new StringBuilder();
try(BufferedReader reader = new BufferedReader(inputStream)) {
String line;

while ((line = reader.readLine()) != null) {
sb.append(line);
}
};

String versionString = sb.toString().replaceAll("[^0-9.]", "");
String versionString = sb.toString().replaceAll("[^0-9.]", "");

if (versionString.isEmpty()) versionString = null;
if (versionString.isEmpty()) versionString = null;

if (versionString == null) {
throw new IOException(
"Version string "
+ sb.toString()
+ " from file produced by WMIC wasn't readable. "
+ "This is the second failed attempt after dorkbox PE failed with exception.",
e);
}

return versionString;
if (versionString == null) {
throw new IOException(
"Version string "
+ sb.toString()
+ " from file produced by WMIC wasn't readable. "
+ "This is the second failed attempt after dorkbox PE failed with exception."
);
}

return versionString;
}

@Nonnull
Expand Down

0 comments on commit 3bfdb3d

Please sign in to comment.