diff --git a/src/main/java/io/linuxserver/fleet/core/FleetBeans.java b/src/main/java/io/linuxserver/fleet/core/FleetBeans.java
index 0199522..fb33103 100644
--- a/src/main/java/io/linuxserver/fleet/core/FleetBeans.java
+++ b/src/main/java/io/linuxserver/fleet/core/FleetBeans.java
@@ -27,7 +27,11 @@ import io.linuxserver.fleet.db.dao.DefaultUserDAO;
import io.linuxserver.fleet.db.migration.DatabaseVersion;
import io.linuxserver.fleet.delegate.*;
import io.linuxserver.fleet.dockerhub.DockerHubV2Client;
+import io.linuxserver.fleet.dockerhub.queue.DockerHubSyncConsumer;
+import io.linuxserver.fleet.dockerhub.queue.DockerHubSyncQueue;
import io.linuxserver.fleet.thread.TaskManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
*
@@ -36,6 +40,8 @@ import io.linuxserver.fleet.thread.TaskManager;
*/
public class FleetBeans {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FleetBeans.class);
+
private final FleetProperties properties;
private final ImageDelegate imageDelegate;
private final RepositoryDelegate repositoryDelegate;
@@ -46,6 +52,7 @@ public class FleetBeans {
private final TaskDelegate taskDelegate;
private final UserDelegate userDelegate;
private final PasswordEncoder passwordEncoder;
+ private final DockerHubSyncQueue dockerHubSyncQueue;
/**
* Ensures the database is kept up to date.
@@ -68,6 +75,14 @@ public class FleetBeans {
userDelegate = new UserDelegate(passwordEncoder, new DefaultUserDAO(databaseConnection));
taskDelegate = new TaskDelegate(this);
authenticationDelegate = new DefaultAuthenticationDelegate(AuthenticatorFactory.getAuthenticator(this));
+ dockerHubSyncQueue = new DockerHubSyncQueue();
+
+ final int consumerThreadCount = properties.getQueueThreadCount();
+ for (int i = 0; i < consumerThreadCount; i++) {
+
+ LOGGER.info("Starting consumer thread " + i + "...");
+ new DockerHubSyncConsumer(imageDelegate, dockerHubSyncQueue, "SyncThread-" + i).start();
+ }
}
public FleetProperties getProperties() {
diff --git a/src/main/java/io/linuxserver/fleet/core/FleetProperties.java b/src/main/java/io/linuxserver/fleet/core/FleetProperties.java
index 6f5b2b4..8b38434 100644
--- a/src/main/java/io/linuxserver/fleet/core/FleetProperties.java
+++ b/src/main/java/io/linuxserver/fleet/core/FleetProperties.java
@@ -79,6 +79,10 @@ public class FleetProperties {
return new DockerHubCredentials(username, password);
}
+ public int getQueueThreadCount() {
+ return Integer.parseInt(getStringProperty("fleet.queue.threads"));
+ }
+
/**
*
* Obtains the property value from three separate sources: first from the config file. If not present, it will look
diff --git a/src/main/java/io/linuxserver/fleet/db/dao/DefaultImageDAO.java b/src/main/java/io/linuxserver/fleet/db/dao/DefaultImageDAO.java
index 5ae5a3e..a01b45b 100644
--- a/src/main/java/io/linuxserver/fleet/db/dao/DefaultImageDAO.java
+++ b/src/main/java/io/linuxserver/fleet/db/dao/DefaultImageDAO.java
@@ -23,6 +23,7 @@ import io.linuxserver.fleet.db.query.InsertUpdateStatus;
import io.linuxserver.fleet.db.query.LimitedResult;
import io.linuxserver.fleet.model.internal.Image;
import io.linuxserver.fleet.model.internal.ImagePullStat;
+import io.linuxserver.fleet.model.internal.Repository;
import io.linuxserver.fleet.model.internal.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -230,7 +231,10 @@ public class DefaultImageDAO implements ImageDAO {
Image image = new Image(
results.getInt("ImageId"),
- results.getInt("RepositoryId"),
+ new Repository(
+ results.getInt("RepositoryId"),
+ results.getString("RepositoryName")
+ ),
results.getString("ImageName"),
new Tag(
results.getString("LatestTagVersion"),
diff --git a/src/main/java/io/linuxserver/fleet/delegate/DockerHubDelegate.java b/src/main/java/io/linuxserver/fleet/delegate/DockerHubDelegate.java
index 369cc6e..e03084b 100644
--- a/src/main/java/io/linuxserver/fleet/delegate/DockerHubDelegate.java
+++ b/src/main/java/io/linuxserver/fleet/delegate/DockerHubDelegate.java
@@ -63,6 +63,10 @@ public class DockerHubDelegate {
return images;
}
+ public DockerImage fetchImageFromRepository(String repositoryName, String imageName) {
+ return convertImage(dockerHubClient.fetchImageFromRepository(repositoryName, imageName));
+ }
+
public List fetchAllTagsForImage(String repositoryName, String imageName) {
return dockerHubClient.fetchAllTagsForImage(repositoryName, imageName).stream().map(this::convertTag).collect(Collectors.toList());
}
@@ -80,6 +84,10 @@ public class DockerHubDelegate {
private DockerImage convertImage(DockerHubV2Image dockerHubV2Image) {
+ if (dockerHubV2Image == null) {
+ return null;
+ }
+
return new DockerImage(
dockerHubV2Image.getName(),
dockerHubV2Image.getNamespace(),
@@ -92,6 +100,10 @@ public class DockerHubDelegate {
private DockerTag convertTag(DockerHubV2Tag dockerHubV2Tag) {
+ if (dockerHubV2Tag == null) {
+ return null;
+ }
+
return new DockerTag(
dockerHubV2Tag.getName(),
dockerHubV2Tag.getFullSize(),
diff --git a/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncConsumer.java b/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncConsumer.java
new file mode 100644
index 0000000..911ac11
--- /dev/null
+++ b/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncConsumer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 LinuxServer.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package io.linuxserver.fleet.dockerhub.queue;
+
+import io.linuxserver.fleet.delegate.ImageDelegate;
+import io.linuxserver.fleet.exception.SaveException;
+import io.linuxserver.fleet.model.internal.Image;
+import io.linuxserver.fleet.queue.AbstractQueueConsumer;
+import io.linuxserver.fleet.queue.RequestQueue;
+
+public class DockerHubSyncConsumer extends AbstractQueueConsumer {
+
+ private final ImageDelegate imageDelegate;
+
+ public DockerHubSyncConsumer(ImageDelegate imageDelegate, RequestQueue requestQueue, String name) {
+ super(requestQueue, name);
+ this.imageDelegate = imageDelegate;
+ }
+
+ @Override
+ protected void handleResponse(DockerHubSyncResponse response) {
+
+ try {
+
+ final Image image = response.getImage();
+ imageDelegate.saveImage(image);
+
+ } catch (SaveException e) {
+ getLogger().error("handleResponse unable to save image: {}", e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncQueue.java b/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncQueue.java
new file mode 100644
index 0000000..54535e4
--- /dev/null
+++ b/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncQueue.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019 LinuxServer.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package io.linuxserver.fleet.dockerhub.queue;
+
+import io.linuxserver.fleet.queue.AbstractRequestQueue;
+
+public class DockerHubSyncQueue extends AbstractRequestQueue {
+}
diff --git a/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncRequest.java b/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncRequest.java
new file mode 100644
index 0000000..3b1b89d
--- /dev/null
+++ b/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncRequest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019 LinuxServer.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package io.linuxserver.fleet.dockerhub.queue;
+
+import io.linuxserver.fleet.delegate.DockerHubDelegate;
+import io.linuxserver.fleet.model.internal.Image;
+import io.linuxserver.fleet.queue.FleetRequest;
+
+import java.util.Objects;
+
+public class DockerHubSyncRequest implements FleetRequest {
+
+ private final DockerHubDelegate dockerHubDelegate;
+ private final Image image;
+
+ public DockerHubSyncRequest(DockerHubDelegate dockerHubDelegate, Image image) {
+
+ this.dockerHubDelegate = dockerHubDelegate;
+ this.image = image;
+ }
+
+ @Override
+ public DockerHubSyncResponse execute() {
+ return new DockerHubSyncResponse(dockerHubDelegate, image);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DockerHubSyncRequest that = (DockerHubSyncRequest) o;
+ return Objects.equals(image, that.image);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(image);
+ }
+}
diff --git a/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncResponse.java b/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncResponse.java
new file mode 100644
index 0000000..f3f84d1
--- /dev/null
+++ b/src/main/java/io/linuxserver/fleet/dockerhub/queue/DockerHubSyncResponse.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019 LinuxServer.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package io.linuxserver.fleet.dockerhub.queue;
+
+import io.linuxserver.fleet.delegate.DockerHubDelegate;
+import io.linuxserver.fleet.model.docker.DockerImage;
+import io.linuxserver.fleet.model.docker.DockerTag;
+import io.linuxserver.fleet.model.internal.Image;
+import io.linuxserver.fleet.model.internal.Tag;
+import io.linuxserver.fleet.queue.FleetResponse;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class DockerHubSyncResponse implements FleetResponse {
+
+ private final DockerHubDelegate dockerHubDelegate;
+ private final Image image;
+
+ public DockerHubSyncResponse(DockerHubDelegate dockerHubDelegate, Image image) {
+
+ this.dockerHubDelegate = dockerHubDelegate;
+ this.image = Image.copyOf(image);
+ }
+
+ @Override
+ public void handle() {
+
+ DockerImage dockerImage = dockerHubDelegate.fetchImageFromRepository(image.getRepository().getName(), image.getName());
+ String versionMask = getVersionMask(image.getRepository().getVersionMask(), image.getVersionMask());
+ Tag maskedVersion = getLatestTagAndCreateMaskedVersion(versionMask);
+
+ image.withPullCount(dockerImage.getPullCount());
+ image.updateTag(maskedVersion);
+ }
+
+ public Image getImage() {
+ return image;
+ }
+
+ private String getVersionMask(String repositoryMask, String imageMask) {
+ return imageMask == null ? repositoryMask : imageMask;
+ }
+
+ private Tag getLatestTagAndCreateMaskedVersion(String versionMask) {
+
+ DockerTag tag = dockerHubDelegate.fetchLatestImageTag(image.getRepository().getName(), image.getName());
+
+ if (null == tag)
+ return Tag.NONE;
+
+ if (isTagJustLatestAndNotAVersion(tag) || null == versionMask)
+ return new Tag(tag.getName(), tag.getName(), tag.getBuildDate());
+
+ return new Tag(tag.getName(), extractMaskedVersion(tag.getName(), versionMask), tag.getBuildDate());
+ }
+
+ private String extractMaskedVersion(String fullTag, String versionMask) {
+
+ Pattern pattern = Pattern.compile(versionMask);
+ Matcher matcher = pattern.matcher(fullTag);
+
+ if (matcher.matches()) {
+
+ StringBuilder tagBuilder = new StringBuilder();
+
+ for (int groupNum = 1; groupNum <= matcher.groupCount(); groupNum++)
+ tagBuilder.append(matcher.group(groupNum));
+
+ return tagBuilder.toString();
+ }
+
+ return fullTag;
+ }
+
+ /**
+ *
+ * If the top-level tag is not versioned, a mask can't be applied.
+ *
+ */
+ private boolean isTagJustLatestAndNotAVersion(DockerTag tag) {
+ return "latest".equals(tag.getName());
+ }
+}
diff --git a/src/main/java/io/linuxserver/fleet/model/internal/Image.java b/src/main/java/io/linuxserver/fleet/model/internal/Image.java
index 83e987c..4a85650 100644
--- a/src/main/java/io/linuxserver/fleet/model/internal/Image.java
+++ b/src/main/java/io/linuxserver/fleet/model/internal/Image.java
@@ -29,34 +29,34 @@ import java.util.Objects;
*/
public class Image extends PersistableItem {
- private final int repositoryId;
- private final String name;
+ private final Repository repository;
+ private final String name;
- private Tag tag;
- private long pullCount;
- private String versionMask;
- private boolean unstable;
- private boolean hidden;
+ private Tag tag;
+ private long pullCount;
+ private String versionMask;
+ private boolean unstable;
+ private boolean hidden;
- private boolean deprecated;
- private String deprecationReason;
+ private boolean deprecated;
+ private String deprecationReason;
- public Image(Integer id, int repositoryId, String name, Tag latestVersion) {
+ public Image(Integer id, Repository repository, String name, Tag latestVersion) {
super(id);
this.name = name;
- this.repositoryId = repositoryId;
+ this.repository = repository;
this.tag = new Tag(latestVersion.getVersion(), latestVersion.getMaskedVersion(), latestVersion.getBuildDate());
}
- public Image(int repositoryId, String name) {
- this(null, repositoryId, name, Tag.NONE);
+ public Image(Repository repository, String name) {
+ this(null, repository, name, Tag.NONE);
}
public static Image copyOf(Image image) {
- Image cloned = new Image(image.getId(), image.repositoryId, image.name, image.tag);
+ Image cloned = new Image(image.getId(), Repository.copyOf(image.repository), image.name, image.tag);
cloned.pullCount = image.pullCount;
cloned.versionMask = image.versionMask;
cloned.unstable = image.unstable;
@@ -108,7 +108,11 @@ public class Image extends PersistableItem {
}
public int getRepositoryId() {
- return repositoryId;
+ return repository.getId();
+ }
+
+ public Repository getRepository() {
+ return repository;
}
public String getName() {
@@ -166,11 +170,11 @@ public class Image extends PersistableItem {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Image image = (Image) o;
- return repositoryId == image.repositoryId && Objects.equals(name, image.name);
+ return Objects.equals(repository, image.repository) && Objects.equals(name, image.name);
}
@Override
public int hashCode() {
- return Objects.hash(repositoryId, name);
+ return Objects.hash(repository, name);
}
}
diff --git a/src/main/java/io/linuxserver/fleet/model/internal/Repository.java b/src/main/java/io/linuxserver/fleet/model/internal/Repository.java
index 6289df2..a8262e4 100644
--- a/src/main/java/io/linuxserver/fleet/model/internal/Repository.java
+++ b/src/main/java/io/linuxserver/fleet/model/internal/Repository.java
@@ -17,6 +17,8 @@
package io.linuxserver.fleet.model.internal;
+import java.util.Objects;
+
public class Repository extends PersistableItem {
private final String name;
@@ -36,6 +38,10 @@ public class Repository extends PersistableItem {
this.name = name;
}
+ public static Repository copyOf(Repository repository) {
+ return new Repository(repository.getId(), repository.name).withVersionMask(repository.versionMask).withSyncEnabled(repository.syncEnabled);
+ }
+
public Repository withVersionMask(String versionMask) {
this.versionMask = versionMask;
@@ -59,4 +65,17 @@ public class Repository extends PersistableItem {
public boolean isSyncEnabled() {
return syncEnabled;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Repository that = (Repository) o;
+ return Objects.equals(name, that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name);
+ }
}
diff --git a/src/main/java/io/linuxserver/fleet/queue/AbstractQueueConsumer.java b/src/main/java/io/linuxserver/fleet/queue/AbstractQueueConsumer.java
new file mode 100644
index 0000000..6ce840c
--- /dev/null
+++ b/src/main/java/io/linuxserver/fleet/queue/AbstractQueueConsumer.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019 LinuxServer.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package io.linuxserver.fleet.queue;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractQueueConsumer> extends Thread implements QueueConsumer {
+
+ private final Logger LOGGER = LoggerFactory.getLogger(getClass().getName());
+
+ private final RequestQueue requestQueue;
+
+ public AbstractQueueConsumer(final RequestQueue requestQueue, final String name) {
+ super(name + "-Consumer");
+ this.requestQueue = requestQueue;
+ }
+
+ @Override
+ public void run() {
+
+ while (true) {
+ consume();
+ }
+ }
+
+ @Override
+ public void start() {
+
+ getLogger().info("Starting...");
+ super.start();
+ }
+
+ @Override
+ public void consume() {
+
+ try {
+
+ T request = requestQueue.takeOneRequest();
+ R response = request.execute();
+
+ handleResponse(response);
+
+ } catch (Exception e) {
+ getLogger().error("consume caught unhandled exception", e);
+ }
+ }
+
+ protected abstract void handleResponse(R response);
+
+ public Logger getLogger() {
+ return LOGGER;
+ }
+}
diff --git a/src/main/java/io/linuxserver/fleet/queue/AbstractRequestQueue.java b/src/main/java/io/linuxserver/fleet/queue/AbstractRequestQueue.java
new file mode 100644
index 0000000..3392685
--- /dev/null
+++ b/src/main/java/io/linuxserver/fleet/queue/AbstractRequestQueue.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 LinuxServer.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package io.linuxserver.fleet.queue;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingDeque;
+
+public class AbstractRequestQueue> implements RequestQueue {
+
+ private final Logger LOGGER = LoggerFactory.getLogger(getClass().getName());
+
+ private final BlockingQueue requestQueue;
+
+ public AbstractRequestQueue() {
+ this.requestQueue = new LinkedBlockingDeque<>();
+ }
+
+ @Override
+ public synchronized void enqueueRequest(final T request) {
+
+ try {
+
+ if (!requestQueue.contains(request)) {
+
+ final boolean added = requestQueue.add(request);
+ if (!added) {
+ LOGGER.warn("enqueueRequest unable to add request to queue");
+ }
+ }
+
+ } catch (Exception e) {
+ LOGGER.error("enqueueRequest caught unhandled exception {}", e.getMessage());
+ }
+ }
+
+ @Override
+ public synchronized T takeOneRequest() {
+
+ try {
+ return requestQueue.take();
+ } catch (InterruptedException e) {
+ LOGGER.error("takeOneRequest was interrupted: {}", e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/io/linuxserver/fleet/queue/FleetRequest.java b/src/main/java/io/linuxserver/fleet/queue/FleetRequest.java
new file mode 100644
index 0000000..5e3616d
--- /dev/null
+++ b/src/main/java/io/linuxserver/fleet/queue/FleetRequest.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019 LinuxServer.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package io.linuxserver.fleet.queue;
+
+public interface FleetRequest {
+
+ T execute();
+}
diff --git a/src/main/java/io/linuxserver/fleet/queue/FleetResponse.java b/src/main/java/io/linuxserver/fleet/queue/FleetResponse.java
new file mode 100644
index 0000000..91a12bd
--- /dev/null
+++ b/src/main/java/io/linuxserver/fleet/queue/FleetResponse.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019 LinuxServer.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package io.linuxserver.fleet.queue;
+
+public interface FleetResponse {
+
+ void handle();
+}
diff --git a/src/main/java/io/linuxserver/fleet/queue/QueueConsumer.java b/src/main/java/io/linuxserver/fleet/queue/QueueConsumer.java
new file mode 100644
index 0000000..d49a187
--- /dev/null
+++ b/src/main/java/io/linuxserver/fleet/queue/QueueConsumer.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019 LinuxServer.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package io.linuxserver.fleet.queue;
+
+public interface QueueConsumer> {
+
+ void consume();
+}
diff --git a/src/main/java/io/linuxserver/fleet/queue/RequestQueue.java b/src/main/java/io/linuxserver/fleet/queue/RequestQueue.java
new file mode 100644
index 0000000..14c4ba0
--- /dev/null
+++ b/src/main/java/io/linuxserver/fleet/queue/RequestQueue.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019 LinuxServer.io
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package io.linuxserver.fleet.queue;
+
+public interface RequestQueue {
+
+ void enqueueRequest(T request);
+
+ T takeOneRequest();
+}
diff --git a/src/main/java/io/linuxserver/fleet/sync/DefaultSynchronisationState.java b/src/main/java/io/linuxserver/fleet/sync/DefaultSynchronisationState.java
index 6c713b0..ab05aa8 100644
--- a/src/main/java/io/linuxserver/fleet/sync/DefaultSynchronisationState.java
+++ b/src/main/java/io/linuxserver/fleet/sync/DefaultSynchronisationState.java
@@ -137,7 +137,7 @@ public class DefaultSynchronisationState implements SynchronisationState {
try {
DockerImage dockerImage = images.get(i);
- Image image = configureImage(repository.getId(), dockerImage, context);
+ Image image = configureImage(repository, dockerImage, context);
String versionMask = getVersionMask(repository.getVersionMask(), image.getVersionMask());
Tag maskedVersion = getLatestTagAndCreateMaskedVersion(repository.getName(), image.getName(), versionMask, context);
@@ -230,15 +230,15 @@ public class DefaultSynchronisationState implements SynchronisationState {
* Looks up the image in the database to see if it already exists. If it does, it gets returned, otherwise a base
* image is created with just the top-level information, as the rest will get updated later.
*/
- private Image configureImage(int repositoryId, DockerImage dockerHubImage, SynchronisationContext context) {
+ private Image configureImage(Repository repository, DockerImage dockerHubImage, SynchronisationContext context) {
- Image image = context.getImageDelegate().findImageByRepositoryAndImageName(repositoryId, dockerHubImage.getName());
+ Image image = context.getImageDelegate().findImageByRepositoryAndImageName(repository.getId(), dockerHubImage.getName());
if (isImageNew(image)) {
try {
- return context.getImageDelegate().saveImage(new Image(repositoryId, dockerHubImage.getName()));
+ return context.getImageDelegate().saveImage(new Image(repository, dockerHubImage.getName()));
} catch (SaveException e) {
LOGGER.error("Tried to save new image during sync but failed", e);
diff --git a/src/main/resources/db/migration/V1.10__UpdateImageViewWithRepository.sql b/src/main/resources/db/migration/V1.10__UpdateImageViewWithRepository.sql
new file mode 100644
index 0000000..4969880
--- /dev/null
+++ b/src/main/resources/db/migration/V1.10__UpdateImageViewWithRepository.sql
@@ -0,0 +1,24 @@
+DELIMITER //
+
+CREATE OR REPLACE VIEW `Image_View` AS (
+
+ SELECT
+ images.`id` AS `ImageId`,
+ images.`repository` AS `RepositoryId`,
+ repositories.`name` AS `RepositoryName`,
+ images.`name` AS `ImageName`,
+ images.`pulls` AS `ImagePullCount`,
+ images.`latest_version` AS `LatestTagVersion`,
+ images.`latest_version_raw` AS `LatestMaskedTagVersion`,
+ images.`latest_version_buildtime` AS `LatestTagBuildDate`,
+ images.`version_mask` AS `ImageVersionMask`,
+ images.`hidden` AS `ImageHidden`,
+ images.`unstable` AS `ImageUnstable`,
+ images.`deprecated` AS `ImageDeprecated`,
+ images.`deprecation_reason` AS `ImageDeprecationReason`,
+ images.`modified` AS `ModifiedTime`
+ FROM
+ Images images
+ JOIN Repositories repositories ON repositories.`id` = images.`repository`
+);
+//
\ No newline at end of file