diff --git a/pom.xml b/pom.xml
index 88e8933..6562040 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,15 +49,15 @@
2.1.0-alpha1
- 2.25.4
+ 2.26.0
- 12.1.8
+ 12.1.10
- 3.1.11
+ 3.1.12
2.3.3.RELEASE
- 6.1.0-SNAPSHOT
+ 6.1.0
6.1.0-1-SNAPSHOT
6.1.0-1-SNAPSHOT
5.6.0-1-SNAPSHOT
@@ -67,7 +67,7 @@
4.7.7
- 2.21
+ 2.22
2.10.0
3.5.0
@@ -84,6 +84,30 @@
UTF-8
AKSW
1.7.0
+
+ 2.1.1
+ 1.20.0
+ 5.13.5.202508271544-r
+ 0.0.9
+ 0.0.9
+ 0.0.9
+ 0.0.1-3
+ 4.8.184
+ 4.13.2
+
+ 1.6.0
+ 3.15.0
+ 3.4.0
+ 2.10.4
+ 3.6.0-M1
+ 3.5.1
+ 1.14
+ 1.13.0
+ 2.4.3
+ 1.6
+ 2.8.2
+ 3.11.0
+ 1.21.0
@@ -124,7 +148,7 @@
javax.ws.rs
javax.ws.rs-api
- 2.1.1
+ ${ws.rs-api.version}
@@ -317,40 +341,40 @@
org.locationtech.jts.io
jts-io-common
- 1.18.1
+ ${jts-io-common.version}
org.eclipse.jgit
org.eclipse.jgit
- 5.6.0.201912101111-r
+ ${jgit.version}
com.jcraft
jsch.agentproxy.jsch
- 0.0.9
+ ${jsch.agentproxy.jsch.version}
com.jcraft
jsch.agentproxy.usocket-jna
- 0.0.9
+ ${jsch.agentproxy.usocket-jna.version}
com.jcraft
jsch.agentproxy.sshagent
- 0.0.9
+ ${jsch.agentproxy.sshagent.version}
org.aksw.thirdparty.com.sshtools
vfs2nio
- 0.0.1-3-SNAPSHOT
+ ${vfs2nio.version}
io.github.classgraph
classgraph
- 4.8.129
+ ${classgraph.version}
@@ -379,7 +403,7 @@
junit
junit
- 4.13.1
+ ${junit.version}
@@ -420,12 +444,12 @@
de.jutzig
github-release-plugin
- 1.4.0
+ ${github-release-plugin.version}
com.amashchenko.maven.plugin
gitflow-maven-plugin
- 1.8.0
+ ${gitflow-maven-plugin.version}
v
@@ -435,7 +459,7 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.11.0
+ ${maven-compiler-plugin.version}
@@ -447,7 +471,7 @@
org.apache.maven.plugins
maven-source-plugin
- 3.0.1
+ ${maven-source-plugin.version}
attach-sources
@@ -461,7 +485,7 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 2.9.1
+ ${maven-javadoc-plugin.version}
attach-javadocs
@@ -480,7 +504,7 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.2.2
+ ${maven-surefire-plugin.version}
@@ -495,22 +519,22 @@
com.google.cloud.tools
jib-maven-plugin
- 3.4.4
+ ${jib-maven-plugin.version}
jdeb
org.vafer
- 1.10
+ ${jdeb.version}
de.dentrassi.maven
rpm
- 1.8.0
+ ${rpm.version}
org.apache.maven.plugins
maven-shade-plugin
- 2.4.3
+ ${maven-shade-plugin.version}
package
@@ -542,7 +566,7 @@
org.apache.maven.plugins
maven-gpg-plugin
- 1.6
+ ${maven-gpg-plugin.version}
sign-artifacts
@@ -571,12 +595,12 @@
org.apache.maven.plugins
maven-deploy-plugin
- 2.8.2
+ ${maven-deploy-plugin.version}
org.apache.maven.plugins
maven-dependency-plugin
- 3.0.2
+ ${maven-dependency-plugin.version}
prepare-package
diff --git a/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/ServletRptServerStatus.java b/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/ServletRptServerStatus.java
new file mode 100644
index 0000000..40a4121
--- /dev/null
+++ b/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/ServletRptServerStatus.java
@@ -0,0 +1,66 @@
+package org.aksw.sparql_integrate.cli.main;
+
+import jakarta.servlet.ServletRegistration;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.ws.rs.core.MediaType;
+import org.aksw.jenax.web.server.boot.ServletBuilder;
+import org.springframework.web.WebApplicationInitializer;
+import org.springframework.web.context.support.GenericWebApplicationContext;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class ServletRptServerStatus extends HttpServlet implements ServletBuilder {
+
+ private AtomicBoolean serverReady = null;
+
+ public static ServletRptServerStatus newBuilder() {
+ return new ServletRptServerStatus();
+ }
+
+ @Override
+ public WebApplicationInitializer build(GenericWebApplicationContext rootContext) {
+ Objects.requireNonNull(serverReady, "Ready signal was not configured");
+ return servletContext -> {
+ ServletRegistration.Dynamic servlet = servletContext.addServlet("rptServerStatus", this);
+ servlet.addMapping("/health");
+ servlet.addMapping("/health/");
+ servlet.setLoadOnStartup(1);
+ };
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ String accept = req.getHeader("Accept");
+ boolean isSse = accept != null && accept.contains("text/event-stream");
+
+ if (false && isSse) {
+ resp.setContentType("text/event-stream;charset=utf-8");
+ resp.setHeader("Cache-Control", "no-cache");
+ resp.setHeader("Connection", "keep-alive");
+
+ PrintWriter writer = resp.getWriter();
+ writer.print("data: " + (serverReady.get() ? "ready" : "starting") + "\n\n");
+ writer.flush();
+ // XXX Would need to keep the connection open for SSE
+ } else {
+ resp.setContentType(MediaType.TEXT_PLAIN);
+ PrintWriter writer = resp.getWriter();
+ writer.println(serverReady.get() ? "ready" : "starting");
+ writer.close();
+ }
+ }
+
+ public ServletRptServerStatus setServerReady(AtomicBoolean serverReady) {
+ this.serverReady = serverReady;
+ return this;
+ }
+
+ public boolean isServerReady() {
+ return serverReady.get();
+ }
+}
diff --git a/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/SparqlIntegrateCmdImpls.java b/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/SparqlIntegrateCmdImpls.java
index dce9880..c668fc2 100644
--- a/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/SparqlIntegrateCmdImpls.java
+++ b/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/SparqlIntegrateCmdImpls.java
@@ -23,6 +23,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
@@ -218,6 +219,8 @@ public static int sparqlIntegrate(CmdSparqlIntegrateMain cmd) throws Exception {
CmdMixinArq.configureGlobal(cmd.arqConfig);
CmdMixinArq.configureCxt(ARQ.getContext(), cmd.arqConfig);
+ AtomicBoolean serverReady = new AtomicBoolean();
+
// JenaRuntime.isRDF11 = !cmd.useRdf10;
//
// CliUtils.configureGlobalSettings();
@@ -971,7 +974,9 @@ public void afterExec() {
// .addServletBuilder(ServletBuilderGraphQlV2.newBuilder().setGraphQlExecFactory(graphQlExecFactory))
.addServletBuilder(
ServletBuilderGraphQlV2.newBuilder().setGraphQlExecFactory(graphQlExecFactoryV2))
- .addServletBuilder(ServletLdvConfigJs.newBuilder().setDbEngine(cmd.engine)).setPort(port);
+ .addServletBuilder(ServletLdvConfigJs.newBuilder().setDbEngine(cmd.engine))
+ .addServletBuilder(ServletRptServerStatus.newBuilder().setServerReady(serverReady))
+ .setPort(port);
if (graphqlSchemaNavigator != null) {
serverBuilder = serverBuilder.addServletBuilder(ServletGraphQlSchema.newBuilder()
@@ -1040,6 +1045,8 @@ public void afterExec() {
logger.info("SPARQL overall execution finished after " + sw.stop());
if (server != null) {
+ serverReady.set(true);
+ // ServletRptServerStatus.setServerReady();
logger.info("Server still running on port " + cmd.serverPort + ". Terminate with CTRL+C");
server.join();
}
diff --git a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-deb-cli/src/deb/resources/usr/bin/rpt-integrate-await b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-deb-cli/src/deb/resources/usr/bin/rpt-integrate-await
new file mode 100755
index 0000000..81b8d10
--- /dev/null
+++ b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-deb-cli/src/deb/resources/usr/bin/rpt-integrate-await
@@ -0,0 +1,145 @@
+#!/bin/bash
+
+# rpt-integrate-await: Wrapper script that starts rpt integrate --server
+# and waits for the server to be ready via SSE health check
+# Returns the PID of the rpt process once server is healthy
+
+set -e
+
+# Default values
+DEFAULT_PORT=8642
+DEFAULT_TIMEOUT=30
+HEALTH_ENDPOINT="/health"
+
+# Arrays to store parsed arguments
+RPT_ARGS=()
+SERVER_MODE=false
+SERVER_PORT=$DEFAULT_PORT
+
+# Parse command line arguments
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --server)
+ SERVER_MODE=true
+ RPT_ARGS+=("$1")
+ shift
+ ;;
+ --port)
+ if [[ -n "$2" && ! "$2" == --* ]]; then
+ SERVER_PORT="$2"
+ RPT_ARGS+=("$1" "$2")
+ shift 2
+ else
+ # Handle --port= format
+ SERVER_PORT="${1#--port=}"
+ RPT_ARGS+=("$1")
+ shift
+ fi
+ ;;
+ --help|-h)
+ echo "Usage: rpt-integrate-await [options] "
+ echo ""
+ echo "Wrapper script for 'rpt integrate --server' that waits for the server to be ready."
+ echo ""
+ echo "Options:"
+ echo " --port= Server port (default: ${DEFAULT_PORT})"
+ echo " --timeout= Wait timeout in seconds (default: ${DEFAULT_TIMEOUT})"
+ echo " --help, -h Show this help message"
+ echo ""
+ echo "All other arguments are passed to 'rpt integrate'."
+ echo "The server must be started with --server flag."
+ echo ""
+ echo "Returns the PID of the rpt process once the server is healthy."
+ exit 0
+ ;;
+ --timeout)
+ if [[ -n "$2" && ! "$2" == --* ]]; then
+ TIMEOUT="$2"
+ shift 2
+ else
+ TIMEOUT="${1#--timeout=}"
+ shift
+ fi
+ ;;
+ *)
+ RPT_ARGS+=("$1")
+ shift
+ ;;
+ esac
+done
+
+# Set default timeout if not specified
+TIMEOUT=${TIMEOUT:-$DEFAULT_TIMEOUT}
+
+# Check if --server is in arguments
+if [[ "$SERVER_MODE" != "true" ]]; then
+ echo "Error: 'rpt-integrate-await' requires the --server flag" >&2
+ echo "Usage: rpt-integrate-await --server [options] " >&2
+ exit 1
+fi
+
+# Build the health check URL
+HEALTH_URL="http://localhost:${SERVER_PORT}${HEALTH_ENDPOINT}"
+
+# Start rpt integrate in background
+# Note: We use 'rpt integrate' instead of the full path to respect the user's environment
+rpt integrate "${RPT_ARGS[@]}" > /dev/null & # 2>&1 would hide log output
+RPT_PID=$!
+
+# Function to check if process is running
+is_process_running() {
+ kill -0 "$RPT_PID" 2>/dev/null
+}
+
+# Wait for server to become available using SSE
+echo "Waiting for server to start on port ${SERVER_PORT}..." >&2
+echo "Health check endpoint: ${HEALTH_URL}" >&2
+
+# Try to connect with SSE for up to TIMEOUT seconds
+START_TIME=$(date +%s)
+HEALTHY=false
+
+while true; do
+ CURRENT_TIME=$(date +%s)
+ ELAPSED=$((CURRENT_TIME - START_TIME))
+
+ if [[ $ELAPSED -ge $TIMEOUT ]]; then
+ echo "Error: Timeout waiting for server to start after ${TIMEOUT} seconds" >&2
+ kill "$RPT_PID" 2>/dev/null || true
+ exit 1
+ fi
+
+ # Check if rpt process is still running
+ if ! is_process_running; then
+ echo "Error: rpt process exited unexpectedly" >&2
+ exit 1
+ fi
+
+ # Try to connect with SSE using curl
+ if curl --no-buffer --silent --fail --max-time 2 --header "Accept: text/event-stream" "$HEALTH_URL" --connect-timeout 1 > /dev/null 2>&1; then
+ # Health check passed, now verify port ownership
+ ACTUAL_PID=$(lsof -t -i :${SERVER_PORT} 2>/dev/null | head -1)
+
+ if [[ -z "$ACTUAL_PID" ]]; then
+ sleep 0.5
+ continue
+ fi
+
+ if [[ "$ACTUAL_PID" != "$RPT_PID" ]]; then
+ echo "Error: Port ${SERVER_PORT} is owned by PID ${ACTUAL_PID}, not our process ${RPT_PID}" >&2
+ exit 1
+ # sleep 0.5
+ # continue
+ fi
+
+ echo "Server is ready!" >&2
+ HEALTHY=true
+ break
+ fi
+
+ sleep 0.5
+done
+
+# Output the PID to stdout so the caller can capture it
+echo "$RPT_PID"
+
diff --git a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/pom.xml b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/pom.xml
index efe7b51..825015f 100644
--- a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/pom.xml
+++ b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/pom.xml
@@ -48,7 +48,7 @@
- eclipse-temurin:17-jre
+ eclipse-temurin:21-jre
org.aksw.rdf_processing_toolkit.cli.main.MainCliRdfProcessingToolkit
@@ -70,6 +70,20 @@
--add-opens=java.security.jgss/sun.security.krb5=ALL-UNNAMED
+
+
+
+ src/main/jib
+ /
+
+
+
+
+ /usr/bin/rpt-integrate-await
+ 755
+
+
+
packaged
diff --git a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/src/main/jib/usr/bin/rpt-integrate-await b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/src/main/jib/usr/bin/rpt-integrate-await
new file mode 100755
index 0000000..81b8d10
--- /dev/null
+++ b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/src/main/jib/usr/bin/rpt-integrate-await
@@ -0,0 +1,145 @@
+#!/bin/bash
+
+# rpt-integrate-await: Wrapper script that starts rpt integrate --server
+# and waits for the server to be ready via SSE health check
+# Returns the PID of the rpt process once server is healthy
+
+set -e
+
+# Default values
+DEFAULT_PORT=8642
+DEFAULT_TIMEOUT=30
+HEALTH_ENDPOINT="/health"
+
+# Arrays to store parsed arguments
+RPT_ARGS=()
+SERVER_MODE=false
+SERVER_PORT=$DEFAULT_PORT
+
+# Parse command line arguments
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --server)
+ SERVER_MODE=true
+ RPT_ARGS+=("$1")
+ shift
+ ;;
+ --port)
+ if [[ -n "$2" && ! "$2" == --* ]]; then
+ SERVER_PORT="$2"
+ RPT_ARGS+=("$1" "$2")
+ shift 2
+ else
+ # Handle --port= format
+ SERVER_PORT="${1#--port=}"
+ RPT_ARGS+=("$1")
+ shift
+ fi
+ ;;
+ --help|-h)
+ echo "Usage: rpt-integrate-await [options] "
+ echo ""
+ echo "Wrapper script for 'rpt integrate --server' that waits for the server to be ready."
+ echo ""
+ echo "Options:"
+ echo " --port= Server port (default: ${DEFAULT_PORT})"
+ echo " --timeout= Wait timeout in seconds (default: ${DEFAULT_TIMEOUT})"
+ echo " --help, -h Show this help message"
+ echo ""
+ echo "All other arguments are passed to 'rpt integrate'."
+ echo "The server must be started with --server flag."
+ echo ""
+ echo "Returns the PID of the rpt process once the server is healthy."
+ exit 0
+ ;;
+ --timeout)
+ if [[ -n "$2" && ! "$2" == --* ]]; then
+ TIMEOUT="$2"
+ shift 2
+ else
+ TIMEOUT="${1#--timeout=}"
+ shift
+ fi
+ ;;
+ *)
+ RPT_ARGS+=("$1")
+ shift
+ ;;
+ esac
+done
+
+# Set default timeout if not specified
+TIMEOUT=${TIMEOUT:-$DEFAULT_TIMEOUT}
+
+# Check if --server is in arguments
+if [[ "$SERVER_MODE" != "true" ]]; then
+ echo "Error: 'rpt-integrate-await' requires the --server flag" >&2
+ echo "Usage: rpt-integrate-await --server [options] " >&2
+ exit 1
+fi
+
+# Build the health check URL
+HEALTH_URL="http://localhost:${SERVER_PORT}${HEALTH_ENDPOINT}"
+
+# Start rpt integrate in background
+# Note: We use 'rpt integrate' instead of the full path to respect the user's environment
+rpt integrate "${RPT_ARGS[@]}" > /dev/null & # 2>&1 would hide log output
+RPT_PID=$!
+
+# Function to check if process is running
+is_process_running() {
+ kill -0 "$RPT_PID" 2>/dev/null
+}
+
+# Wait for server to become available using SSE
+echo "Waiting for server to start on port ${SERVER_PORT}..." >&2
+echo "Health check endpoint: ${HEALTH_URL}" >&2
+
+# Try to connect with SSE for up to TIMEOUT seconds
+START_TIME=$(date +%s)
+HEALTHY=false
+
+while true; do
+ CURRENT_TIME=$(date +%s)
+ ELAPSED=$((CURRENT_TIME - START_TIME))
+
+ if [[ $ELAPSED -ge $TIMEOUT ]]; then
+ echo "Error: Timeout waiting for server to start after ${TIMEOUT} seconds" >&2
+ kill "$RPT_PID" 2>/dev/null || true
+ exit 1
+ fi
+
+ # Check if rpt process is still running
+ if ! is_process_running; then
+ echo "Error: rpt process exited unexpectedly" >&2
+ exit 1
+ fi
+
+ # Try to connect with SSE using curl
+ if curl --no-buffer --silent --fail --max-time 2 --header "Accept: text/event-stream" "$HEALTH_URL" --connect-timeout 1 > /dev/null 2>&1; then
+ # Health check passed, now verify port ownership
+ ACTUAL_PID=$(lsof -t -i :${SERVER_PORT} 2>/dev/null | head -1)
+
+ if [[ -z "$ACTUAL_PID" ]]; then
+ sleep 0.5
+ continue
+ fi
+
+ if [[ "$ACTUAL_PID" != "$RPT_PID" ]]; then
+ echo "Error: Port ${SERVER_PORT} is owned by PID ${ACTUAL_PID}, not our process ${RPT_PID}" >&2
+ exit 1
+ # sleep 0.5
+ # continue
+ fi
+
+ echo "Server is ready!" >&2
+ HEALTHY=true
+ break
+ fi
+
+ sleep 0.5
+done
+
+# Output the PID to stdout so the caller can capture it
+echo "$RPT_PID"
+
diff --git a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/test-jib-files.xml b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/test-jib-files.xml
new file mode 100644
index 0000000..0bed001
--- /dev/null
+++ b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/test-jib-files.xml
@@ -0,0 +1,31 @@
+
+ 4.0.0
+ test
+ test
+ 1.0
+
+
+
+ com.google.cloud.tools
+ jib-maven-plugin
+ 3.4.4
+
+
+ eclipse-temurin:17-jre
+
+
+ test:latest
+
+
+
+
+ /etc/hostname
+ /test-file
+
+
+
+
+
+
+
+
diff --git a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-rpm-cli/src/rpm/resources/usr/bin/rpt-integrate-await b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-rpm-cli/src/rpm/resources/usr/bin/rpt-integrate-await
new file mode 100755
index 0000000..81b8d10
--- /dev/null
+++ b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-rpm-cli/src/rpm/resources/usr/bin/rpt-integrate-await
@@ -0,0 +1,145 @@
+#!/bin/bash
+
+# rpt-integrate-await: Wrapper script that starts rpt integrate --server
+# and waits for the server to be ready via SSE health check
+# Returns the PID of the rpt process once server is healthy
+
+set -e
+
+# Default values
+DEFAULT_PORT=8642
+DEFAULT_TIMEOUT=30
+HEALTH_ENDPOINT="/health"
+
+# Arrays to store parsed arguments
+RPT_ARGS=()
+SERVER_MODE=false
+SERVER_PORT=$DEFAULT_PORT
+
+# Parse command line arguments
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --server)
+ SERVER_MODE=true
+ RPT_ARGS+=("$1")
+ shift
+ ;;
+ --port)
+ if [[ -n "$2" && ! "$2" == --* ]]; then
+ SERVER_PORT="$2"
+ RPT_ARGS+=("$1" "$2")
+ shift 2
+ else
+ # Handle --port= format
+ SERVER_PORT="${1#--port=}"
+ RPT_ARGS+=("$1")
+ shift
+ fi
+ ;;
+ --help|-h)
+ echo "Usage: rpt-integrate-await [options] "
+ echo ""
+ echo "Wrapper script for 'rpt integrate --server' that waits for the server to be ready."
+ echo ""
+ echo "Options:"
+ echo " --port= Server port (default: ${DEFAULT_PORT})"
+ echo " --timeout= Wait timeout in seconds (default: ${DEFAULT_TIMEOUT})"
+ echo " --help, -h Show this help message"
+ echo ""
+ echo "All other arguments are passed to 'rpt integrate'."
+ echo "The server must be started with --server flag."
+ echo ""
+ echo "Returns the PID of the rpt process once the server is healthy."
+ exit 0
+ ;;
+ --timeout)
+ if [[ -n "$2" && ! "$2" == --* ]]; then
+ TIMEOUT="$2"
+ shift 2
+ else
+ TIMEOUT="${1#--timeout=}"
+ shift
+ fi
+ ;;
+ *)
+ RPT_ARGS+=("$1")
+ shift
+ ;;
+ esac
+done
+
+# Set default timeout if not specified
+TIMEOUT=${TIMEOUT:-$DEFAULT_TIMEOUT}
+
+# Check if --server is in arguments
+if [[ "$SERVER_MODE" != "true" ]]; then
+ echo "Error: 'rpt-integrate-await' requires the --server flag" >&2
+ echo "Usage: rpt-integrate-await --server [options] " >&2
+ exit 1
+fi
+
+# Build the health check URL
+HEALTH_URL="http://localhost:${SERVER_PORT}${HEALTH_ENDPOINT}"
+
+# Start rpt integrate in background
+# Note: We use 'rpt integrate' instead of the full path to respect the user's environment
+rpt integrate "${RPT_ARGS[@]}" > /dev/null & # 2>&1 would hide log output
+RPT_PID=$!
+
+# Function to check if process is running
+is_process_running() {
+ kill -0 "$RPT_PID" 2>/dev/null
+}
+
+# Wait for server to become available using SSE
+echo "Waiting for server to start on port ${SERVER_PORT}..." >&2
+echo "Health check endpoint: ${HEALTH_URL}" >&2
+
+# Try to connect with SSE for up to TIMEOUT seconds
+START_TIME=$(date +%s)
+HEALTHY=false
+
+while true; do
+ CURRENT_TIME=$(date +%s)
+ ELAPSED=$((CURRENT_TIME - START_TIME))
+
+ if [[ $ELAPSED -ge $TIMEOUT ]]; then
+ echo "Error: Timeout waiting for server to start after ${TIMEOUT} seconds" >&2
+ kill "$RPT_PID" 2>/dev/null || true
+ exit 1
+ fi
+
+ # Check if rpt process is still running
+ if ! is_process_running; then
+ echo "Error: rpt process exited unexpectedly" >&2
+ exit 1
+ fi
+
+ # Try to connect with SSE using curl
+ if curl --no-buffer --silent --fail --max-time 2 --header "Accept: text/event-stream" "$HEALTH_URL" --connect-timeout 1 > /dev/null 2>&1; then
+ # Health check passed, now verify port ownership
+ ACTUAL_PID=$(lsof -t -i :${SERVER_PORT} 2>/dev/null | head -1)
+
+ if [[ -z "$ACTUAL_PID" ]]; then
+ sleep 0.5
+ continue
+ fi
+
+ if [[ "$ACTUAL_PID" != "$RPT_PID" ]]; then
+ echo "Error: Port ${SERVER_PORT} is owned by PID ${ACTUAL_PID}, not our process ${RPT_PID}" >&2
+ exit 1
+ # sleep 0.5
+ # continue
+ fi
+
+ echo "Server is ready!" >&2
+ HEALTHY=true
+ break
+ fi
+
+ sleep 0.5
+done
+
+# Output the PID to stdout so the caller can capture it
+echo "$RPT_PID"
+