Fix change source update
[nikiroo-utils.git] / src / be / nikiroo / fanfix / library / RemoteLibrary.java
CommitLineData
e42573a0 1package be.nikiroo.fanfix.library;
b0e88ebd 2
68e2c6d2 3import java.awt.image.BufferedImage;
b0e88ebd
NR
4import java.io.File;
5import java.io.IOException;
edf79e5e 6import java.net.URL;
e6249b0f 7import java.net.UnknownHostException;
68e2c6d2
NR
8import java.util.ArrayList;
9import java.util.List;
b0e88ebd 10
e42573a0 11import be.nikiroo.fanfix.Instance;
b0e88ebd
NR
12import be.nikiroo.fanfix.data.MetaData;
13import be.nikiroo.fanfix.data.Story;
b0e88ebd 14import be.nikiroo.utils.Progress;
416c54f8 15import be.nikiroo.utils.StringUtils;
b0e88ebd 16import be.nikiroo.utils.Version;
62c63b07 17import be.nikiroo.utils.serial.server.ConnectActionClientObject;
b0e88ebd 18
68e2c6d2
NR
19/**
20 * This {@link BasicLibrary} will access a remote server to list the available
a85e8077 21 * stories, and download the ones you try to load to the local directory
68e2c6d2
NR
22 * specified in the configuration.
23 *
24 * @author niki
25 */
26public class RemoteLibrary extends BasicLibrary {
b0e88ebd
NR
27 private String host;
28 private int port;
416c54f8 29 private final String md5;
68e2c6d2
NR
30
31 /**
32 * Create a {@link RemoteLibrary} linked to the given server.
33 *
2070ced5
NR
34 * @param key
35 * the key that will allow us to exchange information with the
36 * server
68e2c6d2
NR
37 * @param host
38 * the host to contact or NULL for localhost
39 * @param port
40 * the port to contact it on
41 */
2070ced5 42 public RemoteLibrary(String key, String host, int port) {
416c54f8 43 this.md5 = StringUtils.getMd5Hash(key);
b0e88ebd
NR
44 this.host = host;
45 this.port = port;
b0e88ebd
NR
46 }
47
99ccbdf6
NR
48 @Override
49 public String getLibraryName() {
50 return host + ":" + port;
51 }
52
e6249b0f
NR
53 @Override
54 public Status getStatus() {
55 final Status[] result = new Status[1];
56
57 result[0] = Status.INVALID;
58
59 ConnectActionClientObject action = null;
60 try {
61 action = new ConnectActionClientObject(host, port, true) {
62 @Override
63 public void action(Version serverVersion) throws Exception {
416c54f8 64 Object rep = send(new Object[] { md5, "PING" });
e6249b0f
NR
65 if ("PONG".equals(rep)) {
66 result[0] = Status.READY;
67 } else {
68 result[0] = Status.UNAUTORIZED;
69 }
70 }
71
72 @Override
73 protected void onError(Exception e) {
74 result[0] = Status.UNAVAILABLE;
75 }
76 };
77
78 } catch (UnknownHostException e) {
79 result[0] = Status.INVALID;
80 } catch (IllegalArgumentException e) {
81 result[0] = Status.INVALID;
82 } catch (Exception e) {
83 result[0] = Status.UNAVAILABLE;
84 }
85
86 if (action != null) {
87 try {
88 action.connect();
89 } catch (Exception e) {
90 result[0] = Status.UNAVAILABLE;
91 }
92 }
93
94 return result[0];
95 }
96
b0e88ebd 97 @Override
b9ce9cad
NR
98 public BufferedImage getCover(final String luid) {
99 final BufferedImage[] result = new BufferedImage[1];
b0e88ebd 100
b9ce9cad
NR
101 try {
102 new ConnectActionClientObject(host, port, true) {
103 @Override
104 public void action(Version serverVersion) throws Exception {
416c54f8 105 Object rep = send(new Object[] { md5, "GET_COVER", luid });
b9ce9cad
NR
106 result[0] = (BufferedImage) rep;
107 }
b0e88ebd 108
b9ce9cad
NR
109 @Override
110 protected void onError(Exception e) {
111 Instance.getTraceHandler().error(e);
112 }
113 }.connect();
114 } catch (Exception e) {
115 Instance.getTraceHandler().error(e);
116 }
b0e88ebd 117
b9ce9cad 118 return result[0];
085a2f9a
NR
119 }
120
121 @Override
122 public BufferedImage getSourceCover(final String source) {
b9ce9cad
NR
123 final BufferedImage[] result = new BufferedImage[1];
124
125 try {
126 new ConnectActionClientObject(host, port, true) {
127 @Override
128 public void action(Version serverVersion) throws Exception {
416c54f8 129 Object rep = send(new Object[] { md5, "GET_SOURCE_COVER",
b9ce9cad
NR
130 source });
131 result[0] = (BufferedImage) rep;
132 }
133
134 @Override
135 protected void onError(Exception e) {
136 Instance.getTraceHandler().error(e);
137 }
138 }.connect();
139 } catch (Exception e) {
140 Instance.getTraceHandler().error(e);
141 }
142
143 return result[0];
b0e88ebd 144 }
68e2c6d2
NR
145
146 @Override
ff05b828 147 public synchronized Story getStory(final String luid, Progress pg) {
b9ce9cad
NR
148 final Progress pgF = pg;
149 final Story[] result = new Story[1];
68e2c6d2 150
b9ce9cad
NR
151 try {
152 new ConnectActionClientObject(host, port, true) {
153 @Override
154 public void action(Version serverVersion) throws Exception {
155 Progress pg = pgF;
156 if (pg == null) {
157 pg = new Progress();
158 }
159
416c54f8 160 Object rep = send(new Object[] { md5, "GET_STORY", luid });
b9ce9cad
NR
161
162 MetaData meta = null;
163 if (rep instanceof MetaData) {
164 meta = (MetaData) rep;
165 if (meta.getWords() <= Integer.MAX_VALUE) {
166 pg.setMinMax(0, (int) meta.getWords());
167 }
168 }
169
170 List<Object> list = new ArrayList<Object>();
171 for (Object obj = send(null); obj != null; obj = send(null)) {
172 list.add(obj);
173 pg.add(1);
174 }
175
176 result[0] = RemoteLibraryServer.rebuildStory(list);
177 pg.done();
178 }
179
180 @Override
181 protected void onError(Exception e) {
182 Instance.getTraceHandler().error(e);
183 }
184 }.connect();
185 } catch (Exception e) {
186 Instance.getTraceHandler().error(e);
187 }
188
189 return result[0];
68e2c6d2
NR
190 }
191
192 @Override
b9ce9cad
NR
193 public synchronized Story save(final Story story, final String luid,
194 Progress pg) throws IOException {
0fa0fe95
NR
195 final String[] luidSaved = new String[1];
196 Progress pgSave = new Progress();
197 Progress pgRefresh = new Progress();
198 if (pg == null) {
199 pg = new Progress();
200 }
201
202 pg.setMinMax(0, 10);
203 pg.addProgress(pgSave, 9);
204 pg.addProgress(pgRefresh, 1);
205
206 final Progress pgF = pgSave;
b9ce9cad
NR
207
208 new ConnectActionClientObject(host, port, true) {
209 @Override
210 public void action(Version serverVersion) throws Exception {
211 Progress pg = pgF;
b9ce9cad
NR
212 if (story.getMeta().getWords() <= Integer.MAX_VALUE) {
213 pg.setMinMax(0, (int) story.getMeta().getWords());
214 }
215
416c54f8 216 send(new Object[] { md5, "SAVE_STORY", luid });
b9ce9cad
NR
217
218 List<Object> list = RemoteLibraryServer.breakStory(story);
219 for (Object obj : list) {
220 send(obj);
221 pg.add(1);
222 }
223
edf79e5e 224 luidSaved[0] = (String) send(null);
0fa0fe95 225
b9ce9cad
NR
226 pg.done();
227 }
228
229 @Override
230 protected void onError(Exception e) {
231 Instance.getTraceHandler().error(e);
232 }
233 }.connect();
085a2f9a
NR
234
235 // because the meta changed:
236 clearCache();
0fa0fe95 237 refresh(pgRefresh);
edf79e5e
NR
238
239 MetaData meta = getInfo(luidSaved[0]);
240 meta.setCover(story.getMeta().getCover());
241 story.setMeta(meta);
0fa0fe95
NR
242
243 pg.done();
085a2f9a
NR
244
245 return story;
68e2c6d2
NR
246 }
247
248 @Override
b9ce9cad
NR
249 public synchronized void delete(final String luid) throws IOException {
250 new ConnectActionClientObject(host, port, true) {
251 @Override
252 public void action(Version serverVersion) throws Exception {
416c54f8 253 send(new Object[] { md5, "DELETE_STORY", luid });
b9ce9cad
NR
254 }
255
256 @Override
257 protected void onError(Exception e) {
258 Instance.getTraceHandler().error(e);
259 }
260 }.connect();
68e2c6d2
NR
261 }
262
263 @Override
b9ce9cad
NR
264 public void setSourceCover(final String source, final String luid) {
265 try {
266 new ConnectActionClientObject(host, port, true) {
267 @Override
268 public void action(Version serverVersion) throws Exception {
416c54f8 269 send(new Object[] { md5, "SET_SOURCE_COVER", source, luid });
b9ce9cad
NR
270 }
271
272 @Override
273 protected void onError(Exception e) {
274 Instance.getTraceHandler().error(e);
275 }
276 }.connect();
277 } catch (IOException e) {
278 Instance.getTraceHandler().error(e);
edf79e5e
NR
279 }
280 }
281
282 @Override
283 // Could work (more slowly) without it
284 public Story imprt(final URL url, Progress pg) throws IOException {
285 if (pg == null) {
286 pg = new Progress();
287 }
288
289 pg.setMinMax(0, 2);
290 Progress pgImprt = new Progress();
291 Progress pgGet = new Progress();
292 pg.addProgress(pgImprt, 1);
293 pg.addProgress(pgGet, 1);
294
295 final Progress pgF = pgImprt;
296 final String[] luid = new String[1];
297
298 try {
299 new ConnectActionClientObject(host, port, true) {
300 @Override
301 public void action(Version serverVersion) throws Exception {
302 Progress pg = pgF;
303
304 Object rep = send(new Object[] { md5, "IMPORT",
305 url.toString() });
306
307 while (true) {
308 if (!RemoteLibraryServer.updateProgress(pg, rep)) {
309 break;
310 }
311
312 rep = send(null);
313 }
314
315 pg.done();
316 luid[0] = (String) rep;
317 }
318
319 @Override
320 protected void onError(Exception e) {
321 Instance.getTraceHandler().error(e);
322 }
323 }.connect();
324 } catch (IOException e) {
325 Instance.getTraceHandler().error(e);
326 }
327
328 if (luid[0] == null) {
329 throw new IOException("Remote failure");
330 }
331
332 Story story = getStory(luid[0], pgGet);
333 pgGet.done();
334
335 pg.done();
336 return story;
337 }
338
339 @Override
340 // Could work (more slowly) without it
341 public synchronized void changeSource(final String luid,
342 final String newSource, Progress pg) throws IOException {
343 final Progress pgF = pg == null ? new Progress() : pg;
344
345 try {
346 new ConnectActionClientObject(host, port, true) {
347 @Override
348 public void action(Version serverVersion) throws Exception {
349 Progress pg = pgF;
350
351 Object rep = send(new Object[] { md5, "CHANGE_SOURCE",
352 luid, newSource });
353 while (true) {
354 if (!RemoteLibraryServer.updateProgress(pg, rep)) {
355 break;
356 }
357
358 rep = send(null);
359 }
1b9a09a2
NR
360
361 getInfo(luid).setSource(newSource);
edf79e5e
NR
362 }
363
364 @Override
365 protected void onError(Exception e) {
366 Instance.getTraceHandler().error(e);
367 }
368 }.connect();
369 } catch (IOException e) {
370 Instance.getTraceHandler().error(e);
b9ce9cad 371 }
68e2c6d2
NR
372 }
373
ff05b828 374 @Override
2249988a 375 public synchronized File getFile(final String luid, Progress pg) {
ff05b828
NR
376 throw new java.lang.InternalError(
377 "Operation not supportorted on remote Libraries");
378 }
379
468b960b
NR
380 /**
381 * Stop the server.
382 */
383 public void exit() {
384 try {
385 new ConnectActionClientObject(host, port, true) {
386 @Override
387 public void action(Version serverVersion) throws Exception {
388 send(new Object[] { md5, "EXIT" });
389 }
390
391 @Override
392 protected void onError(Exception e) {
393 Instance.getTraceHandler().error(e);
394 }
395 }.connect();
396 } catch (IOException e) {
397 Instance.getTraceHandler().error(e);
398 }
399 }
400
14b57448 401 @Override
b9ce9cad
NR
402 protected List<MetaData> getMetas(Progress pg) {
403 final Progress pgF = pg;
404 final List<MetaData> metas = new ArrayList<MetaData>();
74a40dfb 405
ff05b828 406 try {
62c63b07 407 new ConnectActionClientObject(host, port, true) {
ff05b828
NR
408 @Override
409 public void action(Version serverVersion) throws Exception {
b9ce9cad
NR
410 Progress pg = pgF;
411 if (pg == null) {
412 pg = new Progress();
851dd538 413 }
74a40dfb 414
416c54f8 415 Object rep = send(new Object[] { md5, "GET_METADATA", "*" });
74a40dfb 416
b9ce9cad
NR
417 while (true) {
418 if (!RemoteLibraryServer.updateProgress(pg, rep)) {
419 break;
420 }
74a40dfb 421
b9ce9cad 422 rep = send(null);
ff05b828 423 }
851dd538 424
b9ce9cad
NR
425 for (MetaData meta : (MetaData[]) rep) {
426 metas.add(meta);
427 }
851dd538
NR
428 }
429
430 @Override
431 protected void onError(Exception e) {
432 Instance.getTraceHandler().error(e);
ff05b828
NR
433 }
434 }.connect();
ff05b828 435 } catch (Exception e) {
62c63b07 436 Instance.getTraceHandler().error(e);
ff05b828 437 }
b9ce9cad
NR
438
439 return metas;
440 }
441
442 @Override
443 protected void clearCache() {
444 }
445
446 // The following methods are only used by Save and Delete in BasicLibrary:
447
448 @Override
449 protected int getNextId() {
450 throw new java.lang.InternalError("Should not have been called");
451 }
452
453 @Override
454 protected void doDelete(String luid) throws IOException {
455 throw new java.lang.InternalError("Should not have been called");
456 }
457
458 @Override
459 protected Story doSave(Story story, Progress pg) throws IOException {
460 throw new java.lang.InternalError("Should not have been called");
e604986c 461 }
b0e88ebd 462}