diff --git a/JShellAPI/src/main/java/org/togetherjava/jshellapi/dto/sessionstats/SessionStats.java b/JShellAPI/src/main/java/org/togetherjava/jshellapi/dto/sessionstats/SessionStats.java new file mode 100644 index 0000000..270a05f --- /dev/null +++ b/JShellAPI/src/main/java/org/togetherjava/jshellapi/dto/sessionstats/SessionStats.java @@ -0,0 +1,17 @@ +package org.togetherjava.jshellapi.dto.sessionstats; + +/** + * Represents the stats of a session. + * + * @param id the id of this session + * @param timeSinceCreation the time in seconds since the creation of this session + * @param timeUntilExpiration the time in seconds until the expiration of this session + * @param totalEvalTime the time spent evaluating code + * @param doingOperation if the session is currently evaluating some code + */ +public record SessionStats( + String id, + long timeSinceCreation, + long timeUntilExpiration, + long totalEvalTime, + boolean doingOperation) {} diff --git a/JShellAPI/src/main/java/org/togetherjava/jshellapi/rest/JShellController.java b/JShellAPI/src/main/java/org/togetherjava/jshellapi/rest/JShellController.java index 2c60570..9b2b59a 100644 --- a/JShellAPI/src/main/java/org/togetherjava/jshellapi/rest/JShellController.java +++ b/JShellAPI/src/main/java/org/togetherjava/jshellapi/rest/JShellController.java @@ -7,6 +7,7 @@ import org.togetherjava.jshellapi.dto.JShellResult; import org.togetherjava.jshellapi.dto.JShellResultWithId; +import org.togetherjava.jshellapi.dto.sessionstats.SessionStats; import org.togetherjava.jshellapi.exceptions.DockerException; import org.togetherjava.jshellapi.service.JShellService; import org.togetherjava.jshellapi.service.JShellSessionService; @@ -71,6 +72,11 @@ public void delete(@PathVariable String id) throws DockerException { service.deleteSession(id); } + @GetMapping("sessions") + public List sessions() { + return service.fetchStats(); + } + @GetMapping("/startup_script/{id}") public String startupScript(@PathVariable StartupScriptId id) { return startupScriptsService.get(id); diff --git a/JShellAPI/src/main/java/org/togetherjava/jshellapi/service/JShellService.java b/JShellAPI/src/main/java/org/togetherjava/jshellapi/service/JShellService.java index 9ecc0c8..2b99a8a 100644 --- a/JShellAPI/src/main/java/org/togetherjava/jshellapi/service/JShellService.java +++ b/JShellAPI/src/main/java/org/togetherjava/jshellapi/service/JShellService.java @@ -6,6 +6,7 @@ import org.springframework.lang.Nullable; import org.togetherjava.jshellapi.dto.*; +import org.togetherjava.jshellapi.dto.sessionstats.SessionStats; import org.togetherjava.jshellapi.exceptions.DockerException; import java.io.*; @@ -21,6 +22,8 @@ public class JShellService implements Closeable { private final String id; private final BufferedWriter writer; private final BufferedReader reader; + private final Instant creationTime; + private long totalEvalTime; private Instant lastTimeoutUpdate; private final long timeout; @@ -66,6 +69,7 @@ public JShellService(DockerService dockerService, JShellSessionService sessionSe throw new DockerException("Creation of the session failed.", e); } this.doingOperation = false; + this.creationTime = Instant.now(); } public Optional eval(String code) throws DockerException { @@ -80,6 +84,7 @@ public Optional eval(String code) throws DockerException { } updateLastTimeout(); sessionService.scheduleEvalTimeoutValidation(id, evalTimeout + evalTimeoutValidationLeeway); + Instant start = Instant.now(); if (!code.endsWith("\n")) code += '\n'; try { @@ -98,6 +103,7 @@ public Optional eval(String code) throws DockerException { close(); throw new DockerException(ex); } finally { + totalEvalTime += Duration.between(start, Instant.now()).getSeconds(); stopOperation(); } } @@ -204,6 +210,18 @@ public String id() { return id; } + public SessionStats fetchSessionInfo() { + long timeSinceCreation = Duration.between(creationTime, Instant.now()).getSeconds(); + long timeUntilExpiration = + Duration.between(Instant.now(), lastTimeoutUpdate.plusSeconds(timeout)) + .getSeconds(); + if (timeUntilExpiration < 0) { + timeUntilExpiration = 0; + } + return new SessionStats( + id, timeSinceCreation, timeUntilExpiration, totalEvalTime, doingOperation); + } + @Override public void close() { LOGGER.debug("Close called for session {}.", id); diff --git a/JShellAPI/src/main/java/org/togetherjava/jshellapi/service/JShellSessionService.java b/JShellAPI/src/main/java/org/togetherjava/jshellapi/service/JShellSessionService.java index 496dd0e..bab01c8 100644 --- a/JShellAPI/src/main/java/org/togetherjava/jshellapi/service/JShellSessionService.java +++ b/JShellAPI/src/main/java/org/togetherjava/jshellapi/service/JShellSessionService.java @@ -9,6 +9,7 @@ import org.springframework.web.server.ResponseStatusException; import org.togetherjava.jshellapi.Config; +import org.togetherjava.jshellapi.dto.sessionstats.SessionStats; import org.togetherjava.jshellapi.exceptions.DockerException; import java.util.*; @@ -133,6 +134,13 @@ public void scheduleEvalTimeoutValidation(String id, long timeSeconds) { }, timeSeconds, TimeUnit.SECONDS); } + public List fetchStats() { + return jshellSessions.values().stream() + .map(JShellService::fetchSessionInfo) + .sorted(Comparator.comparingLong(SessionStats::timeSinceCreation).reversed()) + .toList(); + } + @Autowired public void setConfig(Config config) { this.config = config;