diff --git a/src/main/java/dev/kruhlmann/imgfloat/model/AssetPatch.java b/src/main/java/dev/kruhlmann/imgfloat/model/AssetPatch.java index 6381a1c..7b41d08 100644 --- a/src/main/java/dev/kruhlmann/imgfloat/model/AssetPatch.java +++ b/src/main/java/dev/kruhlmann/imgfloat/model/AssetPatch.java @@ -21,9 +21,8 @@ public record AssetPatch( Double audioPitch, Double audioVolume ) { - public static AssetPatch fromTransform(Asset asset) { - return new AssetPatch( - asset.getId(), + public static TransformSnapshot capture(Asset asset) { + return new TransformSnapshot( asset.getX(), asset.getY(), asset.getWidth(), @@ -32,7 +31,6 @@ public record AssetPatch( asset.getSpeed(), asset.isMuted(), asset.getZIndex(), - null, asset.isAudioLoop(), asset.getAudioDelayMillis(), asset.getAudioSpeed(), @@ -41,6 +39,30 @@ public record AssetPatch( ); } + /** + * Produces a minimal patch from a transform operation. Only fields that changed and were part of + * the incoming request are populated to keep WebSocket payloads small. + */ + public static AssetPatch fromTransform(TransformSnapshot before, Asset asset, TransformRequest request) { + return new AssetPatch( + asset.getId(), + changed(before.x(), asset.getX()), + changed(before.y(), asset.getY()), + changed(before.width(), asset.getWidth()), + changed(before.height(), asset.getHeight()), + changed(before.rotation(), asset.getRotation()), + request.getSpeed() != null ? changed(before.speed(), asset.getSpeed()) : null, + request.getMuted() != null ? changed(before.muted(), asset.isMuted()) : null, + request.getZIndex() != null ? changed(before.zIndex(), asset.getZIndex()) : null, + null, + request.getAudioLoop() != null ? changed(before.audioLoop(), asset.isAudioLoop()) : null, + request.getAudioDelayMillis() != null ? changed(before.audioDelayMillis(), asset.getAudioDelayMillis()) : null, + request.getAudioSpeed() != null ? changed(before.audioSpeed(), asset.getAudioSpeed()) : null, + request.getAudioPitch() != null ? changed(before.audioPitch(), asset.getAudioPitch()) : null, + request.getAudioVolume() != null ? changed(before.audioVolume(), asset.getAudioVolume()) : null + ); + } + public static AssetPatch fromVisibility(Asset asset) { return new AssetPatch( asset.getId(), @@ -60,4 +82,32 @@ public record AssetPatch( null ); } + + private static Double changed(double before, double after) { + return Double.compare(before, after) == 0 ? null : after; + } + + private static Integer changed(int before, int after) { + return before == after ? null : after; + } + + private static Boolean changed(boolean before, boolean after) { + return before == after ? null : after; + } + + public record TransformSnapshot( + double x, + double y, + double width, + double height, + double rotation, + double speed, + boolean muted, + int zIndex, + boolean audioLoop, + int audioDelayMillis, + double audioSpeed, + double audioPitch, + double audioVolume + ) { } } diff --git a/src/main/java/dev/kruhlmann/imgfloat/service/ChannelDirectoryService.java b/src/main/java/dev/kruhlmann/imgfloat/service/ChannelDirectoryService.java index eed3706..4a0aea2 100644 --- a/src/main/java/dev/kruhlmann/imgfloat/service/ChannelDirectoryService.java +++ b/src/main/java/dev/kruhlmann/imgfloat/service/ChannelDirectoryService.java @@ -214,6 +214,7 @@ public class ChannelDirectoryService { return assetRepository.findById(assetId) .filter(asset -> normalized.equals(asset.getBroadcaster())) .map(asset -> { + AssetPatch.TransformSnapshot before = AssetPatch.capture(asset); validateTransform(req); asset.setX(req.getX()); @@ -234,9 +235,11 @@ public class ChannelDirectoryService { assetRepository.save(asset); AssetView view = AssetView.from(normalized, asset); - AssetPatch patch = AssetPatch.fromTransform(asset); - messagingTemplate.convertAndSend(topicFor(broadcaster), - AssetEvent.updated(broadcaster, patch)); + AssetPatch patch = AssetPatch.fromTransform(before, asset, req); + if (hasPatchChanges(patch)) { + messagingTemplate.convertAndSend(topicFor(broadcaster), + AssetEvent.updated(broadcaster, patch)); + } return view; }); } @@ -357,4 +360,21 @@ public class ChannelDirectoryService { .max() .orElse(0) + 1; } + + private boolean hasPatchChanges(AssetPatch patch) { + return patch.x() != null + || patch.y() != null + || patch.width() != null + || patch.height() != null + || patch.rotation() != null + || patch.speed() != null + || patch.muted() != null + || patch.zIndex() != null + || patch.hidden() != null + || patch.audioLoop() != null + || patch.audioDelayMillis() != null + || patch.audioSpeed() != null + || patch.audioPitch() != null + || patch.audioVolume() != null; + } }