mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-22 16:41:46 +03:00
[FEATURE] UpdatesProvider Part 1
This commit is contained in:
parent
a687c5afd8
commit
b8ccbc5e48
6 changed files with 232 additions and 90 deletions
|
@ -70,6 +70,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
|||
/**
|
||||
* The path to the folder with updates/webroot
|
||||
*/
|
||||
@Deprecated
|
||||
public final Path updatesDir;
|
||||
|
||||
// Constant paths
|
||||
|
@ -359,9 +360,7 @@ public void run() {
|
|||
syncProfilesDir();
|
||||
|
||||
// Sync updates dir
|
||||
if (!IOHelper.isDir(updatesDir))
|
||||
Files.createDirectory(updatesDir);
|
||||
updatesManager.readUpdatesDir();
|
||||
config.updatesProvider.syncInitially();
|
||||
|
||||
|
||||
modulesManager.invokeEvent(new LaunchServerProfilesSyncEvent(this));
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
package pro.gravit.launchserver.auth.updates;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.core.hasher.HashedDir;
|
||||
import pro.gravit.launcher.core.serialize.HInput;
|
||||
import pro.gravit.launcher.core.serialize.HOutput;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.modules.events.LaunchServerUpdatesSyncEvent;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class LocalUpdatesProvider extends UpdatesProvider {
|
||||
private final transient Logger logger = LogManager.getLogger();
|
||||
public String cacheFile = ".updates-cache";
|
||||
public String updatesDir = "updates";
|
||||
public boolean cacheUpdates = true;
|
||||
private volatile transient Map<String, HashedDir> updatesDirMap;
|
||||
|
||||
private void writeCache(Path file) throws IOException {
|
||||
try (HOutput output = new HOutput(IOHelper.newOutput(file))) {
|
||||
output.writeLength(updatesDirMap.size(), 0);
|
||||
for (Map.Entry<String, HashedDir> entry : updatesDirMap.entrySet()) {
|
||||
output.writeString(entry.getKey(), 0);
|
||||
entry.getValue().write(output);
|
||||
}
|
||||
}
|
||||
logger.debug("Saved {} updates to cache", updatesDirMap.size());
|
||||
}
|
||||
|
||||
private void readCache(Path file) throws IOException {
|
||||
Map<String, HashedDir> updatesDirMap = new HashMap<>(16);
|
||||
try (HInput input = new HInput(IOHelper.newInput(file))) {
|
||||
int size = input.readLength(0);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
String name = input.readString(0);
|
||||
HashedDir dir = new HashedDir(input);
|
||||
updatesDirMap.put(name, dir);
|
||||
}
|
||||
}
|
||||
logger.debug("Found {} updates from cache", updatesDirMap.size());
|
||||
this.updatesDirMap = Collections.unmodifiableMap(updatesDirMap);
|
||||
}
|
||||
|
||||
public void readUpdatesFromCache() throws IOException {
|
||||
readCache(Path.of(cacheFile));
|
||||
}
|
||||
|
||||
public void readUpdatesDir() throws IOException {
|
||||
var cacheFilePath = Path.of(cacheFile);
|
||||
if (cacheUpdates) {
|
||||
if (Files.exists(cacheFilePath)) {
|
||||
try {
|
||||
readCache(cacheFilePath);
|
||||
return;
|
||||
} catch (Throwable e) {
|
||||
logger.error("Read updates cache failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
sync(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer server) {
|
||||
super.init(server);
|
||||
try {
|
||||
if (!IOHelper.isDir(Path.of(updatesDir)))
|
||||
Files.createDirectory(Path.of(updatesDir));
|
||||
} catch (IOException e) {
|
||||
logger.error("Updates not synced", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncInitially() throws IOException {
|
||||
readUpdatesDir();
|
||||
}
|
||||
|
||||
public void sync(Collection<String> dirs) throws IOException {
|
||||
logger.info("Syncing updates dir");
|
||||
Map<String, HashedDir> newUpdatesDirMap = new HashMap<>(16);
|
||||
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(Path.of(updatesDir))) {
|
||||
for (final Path updateDir : dirStream) {
|
||||
if (Files.isHidden(updateDir))
|
||||
continue; // Skip hidden
|
||||
|
||||
// Resolve name and verify is dir
|
||||
String name = IOHelper.getFileName(updateDir);
|
||||
if (!IOHelper.isDir(updateDir)) {
|
||||
if (!IOHelper.isFile(updateDir) && Stream.of(".jar", ".exe", ".hash").noneMatch(e -> updateDir.toString().endsWith(e)))
|
||||
logger.warn("Not update dir: '{}'", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add from previous map (it's guaranteed to be non-null)
|
||||
if (dirs != null && !dirs.contains(name)) {
|
||||
HashedDir hdir = updatesDirMap.get(name);
|
||||
if (hdir != null) {
|
||||
newUpdatesDirMap.put(name, hdir);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Sync and sign update dir
|
||||
logger.info("Syncing '{}' update dir", name);
|
||||
HashedDir updateHDir = new HashedDir(updateDir, null, true, true);
|
||||
newUpdatesDirMap.put(name, updateHDir);
|
||||
}
|
||||
}
|
||||
updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
|
||||
if (cacheUpdates) {
|
||||
try {
|
||||
writeCache(Path.of(cacheFile));
|
||||
} catch (Throwable e) {
|
||||
logger.error("Write updates cache failed", e);
|
||||
}
|
||||
}
|
||||
server.modulesManager.invokeEvent(new LaunchServerUpdatesSyncEvent(server));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashedDir getUpdatesDir(String updateName) {
|
||||
return updatesDirMap.get(updateName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(String updateName, Map<String, Path> files, boolean deleteAfterUpload) throws IOException {
|
||||
var path = Path.of(updatesDir).resolve(updateName);
|
||||
for(var e : files.entrySet()) {
|
||||
var target = path.resolve(e.getKey());
|
||||
var source = Path.of(e.getKey());
|
||||
IOHelper.createParentDirs(target);
|
||||
if(deleteAfterUpload) {
|
||||
Files.move(source, target);
|
||||
} else {
|
||||
Files.copy(source, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String updateName, List<String> files) throws IOException {
|
||||
var path = Path.of(updatesDir).resolve(updateName);
|
||||
for(var e : files) {
|
||||
var target = path.resolve(e);
|
||||
Files.delete(target);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String updateName) throws IOException {
|
||||
var path = Path.of(updatesDir).resolve(updateName);
|
||||
IOHelper.deleteDir(path, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create(String updateName) throws IOException {
|
||||
var path = Path.of(updatesDir).resolve(updateName);
|
||||
Files.createDirectories(path);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package pro.gravit.launchserver.auth.updates;
|
||||
|
||||
import pro.gravit.launcher.core.hasher.HashedDir;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.utils.ProviderMap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class UpdatesProvider {
|
||||
public static final ProviderMap<UpdatesProvider> providers = new ProviderMap<>("UpdatesProvider");
|
||||
private static boolean registredProviders = false;
|
||||
protected transient LaunchServer server;
|
||||
|
||||
public static void registerProviders() {
|
||||
if (!registredProviders) {
|
||||
registredProviders = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void init(LaunchServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void sync() throws IOException {
|
||||
sync(null);
|
||||
}
|
||||
|
||||
public abstract void syncInitially() throws IOException;
|
||||
|
||||
public abstract void sync(Collection<String> updateNames) throws IOException;
|
||||
|
||||
public abstract HashedDir getUpdatesDir(String updateName);
|
||||
|
||||
public abstract void upload(String updateName, Map<String, Path> files, boolean deleteAfterUpload) throws IOException;
|
||||
|
||||
public abstract void delete(String updateName, List<String> files) throws IOException;
|
||||
|
||||
public abstract void delete(String updateName) throws IOException;
|
||||
|
||||
public abstract void create(String updateName) throws IOException;
|
||||
}
|
|
@ -14,6 +14,8 @@
|
|||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
||||
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
||||
import pro.gravit.launchserver.auth.updates.LocalUpdatesProvider;
|
||||
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
||||
import pro.gravit.launchserver.components.AuthLimiterComponent;
|
||||
import pro.gravit.launchserver.components.Component;
|
||||
import pro.gravit.launchserver.components.ProGuardComponent;
|
||||
|
@ -32,13 +34,13 @@ public final class LaunchServerConfig {
|
|||
public String[] mirrors;
|
||||
public String binaryName;
|
||||
public boolean copyBinaries = true;
|
||||
public boolean cacheUpdates = true;
|
||||
public LauncherConfig.LauncherEnvironment env;
|
||||
public Map<String, AuthProviderPair> auth;
|
||||
// Handlers & Providers
|
||||
public ProtectHandler protectHandler;
|
||||
public Map<String, Component> components;
|
||||
public ProfileProvider profileProvider = new LocalProfileProvider();
|
||||
public UpdatesProvider updatesProvider = new LocalUpdatesProvider();
|
||||
public NettyConfig netty;
|
||||
public LauncherConf launcher;
|
||||
public JarSignerConf sign;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
||||
import pro.gravit.launchserver.components.Component;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.launchserver.socket.WebSocketService;
|
||||
|
@ -48,6 +49,7 @@ public void registerAdapters(GsonBuilder builder) {
|
|||
builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers));
|
||||
builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers));
|
||||
builder.registerTypeAdapter(ProfileProvider.class, new UniversalJsonAdapter<>(ProfileProvider.providers));
|
||||
builder.registerTypeAdapter(UpdatesProvider.class, new UniversalJsonAdapter<>(UpdatesProvider.providers));
|
||||
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
||||
//ClientWebSocketService.appendTypeAdapters(builder);
|
||||
}
|
||||
|
|
|
@ -18,112 +18,38 @@
|
|||
|
||||
public class UpdatesManager {
|
||||
private final LaunchServer server;
|
||||
private final Logger logger = LogManager.getLogger();
|
||||
private final Path cacheFile;
|
||||
private volatile Map<String, HashedDir> updatesDirMap;
|
||||
|
||||
public UpdatesManager(LaunchServer server) {
|
||||
this.server = server;
|
||||
this.cacheFile = server.dir.resolve(".updates-cache");
|
||||
}
|
||||
|
||||
private void writeCache(Path file) throws IOException {
|
||||
try (HOutput output = new HOutput(IOHelper.newOutput(file))) {
|
||||
output.writeLength(updatesDirMap.size(), 0);
|
||||
for (Map.Entry<String, HashedDir> entry : updatesDirMap.entrySet()) {
|
||||
output.writeString(entry.getKey(), 0);
|
||||
entry.getValue().write(output);
|
||||
}
|
||||
}
|
||||
logger.debug("Saved {} updates to cache", updatesDirMap.size());
|
||||
}
|
||||
|
||||
private void readCache(Path file) throws IOException {
|
||||
Map<String, HashedDir> updatesDirMap = new HashMap<>(16);
|
||||
try (HInput input = new HInput(IOHelper.newInput(file))) {
|
||||
int size = input.readLength(0);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
String name = input.readString(0);
|
||||
HashedDir dir = new HashedDir(input);
|
||||
updatesDirMap.put(name, dir);
|
||||
}
|
||||
}
|
||||
logger.debug("Found {} updates from cache", updatesDirMap.size());
|
||||
this.updatesDirMap = Collections.unmodifiableMap(updatesDirMap);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void readUpdatesFromCache() throws IOException {
|
||||
readCache(cacheFile);
|
||||
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void readUpdatesDir() throws IOException {
|
||||
if (server.config.cacheUpdates) {
|
||||
if (Files.exists(cacheFile)) {
|
||||
try {
|
||||
readCache(cacheFile);
|
||||
return;
|
||||
} catch (Throwable e) {
|
||||
logger.error("Read updates cache failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
syncUpdatesDir(null);
|
||||
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
||||
logger.info("Syncing updates dir");
|
||||
Map<String, HashedDir> newUpdatesDirMap = new HashMap<>(16);
|
||||
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(server.updatesDir)) {
|
||||
for (final Path updateDir : dirStream) {
|
||||
if (Files.isHidden(updateDir))
|
||||
continue; // Skip hidden
|
||||
|
||||
// Resolve name and verify is dir
|
||||
String name = IOHelper.getFileName(updateDir);
|
||||
if (!IOHelper.isDir(updateDir)) {
|
||||
if (!IOHelper.isFile(updateDir) && Stream.of(".jar", ".exe", ".hash").noneMatch(e -> updateDir.toString().endsWith(e)))
|
||||
logger.warn("Not update dir: '{}'", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add from previous map (it's guaranteed to be non-null)
|
||||
if (dirs != null && !dirs.contains(name)) {
|
||||
HashedDir hdir = updatesDirMap.get(name);
|
||||
if (hdir != null) {
|
||||
newUpdatesDirMap.put(name, hdir);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Sync and sign update dir
|
||||
logger.info("Syncing '{}' update dir", name);
|
||||
HashedDir updateHDir = new HashedDir(updateDir, null, true, true);
|
||||
newUpdatesDirMap.put(name, updateHDir);
|
||||
}
|
||||
}
|
||||
updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
|
||||
if (server.config.cacheUpdates) {
|
||||
try {
|
||||
writeCache(cacheFile);
|
||||
} catch (Throwable e) {
|
||||
logger.error("Write updates cache failed", e);
|
||||
}
|
||||
}
|
||||
server.modulesManager.invokeEvent(new LaunchServerUpdatesSyncEvent(server));
|
||||
server.config.updatesProvider.sync(dirs);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public HashSet<String> getUpdatesList() {
|
||||
HashSet<String> set = new HashSet<>();
|
||||
for (Map.Entry<String, HashedDir> entry : updatesDirMap.entrySet())
|
||||
set.add(entry.getKey());
|
||||
return set;
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public HashedDir getUpdate(String name) {
|
||||
return updatesDirMap.get(name);
|
||||
return server.config.updatesProvider.getUpdatesDir(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void addUpdate(String name, HashedDir dir) {
|
||||
updatesDirMap.put(name, dir);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue