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