Store model portraits on the server in client/server mode
This commit is contained in:
parent
f293f511f1
commit
39da801a61
|
@ -12,6 +12,9 @@ import ctbrec.event.Event;
|
|||
import ctbrec.event.EventBusHolder;
|
||||
import ctbrec.event.EventHandler;
|
||||
import ctbrec.event.EventHandlerConfiguration;
|
||||
import ctbrec.image.LocalPortraitStore;
|
||||
import ctbrec.image.PortraitStore;
|
||||
import ctbrec.image.RemotePortraitStore;
|
||||
import ctbrec.io.BandwidthMeter;
|
||||
import ctbrec.io.ByteUnitFormatter;
|
||||
import ctbrec.io.HttpClient;
|
||||
|
@ -94,6 +97,7 @@ public class CamrecApplication extends Application {
|
|||
private final TabPane tabPane = new TabPane();
|
||||
private final List<Site> sites = new ArrayList<>();
|
||||
public static HttpClient httpClient;
|
||||
public static PortraitStore portraitStore;
|
||||
public static String title;
|
||||
private Stage primaryStage;
|
||||
private RecordingsTab recordingsTab;
|
||||
|
@ -122,12 +126,21 @@ public class CamrecApplication extends Application {
|
|||
createRecorder();
|
||||
initSites();
|
||||
startOnlineMonitor();
|
||||
createPortraitStore();
|
||||
createGui(primaryStage);
|
||||
checkForUpdates();
|
||||
registerClipboardListener();
|
||||
registerTrayIconListener();
|
||||
}
|
||||
|
||||
private void createPortraitStore() {
|
||||
if (config.getSettings().localRecording) {
|
||||
portraitStore = new LocalPortraitStore(config);
|
||||
} else {
|
||||
portraitStore = new RemotePortraitStore(httpClient, config);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerTrayIconListener() {
|
||||
EventBusHolder.BUS.register(new Object() {
|
||||
@Subscribe
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
package ctbrec.ui.action;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.event.EventBusHolder;
|
||||
import ctbrec.ui.CamrecApplication;
|
||||
import javafx.scene.Node;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class AbstractPortraitAction {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractPortraitAction.class);
|
||||
public static final String FORMAT = "jpg";
|
||||
|
||||
protected Node source;
|
||||
|
@ -32,11 +28,11 @@ public abstract class AbstractPortraitAction {
|
|||
return bimage;
|
||||
}
|
||||
|
||||
protected boolean copyToCacheAsJpg(String portraitId, BufferedImage portrait) throws IOException {
|
||||
File output = getPortraitFile(portraitId);
|
||||
Files.createDirectories(output.getParentFile().toPath());
|
||||
LOG.debug("Writing scaled portrait to {}", output);
|
||||
return ImageIO.write(portrait, FORMAT, output);
|
||||
protected boolean store(String modelUrl, BufferedImage portrait) throws IOException {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
ImageIO.write(portrait, FORMAT, bytes);
|
||||
CamrecApplication.portraitStore.writePortrait(modelUrl, bytes.toByteArray());
|
||||
return true;
|
||||
}
|
||||
|
||||
protected File getPortraitFile(String portraitId) {
|
||||
|
@ -63,7 +59,7 @@ public abstract class AbstractPortraitAction {
|
|||
|
||||
protected BufferedImage cropTopAndBottom(BufferedImage img) {
|
||||
int overlap = img.getHeight() - img.getWidth();
|
||||
return img.getSubimage(0, overlap/2, img.getWidth(), img.getWidth());
|
||||
return img.getSubimage(0, overlap / 2, img.getWidth(), img.getWidth());
|
||||
}
|
||||
|
||||
protected void firePortraitChanged() {
|
||||
|
@ -71,7 +67,7 @@ public abstract class AbstractPortraitAction {
|
|||
}
|
||||
|
||||
public static class PortraitChangedEvent {
|
||||
private Model mdl;
|
||||
private final Model mdl;
|
||||
|
||||
public PortraitChangedEvent(Model model) {
|
||||
this.mdl = model;
|
||||
|
|
|
@ -1,22 +1,8 @@
|
|||
package ctbrec.ui.action;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.StringUtil;
|
||||
import ctbrec.ui.CamrecApplication;
|
||||
import ctbrec.ui.controls.Dialogs;
|
||||
import ctbrec.ui.controls.FileSelectionBox;
|
||||
import javafx.geometry.Insets;
|
||||
|
@ -24,11 +10,20 @@ import javafx.scene.Cursor;
|
|||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class SetPortraitAction extends AbstractPortraitAction {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SetPortraitAction.class);
|
||||
|
||||
private Consumer<Model> callback;
|
||||
private final Consumer<Model> callback;
|
||||
|
||||
public SetPortraitAction(Node source, Model selectedModel, Consumer<Model> callback) {
|
||||
this.source = source;
|
||||
|
@ -38,9 +33,6 @@ public class SetPortraitAction extends AbstractPortraitAction {
|
|||
|
||||
public void execute() {
|
||||
source.setCursor(Cursor.WAIT);
|
||||
String portraitId = Config.getInstance().getSettings().modelPortraits.getOrDefault(model.getUrl(),
|
||||
UUID.nameUUIDFromBytes(model.getUrl().getBytes(StandardCharsets.UTF_8)).toString());
|
||||
|
||||
GridPane pane = new GridPane();
|
||||
Label l = new Label("Select a portrait image. Leave empty to remove a portrait again.");
|
||||
pane.add(l, 0, 0);
|
||||
|
@ -56,17 +48,15 @@ public class SetPortraitAction extends AbstractPortraitAction {
|
|||
String selectedFile = portraitSelectionBox.fileProperty().getValue();
|
||||
|
||||
if (StringUtil.isBlank(selectedFile)) {
|
||||
removePortrait(portraitId);
|
||||
removePortrait(model.getUrl());
|
||||
} else {
|
||||
LOG.debug("User selected {}", selectedFile);
|
||||
boolean success = processImageFile(portraitId, selectedFile);
|
||||
boolean success = processImageFile(selectedFile);
|
||||
if (success) {
|
||||
Config.getInstance().getSettings().modelPortraits.put(model.getUrl(), portraitId);
|
||||
try {
|
||||
Config.getInstance().save();
|
||||
firePortraitChanged();
|
||||
runCallback();
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
Dialogs.showError("Set Portrait", "Couldn't change portrait image: ", e);
|
||||
}
|
||||
}
|
||||
|
@ -74,14 +64,10 @@ public class SetPortraitAction extends AbstractPortraitAction {
|
|||
source.setCursor(Cursor.DEFAULT);
|
||||
}
|
||||
|
||||
private void removePortrait(String portraitId) {
|
||||
File portraitFile = getPortraitFile(portraitId);
|
||||
private void removePortrait(String modelUrl) {
|
||||
try {
|
||||
if (portraitFile.exists()) {
|
||||
Files.delete(portraitFile.toPath());
|
||||
}
|
||||
Config.getInstance().getSettings().modelPortraits.remove(model.getUrl());
|
||||
Config.getInstance().save();
|
||||
CamrecApplication.portraitStore.removePortrait(modelUrl);
|
||||
firePortraitChanged();
|
||||
runCallback();
|
||||
} catch (IOException e) {
|
||||
Dialogs.showError("Remove Portrait", "Couldn't remove portrait image: ", e);
|
||||
|
@ -98,12 +84,12 @@ public class SetPortraitAction extends AbstractPortraitAction {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean processImageFile(String portraitId, String selectedFile) {
|
||||
private boolean processImageFile(String selectedFile) {
|
||||
try {
|
||||
BufferedImage original = ImageIO.read(new File(selectedFile));
|
||||
BufferedImage croppedImage = cropImage(original);
|
||||
BufferedImage portrait = convertToScaledJpg(croppedImage);
|
||||
boolean success = copyToCacheAsJpg(portraitId, portrait);
|
||||
boolean success = store(model.getUrl(), portrait);
|
||||
if (!success) {
|
||||
LOG.debug("Available formats: {}", Arrays.toString(ImageIO.getWriterFormatNames()));
|
||||
throw new IOException("No suitable writer found for image format " + FORMAT);
|
||||
|
|
|
@ -1,25 +1,23 @@
|
|||
package ctbrec.ui.action;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.GlobalThreadPool;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ui.controls.Dialogs;
|
||||
import javafx.application.Platform;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.image.Image;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class SetThumbAsPortraitAction extends AbstractPortraitAction {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SetThumbAsPortraitAction.class);
|
||||
|
||||
private Image image;
|
||||
private final Image image;
|
||||
|
||||
public SetThumbAsPortraitAction(Node source, Model model, Image image) {
|
||||
this.source = source;
|
||||
|
@ -29,20 +27,20 @@ public class SetThumbAsPortraitAction extends AbstractPortraitAction {
|
|||
|
||||
public void execute() {
|
||||
source.setCursor(Cursor.WAIT);
|
||||
try {
|
||||
BufferedImage bufferedImage = convertFxImageToAwt(image);
|
||||
BufferedImage croppedImage = cropImage(bufferedImage);
|
||||
BufferedImage portrait = convertToScaledJpg(croppedImage);
|
||||
String portraitId = UUID.nameUUIDFromBytes(model.getUrl().getBytes(StandardCharsets.UTF_8)).toString();
|
||||
copyToCacheAsJpg(portraitId, portrait);
|
||||
Config.getInstance().getSettings().modelPortraits.put(model.getUrl(), portraitId);
|
||||
Config.getInstance().save();
|
||||
firePortraitChanged();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while changing portrait image", e);
|
||||
Dialogs.showError("Set Portrait", "Couldn't change portrait image: ", e);
|
||||
}
|
||||
source.setCursor(Cursor.DEFAULT);
|
||||
GlobalThreadPool.submit(() -> {
|
||||
try {
|
||||
BufferedImage bufferedImage = convertFxImageToAwt(image);
|
||||
BufferedImage croppedImage = cropImage(bufferedImage);
|
||||
BufferedImage portrait = convertToScaledJpg(croppedImage);
|
||||
store(model.getUrl(), portrait);
|
||||
firePortraitChanged();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while changing portrait image", e);
|
||||
Platform.runLater(() -> Dialogs.showError("Set Portrait", "Couldn't change portrait image: ", e));
|
||||
} finally {
|
||||
Platform.runLater(() -> source.setCursor(Cursor.DEFAULT));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private BufferedImage convertFxImageToAwt(Image img) {
|
||||
|
|
|
@ -4,11 +4,17 @@ import com.google.common.cache.CacheBuilder;
|
|||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import ctbrec.*;
|
||||
import ctbrec.Config;
|
||||
import ctbrec.GlobalThreadPool;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.StringUtil;
|
||||
import ctbrec.event.EventBusHolder;
|
||||
import ctbrec.image.PortraitStore;
|
||||
import ctbrec.io.HttpException;
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.sites.Site;
|
||||
import ctbrec.ui.AutosizeAlert;
|
||||
import ctbrec.ui.CamrecApplication;
|
||||
import ctbrec.ui.JavaFxModel;
|
||||
import ctbrec.ui.PreviewPopupHandler;
|
||||
import ctbrec.ui.action.AbstractPortraitAction.PortraitChangedEvent;
|
||||
|
@ -48,9 +54,9 @@ import javafx.scene.layout.HBox;
|
|||
import javafx.scene.layout.Priority;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.util.Callback;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
|
@ -60,8 +66,8 @@ import java.util.Objects;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractRecordedModelsTab extends Tab implements TabSelectionListener {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractRecordedModelsTab.class);
|
||||
private static final Image SILHOUETTE = new Image(AbstractRecordedModelsTab.class.getResourceAsStream("/silhouette_256.png"));
|
||||
protected static final String STYLE_ALIGN_CENTER = "-fx-alignment: CENTER;";
|
||||
|
||||
|
@ -100,7 +106,7 @@ public abstract class AbstractRecordedModelsTab extends Tab implements TabSelect
|
|||
AbstractRecordedModelsTab(String text, String stateStorePrefix) {
|
||||
super(text);
|
||||
config = Config.getInstance();
|
||||
portraitStore = new PortraitStore(config);
|
||||
portraitStore = CamrecApplication.portraitStore;
|
||||
tableStateStore = new SettingTableViewStateStore(config, stateStorePrefix);
|
||||
table = new StatePersistingTableView<>(tableStateStore);
|
||||
registerPortraitListener();
|
||||
|
@ -112,6 +118,7 @@ public abstract class AbstractRecordedModelsTab extends Tab implements TabSelect
|
|||
|
||||
@Subscribe
|
||||
public void portraitChanged(PortraitChangedEvent e) {
|
||||
log.debug("Invalidate cache for {}", e.getModel());
|
||||
portraitCache.invalidate(e.getModel());
|
||||
if (table != null) {
|
||||
table.refresh();
|
||||
|
@ -230,7 +237,7 @@ public abstract class AbstractRecordedModelsTab extends Tab implements TabSelect
|
|||
} catch (IOException e) {
|
||||
String msg = "An error occurred while exporting the model list";
|
||||
Dialogs.showError(getTabPane().getScene(), "Export models", msg, e);
|
||||
LOG.error(msg, e);
|
||||
log.error(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +251,7 @@ public abstract class AbstractRecordedModelsTab extends Tab implements TabSelect
|
|||
try {
|
||||
recorder.addModel(model);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Couldn't add model to recording list", e);
|
||||
log.error("Couldn't add model to recording list", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -269,7 +276,7 @@ public abstract class AbstractRecordedModelsTab extends Tab implements TabSelect
|
|||
} catch (IOException e) {
|
||||
String msg = "An error occurred while importing the model list";
|
||||
Dialogs.showError(getTabPane().getScene(), "Import models", msg, e);
|
||||
LOG.error(msg, e);
|
||||
log.error(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -370,14 +377,14 @@ public abstract class AbstractRecordedModelsTab extends Tab implements TabSelect
|
|||
ContextMenu menu = new CustomMouseBehaviorContextMenu();
|
||||
|
||||
ModelMenuContributor.newContributor(getTabPane(), Config.getInstance(), recorder) //
|
||||
.withStartStopCallback(m -> Platform.runLater(this::reload)) //
|
||||
.removeModelAfterIgnore(true) //
|
||||
.withPortraitCallback(m -> Platform.runLater(() -> {
|
||||
portraitCache.invalidate(m);
|
||||
table.refresh();
|
||||
}))
|
||||
.afterwards(() -> Platform.runLater(this::reload))
|
||||
.contributeToMenu(selectedModels, menu);
|
||||
.withStartStopCallback(m -> Platform.runLater(this::reload)) //
|
||||
.removeModelAfterIgnore(true) //
|
||||
// .withPortraitCallback(m -> Platform.runLater(() -> {
|
||||
// portraitCache.invalidate(m);
|
||||
// table.refresh();
|
||||
// }))
|
||||
.afterwards(() -> Platform.runLater(this::reload))
|
||||
.contributeToMenu(selectedModels, menu);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
@ -408,8 +415,8 @@ public abstract class AbstractRecordedModelsTab extends Tab implements TabSelect
|
|||
new MarkForLaterRecordingAction(modelInputField, List.of(newModel), true, recorder).execute(m -> Platform.runLater(this::reload));
|
||||
} else {
|
||||
new StartRecordingAction(modelInputField, List.of(newModel), recorder)
|
||||
.execute()
|
||||
.whenComplete((r, ex) -> Platform.runLater(this::reload));
|
||||
.execute()
|
||||
.whenComplete((r, ex) -> Platform.runLater(this::reload));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -437,8 +444,8 @@ public abstract class AbstractRecordedModelsTab extends Tab implements TabSelect
|
|||
new MarkForLaterRecordingAction(modelInputField, List.of(newModel), true, recorder).execute(m -> Platform.runLater(this::reload));
|
||||
} else {
|
||||
new StartRecordingAction(modelInputField, List.of(newModel), recorder)
|
||||
.execute()
|
||||
.whenComplete((r, ex) -> Platform.runLater(this::reload));
|
||||
.execute()
|
||||
.whenComplete((r, ex) -> Platform.runLater(this::reload));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -558,6 +565,18 @@ public abstract class AbstractRecordedModelsTab extends Tab implements TabSelect
|
|||
}
|
||||
|
||||
protected Image loadModelPortrait(Model model) {
|
||||
return portraitStore.loadModelPortrait(model.getUrl()).orElse(SILHOUETTE);
|
||||
try {
|
||||
return portraitStore
|
||||
.loadModelPortraitByModelUrl(model.getUrl())
|
||||
.map(bytes -> new Image(new ByteArrayInputStream(bytes)))
|
||||
.orElse(SILHOUETTE);
|
||||
} catch (HttpException e) {
|
||||
if (e.getResponseCode() != 404) {
|
||||
log.debug("Could not load portrait from server", e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.debug("Could not load portrait from server", e);
|
||||
}
|
||||
return SILHOUETTE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ import com.squareup.moshi.JsonReader.Token;
|
|||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ModelGroup;
|
||||
import ctbrec.io.FileJsonAdapter;
|
||||
import ctbrec.io.LocalTimeJsonAdapter;
|
||||
import ctbrec.io.ModelJsonAdapter;
|
||||
import ctbrec.io.UuidJSonAdapter;
|
||||
import ctbrec.image.LocalPortraitStore;
|
||||
import ctbrec.image.PortraitStore;
|
||||
import ctbrec.image.RemotePortraitStore;
|
||||
import ctbrec.io.*;
|
||||
import ctbrec.sites.Site;
|
||||
import okio.Buffer;
|
||||
import okio.Okio;
|
||||
|
@ -66,14 +66,25 @@ public class ModelImportExport {
|
|||
}
|
||||
if (exportOptions.includes().contains(ExportIncludes.PORTRAITS)) {
|
||||
var portraits = config.getSettings().modelPortraits;
|
||||
var portraitLoader = new PortraitStore(config);
|
||||
PortraitStore portraitLoader;
|
||||
if (config.getSettings().localRecording) {
|
||||
portraitLoader = new LocalPortraitStore(config);
|
||||
} else {
|
||||
var httpClient = new HttpClient("camrec", config) {
|
||||
@Override
|
||||
public boolean login() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
portraitLoader = new RemotePortraitStore(httpClient, config);
|
||||
}
|
||||
if (portraits != null && !portraits.isEmpty()) {
|
||||
writer.name("portraits");
|
||||
writer.beginArray();
|
||||
for (Map.Entry<String, String> entry : config.getSettings().modelPortraits.entrySet()) {
|
||||
String modelUrl = entry.getKey();
|
||||
String portraitId = entry.getValue();
|
||||
Optional<byte[]> portrait = portraitLoader.loadModelPortraitFile(modelUrl);
|
||||
Optional<byte[]> portrait = portraitLoader.loadModelPortraitByModelUrl(modelUrl);
|
||||
if (portrait.isPresent()) {
|
||||
writer.beginObject();
|
||||
writer.name("url").value(modelUrl);
|
||||
|
@ -122,7 +133,18 @@ public class ModelImportExport {
|
|||
}
|
||||
|
||||
private static void importPortraits(JsonReader reader, Config config) throws IOException {
|
||||
PortraitStore portraitStore = new PortraitStore(config);
|
||||
PortraitStore portraitStore;
|
||||
if (config.getSettings().localRecording) {
|
||||
portraitStore = new LocalPortraitStore(config);
|
||||
} else {
|
||||
var httpClient = new HttpClient("camrec", config) {
|
||||
@Override
|
||||
public boolean login() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
portraitStore = new RemotePortraitStore(httpClient, config);
|
||||
}
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
reader.beginObject();
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
package ctbrec.ui.tabs.recorded;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.StringUtil;
|
||||
import javafx.scene.image.Image;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Optional;
|
||||
|
||||
import static ctbrec.ui.action.AbstractPortraitAction.FORMAT;
|
||||
|
||||
public record PortraitStore(Config config) {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PortraitStore.class);
|
||||
|
||||
public Optional<Image> loadModelPortrait(String modelUrl) {
|
||||
return loadModelPortraitFile(modelUrl).map(bytes -> new Image(new ByteArrayInputStream(bytes)));
|
||||
}
|
||||
|
||||
public Optional<byte[]> loadModelPortraitFile(String modelUrl) {
|
||||
String portraitId = config.getSettings().modelPortraits.get(modelUrl);
|
||||
if (StringUtil.isNotBlank(portraitId)) {
|
||||
File configDir = config.getConfigDir();
|
||||
File portraitDir = new File(configDir, "portraits");
|
||||
File portraitFile = new File(portraitDir, portraitId + '.' + FORMAT);
|
||||
try {
|
||||
return Optional.of(Files.readAllBytes(portraitFile.toPath()));
|
||||
} catch (IOException e) {
|
||||
LOG.error("Couldn't load portrait file {}", portraitFile, e);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void writePortrait(String id, byte[] data) throws IOException {
|
||||
File configDir = config.getConfigDir();
|
||||
File portraitDir = new File(configDir, "portraits");
|
||||
File portraitFile = new File(portraitDir, id + '.' + FORMAT);
|
||||
Files.createDirectories(portraitDir.toPath());
|
||||
Files.write(portraitFile.toPath(), data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package ctbrec.image;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.StringUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
@Slf4j
|
||||
public record LocalPortraitStore(Config config) implements PortraitStore {
|
||||
|
||||
@Override
|
||||
public Optional<byte[]> loadModelPortraitByModelUrl(String modelUrl) {
|
||||
String portraitId = config.getSettings().modelPortraits.get(modelUrl);
|
||||
return loadModelPortraitById(portraitId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<byte[]> loadModelPortraitById(String portraitId) {
|
||||
if (StringUtil.isNotBlank(portraitId)) {
|
||||
File configDir = config.getConfigDir();
|
||||
File portraitDir = new File(configDir, "portraits");
|
||||
File portraitFile = new File(portraitDir, portraitId + '.' + FORMAT);
|
||||
try {
|
||||
return Optional.of(Files.readAllBytes(portraitFile.toPath()));
|
||||
} catch (IOException e) {
|
||||
log.error("Couldn't load portrait file {}", portraitFile, e);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePortrait(String modelUrl, byte[] data) throws IOException {
|
||||
String portraitId = config.getSettings().modelPortraits.getOrDefault(modelUrl, UUID.nameUUIDFromBytes(modelUrl.getBytes(UTF_8)).toString());
|
||||
File portraitFile = getPortraitFile(portraitId);
|
||||
Files.write(portraitFile.toPath(), data);
|
||||
config.getSettings().modelPortraits.put(modelUrl, portraitId);
|
||||
config.save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePortrait(String modelUrl) throws IOException {
|
||||
String portraitId = config.getSettings().modelPortraits.get(modelUrl);
|
||||
File portraitFile = getPortraitFile(portraitId);
|
||||
Files.delete(portraitFile.toPath());
|
||||
config.getSettings().modelPortraits.remove(modelUrl);
|
||||
config.save();
|
||||
}
|
||||
|
||||
private File getPortraitFile(String portraitId) throws IOException {
|
||||
File configDir = config.getConfigDir();
|
||||
File portraitDir = new File(configDir, "portraits");
|
||||
Files.createDirectories(portraitDir.toPath());
|
||||
return new File(portraitDir, portraitId + '.' + FORMAT);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package ctbrec.image;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface PortraitStore {
|
||||
|
||||
String FORMAT = "jpg";
|
||||
|
||||
Optional<byte[]> loadModelPortraitById(String id) throws IOException;
|
||||
|
||||
Optional<byte[]> loadModelPortraitByModelUrl(String modelUrl) throws IOException;
|
||||
|
||||
//void writePortrait(String id, byte[] data) throws IOException;
|
||||
void writePortrait(String modelUrl, byte[] data) throws IOException;
|
||||
|
||||
void removePortrait(String modelUrl) throws IOException;
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package ctbrec.image;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.io.HttpClient;
|
||||
import ctbrec.io.HttpException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Optional;
|
||||
|
||||
import static ctbrec.io.HttpConstants.MIMETYPE_IMAGE_JPG;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class RemotePortraitStore implements PortraitStore {
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final Config config;
|
||||
|
||||
private String getEndpoint() {
|
||||
return config.getServerUrl() + "/image/portrait";
|
||||
}
|
||||
|
||||
private String getModelUrlEndpoint() {
|
||||
return getEndpoint() + "/url/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<byte[]> loadModelPortraitById(String id) throws IOException {
|
||||
return load(getEndpoint() + '/' + id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<byte[]> loadModelPortraitByModelUrl(String modelUrl) throws IOException {
|
||||
return load(getModelUrlEndpoint() + URLEncoder.encode(modelUrl, UTF_8));
|
||||
}
|
||||
|
||||
private Optional<byte[]> load(String url) throws IOException {
|
||||
Request req = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
try (Response resp = httpClient.execute(req)) {
|
||||
if (resp.isSuccessful()) {
|
||||
return Optional.of(resp.body().bytes());
|
||||
} else {
|
||||
throw new HttpException(resp.code(), resp.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePortrait(String modelUrl, byte[] data) throws IOException {
|
||||
RequestBody body = RequestBody.create(data, MediaType.parse(MIMETYPE_IMAGE_JPG));
|
||||
Request req = new Request.Builder()
|
||||
.url(getModelUrlEndpoint() + URLEncoder.encode(modelUrl, UTF_8))
|
||||
.post(body)
|
||||
.build();
|
||||
try (Response resp = httpClient.execute(req)) {
|
||||
if (!resp.isSuccessful()) {
|
||||
throw new HttpException(resp.code(), resp.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePortrait(String modelUrl) throws IOException {
|
||||
Request req = new Request.Builder()
|
||||
.url(getModelUrlEndpoint() + URLEncoder.encode(modelUrl, UTF_8))
|
||||
.delete()
|
||||
.build();
|
||||
try (Response resp = httpClient.execute(req)) {
|
||||
if (!resp.isSuccessful()) {
|
||||
throw new HttpException(resp.code(), resp.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ public class HttpConstants {
|
|||
public static final String FORM_ENCODED = "application/x-www-form-urlencoded; charset=UTF-8";
|
||||
public static final String KEEP_ALIVE = "keep-alive";
|
||||
public static final String MIMETYPE_APPLICATION_JSON = "application/json";
|
||||
public static final String MIMETYPE_IMAGE_JPG = "image/jpeg";
|
||||
public static final String MIMETYPE_TEXT_HTML = "text/html";
|
||||
public static final String NO_CACHE = "no-cache";
|
||||
public static final String ORIGIN = "Origin";
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
package ctbrec.recorder.server;
|
||||
|
||||
import static javax.servlet.http.HttpServletResponse.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Hmac;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Hmac;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
|
||||
public abstract class AbstractCtbrecServlet extends HttpServlet {
|
||||
|
||||
|
@ -23,17 +22,17 @@ public abstract class AbstractCtbrecServlet extends HttpServlet {
|
|||
|
||||
boolean checkAuthentication(HttpServletRequest req, String body) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
|
||||
boolean authenticated = false;
|
||||
if(Config.getInstance().getSettings().key != null) {
|
||||
if (Config.getInstance().getSettings().key != null) {
|
||||
String reqParamHmac = req.getParameter("hmac");
|
||||
String httpHeaderHmac = req.getHeader("CTBREC-HMAC");
|
||||
String hmac = null;
|
||||
String url = req.getRequestURI();
|
||||
url = url.substring(getServletContext().getContextPath().length());
|
||||
|
||||
if(reqParamHmac != null) {
|
||||
if (reqParamHmac != null) {
|
||||
hmac = reqParamHmac;
|
||||
}
|
||||
if(httpHeaderHmac != null) {
|
||||
if (httpHeaderHmac != null) {
|
||||
hmac = httpHeaderHmac;
|
||||
}
|
||||
|
||||
|
@ -50,13 +49,19 @@ public abstract class AbstractCtbrecServlet extends HttpServlet {
|
|||
String body(HttpServletRequest req) throws IOException {
|
||||
StringBuilder body = new StringBuilder();
|
||||
BufferedReader br = req.getReader();
|
||||
String line= null;
|
||||
while( (line = br.readLine()) != null ) {
|
||||
String line = null;
|
||||
while ((line = br.readLine()) != null) {
|
||||
body.append(line).append("\n");
|
||||
}
|
||||
return body.toString().trim();
|
||||
}
|
||||
|
||||
byte[] bodyAsByteArray(HttpServletRequest req) throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(req.getContentLength());
|
||||
req.getInputStream().transferTo(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
void sendResponse(HttpServletResponse resp, int httpStatus, String message) {
|
||||
try {
|
||||
resp.setStatus(httpStatus);
|
||||
|
|
|
@ -7,6 +7,7 @@ import ctbrec.Version;
|
|||
import ctbrec.event.EventBusHolder;
|
||||
import ctbrec.event.EventHandler;
|
||||
import ctbrec.event.EventHandlerConfiguration;
|
||||
import ctbrec.image.LocalPortraitStore;
|
||||
import ctbrec.recorder.NextGenLocalRecorder;
|
||||
import ctbrec.recorder.OnlineMonitor;
|
||||
import ctbrec.recorder.Recorder;
|
||||
|
@ -59,6 +60,7 @@ import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
|
|||
|
||||
public class HttpServer {
|
||||
|
||||
private static final int MiB = 1024 * 1024; // NOSONAR
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HttpServer.class);
|
||||
private final Recorder recorder;
|
||||
private final OnlineMonitor onlineMonitor;
|
||||
|
@ -188,7 +190,7 @@ public class HttpServer {
|
|||
sslContextFactory.setTrustStorePassword(keyStorePassword);
|
||||
|
||||
try (ServerConnector http = new ServerConnector(server, httpConnectionFactory);
|
||||
ServerConnector https = new ServerConnector(server, sslContextFactory, httpConnectionFactory)) {
|
||||
ServerConnector https = new ServerConnector(server, sslContextFactory, httpConnectionFactory)) {
|
||||
|
||||
// connector for http
|
||||
http.setPort(this.config.getSettings().httpPort);
|
||||
|
@ -219,6 +221,22 @@ public class HttpServer {
|
|||
holder = new ServletHolder(hlsServlet);
|
||||
defaultContext.addServlet(holder, "/hls/*");
|
||||
|
||||
LocalPortraitStore portraitStore = new LocalPortraitStore(config);
|
||||
ImageServlet imageServlet = new ImageServlet(portraitStore, config);
|
||||
holder = new ServletHolder(imageServlet);
|
||||
String location;
|
||||
try {
|
||||
location = File.createTempFile("upload", "").getParentFile().toString();
|
||||
} catch (IOException e) {
|
||||
location = ".";
|
||||
}
|
||||
long maxFileSize = 10L * MiB;
|
||||
long maxRequestSize = 10L * MiB;
|
||||
int fileSizeThreshold = MiB;
|
||||
MultipartConfigElement multipartConfig = new MultipartConfigElement(location, maxFileSize, maxRequestSize, fileSizeThreshold);
|
||||
holder.getRegistration().setMultipartConfig(multipartConfig);
|
||||
defaultContext.addServlet(holder, ImageServlet.BASE_URL + "/*");
|
||||
|
||||
if (this.config.getSettings().webinterface) {
|
||||
startWebInterface(defaultContext, basicAuthContext);
|
||||
}
|
||||
|
@ -227,9 +245,9 @@ public class HttpServer {
|
|||
HandlerList handlers = new HandlerList();
|
||||
if (this.config.getSettings().transportLayerSecurity) {
|
||||
server.addConnector(https);
|
||||
handlers.setHandlers(new Handler[] { new SecuredRedirectHandler(), basicAuthContext, defaultContext });
|
||||
handlers.setHandlers(new Handler[]{new SecuredRedirectHandler(), basicAuthContext, defaultContext});
|
||||
} else {
|
||||
handlers.setHandlers(new Handler[] { basicAuthContext, defaultContext });
|
||||
handlers.setHandlers(new Handler[]{basicAuthContext, defaultContext});
|
||||
}
|
||||
server.setHandler(handlers);
|
||||
|
||||
|
@ -255,7 +273,7 @@ public class HttpServer {
|
|||
ServletHolder holder = new ServletHolder(staticFileServlet);
|
||||
String staticFileContext = "/static/*";
|
||||
defaultContext.addServlet(holder, staticFileContext);
|
||||
LOG.info("Register static file servlet under {}", defaultContext.getContextPath()+staticFileContext);
|
||||
LOG.info("Register static file servlet under {}", defaultContext.getContextPath() + staticFileContext);
|
||||
|
||||
// servlet to retrieve the HMAC (secured by basic auth if a hmac key is set in the config)
|
||||
String username = this.config.getSettings().webinterfaceUsername;
|
||||
|
@ -298,7 +316,7 @@ public class HttpServer {
|
|||
@Override
|
||||
protected void handleErrorPage(HttpServletRequest request, Writer writer, int code, String message) throws IOException {
|
||||
if (code == 404) {
|
||||
writer.write("<html><head><title>404</title><style>* {font-family: sans-serif}</style></head><body><h1>404</h1><p>Looking for <a href=\""+contextPath+"/static/index.html\">CTB Recorder</a>?</p></body>");
|
||||
writer.write("<html><head><title>404</title><style>* {font-family: sans-serif}</style></head><body><h1>404</h1><p>Looking for <a href=\"" + contextPath + "/static/index.html\">CTB Recorder</a>?</p></body>");
|
||||
} else {
|
||||
super.handleErrorPage(request, writer, code, message);
|
||||
}
|
||||
|
@ -315,7 +333,7 @@ public class HttpServer {
|
|||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
((HttpServletResponse)response).addHeader("Server", "CTB Recorder/" + getVersion());
|
||||
((HttpServletResponse) response).addHeader("Server", "CTB Recorder/" + getVersion());
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
|
@ -330,14 +348,14 @@ public class HttpServer {
|
|||
private static SecurityHandler basicAuth(String username, String password) {
|
||||
String realm = "CTB Recorder";
|
||||
UserStore userStore = new UserStore();
|
||||
userStore.addUser(username, Credential.getCredential(password), new String[] { "user" });
|
||||
userStore.addUser(username, Credential.getCredential(password), new String[]{"user"});
|
||||
HashLoginService l = new HashLoginService();
|
||||
l.setUserStore(userStore);
|
||||
l.setName(realm);
|
||||
|
||||
Constraint constraint = new Constraint();
|
||||
constraint.setName(Constraint.__BASIC_AUTH);
|
||||
constraint.setRoles(new String[] { "user" });
|
||||
constraint.setRoles(new String[]{"user"});
|
||||
constraint.setAuthenticate(true);
|
||||
|
||||
ConstraintMapping cm = new ConstraintMapping();
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
package ctbrec.recorder.server;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.image.PortraitStore;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static ctbrec.io.HttpConstants.MIMETYPE_IMAGE_JPG;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static javax.servlet.http.HttpServletResponse.*;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ImageServlet extends AbstractCtbrecServlet {
|
||||
|
||||
public static final String BASE_URL = "/image";
|
||||
public static final String INTERNAL_SERVER_ERROR = "Internal Server Error";
|
||||
private static final Pattern URL_PATTERN_PORTRAIT_BY_ID = Pattern.compile(BASE_URL + "/portrait/([0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12})");
|
||||
private static final Pattern URL_PATTERN_PORTRAIT_BY_URL = Pattern.compile(BASE_URL + "/portrait/url/(.*)");
|
||||
private final PortraitStore portraitStore;
|
||||
private final Config config;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
|
||||
String requestURI = req.getRequestURI();
|
||||
try {
|
||||
boolean authenticated = checkAuthentication(req, body(req));
|
||||
if (!authenticated) {
|
||||
sendResponse(resp, SC_UNAUTHORIZED, "HMAC does not match");
|
||||
return;
|
||||
}
|
||||
|
||||
Matcher m;
|
||||
if ((m = URL_PATTERN_PORTRAIT_BY_ID.matcher(requestURI)).matches()) {
|
||||
String portraitId = m.group(1);
|
||||
servePortrait(resp, portraitId);
|
||||
} else if ((m = URL_PATTERN_PORTRAIT_BY_URL.matcher(requestURI)).matches()) {
|
||||
String modelUrl = URLDecoder.decode(m.group(1), UTF_8);
|
||||
String portraitId = config.getSettings().modelPortraits.get(modelUrl);
|
||||
servePortrait(resp, portraitId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(INTERNAL_SERVER_ERROR, e);
|
||||
sendResponse(resp, SC_INTERNAL_SERVER_ERROR, INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
private void servePortrait(HttpServletResponse resp, String portraitId) throws IOException {
|
||||
log.debug("serving portrait {}", portraitId);
|
||||
Optional<byte[]> imageData = portraitStore.loadModelPortraitById(portraitId);
|
||||
if (imageData.isPresent()) {
|
||||
resp.setStatus(SC_OK);
|
||||
resp.setContentType(MIMETYPE_IMAGE_JPG);
|
||||
byte[] b = imageData.get();
|
||||
resp.setContentLength(b.length);
|
||||
resp.getOutputStream().write(b, 0, b.length);
|
||||
resp.getOutputStream().flush();
|
||||
} else {
|
||||
sendResponse(resp, SC_NOT_FOUND, "Portrait with ID " + portraitId + " not found");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
|
||||
String requestURI = req.getRequestURI();
|
||||
try {
|
||||
// boolean authenticated = checkAuthentication(req, body(req));
|
||||
// if (!authenticated) {
|
||||
// sendResponse(resp, SC_UNAUTHORIZED, "HMAC does not match");
|
||||
// return;
|
||||
// }
|
||||
|
||||
Matcher m;
|
||||
if ((m = URL_PATTERN_PORTRAIT_BY_URL.matcher(requestURI)).matches()) {
|
||||
String modelUrl = URLDecoder.decode(m.group(1), UTF_8);
|
||||
byte[] data = bodyAsByteArray(req);
|
||||
portraitStore.writePortrait(modelUrl, data);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(INTERNAL_SERVER_ERROR, e);
|
||||
sendResponse(resp, SC_INTERNAL_SERVER_ERROR, INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) {
|
||||
String requestURI = req.getRequestURI();
|
||||
try {
|
||||
// boolean authenticated = checkAuthentication(req, body(req));
|
||||
// if (!authenticated) {
|
||||
// sendResponse(resp, SC_UNAUTHORIZED, "HMAC does not match");
|
||||
// return;
|
||||
// }
|
||||
|
||||
Matcher m;
|
||||
if ((m = URL_PATTERN_PORTRAIT_BY_URL.matcher(requestURI)).matches()) {
|
||||
String modelUrl = URLDecoder.decode(m.group(1), UTF_8);
|
||||
portraitStore.removePortrait(modelUrl);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(INTERNAL_SERVER_ERROR, e);
|
||||
sendResponse(resp, SC_INTERNAL_SERVER_ERROR, INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue