Skip to content

Commit

Permalink
Fallback upon fail to load native libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
LazoYoung committed Feb 20, 2023
1 parent a78101a commit 5e1d78c
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 20 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ SimOverlayNG is a software creating livestream overlays for flight simmers.
## Links

- [Download](https://github.com/LazoYoung/SimOverlayNG/releases)
- [How to use](https://github.com/LazoYoung/SimOverlayNG/wiki)
- [Documentation](https://github.com/LazoYoung/SimOverlayNG/wiki)
- [Roadmap](https://github.com/LazoYoung/SimOverlayNG/wiki/Roadmap)

Please note that [Java 17+](https://www.oracle.com/java/technologies/downloads/) and [FSUIPC](http://www.fsuipc.com/) is required.
Expand Down
103 changes: 96 additions & 7 deletions src/main/java/com/naver/idealproduction/song/SimOverlayNG.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import com.mouseviator.fsuipc.FSUIPC;
import com.naver.idealproduction.song.domain.Properties;
import com.naver.idealproduction.song.gui.Console;
import com.naver.idealproduction.song.gui.Window;
import com.naver.idealproduction.song.gui.panel.Console;
import com.naver.idealproduction.song.servlet.service.SimTracker;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
Expand All @@ -12,28 +12,33 @@
import org.springframework.core.io.ClassPathResource;

import javax.swing.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.*;

import static com.mouseviator.fsuipc.FSUIPC.*;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static javax.swing.JOptionPane.*;

@SpringBootApplication
public class SimOverlayNG {
private static final Logger logger = Logger.getLogger(SimOverlayNG.class.getName());
private static final String hostAddress = "localhost";
private static final String portKey = "server.port";
private static final String directory = "SimOverlayNG";
private static Window window;

public static void main(String[] args) {
var window = new Window();
window = new Window();
var console = new Console(logger, window);
var builder = new SpringApplicationBuilder(SimOverlayNG.class);
var props = new HashMap<String, Object>();
Expand Down Expand Up @@ -61,8 +66,7 @@ public static void main(String[] args) {
exit(context);
}

if (FSUIPC.load() != FSUIPC.LIB_LOAD_RESULT_OK) {
logger.severe("Failed to load library: FSUIPC_Java");
if (loadLibrary() != FSUIPC.LIB_LOAD_RESULT_OK) {
exit(context);
}

Expand All @@ -74,7 +78,7 @@ public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
window.start(console, simTracker, context);
if (finalPort != defaultPort) {
window.showDialog(JOptionPane.WARNING_MESSAGE, String.format("Failed to bind port %d.\nUsing new port: %d", defaultPort, finalPort));
window.showDialog(WARNING_MESSAGE, String.format("Failed to bind port %d.\nUsing new port: %d", defaultPort, finalPort));
}
});
simTracker.start();
Expand Down Expand Up @@ -126,6 +130,91 @@ private static void copyLibraries() throws IOException {
Files.copy(fsuipc64Stream, userDir.resolve(fsuipc64), REPLACE_EXISTING);
}

private static byte loadLibrary() {
String arch;
String library;
String fileName;

try {
arch = System.getProperty("sun.arch.data.model");

if (arch.equals("32")) {
library = LIBRARY_NAME32;
} else if (arch.equals("64")) {
library = LIBRARY_NAME64;
} else {
throw new RuntimeException();
}
fileName = library + ".dll";
} catch (Exception e) {
window.showDialog(ERROR_MESSAGE, "Failed to determine system architecture!");
return LIB_LOAD_RESULT_FAILED;
}

try {
var isLoaded = Class.forName(FSUIPC.class.getName()).getDeclaredField("libraryLoaded");
isLoaded.setAccessible(true);

if (isLoaded.getBoolean(null)) {
return LIB_LOAD_RESULT_ALREADY_LOADED;
} else {
System.loadLibrary(library);
logger.info("Loaded library: " + library);
isLoaded.setBoolean(null, true);
return LIB_LOAD_RESULT_OK;
}
} catch (UnsatisfiedLinkError e) {
window.showDialog(ERROR_MESSAGE, "System failed to read native libraries. Resolving...");
} catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
return LIB_LOAD_RESULT_FAILED;
}

Path binPath = Paths.get(System.getProperty("java.home"), "bin");
File bin = binPath.toFile();
FileInputStream fileInput = null;
boolean canRead;
boolean canWrite;

try {
Path userDir = Path.of(System.getProperty("user.dir"));
fileInput = new FileInputStream(userDir.resolve(fileName).toFile());
canRead = bin.canRead();
canWrite = bin.canWrite();

if (!canRead && !bin.setReadable(true)) {
throw new RuntimeException("File not readable.");
}
if (!canWrite && !bin.setWritable(true)) {
throw new RuntimeException("File not writable.");
}
Files.copy(fileInput, binPath.resolve(fileName), REPLACE_EXISTING);
} catch (Exception e) {
window.showDialog(ERROR_MESSAGE, "Failed to load native libraries!\nTry running this program as administrator.");
return LIB_LOAD_RESULT_FAILED;
} finally {
if (fileInput != null) {
try {
fileInput.close();
} catch (IOException e) {
logger.log(Level.SEVERE, e.getMessage(), e);
}
}
}

try {
var ignored1 = bin.setReadable(canRead);
var ignored2 = bin.setWritable(canWrite);
} catch (SecurityException ignored) {}

try {
return FSUIPC.load();
} catch (Exception e) {
logger.log(Level.SEVERE, "Failed to load FSUIPC!", e);
return LIB_LOAD_RESULT_FAILED;
}
}

private static boolean isPortAvailable(int port) {
try (var ignored = new Socket(hostAddress, port)) {
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.naver.idealproduction.song.gui.panel;
package com.naver.idealproduction.song.gui;

import com.naver.idealproduction.song.gui.Window;
import org.apache.commons.lang3.exception.ExceptionUtils;

import javax.swing.*;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.naver.idealproduction.song.gui;

import com.naver.idealproduction.song.gui.panel.Dispatcher;
import com.naver.idealproduction.song.gui.panel.SimMonitor;
import com.naver.idealproduction.song.gui.panel.SimvarMonitor;
import com.naver.idealproduction.song.gui.subpanel.Dispatcher;
import com.naver.idealproduction.song.gui.subpanel.SimMonitor;
import com.naver.idealproduction.song.gui.subpanel.SimvarMonitor;
import org.springframework.context.ConfigurableApplicationContext;

import javax.swing.*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,23 @@

import static java.awt.Dialog.ModalityType.APPLICATION_MODAL;
import static java.lang.Short.MAX_VALUE;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Level.*;
import static javax.swing.BoxLayout.Y_AXIS;
import static org.burningwave.core.assembler.StaticComponentContainer.Modules;

public class Overlays extends JPanel {
private final Logger logger = Logger.getLogger(SimOverlayNG.class.getName());
private final String validURL = SimOverlayNG.getWebURL("/overlay").toString();
private final String invalidURL = SimOverlayNG.getWebURL("/404").toString();
private final Window window;
private final OverlayService repository;
private final JComboBox<String> selector;
private final JPanel overlayPane;
private CefApp cefApp;
private CefBrowser browser = null;

public Overlays(Window window, OverlayService repository) {
this.window = window;
this.repository = repository;
var items = repository.getOverlays()
.stream()
Expand Down Expand Up @@ -187,7 +189,9 @@ private void onComboSelect(ActionEvent event) {
.filter(e -> e.getName().equals(overlayName))
.findAny();

if (overlay.isPresent()) {
if (browser == null) {
window.showDialog(JOptionPane.INFORMATION_MESSAGE, "Viewer is still loading...");
} else if (overlay.isPresent()) {
repository.select(overlay.get().getId());
updateBrowser(validURL);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.naver.idealproduction.song.gui;

import com.naver.idealproduction.song.SimOverlayNG;
import com.naver.idealproduction.song.gui.panel.Console;
import com.naver.idealproduction.song.servlet.service.OverlayService;
import com.naver.idealproduction.song.servlet.service.SimTracker;
import org.springframework.context.ConfigurableApplicationContext;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.naver.idealproduction.song.gui.panel;
package com.naver.idealproduction.song.gui.subpanel;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.naver.idealproduction.song.gui.panel;
package com.naver.idealproduction.song.gui.subpanel;

import com.naver.idealproduction.song.gui.Dashboard;
import com.naver.idealproduction.song.servlet.service.SimBridge;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.naver.idealproduction.song.gui.panel;
package com.naver.idealproduction.song.gui.subpanel;

import javax.swing.*;
import javax.swing.border.Border;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.naver.idealproduction.song.gui.panel;
package com.naver.idealproduction.song.gui.subpanel;

import com.naver.idealproduction.song.SimOverlayNG;
import com.naver.idealproduction.song.domain.overlay.Simvar;
Expand Down

0 comments on commit 5e1d78c

Please sign in to comment.