diff --git a/src/main/java/org/zephyrsoft/sdb2/FileAndDirectoryLocations.java b/src/main/java/org/zephyrsoft/sdb2/FileAndDirectoryLocations.java index b9cd662f..73bf655e 100644 --- a/src/main/java/org/zephyrsoft/sdb2/FileAndDirectoryLocations.java +++ b/src/main/java/org/zephyrsoft/sdb2/FileAndDirectoryLocations.java @@ -44,6 +44,7 @@ public class FileAndDirectoryLocations { private static final String STATISTICS_FILE_STRING = "statistics.xml"; private static final String DB_FILE_STRING = "db.xml"; private static final String DB_PROPERTIES_FILE_STRING = "db.properties.xml"; + private static final String DB_BLOB_SUBDIR_STRING = "blobs"; private static final DateTimeFormatter YEAR_MONTH = DateTimeFormatter.ofPattern("yyyy-MM"); @@ -90,6 +91,15 @@ public static String getStatisticsMonthlyExportFileName(LocalDate date) { return getStatisticsDir() + File.separator + YEAR_MONTH.format(date) + ".xls"; } + /** this is used when remote control (via MQTT) is active */ + public static String getDBBlobDir() { + if (Options.getInstance().getBlobDatabaseDir() == null) { + return getDir(DB_BLOB_SUBDIR_STRING, true); + } else { + return getDir(Options.getInstance().getBlobDatabaseDir(), false); + } + } + /** this is used when remote control (via MQTT) is active */ private static String getDBDir() { if (Options.getInstance().getDatabaseDir() == null) { diff --git a/src/main/java/org/zephyrsoft/sdb2/Options.java b/src/main/java/org/zephyrsoft/sdb2/Options.java index 8233edba..12b23769 100644 --- a/src/main/java/org/zephyrsoft/sdb2/Options.java +++ b/src/main/java/org/zephyrsoft/sdb2/Options.java @@ -77,6 +77,11 @@ public static Options getInstance() { @Option(name = "--database", aliases = "-db", metaVar = "
- * You may set a prefix if you want to share a broker with multiple instance groups. - * The prefix may be a code, where only selected users have access too. It must be set if you want to set up or use - * a global mqtt server for multiple organizations. - * A Organization may have different rooms, to split up presentation instances into. - * Users may have only access to some rooms. + * You may set a prefix if you want to share a broker with multiple instance + * groups. The prefix may be a code, where only selected users have access too. + * It must be set if you want to set up or use a global mqtt server for multiple + * organizations. A Organization may have different rooms, to split up + * presentation instances into. Users may have only access to some rooms. *
* A room contains one shared presentation, and multiple playlists. *
- * All properties are by default without local notify. They can't be used for in program synchronization.
- * Furthermore they are retained.
+ * All properties are by default without local notify. They can't be used for in
+ * program synchronization. Furthermore they are retained.
*
- * @param mainWindow
- * can be null, if headless
+ * @param mainWindow can be null, if headless
*/
public RemoteController(RemotePreferences remotePreferences, MainController mainController, MainWindow mainWindow) {
this.remotePreferences = remotePreferences;
-
+
position = new MqttObject<>(formatTopic(RemoteTopic.POSITION), (s) -> (Position) parseXML(s),
- RemoteController::toXML, RemoteTopic.POSITION_QOS, RemoteTopic.POSITION_RETAINED,
- null);
+ RemoteController::toXML, RemoteTopic.POSITION_QOS, RemoteTopic.POSITION_RETAINED, null);
position.onRemoteChange((p, a) -> updateSongOrPosition(mainController, mainWindow));
-
- song = new MqttObject<>(formatTopic(RemoteTopic.SONG),
- (s) -> (Song) parseXML(s), RemoteController::toXML, RemoteTopic.SONG_QOS, RemoteTopic.SONG_RETAINED,
- null);
+
+ song = new MqttObject<>(formatTopic(RemoteTopic.SONG), (s) -> (Song) parseXML(s), RemoteController::toXML,
+ RemoteTopic.SONG_QOS, RemoteTopic.SONG_RETAINED, null);
song.onRemoteChange((s, a) -> updateSongOrPosition(mainController, mainWindow));
-
+
+ filesRequestGet = new MqttObject<>(formatClientIDTopic(RemoteTopic.FILES_REQUEST_GET),
+ RemoteController::toXML, RemoteTopic.FILES_REQUEST_GET_QOS, RemoteTopic.FILES_REQUEST_GET_RETAINED);
+
+ filesRequestFile = new MqttObject<>(formatClientIDTopic(RemoteTopic.FILES_REQUEST_FILE), null, null,
+ RemoteTopic.FILES_REQUEST_FILE_QOS, RemoteTopic.FILES_REQUEST_FILE_RETAINED, (a, b) -> false);
+
if (mainWindow != null) {
- playlist = new MqttObject<>(formatTopic(RemoteTopic.PLAYLIST),
- (s) -> (SongsModel) parseXML(s),
- RemoteController::toXML, RemoteTopic.PLAYLIST_QOS, RemoteTopic.PLAYLIST_RETAINED,
- null);
- playlist.onRemoteChange((p, a) -> mainWindow.updatePlaylist(p));
- mainWindow.getPresentModel().addSongsModelListener(() -> playlist.set(new SongsModel(mainWindow.getPresentModel())));
-
+ playlist = new MqttObject<>(formatTopic(RemoteTopic.PLAYLIST), (s) -> (SongsModel) parseXML(s),
+ RemoteController::toXML, RemoteTopic.PLAYLIST_QOS, RemoteTopic.PLAYLIST_RETAINED, null);
+ playlist.onRemoteChange((p, a) -> fileController.downloadFiles(p, () -> mainWindow.updatePlaylist(p)));
+ mainWindow.getPresentModel().addSongsModelListener(() -> fileController.uploadFiles(mainWindow.getPresentModel(), (s) -> playlist.set(new SongsModel(s))));
+
latestVersion = new MqttObject<>(formatTopic(RemoteTopic.PATCHES_LATEST_VERSION),
- (s) -> (Version) parseXML(s),
- RemoteController::toXML, RemoteTopic.PATCHES_LATEST_VERSION_QOS, RemoteTopic.PATCHES_LATEST_VERSION_RETAINED,
- (a, b) -> false);
-
+ (s) -> (Version) parseXML(s), RemoteController::toXML, RemoteTopic.PATCHES_LATEST_VERSION_QOS,
+ RemoteTopic.PATCHES_LATEST_VERSION_RETAINED, (a, b) -> false);
+
latestChanges = new MqttObject<>(formatTopic(RemoteTopic.PATCHES_LATEST_CHANGES),
- (s) -> (SongsModel) parseXML(s),
- RemoteController::toXML, RemoteTopic.PATCHES_LATEST_CHANGES_QOS, RemoteTopic.PATCHES_LATEST_CHANEGS_RETAINED,
- (a, b) -> false);
-
+ (s) -> (SongsModel) parseXML(s), RemoteController::toXML, RemoteTopic.PATCHES_LATEST_CHANGES_QOS,
+ RemoteTopic.PATCHES_LATEST_CHANEGS_RETAINED, (a, b) -> false);
+
latestReject = new MqttObject<>(formatTopic(RemoteTopic.PATCHES_LATEST_REJECT),
- (s) -> (ChangeReject) parseXML(s),
- null, RemoteTopic.PATCHES_LATEST_REJECT_QOS, RemoteTopic.PATCHES_LATEST_REJECT_RETAINED,
- (a, b) -> false);
-
- requestGet = new MqttObject<>(formatClientIDTopic(RemoteTopic.PATCHES_REQUEST_GET),
- RemoteController::toXML, RemoteTopic.PATCHES_REQUEST_GET_QOS, RemoteTopic.PATCHES_REQUEST_GET_RETAINED);
-
+ (s) -> (ChangeReject) parseXML(s), null, RemoteTopic.PATCHES_LATEST_REJECT_QOS,
+ RemoteTopic.PATCHES_LATEST_REJECT_RETAINED, (a, b) -> false);
+
+ requestGet = new MqttObject<>(formatClientIDTopic(RemoteTopic.PATCHES_REQUEST_GET), RemoteController::toXML,
+ RemoteTopic.PATCHES_REQUEST_GET_QOS, RemoteTopic.PATCHES_REQUEST_GET_RETAINED);
+
requestPatches = new MqttObject<>(formatClientIDTopic(RemoteTopic.PATCHES_REQUEST_PATCHES),
- (s) -> (Patches) parseXML(s),
- RemoteController::toXML, RemoteTopic.PATCHES_REQUEST_PATCHES_QOS, RemoteTopic.PATCHES_REQUEST_PATCHES_RETAINED,
- (a, b) -> false);
-
- healthDB = new MqttObject<>(formatPrefixTopic(RemoteTopic.HEALTH_DB),
- Health::valueOfBytes, null, RemoteTopic.HEALTH_DB_QOS, RemoteTopic.HEALTH_DB_RETAINED, null);
+ (s) -> (Patches) parseXML(s), RemoteController::toXML, RemoteTopic.PATCHES_REQUEST_PATCHES_QOS,
+ RemoteTopic.PATCHES_REQUEST_PATCHES_RETAINED, (a, b) -> false);
+
+ filesRequestSet = new MqttObject<>(formatClientIDTopic(RemoteTopic.FILES_REQUEST_SET), (b) -> b,
+ RemoteTopic.FILES_REQUEST_SET_QOS, RemoteTopic.FILES_REQUEST_SET_RETAINED);
+
+ filesRequestSetResponse = new MqttObject<>(formatClientIDTopic(RemoteTopic.FILES_REQUEST_SET_RESPONSE),
+ (s) -> (FileSetResponse) parseXML(s), null, RemoteTopic.FILES_REQUEST_SET_RESPONSE_QOS,
+ RemoteTopic.FILES_REQUEST_SET_RESPONSE_RETAINED, (a, b) -> false);
+
+ healthDB = new MqttObject<>(formatPrefixTopic(RemoteTopic.HEALTH_DB), Health::valueOfBytes, null,
+ RemoteTopic.HEALTH_DB_QOS, RemoteTopic.HEALTH_DB_RETAINED, null);
} else {
this.playlist = null;
this.requestPatches = null;
@@ -118,11 +136,14 @@ public RemoteController(RemotePreferences remotePreferences, MainController main
this.latestReject = null;
this.latestChanges = null;
this.healthDB = null;
+ this.filesRequestSet = null;
+ this.filesRequestSetResponse = null;
}
+ fileController = new FileController(this);
remotePresenter = new RemotePresenter(this);
}
-
+
public void connectTo(MQTT mqtt) throws MqttException {
song.connectTo(mqtt);
position.connectTo(mqtt);
@@ -133,8 +154,12 @@ public void connectTo(MQTT mqtt) throws MqttException {
requestPatches.connectTo(mqtt);
latestReject.connectTo(mqtt);
healthDB.connectTo(mqtt);
+ filesRequestFile.connectTo(mqtt);
+ filesRequestGet.connectTo(mqtt);
+ filesRequestSet.connectTo(mqtt);
+ filesRequestSetResponse.connectTo(mqtt);
}
-
+
private void updateSongOrPosition(MainController mainController, MainWindow mainWindow) {
if (position == null || song == null)
return;
@@ -147,50 +172,49 @@ private void updateSongOrPosition(MainController mainController, MainWindow main
if (s == null) {
return;
}
-
+
if (StringTools.equals(s.getUUID(), p.getUUID())) {
if (p.isVisible()) {
+ p = StringTools.isEmpty(s.getImage()) ? p : null;
presentSong(mainController, mainWindow, s, p);
} else {
presentSong(mainController, mainWindow, null, null);
}
}
}
-
+
private void presentSong(MainController mainController, MainWindow mainWindow, Song s, Position p) {
- SongPresentationPosition spp = p != null
- ? new SongPresentationPosition(p.getPart(), p.getLine())
- : null;
+ SongPresentationPosition spp = p != null ? new SongPresentationPosition(p.getPart(), p.getLine()) : null;
if (mainWindow != null) {
mainWindow.present(s, spp);
} else {
mainController.present(new Presentable(s, null), spp);
}
}
-
+
public MqttObject