remote: better handling of key error
[fanfix.git] / src / be / nikiroo / fanfix / library / RemoteLibrary.java
CommitLineData
e42573a0 1package be.nikiroo.fanfix.library;
b0e88ebd
NR
2
3import java.io.File;
4import java.io.IOException;
edf79e5e 5import java.net.URL;
e6249b0f 6import java.net.UnknownHostException;
68e2c6d2
NR
7import java.util.ArrayList;
8import java.util.List;
b0e88ebd 9
7e51d91c
NR
10import javax.net.ssl.SSLException;
11
e42573a0 12import be.nikiroo.fanfix.Instance;
b0e88ebd
NR
13import be.nikiroo.fanfix.data.MetaData;
14import be.nikiroo.fanfix.data.Story;
16a81ef7 15import be.nikiroo.utils.Image;
b0e88ebd
NR
16import be.nikiroo.utils.Progress;
17import be.nikiroo.utils.Version;
62c63b07 18import be.nikiroo.utils.serial.server.ConnectActionClientObject;
b0e88ebd 19
68e2c6d2
NR
20/**
21 * This {@link BasicLibrary} will access a remote server to list the available
a85e8077 22 * stories, and download the ones you try to load to the local directory
68e2c6d2
NR
23 * specified in the configuration.
24 *
25 * @author niki
26 */
27public class RemoteLibrary extends BasicLibrary {
b0e88ebd
NR
28 private String host;
29 private int port;
ea734ab4 30 private final String key;
68e2c6d2
NR
31
32 /**
33 * Create a {@link RemoteLibrary} linked to the given server.
34 *
2070ced5
NR
35 * @param key
36 * the key that will allow us to exchange information with the
37 * server
68e2c6d2
NR
38 * @param host
39 * the host to contact or NULL for localhost
40 * @param port
41 * the port to contact it on
42 */
2070ced5 43 public RemoteLibrary(String key, String host, int port) {
ea734ab4 44 this.key = key;
b0e88ebd
NR
45 this.host = host;
46 this.port = port;
b0e88ebd
NR
47 }
48
99ccbdf6
NR
49 @Override
50 public String getLibraryName() {
51 return host + ":" + port;
52 }
53
e6249b0f
NR
54 @Override
55 public Status getStatus() {
56 final Status[] result = new Status[1];
57
58 result[0] = Status.INVALID;
59
e6249b0f 60 try {
41029926 61 Instance.getTraceHandler().trace("Getting remote lib status...");
3040c4f0 62 new ConnectActionClientObject(host, port, key) {
e6249b0f
NR
63 @Override
64 public void action(Version serverVersion) throws Exception {
7e51d91c 65 Object rep = send(new Object[] { "PING" });
ea734ab4 66
7e51d91c
NR
67 if ("PONG".equals(rep)) {
68 result[0] = Status.READY;
69 } else {
e6249b0f
NR
70 result[0] = Status.UNAUTORIZED;
71 }
72 }
73
74 @Override
75 protected void onError(Exception e) {
7e51d91c
NR
76 if (e instanceof SSLException) {
77 result[0] = Status.UNAUTORIZED;
78 } else {
79 result[0] = Status.UNAVAILABLE;
80 }
e6249b0f 81 }
ea734ab4 82 }.connect();
e6249b0f
NR
83 } catch (UnknownHostException e) {
84 result[0] = Status.INVALID;
85 } catch (IllegalArgumentException e) {
86 result[0] = Status.INVALID;
87 } catch (Exception e) {
88 result[0] = Status.UNAVAILABLE;
89 }
90
41029926 91 Instance.getTraceHandler().trace("Remote lib status: " + result[0]);
e6249b0f
NR
92 return result[0];
93 }
94
b0e88ebd 95 @Override
16a81ef7
NR
96 public Image getCover(final String luid) {
97 final Image[] result = new Image[1];
b0e88ebd 98
b9ce9cad 99 try {
3040c4f0 100 new ConnectActionClientObject(host, port, key) {
b9ce9cad
NR
101 @Override
102 public void action(Version serverVersion) throws Exception {
3358927d 103 Object rep = send(new Object[] { "GET_COVER", luid });
16a81ef7 104 result[0] = (Image) rep;
b9ce9cad 105 }
b0e88ebd 106
b9ce9cad
NR
107 @Override
108 protected void onError(Exception e) {
7e51d91c
NR
109 if (e instanceof SSLException) {
110 Instance.getTraceHandler().error(
111 "Connection refused (bad key)");
112 } else {
113 Instance.getTraceHandler().error(e);
114 }
b9ce9cad
NR
115 }
116 }.connect();
117 } catch (Exception e) {
118 Instance.getTraceHandler().error(e);
119 }
b0e88ebd 120
b9ce9cad 121 return result[0];
085a2f9a
NR
122 }
123
124 @Override
e1de8087 125 public Image getCustomSourceCover(final String source) {
3989dfc5
NR
126 return getCustomCover(source, "SOURCE");
127 }
128
129 @Override
130 public Image getCustomAuthorCover(final String author) {
131 return getCustomCover(author, "AUTHOR");
132 }
133
134 // type: "SOURCE" or "AUTHOR"
135 private Image getCustomCover(final String source, final String type) {
16a81ef7 136 final Image[] result = new Image[1];
b9ce9cad
NR
137
138 try {
3040c4f0 139 new ConnectActionClientObject(host, port, key) {
b9ce9cad
NR
140 @Override
141 public void action(Version serverVersion) throws Exception {
3358927d
NR
142 Object rep = send(new Object[] { "GET_CUSTOM_COVER", type,
143 source });
16a81ef7 144 result[0] = (Image) rep;
b9ce9cad
NR
145 }
146
147 @Override
148 protected void onError(Exception e) {
7e51d91c
NR
149 if (e instanceof SSLException) {
150 Instance.getTraceHandler().error(
151 "Connection refused (bad key)");
152 } else {
153 Instance.getTraceHandler().error(e);
154 }
b9ce9cad
NR
155 }
156 }.connect();
157 } catch (Exception e) {
158 Instance.getTraceHandler().error(e);
159 }
160
161 return result[0];
b0e88ebd 162 }
68e2c6d2
NR
163
164 @Override
ff05b828 165 public synchronized Story getStory(final String luid, Progress pg) {
b9ce9cad
NR
166 final Progress pgF = pg;
167 final Story[] result = new Story[1];
68e2c6d2 168
b9ce9cad 169 try {
3040c4f0 170 new ConnectActionClientObject(host, port, key) {
b9ce9cad
NR
171 @Override
172 public void action(Version serverVersion) throws Exception {
173 Progress pg = pgF;
174 if (pg == null) {
175 pg = new Progress();
176 }
177
3358927d 178 Object rep = send(new Object[] { "GET_STORY", luid });
b9ce9cad
NR
179
180 MetaData meta = null;
181 if (rep instanceof MetaData) {
182 meta = (MetaData) rep;
183 if (meta.getWords() <= Integer.MAX_VALUE) {
184 pg.setMinMax(0, (int) meta.getWords());
185 }
186 }
187
188 List<Object> list = new ArrayList<Object>();
27eba894 189 for (Object obj = send(null); obj != null; obj = send(null)) {
b9ce9cad
NR
190 list.add(obj);
191 pg.add(1);
192 }
193
194 result[0] = RemoteLibraryServer.rebuildStory(list);
195 pg.done();
196 }
197
198 @Override
199 protected void onError(Exception e) {
7e51d91c
NR
200 if (e instanceof SSLException) {
201 Instance.getTraceHandler().error(
202 "Connection refused (bad key)");
203 } else {
204 Instance.getTraceHandler().error(e);
205 }
b9ce9cad
NR
206 }
207 }.connect();
208 } catch (Exception e) {
209 Instance.getTraceHandler().error(e);
210 }
211
212 return result[0];
68e2c6d2
NR
213 }
214
215 @Override
b9ce9cad
NR
216 public synchronized Story save(final Story story, final String luid,
217 Progress pg) throws IOException {
0fa0fe95
NR
218 final String[] luidSaved = new String[1];
219 Progress pgSave = new Progress();
220 Progress pgRefresh = new Progress();
221 if (pg == null) {
222 pg = new Progress();
223 }
224
225 pg.setMinMax(0, 10);
226 pg.addProgress(pgSave, 9);
227 pg.addProgress(pgRefresh, 1);
228
229 final Progress pgF = pgSave;
b9ce9cad 230
3040c4f0 231 new ConnectActionClientObject(host, port, key) {
b9ce9cad
NR
232 @Override
233 public void action(Version serverVersion) throws Exception {
234 Progress pg = pgF;
b9ce9cad
NR
235 if (story.getMeta().getWords() <= Integer.MAX_VALUE) {
236 pg.setMinMax(0, (int) story.getMeta().getWords());
237 }
238
3358927d 239 send(new Object[] { "SAVE_STORY", luid });
b9ce9cad
NR
240
241 List<Object> list = RemoteLibraryServer.breakStory(story);
242 for (Object obj : list) {
243 send(obj);
244 pg.add(1);
245 }
246
edf79e5e 247 luidSaved[0] = (String) send(null);
0fa0fe95 248
b9ce9cad
NR
249 pg.done();
250 }
251
252 @Override
253 protected void onError(Exception e) {
7e51d91c
NR
254 if (e instanceof SSLException) {
255 Instance.getTraceHandler().error(
256 "Connection refused (bad key)");
257 } else {
258 Instance.getTraceHandler().error(e);
259 }
b9ce9cad
NR
260 }
261 }.connect();
085a2f9a
NR
262
263 // because the meta changed:
edf79e5e 264 MetaData meta = getInfo(luidSaved[0]);
efa3c511
NR
265 if (story.getMeta().getClass() != null) {
266 // If already available locally:
267 meta.setCover(story.getMeta().getCover());
268 } else {
269 // If required:
270 meta.setCover(getCover(meta.getLuid()));
271 }
edf79e5e 272 story.setMeta(meta);
0fa0fe95
NR
273
274 pg.done();
085a2f9a
NR
275
276 return story;
68e2c6d2
NR
277 }
278
279 @Override
b9ce9cad 280 public synchronized void delete(final String luid) throws IOException {
3040c4f0 281 new ConnectActionClientObject(host, port, key) {
b9ce9cad
NR
282 @Override
283 public void action(Version serverVersion) throws Exception {
3358927d 284 send(new Object[] { "DELETE_STORY", luid });
b9ce9cad
NR
285 }
286
287 @Override
288 protected void onError(Exception e) {
7e51d91c
NR
289 if (e instanceof SSLException) {
290 Instance.getTraceHandler().error(
291 "Connection refused (bad key)");
292 } else {
293 Instance.getTraceHandler().error(e);
294 }
b9ce9cad
NR
295 }
296 }.connect();
68e2c6d2
NR
297 }
298
299 @Override
b9ce9cad 300 public void setSourceCover(final String source, final String luid) {
3989dfc5
NR
301 setCover(source, luid, "SOURCE");
302 }
303
304 @Override
305 public void setAuthorCover(final String author, final String luid) {
306 setCover(author, luid, "AUTHOR");
307 }
308
309 // type = "SOURCE" | "AUTHOR"
310 private void setCover(final String value, final String luid,
311 final String type) {
b9ce9cad 312 try {
3040c4f0 313 new ConnectActionClientObject(host, port, key) {
b9ce9cad
NR
314 @Override
315 public void action(Version serverVersion) throws Exception {
3358927d 316 send(new Object[] { "SET_COVER", type, value, luid });
b9ce9cad
NR
317 }
318
319 @Override
320 protected void onError(Exception e) {
7e51d91c
NR
321 if (e instanceof SSLException) {
322 Instance.getTraceHandler().error(
323 "Connection refused (bad key)");
324 } else {
325 Instance.getTraceHandler().error(e);
326 }
b9ce9cad
NR
327 }
328 }.connect();
329 } catch (IOException e) {
330 Instance.getTraceHandler().error(e);
edf79e5e
NR
331 }
332 }
333
334 @Override
335 // Could work (more slowly) without it
336 public Story imprt(final URL url, Progress pg) throws IOException {
00f6344a
NR
337 // Import the file locally if it is actually a file
338 if (url == null || url.getProtocol().equalsIgnoreCase("file")) {
339 return super.imprt(url, pg);
340 }
341
342 // Import it remotely if it is an URL
343
edf79e5e
NR
344 if (pg == null) {
345 pg = new Progress();
346 }
347
348 pg.setMinMax(0, 2);
349 Progress pgImprt = new Progress();
350 Progress pgGet = new Progress();
351 pg.addProgress(pgImprt, 1);
352 pg.addProgress(pgGet, 1);
353
354 final Progress pgF = pgImprt;
355 final String[] luid = new String[1];
356
357 try {
3040c4f0 358 new ConnectActionClientObject(host, port, key) {
edf79e5e
NR
359 @Override
360 public void action(Version serverVersion) throws Exception {
361 Progress pg = pgF;
362
3358927d 363 Object rep = send(new Object[] { "IMPORT", url.toString() });
edf79e5e
NR
364
365 while (true) {
366 if (!RemoteLibraryServer.updateProgress(pg, rep)) {
367 break;
368 }
369
370 rep = send(null);
371 }
372
373 pg.done();
374 luid[0] = (String) rep;
375 }
376
377 @Override
378 protected void onError(Exception e) {
7e51d91c
NR
379 if (e instanceof SSLException) {
380 Instance.getTraceHandler().error(
381 "Connection refused (bad key)");
382 } else {
383 Instance.getTraceHandler().error(e);
384 }
edf79e5e
NR
385 }
386 }.connect();
387 } catch (IOException e) {
388 Instance.getTraceHandler().error(e);
389 }
390
391 if (luid[0] == null) {
392 throw new IOException("Remote failure");
393 }
394
395 Story story = getStory(luid[0], pgGet);
396 pgGet.done();
397
398 pg.done();
399 return story;
400 }
401
402 @Override
403 // Could work (more slowly) without it
c8d48938
NR
404 protected synchronized void changeSTA(final String luid,
405 final String newSource, final String newTitle,
406 final String newAuthor, Progress pg) throws IOException {
edf79e5e
NR
407 final Progress pgF = pg == null ? new Progress() : pg;
408
409 try {
3040c4f0 410 new ConnectActionClientObject(host, port, key) {
edf79e5e
NR
411 @Override
412 public void action(Version serverVersion) throws Exception {
413 Progress pg = pgF;
414
3358927d
NR
415 Object rep = send(new Object[] { "CHANGE_STA", luid,
416 newSource, newTitle, newAuthor });
edf79e5e
NR
417 while (true) {
418 if (!RemoteLibraryServer.updateProgress(pg, rep)) {
419 break;
420 }
421
422 rep = send(null);
423 }
424 }
425
426 @Override
427 protected void onError(Exception e) {
7e51d91c
NR
428 if (e instanceof SSLException) {
429 Instance.getTraceHandler().error(
430 "Connection refused (bad key)");
431 } else {
432 Instance.getTraceHandler().error(e);
433 }
edf79e5e
NR
434 }
435 }.connect();
436 } catch (IOException e) {
437 Instance.getTraceHandler().error(e);
b9ce9cad 438 }
68e2c6d2
NR
439 }
440
ff05b828 441 @Override
2249988a 442 public synchronized File getFile(final String luid, Progress pg) {
ff05b828
NR
443 throw new java.lang.InternalError(
444 "Operation not supportorted on remote Libraries");
445 }
446
468b960b
NR
447 /**
448 * Stop the server.
449 */
450 public void exit() {
451 try {
3040c4f0 452 new ConnectActionClientObject(host, port, key) {
468b960b
NR
453 @Override
454 public void action(Version serverVersion) throws Exception {
3358927d 455 send(new Object[] { "EXIT" });
468b960b
NR
456 }
457
458 @Override
459 protected void onError(Exception e) {
7e51d91c
NR
460 if (e instanceof SSLException) {
461 Instance.getTraceHandler().error(
462 "Connection refused (bad key)");
463 } else {
464 Instance.getTraceHandler().error(e);
465 }
468b960b
NR
466 }
467 }.connect();
468 } catch (IOException e) {
469 Instance.getTraceHandler().error(e);
470 }
471 }
472
e272f05f
NR
473 @Override
474 public synchronized MetaData getInfo(String luid) {
475 List<MetaData> metas = getMetasList(luid, null);
476 if (!metas.isEmpty()) {
477 return metas.get(0);
478 }
479
480 return null;
481 }
482
14b57448 483 @Override
b9ce9cad 484 protected List<MetaData> getMetas(Progress pg) {
e272f05f
NR
485 return getMetasList("*", pg);
486 }
487
488 @Override
efa3c511
NR
489 protected void updateInfo(MetaData meta) {
490 // Will be taken care of directly server side
491 }
492
493 @Override
c8d48938 494 protected void invalidateInfo(String luid) {
efa3c511 495 // Will be taken care of directly server side
e272f05f
NR
496 }
497
498 // The following methods are only used by Save and Delete in BasicLibrary:
499
500 @Override
501 protected int getNextId() {
502 throw new java.lang.InternalError("Should not have been called");
503 }
504
505 @Override
506 protected void doDelete(String luid) throws IOException {
507 throw new java.lang.InternalError("Should not have been called");
508 }
509
510 @Override
511 protected Story doSave(Story story, Progress pg) throws IOException {
512 throw new java.lang.InternalError("Should not have been called");
513 }
514
515 //
516
517 /**
518 * Return the meta of the given story or a list of all known metas if the
519 * luid is "*".
9f51d8ab
NR
520 * <p>
521 * Will not get the covers.
e272f05f
NR
522 *
523 * @param luid
524 * the luid of the story or *
525 * @param pg
526 * the optional progress
527 *
528 *
529 * @return the metas
530 */
531 private List<MetaData> getMetasList(final String luid, Progress pg) {
b9ce9cad
NR
532 final Progress pgF = pg;
533 final List<MetaData> metas = new ArrayList<MetaData>();
74a40dfb 534
ff05b828 535 try {
3040c4f0 536 new ConnectActionClientObject(host, port, key) {
ff05b828
NR
537 @Override
538 public void action(Version serverVersion) throws Exception {
b9ce9cad
NR
539 Progress pg = pgF;
540 if (pg == null) {
541 pg = new Progress();
851dd538 542 }
74a40dfb 543
3358927d 544 Object rep = send(new Object[] { "GET_METADATA", luid });
74a40dfb 545
b9ce9cad
NR
546 while (true) {
547 if (!RemoteLibraryServer.updateProgress(pg, rep)) {
548 break;
549 }
74a40dfb 550
b9ce9cad 551 rep = send(null);
ff05b828 552 }
851dd538 553
e272f05f
NR
554 if (rep instanceof MetaData[]) {
555 for (MetaData meta : (MetaData[]) rep) {
556 metas.add(meta);
557 }
558 } else if (rep != null) {
559 metas.add((MetaData) rep);
b9ce9cad 560 }
851dd538
NR
561 }
562
563 @Override
564 protected void onError(Exception e) {
7e51d91c
NR
565 if (e instanceof SSLException) {
566 Instance.getTraceHandler().error(
567 "Connection refused (bad key)");
568 } else {
569 Instance.getTraceHandler().error(e);
570 }
ff05b828
NR
571 }
572 }.connect();
ff05b828 573 } catch (Exception e) {
62c63b07 574 Instance.getTraceHandler().error(e);
ff05b828 575 }
b9ce9cad
NR
576
577 return metas;
578 }
b0e88ebd 579}