Anthony Stirling 36e6fe03d8 merge
2025-06-23 15:29:37 +01:00

152 lines
5.2 KiB
Java

package stirling.software.SPDF;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.file.Path;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import io.github.pixee.security.SystemCommand;
import lombok.extern.slf4j.Slf4j;
import stirling.software.common.service.TempFileCleanupService;
import stirling.software.common.util.ApplicationContextProvider;
import stirling.software.common.util.TempFileManager;
@Slf4j
@Component
public class UnoconvServer {
private static final long ACTIVITY_TIMEOUT = 20L * 60 * 1000; // 20 minutes
private static UnoconvServer INSTANCE;
private static final int LISTENER_PORT = 2002;
private ExecutorService executorService;
private long lastActivityTime;
private Process process;
private Path tempDir;
private final TempFileManager tempFileManager;
private final TempFileCleanupService cleanupService;
@Autowired
public UnoconvServer(TempFileManager tempFileManager, TempFileCleanupService cleanupService) {
this.tempFileManager = tempFileManager;
this.cleanupService = cleanupService;
INSTANCE = this;
}
public static UnoconvServer getInstance() {
// If INSTANCE is not set through Spring, try to get it from the ApplicationContext
if (INSTANCE == null) {
INSTANCE = ApplicationContextProvider.getBean(UnoconvServer.class);
if (INSTANCE == null) {
log.warn("Creating UnoconvServer without Spring context");
INSTANCE = new UnoconvServer(null, null);
}
}
return INSTANCE;
}
private boolean isServerRunning() {
log.info("Checking if unoconv server is running");
try (Socket socket = new Socket()) {
socket.connect(
new InetSocketAddress("localhost", LISTENER_PORT),
1000); // Timeout after 1 second
return true;
} catch (Exception e) {
return false;
}
}
public void start() throws IOException {
// Check if the server is already running
if (process != null && process.isAlive()) {
return;
}
// Create and register a temp directory for unoconv if TempFileManager is available
if (tempFileManager != null) {
tempDir = tempFileManager.registerLibreOfficeTempDir();
log.info("Created unoconv temp directory: {}", tempDir);
}
String command;
if (tempDir != null) {
command = "unoconv-server --user-profile " + tempDir.toString();
} else {
command = "unoconv-server";
}
// Start the server process
process = SystemCommand.runCommand(Runtime.getRuntime(), command);
lastActivityTime = System.currentTimeMillis();
// Start a background thread to monitor the activity timeout
executorService = Executors.newSingleThreadExecutor();
executorService.submit(
() -> {
while (true) {
long idleTime = System.currentTimeMillis() - lastActivityTime;
if (idleTime >= ACTIVITY_TIMEOUT) {
process.destroy();
if (cleanupService != null) {
cleanupService.cleanupLibreOfficeTempFiles();
}
break;
}
try {
Thread.sleep(5000); // Check for inactivity every 5 seconds
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
});
// Wait for the server to start up
long startTime = System.currentTimeMillis();
long timeout = 30000; // Timeout after 30 seconds
while (System.currentTimeMillis() - startTime < timeout) {
if (isServerRunning()) {
lastActivityTime = System.currentTimeMillis();
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("Error waiting for server to start", e);
} // Check every 1 second
}
}
public synchronized void stop() {
// Stop the activity timeout monitor thread
if (executorService != null) {
executorService.shutdownNow();
}
// Stop the server process
if (process != null && process.isAlive()) {
process.destroy();
}
if (cleanupService != null) {
cleanupService.cleanupLibreOfficeTempFiles();
}
}
/**
* Notify that unoconv is being used, to reset the inactivity timer.
*/
public void notifyActivity() {
lastActivityTime = System.currentTimeMillis();
}
}