Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ scripts/freeroutingp
scripts/logs
scripts/test.dsn
scripts/test.ses
scripts/freeroutingp.exe
scripts/freeroutingp.exe
.aider*
.env
45 changes: 37 additions & 8 deletions src/main/java/app/freerouting/api/v1/JobControllerV1.java
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,10 @@ public Response uploadInput(
@Produces(MediaType.APPLICATION_JSON)
public Response downloadOutput(
@PathParam("jobId")
String jobId)
String jobId,
@QueryParam("speculative")
@DefaultValue("false")
boolean speculative)
{
// Authenticate the user
UUID userId = AuthenticateUser();
Expand All @@ -361,20 +364,46 @@ public Response downloadOutput(
return Response.status(Response.Status.BAD_REQUEST).entity("{\"error\":\"The session ID '" + job.sessionId + "' is invalid.\"}").build();
}

// Check if the job is completed
if (job.state != RoutingJobState.COMPLETED)
// Check if we can return output
if (!speculative && job.state != RoutingJobState.COMPLETED)
{
return Response.status(Response.Status.BAD_REQUEST).entity("{\"error\":\"The job hasn't finished yet.\"}").build();
}

// For speculative results, only return if the job is running or completed
if (speculative && job.state != RoutingJobState.RUNNING && job.state != RoutingJobState.COMPLETED)
{
return Response.status(Response.Status.BAD_REQUEST).entity("{\"error\":\"The job must be running or completed to get speculative results.\"}").build();
}

var result = new BoardFilePayload();
result.jobId = job.id;
result.setFilename(job.output.getFilename());
result.setData(job.output.getData().readAllBytes());
result.dataBase64 = java.util.Base64.getEncoder().encodeToString(result.getData().readAllBytes());
result.setFilename(job.output != null ? job.output.getFilename() : job.input.getFilename().replace(".dsn", ".ses"));

// For speculative results, get the current board state
if (speculative && job.state == RoutingJobState.RUNNING)
{
// Get the current board state as a session file
byte[] speculativeData = job.getSpeculativeOutput();
if (speculativeData != null)
{
result.setData(speculativeData);
result.dataBase64 = java.util.Base64.getEncoder().encodeToString(speculativeData);
}
else
{
return Response.status(Response.Status.BAD_REQUEST).entity("{\"error\":\"No speculative results available yet.\"}").build();
}
}
else
{
// Return the final output
result.setData(job.output.getData().readAllBytes());
result.dataBase64 = java.util.Base64.getEncoder().encodeToString(result.getData().readAllBytes());
}

var response = GSON.toJson(result);
FRAnalytics.apiEndpointCalled("GET v1/jobs/" + jobId + "/output", "", response.replace(result.dataBase64, TextManager.shortenString(result.dataBase64, 4)));
FRAnalytics.apiEndpointCalled("GET v1/jobs/" + jobId + "/output" + (speculative ? "?speculative=true" : ""), "", response.replace(result.dataBase64, TextManager.shortenString(result.dataBase64, 4)));
return Response.ok(response).build();
}

Expand Down Expand Up @@ -411,4 +440,4 @@ public Response logs(
FRAnalytics.apiEndpointCalled("GET v1/jobs/" + jobId + "/logs", "", response);
return Response.ok(response).build();
}
}
}
24 changes: 22 additions & 2 deletions src/main/java/app/freerouting/core/RoutingJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
Expand Down Expand Up @@ -520,4 +525,19 @@ public void fireOutputUpdatedEvent()
}
}

}
/**
* Gets the current board state as a session file.
* Used to provide intermediate routing results while the job is still running.
* @return The current board state as a byte array, or null if not available
*/
public byte[] getSpeculativeOutput()
{
// Only return speculative results if we have a board and are running
if (board == null || state != RoutingJobState.RUNNING) {
return null;
}

// TODO
}

}
Loading