/*
* This file is part of Technic Launcher Core.
* Copyright ©2015 Syndicate, LLC
*
* Technic Launcher Core is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Technic Launcher Core 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,
* as well as a copy of the GNU Lesser General Public License,
* along with Technic Launcher Core. If not, see <http://www.gnu.org/licenses/>.
*/
package net.technicpack.solder.cache;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.gson.JsonSyntaxException;
import net.technicpack.launchercore.exception.BuildInaccessibleException;
import net.technicpack.launchercore.install.LauncherDirectories;
import net.technicpack.rest.RestfulAPIException;
import net.technicpack.rest.io.Modpack;
import net.technicpack.solder.ISolderPackApi;
import net.technicpack.solder.io.SolderPackInfo;
import net.technicpack.utilslib.Utils;
import org.apache.commons.io.FileUtils;
import org.joda.time.DateTime;
import org.joda.time.Seconds;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
public class CachedSolderPackApi implements ISolderPackApi {
private LauncherDirectories directories;
private ISolderPackApi innerApi;
private int cacheInSeconds;
private String packSlug;
private SolderPackInfo rootInfoCache = null;
private DateTime lastInfoAccess = new DateTime(0);
private Cache<String, Modpack> buildCache;
private Cache<String, Boolean> deadBuildCache;
public CachedSolderPackApi(LauncherDirectories directories, ISolderPackApi innerApi, int cacheInSeconds, String packSlug) {
this.directories = directories;
this.innerApi = innerApi;
this.cacheInSeconds = cacheInSeconds;
this.packSlug = packSlug;
buildCache = CacheBuilder.newBuilder()
.concurrencyLevel(4)
.maximumSize(300)
.expireAfterWrite(cacheInSeconds, TimeUnit.SECONDS)
.build();
deadBuildCache = CacheBuilder.newBuilder()
.concurrencyLevel(4)
.maximumSize(300)
.expireAfterWrite(cacheInSeconds / 10, TimeUnit.SECONDS)
.build();
}
@Override
public String getMirrorUrl() {
return innerApi.getMirrorUrl();
}
@Override
public SolderPackInfo getPackInfoForBulk() throws RestfulAPIException {
if (rootInfoCache != null)
return rootInfoCache;
loadForeverCache();
if (rootInfoCache != null)
return rootInfoCache;
return pullAndCache();
}
@Override
public SolderPackInfo getPackInfo() throws RestfulAPIException {
if (Seconds.secondsBetween(lastInfoAccess, DateTime.now()).isLessThan(Seconds.seconds(cacheInSeconds))) {
if (rootInfoCache != null)
return rootInfoCache;
}
if (Seconds.secondsBetween(lastInfoAccess, DateTime.now()).isLessThan(Seconds.seconds(cacheInSeconds / 10)))
return rootInfoCache;
try {
return pullAndCache();
} catch (RestfulAPIException ex) {
ex.printStackTrace();
return getPackInfoForBulk();
}
}
private SolderPackInfo pullAndCache() throws RestfulAPIException {
try {
rootInfoCache = innerApi.getPackInfoForBulk();
saveForeverCache(rootInfoCache);
return rootInfoCache;
} finally {
lastInfoAccess = DateTime.now();
}
}
private void loadForeverCache() {
File cacheFile = new File(new File(new File(directories.getAssetsDirectory(), "packs"), packSlug), "soldercache.json");
if (!cacheFile.exists())
return;
try {
String packCache = FileUtils.readFileToString(cacheFile, Charset.forName("UTF-8"));
rootInfoCache = Utils.getGson().fromJson(packCache, SolderPackInfo.class);
if (rootInfoCache != null)
rootInfoCache.setLocal();
} catch (IOException ex) {
} catch (JsonSyntaxException ex) {
}
}
private void saveForeverCache(SolderPackInfo info) {
File cacheFile = new File(new File(new File(directories.getAssetsDirectory(), "packs"), info.getName()), "soldercache.json");
String packCache = Utils.getGson().toJson(info);
try {
FileUtils.writeStringToFile(cacheFile, packCache, Charset.forName("UTF-8"));
} catch (IOException e) {
return;
}
}
@Override
public Modpack getPackBuild(String build) throws BuildInaccessibleException {
Boolean isDead = deadBuildCache.getIfPresent(build);
if (isDead != null && isDead.booleanValue())
return null;
Modpack modpack = buildCache.getIfPresent(build);
if (modpack != null) {
return modpack;
}
try {
modpack = innerApi.getPackBuild(build);
if (modpack != null) {
buildCache.put(build, modpack);
}
return modpack;
} finally {
deadBuildCache.put(build, modpack == null);
}
}
}