From ff05b8284e6e415b13d3543650075d0f7cd27ff5 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sun, 26 Nov 2017 14:30:32 +0100 Subject: [PATCH] Improve temporary cache system --- src/be/nikiroo/fanfix/Main.java | 12 +- .../nikiroo/fanfix/library/BasicLibrary.java | 19 +- .../nikiroo/fanfix/library/CacheLibrary.java | 202 ++++++++++++++++++ .../nikiroo/fanfix/library/LocalLibrary.java | 26 +-- .../nikiroo/fanfix/library/RemoteLibrary.java | 150 +++++-------- src/be/nikiroo/fanfix/reader/BasicReader.java | 2 +- src/be/nikiroo/fanfix/reader/GuiReader.java | 73 +++---- 7 files changed, 318 insertions(+), 166 deletions(-) create mode 100644 src/be/nikiroo/fanfix/library/CacheLibrary.java diff --git a/src/be/nikiroo/fanfix/Main.java b/src/be/nikiroo/fanfix/Main.java index c17a1d8b..69a7a7c3 100644 --- a/src/be/nikiroo/fanfix/Main.java +++ b/src/be/nikiroo/fanfix/Main.java @@ -5,9 +5,12 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import be.nikiroo.fanfix.bundles.Config; import be.nikiroo.fanfix.bundles.StringId; import be.nikiroo.fanfix.data.Chapter; import be.nikiroo.fanfix.data.Story; +import be.nikiroo.fanfix.library.BasicLibrary; +import be.nikiroo.fanfix.library.CacheLibrary; import be.nikiroo.fanfix.library.LocalLibrary; import be.nikiroo.fanfix.library.RemoteLibrary; import be.nikiroo.fanfix.library.RemoteLibraryServer; @@ -185,8 +188,13 @@ public class Main { host = args[i]; } else if (port == null) { port = Integer.parseInt(args[i]); - BasicReader - .setDefaultLibrary(new RemoteLibrary(host, port)); + + File remoteCacheDir = Instance.getRemoteDir(host); + BasicLibrary lib = new RemoteLibrary(host, port); + lib = new CacheLibrary(remoteCacheDir, lib); + + BasicReader.setDefaultLibrary(lib); + action = MainAction.START; } else { exitCode = 255; diff --git a/src/be/nikiroo/fanfix/library/BasicLibrary.java b/src/be/nikiroo/fanfix/library/BasicLibrary.java index 328ef656..b11e1ec5 100644 --- a/src/be/nikiroo/fanfix/library/BasicLibrary.java +++ b/src/be/nikiroo/fanfix/library/BasicLibrary.java @@ -48,10 +48,12 @@ abstract public class BasicLibrary { * * @param luid * the Library UID of the story + * @param pg + * the optional {@link Progress} * * @return the corresponding {@link Story} */ - public abstract File getFile(String luid); + public abstract File getFile(String luid, Progress pg); /** * Return the cover image associated to this story. @@ -294,21 +296,29 @@ abstract public class BasicLibrary { * @return the corresponding {@link Story} or NULL if not found */ public synchronized Story getStory(String luid, Progress pg) { - // TODO: pg if (pg == null) { pg = new Progress(); } + Progress pgGet = new Progress(); + Progress pgProcess = new Progress(); + + pg.setMinMax(0, 2); + pg.addProgress(pgGet, 1); + pg.addProgress(pgProcess, 1); + Story story = null; for (MetaData meta : getMetas(null)) { if (meta.getLuid().equals(luid)) { - File file = getFile(luid); + File file = getFile(luid, pgGet); + pgGet.done(); try { SupportType type = SupportType.valueOfAllOkUC(meta .getType()); URL url = file.toURI().toURL(); if (type != null) { - story = BasicSupport.getSupport(type).process(url, pg); + story = BasicSupport.getSupport(type).process(url, + pgProcess); } else { throw new IOException("Unknown type: " + meta.getType()); } @@ -318,6 +328,7 @@ abstract public class BasicLibrary { Instance.syserr(new IOException( "Cannot load file from library: " + file, e)); } finally { + pgProcess.done(); pg.done(); } diff --git a/src/be/nikiroo/fanfix/library/CacheLibrary.java b/src/be/nikiroo/fanfix/library/CacheLibrary.java new file mode 100644 index 00000000..40128979 --- /dev/null +++ b/src/be/nikiroo/fanfix/library/CacheLibrary.java @@ -0,0 +1,202 @@ +package be.nikiroo.fanfix.library; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.List; + +import be.nikiroo.fanfix.Instance; +import be.nikiroo.fanfix.bundles.UiConfig; +import be.nikiroo.fanfix.data.MetaData; +import be.nikiroo.fanfix.data.Story; +import be.nikiroo.utils.Progress; + +/** + * This library will cache another pre-existing {@link BasicLibrary}. + * + * @author niki + */ +public class CacheLibrary extends BasicLibrary { + private List metas; + private BasicLibrary lib; + private LocalLibrary cacheLib; + + /** + * Create a cache library around the given one. + *

+ * It will return the same result, but those will be saved to disk at the + * same time to be fetched quicker the next time. + * + * @param cacheDir + * the cache directory where to save the files to disk + * @param lib + * the original library to wrap + */ + public CacheLibrary(File cacheDir, BasicLibrary lib) { + this.cacheLib = new LocalLibrary(cacheDir, Instance.getUiConfig() + .getString(UiConfig.GUI_NON_IMAGES_DOCUMENT_TYPE), Instance + .getUiConfig().getString(UiConfig.GUI_IMAGES_DOCUMENT_TYPE), + true); + this.lib = lib; + } + + @Override + public String getLibraryName() { + return lib.getLibraryName(); + } + + @Override + protected List getMetas(Progress pg) { + if (pg == null) { + pg = new Progress(); + } + + if (metas == null) { + metas = lib.getMetas(pg); + } + + pg.done(); + return metas; + } + + @Override + public synchronized File getFile(final String luid, Progress pg) { + if (pg == null) { + pg = new Progress(); + } + + Progress pgImport = new Progress(); + Progress pgGet = new Progress(); + Progress pgRecall = new Progress(); + + pg.setMinMax(0, 5); + pg.addProgress(pgImport, 3); + pg.addProgress(pgGet, 1); + pg.addProgress(pgRecall, 1); + + if (!isCached(luid)) { + try { + cacheLib.imprt(lib, luid, pgImport); + pgImport.done(); + Story story = cacheLib.getStory(luid, pgGet); + metas.remove(story.getMeta()); + metas.add(story.getMeta()); + } catch (IOException e) { + Instance.syserr(e); + } + + pgImport.done(); + pgGet.done(); + } + + File file = cacheLib.getFile(luid, pgRecall); + pgRecall.done(); + + pg.done(); + return file; + } + + @Override + public BufferedImage getCover(final String luid) { + // Retrieve it from the cache if possible: + if (isCached(luid)) { + return cacheLib.getCover(luid); + } + + return lib.getCover(luid); + } + + @Override + protected void clearCache() { + metas = null; + cacheLib.clearCache(); + lib.clearCache(); + } + + @Override + public synchronized Story save(Story story, String luid, Progress pg) + throws IOException { + story = lib.save(story, luid, pg); + clearCache(); + return story; + } + + @Override + public synchronized void delete(String luid) throws IOException { + cacheLib.delete(luid); + lib.delete(luid); + clearCache(); + } + + @Override + public void setSourceCover(String source, String luid) { + cacheLib.setSourceCover(source, luid); + lib.setSourceCover(source, luid); + } + + @Override + public synchronized void changeSource(String luid, String newSource, + Progress pg) throws IOException { + if (pg == null) { + pg = new Progress(); + } + + Progress pgCache = new Progress(); + Progress pgOrig = new Progress(); + pg.setMinMax(0, 2); + pg.addProgress(pgCache, 1); + pg.addProgress(pgOrig, 1); + + cacheLib.changeSource(luid, newSource, pgCache); + pgCache.done(); + lib.changeSource(luid, newSource, pgOrig); + pgOrig.done(); + + pg.done(); + } + + /** + * Check if the {@link Story} denoted by this Library UID is present in the + * cache. + * + * @param luid + * the Library UID + * + * @return TRUE if it is + */ + public boolean isCached(String luid) { + return cacheLib.getInfo(luid) != null; + } + + /** + * Clear the {@link Story} from the cache. + * + * @param luid + * the story to clear + * + * @throws IOException + * in case of I/O error + */ + public void clearFromCache(String luid) throws IOException { + cacheLib.delete(luid); + clearCache(); + } + + // All the following methods are only used by Save and Delete in + // BasicLibrary: + + @Override + protected int getNextId() { + throw new java.lang.InternalError("Should not have been called"); + } + + @Override + protected void doDelete(String luid) throws IOException { + throw new java.lang.InternalError("Should not have been called"); + } + + @Override + protected Story doSave(Story story, Progress pg) throws IOException { + throw new java.lang.InternalError("Should not have been called"); + } +} diff --git a/src/be/nikiroo/fanfix/library/LocalLibrary.java b/src/be/nikiroo/fanfix/library/LocalLibrary.java index d811d2b2..f9350efc 100644 --- a/src/be/nikiroo/fanfix/library/LocalLibrary.java +++ b/src/be/nikiroo/fanfix/library/LocalLibrary.java @@ -57,12 +57,19 @@ public class LocalLibrary extends BasicLibrary { * * @param baseDir * the directory where to find the {@link Story} objects + * @param text + * the {@link OutputType} to use for non-image documents + * @param image + * the {@link OutputType} to use for image documents + * @param defaultIsHtml + * if the given text or image is invalid, use HTML by default (if + * not, it will be INFO_TEXT/CBZ by default) */ public LocalLibrary(File baseDir, String text, String image, boolean defaultIsHtml) { - this(baseDir, OutputType.valueOfNullOkUC(text, + this(baseDir, OutputType.valueOfAllOkUC(text, defaultIsHtml ? OutputType.HTML : OutputType.INFO_TEXT), - OutputType.valueOfNullOkUC(image, + OutputType.valueOfAllOkUC(image, defaultIsHtml ? OutputType.HTML : OutputType.CBZ)); } @@ -94,8 +101,8 @@ public class LocalLibrary extends BasicLibrary { } @Override - public File getFile(String luid) { - File[] files = getStories(null).get(getInfo(luid)); + public File getFile(String luid, Progress pg) { + File[] files = getStories(pg).get(getInfo(luid)); if (files != null) { return files[1]; } @@ -214,17 +221,10 @@ public class LocalLibrary extends BasicLibrary { pg = new Progress(); } - LocalLibrary otherLocalLibrary = null; - if (other instanceof RemoteLibrary) { - otherLocalLibrary = ((RemoteLibrary) other).getLocalLibrary(); - } - + // Check if we can simply copy the files instead of the whole process if (other instanceof LocalLibrary) { - otherLocalLibrary = (LocalLibrary) other; - } + LocalLibrary otherLocalLibrary = (LocalLibrary) other; - // Check if we can simply copy the files instead of the whole process - if (otherLocalLibrary != null) { MetaData meta = otherLocalLibrary.getInfo(luid); String expectedType = "" + (meta != null && meta.isImageDocument() ? image : text); diff --git a/src/be/nikiroo/fanfix/library/RemoteLibrary.java b/src/be/nikiroo/fanfix/library/RemoteLibrary.java index 63082ce9..27a02804 100644 --- a/src/be/nikiroo/fanfix/library/RemoteLibrary.java +++ b/src/be/nikiroo/fanfix/library/RemoteLibrary.java @@ -23,10 +23,6 @@ import be.nikiroo.utils.serial.ConnectActionClient; public class RemoteLibrary extends BasicLibrary { private String host; private int port; - private File baseDir; - - private LocalLibrary lib; - private List metas; /** * Create a {@link RemoteLibrary} linked to the given server. @@ -39,11 +35,6 @@ public class RemoteLibrary extends BasicLibrary { public RemoteLibrary(String host, int port) { this.host = host; this.port = port; - - this.baseDir = Instance.getRemoteDir(host); - this.baseDir.mkdirs(); - - this.lib = new LocalLibrary(baseDir); } @Override @@ -54,34 +45,13 @@ public class RemoteLibrary extends BasicLibrary { @Override protected List getMetas(Progress pg) { // TODO: progress + final List metas = new ArrayList(); + MetaData[] fromNetwork = this + . getRemoteObject("GET_METADATA *"); - if (metas == null) { - metas = new ArrayList(); - - try { - new ConnectActionClient(host, port, true) { - @Override - public void action(Version serverVersion) throws Exception { - try { - Object rep = send("GET_METADATA *"); - for (MetaData meta : (MetaData[]) rep) { - metas.add(meta); - } - } catch (Exception e) { - Instance.syserr(e); - } - } - }.connect(); - } catch (IOException e) { - Instance.syserr(e); - } - - List test = new ArrayList(); - for (MetaData meta : metas) { - if (test.contains(meta.getLuid())) { - throw new RuntimeException("wwops"); - } - test.add(meta.getLuid()); + if (fromNetwork != null) { + for (MetaData meta : fromNetwork) { + metas.add(meta); } } @@ -89,72 +59,17 @@ public class RemoteLibrary extends BasicLibrary { } @Override - public synchronized File getFile(final String luid) { - File file = lib.getFile(luid); - if (file == null) { - final File[] tmp = new File[1]; - try { - new ConnectActionClient(host, port, true) { - @Override - public void action(Version serverVersion) throws Exception { - try { - Object rep = send("GET_STORY " + luid); - Story story = (Story) rep; - if (story != null) { - lib.save(story, luid, null); - tmp[0] = lib.getFile(luid); - } - } catch (Exception e) { - Instance.syserr(e); - } - } - }.connect(); - } catch (IOException e) { - Instance.syserr(e); - } - - file = tmp[0]; - } - - if (file != null) { - MetaData meta = getInfo(luid); - metas.add(meta); - } - - return file; + public BufferedImage getCover(final String luid) { + return this. getRemoteObject("GET_COVER " + luid); } @Override - public BufferedImage getCover(final String luid) { - // Retrieve it from the cache if possible: - if (lib.getInfo(luid) != null) { - return lib.getCover(luid); - } - - final BufferedImage[] result = new BufferedImage[1]; - try { - new ConnectActionClient(host, port, true) { - @Override - public void action(Version serverVersion) throws Exception { - try { - Object rep = send("GET_COVER " + luid); - result[0] = (BufferedImage) rep; - } catch (Exception e) { - Instance.syserr(e); - } - } - }.connect(); - } catch (IOException e) { - Instance.syserr(e); - } - - return result[0]; + public synchronized Story getStory(final String luid, Progress pg) { + return this. getRemoteObject("GET_STORY " + luid); } @Override protected void clearCache() { - metas = null; - lib.clearCache(); } @Override @@ -176,8 +91,13 @@ public class RemoteLibrary extends BasicLibrary { "No write support allowed on remote Libraries"); } - // All the following methods are only used by Save and Delete in - // BasicLibrary: + @Override + public synchronized File getFile(final String luid) { + throw new java.lang.InternalError( + "Operation not supportorted on remote Libraries"); + } + + // The following methods are only used by Save and Delete in BasicLibrary: @Override protected int getNextId() { @@ -195,11 +115,39 @@ public class RemoteLibrary extends BasicLibrary { } /** - * Return the backing local library. + * Return an object from the server. + * + * @param + * the expected type of object + * @param command + * the command to send * - * @return the library + * @return the object or NULL */ - LocalLibrary getLocalLibrary() { - return lib; + @SuppressWarnings("unchecked") + private T getRemoteObject(final String command) { + final Object[] result = new Object[1]; + try { + new ConnectActionClient(host, port, true) { + @Override + public void action(Version serverVersion) throws Exception { + try { + Object rep = send(command); + result[0] = rep; + } catch (Exception e) { + Instance.syserr(e); + } + } + }.connect(); + } catch (IOException e) { + Instance.syserr(e); + } + + try { + return (T) result[0]; + } catch (Exception e) { + Instance.syserr(e); + return null; + } } } diff --git a/src/be/nikiroo/fanfix/reader/BasicReader.java b/src/be/nikiroo/fanfix/reader/BasicReader.java index a261c04b..eef3aef5 100644 --- a/src/be/nikiroo/fanfix/reader/BasicReader.java +++ b/src/be/nikiroo/fanfix/reader/BasicReader.java @@ -215,7 +215,7 @@ public abstract class BasicReader implements Reader { public static void openExternal(BasicLibrary lib, String luid) throws IOException { MetaData meta = lib.getInfo(luid); - File target = lib.getFile(luid); + File target = lib.getFile(luid, null); openExternal(meta, target); } diff --git a/src/be/nikiroo/fanfix/reader/GuiReader.java b/src/be/nikiroo/fanfix/reader/GuiReader.java index 410e05e5..8ff9d920 100644 --- a/src/be/nikiroo/fanfix/reader/GuiReader.java +++ b/src/be/nikiroo/fanfix/reader/GuiReader.java @@ -14,9 +14,10 @@ import javax.swing.event.HyperlinkListener; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.VersionCheck; -import be.nikiroo.fanfix.bundles.UiConfig; import be.nikiroo.fanfix.data.MetaData; import be.nikiroo.fanfix.data.Story; +import be.nikiroo.fanfix.library.BasicLibrary; +import be.nikiroo.fanfix.library.CacheLibrary; import be.nikiroo.fanfix.library.LocalLibrary; import be.nikiroo.utils.Progress; import be.nikiroo.utils.Version; @@ -25,7 +26,9 @@ import be.nikiroo.utils.ui.UIUtils; class GuiReader extends BasicReader { static private boolean nativeLookLoaded; - private LocalLibrary localLibrary; + private CacheLibrary cacheLib; + + private File cacheDir; public GuiReader() throws IOException { if (!nativeLookLoaded) { @@ -33,16 +36,27 @@ class GuiReader extends BasicReader { nativeLookLoaded = true; } - File dir = Instance.getReaderDir(); - dir.mkdirs(); - if (!dir.exists()) { + cacheDir = Instance.getReaderDir(); + cacheDir.mkdirs(); + if (!cacheDir.exists()) { throw new IOException( - "Cannote create cache directory for local reader: " + dir); + "Cannote create cache directory for local reader: " + + cacheDir); + } + } + + @Override + public synchronized BasicLibrary getLibrary() { + if (cacheLib == null) { + BasicLibrary lib = super.getLibrary(); + if (lib instanceof CacheLibrary) { + cacheLib = (CacheLibrary) lib; + } else { + cacheLib = new CacheLibrary(cacheDir, lib); + } } - localLibrary = new LocalLibrary(dir, Instance.getUiConfig().getString( - UiConfig.GUI_NON_IMAGES_DOCUMENT_TYPE), Instance.getUiConfig() - .getString(UiConfig.GUI_IMAGES_DOCUMENT_TYPE), true); + return cacheLib; } @Override @@ -56,27 +70,6 @@ class GuiReader extends BasicReader { read(meta.getLuid(), null); } - /** - * Import the story into the local reader library, and keep the same LUID. - * - * @param luid - * the Library UID - * @param pg - * the optional progress reporter - * - * @throws IOException - * in case of I/O error - */ - public void imprt(String luid, Progress pg) throws IOException { - try { - localLibrary.imprt(getLibrary(), luid, pg); - } catch (IOException e) { - throw new IOException( - "Cannot import story from library to LocalReader library: " - + luid, e); - } - } - /** * Check if the {@link Story} denoted by this Library UID is present in the * {@link GuiReader} cache. @@ -87,7 +80,7 @@ class GuiReader extends BasicReader { * @return TRUE if it is */ public boolean isCached(String luid) { - return localLibrary.getInfo(luid) != null; + return cacheLib.isCached(luid); } @Override @@ -158,7 +151,7 @@ class GuiReader extends BasicReader { // delete from local reader library void clearLocalReaderCache(String luid) { try { - localLibrary.delete(luid); + cacheLib.clearFromCache(luid); } catch (IOException e) { Instance.syserr(e); } @@ -167,10 +160,7 @@ class GuiReader extends BasicReader { // delete from main library void delete(String luid) { try { - if (localLibrary.getInfo(luid) != null) { - localLibrary.delete(luid); - } - getLibrary().delete(luid); + cacheLib.delete(luid); } catch (IOException e) { Instance.syserr(e); } @@ -178,11 +168,7 @@ class GuiReader extends BasicReader { // open the given book void read(String luid, Progress pg) throws IOException { - File file = localLibrary.getFile(luid); - if (file == null) { - imprt(luid, pg); - file = localLibrary.getFile(luid); - } + File file = cacheLib.getFile(luid, pg); // TODO: show a special page for the chapter? openExternal(getLibrary().getInfo(luid), file); @@ -190,10 +176,7 @@ class GuiReader extends BasicReader { void changeType(String luid, String newSource) { try { - if (localLibrary.getInfo(luid) != null) { - localLibrary.changeSource(luid, newSource, null); - } - getLibrary().changeSource(luid, newSource, null); + cacheLib.changeSource(luid, newSource, null); } catch (IOException e) { Instance.syserr(e); } -- 2.27.0