In RecordedModelsTab get online state from the recorder

Get the online state of the models on the recorded models tab
from the recorder instead of requesting it from each model. The
recorder knows the state anyways, so there is no need to do the
requests again.
This commit is contained in:
0xboobface 2018-11-13 00:59:09 +01:00
parent 6c1a757af3
commit 705b04b0da
6 changed files with 158 additions and 52 deletions

View File

@ -19,7 +19,9 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -239,6 +241,20 @@ public class LocalRecorder implements Recorder {
}
}
@Override
public List<Model> getOnlineModels() {
return getModelsRecording()
.stream()
.filter(m -> {
try {
return m.isOnline();
} catch (IOException | ExecutionException | InterruptedException e) {
return false;
}
})
.collect(Collectors.toList());
}
@Override
public void shutdown() {
LOG.info("Shutting down");

View File

@ -33,4 +33,10 @@ public interface Recorder {
public void resumeRecording(Model model) throws IOException, InvalidKeyException, NoSuchAlgorithmException, IllegalStateException;
public boolean isSuspended(Model model);
/**
* Returns only the models from getModelsRecording(), which are online
* @return
*/
public List<Model> getOnlineModels();
}

View File

@ -42,6 +42,7 @@ public class RemoteRecorder implements Recorder {
private JsonAdapter<ModelRequest> modelRequestAdapter = moshi.adapter(ModelRequest.class);
private List<Model> models = Collections.emptyList();
private List<Model> onlineModels = Collections.emptyList();
private List<Site> sites;
private Config config;
@ -145,39 +146,76 @@ public class RemoteRecorder implements Recorder {
public void run() {
running = true;
while(running) {
try {
String msg = "{\"action\": \"list\"}";
RequestBody body = RequestBody.create(JSON, msg);
Request.Builder builder = new Request.Builder()
.url("http://" + config.getSettings().httpServer + ":" + config.getSettings().httpPort + "/rec")
.post(body);
addHmacIfNeeded(msg, builder);
Request request = builder.build();
Response response = client.execute(request);
String json = response.body().string();
if(response.isSuccessful()) {
ModelListResponse resp = modelListResponseAdapter.fromJson(json);
if(resp.status.equals("success")) {
models = resp.models;
for (Model model : models) {
for (Site site : sites) {
if(site.isSiteForModel(model)) {
model.setSite(site);
}
syncModels();
syncOnlineModels();
sleep();
}
}
private void syncModels() {
try {
String msg = "{\"action\": \"list\"}";
RequestBody body = RequestBody.create(JSON, msg);
Request.Builder builder = new Request.Builder()
.url("http://" + config.getSettings().httpServer + ":" + config.getSettings().httpPort + "/rec")
.post(body);
addHmacIfNeeded(msg, builder);
Request request = builder.build();
Response response = client.execute(request);
String json = response.body().string();
if(response.isSuccessful()) {
ModelListResponse resp = modelListResponseAdapter.fromJson(json);
if(resp.status.equals("success")) {
models = resp.models;
for (Model model : models) {
for (Site site : sites) {
if(site.isSiteForModel(model)) {
model.setSite(site);
}
}
}
lastSync = Instant.now();
} else {
LOG.error("Server returned error: {} - {}", resp.status, resp.msg);
}
} else {
LOG.error("Couldn't synchronize with server. HTTP status: {} - {}", response.code(), json);
}
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e) {
LOG.error("Couldn't synchronize with server", e);
}
}
private void syncOnlineModels() {
try {
String msg = "{\"action\": \"listOnline\"}";
RequestBody body = RequestBody.create(JSON, msg);
Request.Builder builder = new Request.Builder()
.url("http://" + config.getSettings().httpServer + ":" + config.getSettings().httpPort + "/rec")
.post(body);
addHmacIfNeeded(msg, builder);
Request request = builder.build();
Response response = client.execute(request);
String json = response.body().string();
if(response.isSuccessful()) {
ModelListResponse resp = modelListResponseAdapter.fromJson(json);
if(resp.status.equals("success")) {
onlineModels = resp.models;
for (Model model : models) {
for (Site site : sites) {
if(site.isSiteForModel(model)) {
model.setSite(site);
}
}
lastSync = Instant.now();
} else {
LOG.error("Server returned error: {} - {}", resp.status, resp.msg);
}
} else {
LOG.error("Couldn't synchronize with server. HTTP status: {} - {}", response.code(), json);
LOG.error("Server returned error: {} - {}", resp.status, resp.msg);
}
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e) {
LOG.error("Couldn't synchronize with server", e);
} else {
LOG.error("Couldn't synchronize with server. HTTP status: {} - {}", response.code(), json);
}
sleep();
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e) {
LOG.error("Couldn't synchronize with server", e);
}
}
@ -219,7 +257,6 @@ public class RemoteRecorder implements Recorder {
Response response = client.execute(request);
String json = response.body().string();
if(response.isSuccessful()) {
LOG.debug(json);
RecordingListResponse resp = recordingListResponseAdapter.fromJson(json);
if(resp.status.equals("success")) {
List<Recording> recordings = resp.recordings;
@ -311,4 +348,9 @@ public class RemoteRecorder implements Recorder {
m.setSuspended(false);
}
}
@Override
public List<Model> getOnlineModels() {
return onlineModels;
}
}

View File

@ -85,6 +85,19 @@ public class RecorderServlet extends AbstractCtbrecServlet {
}
resp.getWriter().write("]}");
break;
case "listOnline":
resp.getWriter().write("{\"status\": \"success\", \"msg\": \"List of online models\", \"models\": [");
modelAdapter = new ModelJsonAdapter();
models = recorder.getOnlineModels();
for (Iterator<Model> iterator = models.iterator(); iterator.hasNext();) {
Model model = iterator.next();
resp.getWriter().write(modelAdapter.toJson(model));
if(iterator.hasNext()) {
resp.getWriter().write(',');
}
}
resp.getWriter().write("]}");
break;
case "recordings":
resp.getWriter().write("{\"status\": \"success\", \"msg\": \"List of recordings\", \"recordings\": [");
JsonAdapter<Recording> recAdapter = moshi.adapter(Recording.class);

View File

@ -20,6 +20,7 @@ import javafx.beans.property.SimpleBooleanProperty;
*/
public class JavaFxModel implements Model {
private transient BooleanProperty onlineProperty = new SimpleBooleanProperty();
private transient BooleanProperty recordingProperty = new SimpleBooleanProperty();
private transient BooleanProperty pausedProperty = new SimpleBooleanProperty();
private Model delegate;
@ -86,6 +87,10 @@ public class JavaFxModel implements Model {
return onlineProperty;
}
public BooleanProperty getRecordingProperty() {
return recordingProperty;
}
public BooleanProperty getPausedProperty() {
return pausedProperty;
}

View File

@ -15,11 +15,13 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Model;
import ctbrec.Recording;
import ctbrec.recorder.Recorder;
import ctbrec.sites.Site;
import javafx.application.Platform;
@ -59,7 +61,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
static ExecutorService threadPool = new ThreadPoolExecutor(2, 2, 10, TimeUnit.MINUTES, queue);
private ScheduledService<List<Model>> updateService;
private ScheduledService<List<JavaFxModel>> updateService;
private Recorder recorder;
private List<Site> sites;
@ -103,12 +105,16 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
TableColumn<JavaFxModel, Boolean> online = new TableColumn<>("Online");
online.setCellValueFactory((cdf) -> cdf.getValue().getOnlineProperty());
online.setCellFactory(CheckBoxTableCell.forTableColumn(online));
online.setPrefWidth(60);
online.setPrefWidth(100);
TableColumn<JavaFxModel, Boolean> recording = new TableColumn<>("Recording");
recording.setCellValueFactory((cdf) -> cdf.getValue().getRecordingProperty());
recording.setCellFactory(CheckBoxTableCell.forTableColumn(recording));
recording.setPrefWidth(100);
TableColumn<JavaFxModel, Boolean> paused = new TableColumn<>("Paused");
paused.setCellValueFactory((cdf) -> cdf.getValue().getPausedProperty());
paused.setCellFactory(CheckBoxTableCell.forTableColumn(paused));
paused.setPrefWidth(60);
table.getColumns().addAll(name, url, online, paused);
paused.setPrefWidth(100);
table.getColumns().addAll(name, url, online, recording, paused);
table.setItems(observableModels);
table.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, event -> {
popup = createContextMenu();
@ -185,28 +191,24 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
updateService = createUpdateService();
updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(2)));
updateService.setOnSucceeded((event) -> {
List<Model> models = updateService.getValue();
List<JavaFxModel> models = updateService.getValue();
if(models == null) {
return;
}
queue.clear();
for (Model model : models) {
int index = observableModels.indexOf(model);
final JavaFxModel javaFxModel;
for (JavaFxModel updatedModel : models) {
int index = observableModels.indexOf(updatedModel);
if (index == -1) {
javaFxModel = new JavaFxModel(model);
observableModels.add(javaFxModel);
observableModels.add(updatedModel);
} else {
// make sure to update the JavaFX online property, so that the table cell is updated
javaFxModel = observableModels.get(index);
JavaFxModel oldModel = observableModels.get(index);
oldModel.setSuspended(updatedModel.isSuspended());
oldModel.getOnlineProperty().set(updatedModel.getOnlineProperty().get());
oldModel.getRecordingProperty().set(updatedModel.getRecordingProperty().get());
}
threadPool.submit(() -> {
try {
javaFxModel.getOnlineProperty().set(javaFxModel.isOnline());
javaFxModel.setSuspended(model.isSuspended());
} catch (IOException | ExecutionException | InterruptedException e) {}
});
}
for (Iterator<JavaFxModel> iterator = observableModels.iterator(); iterator.hasNext();) {
Model model = iterator.next();
if (!models.contains(model)) {
@ -219,15 +221,37 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
});
}
private ScheduledService<List<Model>> createUpdateService() {
ScheduledService<List<Model>> updateService = new ScheduledService<List<Model>>() {
private ScheduledService<List<JavaFxModel>> createUpdateService() {
ScheduledService<List<JavaFxModel>> updateService = new ScheduledService<List<JavaFxModel>>() {
@Override
protected Task<List<Model>> createTask() {
return new Task<List<Model>>() {
protected Task<List<JavaFxModel>> createTask() {
return new Task<List<JavaFxModel>>() {
@Override
public List<Model> call() {
public List<JavaFxModel> call() throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, IOException {
LOG.trace("Updating recorded models");
return recorder.getModelsRecording();
List<Recording> recordings = recorder.getRecordings();
List<Model> onlineModels = recorder.getOnlineModels();
return recorder.getModelsRecording()
.stream()
.map(m -> new JavaFxModel(m))
.peek(fxm -> {
for (Recording recording : recordings) {
if(recording.getStatus() == Recording.STATUS.RECORDING &&
recording.getModelName().equals(fxm.getName()))
{
fxm.getRecordingProperty().set(true);
break;
}
}
for (Model onlineModel : onlineModels) {
if(Objects.equals(onlineModel, fxm)) {
fxm.getOnlineProperty().set(true);
break;
}
}
})
.collect(Collectors.toList());
}
};
}