allow clean disk cache
[fanfix.git] / src / be / nikiroo / fanfix / Instance.java
CommitLineData
08fe2e33
NR
1package be.nikiroo.fanfix;
2
3import java.io.File;
4import java.io.IOException;
b42117f1 5import java.util.Date;
08fe2e33
NR
6
7import be.nikiroo.fanfix.bundles.Config;
8import be.nikiroo.fanfix.bundles.ConfigBundle;
99ccbdf6 9import be.nikiroo.fanfix.bundles.StringId;
08fe2e33 10import be.nikiroo.fanfix.bundles.StringIdBundle;
5bc9573b 11import be.nikiroo.fanfix.bundles.StringIdGuiBundle;
b4dc6ab5
NR
12import be.nikiroo.fanfix.bundles.UiConfig;
13import be.nikiroo.fanfix.bundles.UiConfigBundle;
e42573a0 14import be.nikiroo.fanfix.library.BasicLibrary;
5895a958 15import be.nikiroo.fanfix.library.CacheLibrary;
e42573a0 16import be.nikiroo.fanfix.library.LocalLibrary;
e023483b 17import be.nikiroo.fanfix.library.RemoteLibrary;
581d42c0 18import be.nikiroo.utils.Cache;
b42117f1 19import be.nikiroo.utils.IOUtils;
2aac79c7 20import be.nikiroo.utils.TempFiles;
581d42c0 21import be.nikiroo.utils.TraceHandler;
08fe2e33
NR
22import be.nikiroo.utils.resources.Bundles;
23
24/**
25 * Global state for the program (services and singletons).
26 *
27 * @author niki
28 */
29public class Instance {
30 private static ConfigBundle config;
b4dc6ab5 31 private static UiConfigBundle uiconfig;
08fe2e33 32 private static StringIdBundle trans;
f1fb834c 33 private static DataLoader cache;
5bc9573b 34 private static StringIdGuiBundle transGui;
e023483b 35 private static BasicLibrary lib;
08fe2e33 36 private static File coverDir;
3727aae2 37 private static File readerTmp;
b0e88ebd 38 private static File remoteDir;
b42117f1 39 private static String configDir;
581d42c0 40 private static TraceHandler tracer;
2aac79c7 41 private static TempFiles tempFiles;
a8209dd0 42
8928e885
NR
43 private static File cacheDir;
44
08fe2e33 45 static {
62c63b07 46 // Before we can configure it:
ae78e517 47 tracer = new TraceHandler(true, checkEnv("DEBUG"), checkEnv("DEBUG"));
62c63b07 48
9f705f1a
NR
49 // config dir:
50 configDir = getConfigDir();
b42117f1
NR
51 if (!new File(configDir).exists()) {
52 new File(configDir).mkdirs();
fe999aa4
NR
53 }
54
9f705f1a 55 // Most of the rest is dependent upon this:
38febea9 56 createConfigs(configDir, false);
2206ef66 57
9f705f1a 58 // update tracer:
581d42c0
NR
59 boolean debug = Instance.getConfig()
60 .getBoolean(Config.DEBUG_ERR, false);
61 boolean trace = Instance.getConfig().getBoolean(Config.DEBUG_TRACE,
62 false);
d0114000
NR
63
64 if (checkEnv("DEBUG")) {
65 debug = true;
ae78e517 66 trace = true;
d0114000
NR
67 }
68
62c63b07 69 tracer = new TraceHandler(true, debug, trace);
581d42c0 70
9f705f1a
NR
71 // default Library
72 remoteDir = new File(configDir, "remote");
73 lib = createDefaultLibrary(remoteDir);
778d8d85 74
9f705f1a 75 // create cache
8928e885
NR
76 cacheDir = getFile(Config.CACHE_DIR);
77 if (cacheDir == null) {
9f705f1a 78 // Could have used: System.getProperty("java.io.tmpdir")
8928e885 79 cacheDir = new File(configDir, "tmp");
68e370a4 80 }
ae78e517 81 String ua = config.getString(Config.USER_AGENT);
08fe2e33 82 try {
08fe2e33
NR
83 int hours = config.getInteger(Config.CACHE_MAX_TIME_CHANGING, -1);
84 int hoursLarge = config
85 .getInteger(Config.CACHE_MAX_TIME_STABLE, -1);
8928e885 86 cache = new DataLoader(cacheDir, ua, hours, hoursLarge);
08fe2e33 87 } catch (IOException e) {
62c63b07 88 tracer.error(new IOException(
08fe2e33 89 "Cannot create cache (will continue without cache)", e));
ae78e517 90 cache = new DataLoader(ua);
08fe2e33 91 }
ae78e517
NR
92
93 cache.setTraceHandler(tracer);
9f705f1a
NR
94
95 // readerTmp / coverDir
96 readerTmp = getFile(UiConfig.CACHE_DIR_LOCAL_READER);
97 if (readerTmp == null) {
98 readerTmp = new File(configDir, "tmp-reader");
99 }
100
101 coverDir = getFile(Config.DEFAULT_COVERS_DIR);
102 if (coverDir != null && !coverDir.exists()) {
103 tracer.error(new IOException(
104 "The 'default covers' directory does not exists: "
105 + coverDir));
106 coverDir = null;
107 }
2aac79c7
NR
108
109 try {
110 tempFiles = new TempFiles("fanfix");
111 } catch (IOException e) {
112 tracer.error(new IOException("Cannot create temporary directory", e));
113 }
08fe2e33
NR
114 }
115
581d42c0
NR
116 /**
117 * The traces handler for this {@link Cache}.
62c63b07
NR
118 * <p>
119 * It is never NULL.
581d42c0 120 *
62c63b07 121 * @return the traces handler (never NULL)
581d42c0
NR
122 */
123 public static TraceHandler getTraceHandler() {
124 return tracer;
125 }
126
127 /**
128 * The traces handler for this {@link Cache}.
129 *
130 * @param tracer
131 * the new traces handler or NULL
132 */
133 public static void setTraceHandler(TraceHandler tracer) {
62c63b07
NR
134 if (tracer == null) {
135 tracer = new TraceHandler(false, false, false);
136 }
137
581d42c0 138 Instance.tracer = tracer;
ae78e517 139 cache.setTraceHandler(tracer);
581d42c0
NR
140 }
141
08fe2e33
NR
142 /**
143 * Get the (unique) configuration service for the program.
144 *
145 * @return the configuration service
146 */
147 public static ConfigBundle getConfig() {
148 return config;
149 }
150
b4dc6ab5
NR
151 /**
152 * Get the (unique) UI configuration service for the program.
153 *
154 * @return the configuration service
155 */
156 public static UiConfigBundle getUiConfig() {
157 return uiconfig;
158 }
159
ae78e517
NR
160 /**
161 * Reset the configuration.
162 *
163 * @param resetTrans
164 * also reset the translation files
165 */
166 public static void resetConfig(boolean resetTrans) {
167 String dir = Bundles.getDirectory();
168 Bundles.setDirectory(null);
169 try {
170 try {
171 ConfigBundle config = new ConfigBundle();
172 config.updateFile(configDir);
173 } catch (IOException e) {
174 tracer.error(e);
175 }
176 try {
177 UiConfigBundle uiconfig = new UiConfigBundle();
178 uiconfig.updateFile(configDir);
179 } catch (IOException e) {
180 tracer.error(e);
181 }
182
183 if (resetTrans) {
184 try {
185 StringIdBundle trans = new StringIdBundle(null);
186 trans.updateFile(configDir);
187 } catch (IOException e) {
188 tracer.error(e);
189 }
190 }
191 } finally {
192 Bundles.setDirectory(dir);
193 }
194 }
195
08fe2e33 196 /**
f1fb834c 197 * Get the (unique) {@link DataLoader} for the program.
08fe2e33 198 *
f1fb834c 199 * @return the {@link DataLoader}
08fe2e33 200 */
f1fb834c 201 public static DataLoader getCache() {
08fe2e33
NR
202 return cache;
203 }
204
205 /**
206 * Get the (unique) {link StringIdBundle} for the program.
5bc9573b
NR
207 * <p>
208 * This is used for the translations of the core parts of Fanfix.
39c3c689 209 *
08fe2e33
NR
210 * @return the {link StringIdBundle}
211 */
212 public static StringIdBundle getTrans() {
213 return trans;
214 }
215
5bc9573b
NR
216 /**
217 * Get the (unique) {link StringIdGuiBundle} for the program.
218 * <p>
219 * This is used for the translations of the GUI parts of Fanfix.
220 *
221 * @return the {link StringIdGuiBundle}
222 */
223 public static StringIdGuiBundle getTransGui() {
224 return transGui;
225 }
226
08fe2e33 227 /**
68e2c6d2 228 * Get the (unique) {@link LocalLibrary} for the program.
08fe2e33 229 *
68e2c6d2 230 * @return the {@link LocalLibrary}
08fe2e33 231 */
68e2c6d2 232 public static BasicLibrary getLibrary() {
778d8d85
NR
233 if (lib == null) {
234 throw new NullPointerException("We don't have a library to return");
235 }
236
08fe2e33
NR
237 return lib;
238 }
239
240 /**
241 * Return the directory where to look for default cover pages.
242 *
243 * @return the default covers directory
244 */
245 public static File getCoverDir() {
246 return coverDir;
247 }
248
3727aae2
NR
249 /**
250 * Return the directory where to store temporary files for the local reader.
251 *
252 * @return the directory
253 */
254 public static File getReaderDir() {
255 return readerTmp;
256 }
257
b0e88ebd
NR
258 /**
259 * Return the directory where to store temporary files for the remote
68e2c6d2 260 * {@link LocalLibrary}.
b0e88ebd
NR
261 *
262 * @param host
263 * the remote for this host
264 *
265 * @return the directory
266 */
267 public static File getRemoteDir(String host) {
9f705f1a
NR
268 return getRemoteDir(remoteDir, host);
269 }
270
271 /**
272 * Return the directory where to store temporary files for the remote
273 * {@link LocalLibrary}.
274 *
275 * @param remoteDir
276 * the base remote directory
277 * @param host
278 * the remote for this host
279 *
280 * @return the directory
281 */
282 private static File getRemoteDir(File remoteDir, String host) {
b0e88ebd
NR
283 remoteDir.mkdirs();
284
285 if (host != null) {
286 return new File(remoteDir, host);
287 }
288
289 return remoteDir;
290 }
291
b42117f1
NR
292 /**
293 * Check if we need to check that a new version of Fanfix is available.
294 *
295 * @return TRUE if we need to
296 */
297 public static boolean isVersionCheckNeeded() {
298 try {
a3641e4b
NR
299 long wait = config.getInteger(Config.UPDATE_INTERVAL, 1) * 24 * 60
300 * 60 * 1000;
b42117f1
NR
301 if (wait >= 0) {
302 String lastUpString = IOUtils.readSmallFile(new File(configDir,
303 "LAST_UPDATE"));
304 long delay = new Date().getTime()
305 - Long.parseLong(lastUpString);
306 if (delay > wait) {
307 return true;
308 }
309 } else {
310 return false;
311 }
312 } catch (Exception e) {
313 // No file or bad file:
314 return true;
315 }
316
317 return false;
318 }
319
320 /**
321 * Notify that we checked for a new version of Fanfix.
322 */
323 public static void setVersionChecked() {
324 try {
325 IOUtils.writeSmallFile(new File(configDir), "LAST_UPDATE",
326 Long.toString(new Date().getTime()));
327 } catch (IOException e) {
581d42c0 328 tracer.error(e);
08fe2e33
NR
329 }
330 }
331
2aac79c7
NR
332 /**
333 * The facility to use temporary files in this program.
334 * <p>
335 * <b>MUST</b> be closed at end of program.
336 *
337 * @return the facility
338 */
339 public static TempFiles getTempFiles() {
340 return tempFiles;
341 }
342
8928e885
NR
343 /**
344 * Delete all the cache files, can be very long...
345 */
346 public static void PATCH_emptyCache() {
347 IOUtils.deltree(cacheDir);
348 cacheDir.mkdirs();
349 }
350
9f705f1a
NR
351 /**
352 * The configuration directory (will check, in order of preference,
353 * {@link Bundles#getDirectory()}, the system properties, the environment
354 * and then defaults to $HOME/.fanfix).
355 *
356 * @return the config directory
357 */
358 private static String getConfigDir() {
359 String configDir = Bundles.getDirectory();
360
361 if (configDir == null) {
362 configDir = System.getProperty("CONFIG_DIR");
363 }
364
365 if (configDir == null) {
366 configDir = System.getenv("CONFIG_DIR");
367 }
368
369 if (configDir == null) {
370 configDir = new File(getHome(), ".fanfix").getPath();
371 }
372
373 return configDir;
374 }
375
376 /**
377 * Create the config variables ({@link Instance#config},
5bc9573b
NR
378 * {@link Instance#uiconfig}, {@link Instance#trans} and
379 * {@link Instance#transGui}).
9f705f1a
NR
380 *
381 * @param configDir
382 * the directory where to find the configuration files
383 * @param refresh
38febea9 384 * TRUE to reset the configuration files from the default
9f705f1a
NR
385 * included ones
386 */
387 private static void createConfigs(String configDir, boolean refresh) {
388 if (!refresh) {
389 Bundles.setDirectory(configDir);
390 }
391
392 try {
393 config = new ConfigBundle();
394 config.updateFile(configDir);
395 } catch (IOException e) {
396 tracer.error(e);
397 }
398
399 try {
400 uiconfig = new UiConfigBundle();
401 uiconfig.updateFile(configDir);
402 } catch (IOException e) {
403 tracer.error(e);
404 }
405
406 // No updateFile for this one! (we do not want the user to have custom
407 // translations that won't accept updates from newer versions)
408 trans = new StringIdBundle(getLang());
5bc9573b 409 transGui = new StringIdGuiBundle(getLang());
9f705f1a
NR
410
411 // Fix an old bug (we used to store custom translation files by
412 // default):
413 if (trans.getString(StringId.INPUT_DESC_CBZ) == null) {
414 trans.deleteFile(configDir);
415 }
416
417 if (checkEnv("NOUTF")) {
418 trans.setUnicode(false);
5bc9573b 419 transGui.setUnicode(false);
9f705f1a
NR
420 }
421
422 Bundles.setDirectory(configDir);
423 }
424
425 /**
426 * Create the default library as specified by the config.
427 *
428 * @param remoteDir
429 * the base remote directory if needed
430 *
431 * @return the default {@link BasicLibrary}
432 */
433 private static BasicLibrary createDefaultLibrary(File remoteDir) {
434 BasicLibrary lib = null;
435
436 String remoteLib = config.getString(Config.DEFAULT_LIBRARY);
437 if (remoteLib == null || remoteLib.trim().isEmpty()) {
438 String libDir = System.getProperty("fanfix.libdir");
439 if (libDir == null || libDir.isEmpty()) {
38febea9 440 libDir = config.getString(Config.LIBRARY_DIR);
9f705f1a
NR
441 }
442 try {
443 lib = new LocalLibrary(getFile(libDir));
444 } catch (Exception e) {
445 tracer.error(new IOException(
446 "Cannot create library for directory: "
447 + getFile(libDir), e));
448 }
449 } else {
450 int pos = remoteLib.lastIndexOf(":");
451 if (pos >= 0) {
452 String port = remoteLib.substring(pos + 1).trim();
453 remoteLib = remoteLib.substring(0, pos);
454 pos = remoteLib.lastIndexOf(":");
455 if (pos >= 0) {
456 String host = remoteLib.substring(pos + 1).trim();
457 String key = remoteLib.substring(0, pos).trim();
458
459 try {
460 tracer.trace("Selecting remote library " + host + ":"
461 + port);
462 lib = new RemoteLibrary(key, host,
463 Integer.parseInt(port));
464 lib = new CacheLibrary(getRemoteDir(remoteDir, host),
465 lib);
466
467 } catch (Exception e) {
468 }
469 }
470 }
471
472 if (lib == null) {
473 tracer.error(new IOException(
474 "Cannot create remote library for: " + remoteLib));
475 }
476 }
477
478 return lib;
479 }
480
08fe2e33
NR
481 /**
482 * Return a path, but support the special $HOME variable.
483 *
484 * @return the path
485 */
486 private static File getFile(Config id) {
b4dc6ab5
NR
487 return getFile(config.getString(id));
488 }
489
490 /**
491 * Return a path, but support the special $HOME variable.
492 *
493 * @return the path
494 */
495 private static File getFile(UiConfig id) {
496 return getFile(uiconfig.getString(id));
497 }
498
499 /**
500 * Return a path, but support the special $HOME variable.
501 *
502 * @return the path
503 */
504 private static File getFile(String path) {
08fe2e33 505 File file = null;
08fe2e33
NR
506 if (path != null && !path.isEmpty()) {
507 path = path.replace('/', File.separatorChar);
508 if (path.contains("$HOME")) {
ae78e517 509 path = path.replace("$HOME", getHome());
08fe2e33
NR
510 }
511
512 file = new File(path);
513 }
514
515 return file;
516 }
517
ae78e517
NR
518 /**
519 * Return the home directory from the system properties.
520 *
521 * @return the home
522 */
523 private static String getHome() {
b4f9071c
NR
524 String home = System.getProperty("fanfix.home");
525 if (home != null && new File(home).isFile()) {
526 home = null;
527 }
528
529 if (home == null || home.trim().isEmpty()) {
530 home = System.getProperty("user.home");
531 if (!new File(home).isDirectory()) {
532 home = null;
533 }
534 }
535
ae78e517
NR
536 if (home == null || home.trim().isEmpty()) {
537 home = System.getProperty("java.io.tmpdir");
b4f9071c
NR
538 if (!new File(home).isDirectory()) {
539 home = null;
540 }
ae78e517
NR
541 }
542
543 if (home == null) {
544 home = "";
545 }
546
547 return home;
548 }
549
08fe2e33
NR
550 /**
551 * The language to use for the application (NULL = default system language).
552 *
553 * @return the language
554 */
555 private static String getLang() {
556 String lang = config.getString(Config.LANG);
557
fee80815
NR
558 if (lang == null | lang.isEmpty()) {
559 if (System.getenv("LANG") != null
560 && !System.getenv("LANG").isEmpty()) {
561 lang = System.getenv("LANG");
562 }
08fe2e33
NR
563 }
564
565 if (lang != null && lang.isEmpty()) {
566 lang = null;
567 }
568
569 return lang;
570 }
d0114000
NR
571
572 /**
573 * Check that the given environment variable is "enabled".
574 *
575 * @param key
576 * the variable to check
577 *
578 * @return TRUE if it is
579 */
580 private static boolean checkEnv(String key) {
581 String value = System.getenv(key);
582 if (value != null) {
583 value = value.trim().toLowerCase();
584 if ("yes".equals(value) || "true".equals(value)
585 || "on".equals(value) || "1".equals(value)
586 || "y".equals(value)) {
587 return true;
588 }
589 }
590
591 return false;
592 }
08fe2e33 593}