f3104135f2977b689a222ea68242c8bc5be75d27
[fanfix.git] / src / be / nikiroo / fanfix / library / RemoteLibrary.java
1 package be.nikiroo.fanfix.library;
2
3 import java.awt.image.BufferedImage;
4 import java.io.File;
5 import java.io.IOException;
6 import java.net.UnknownHostException;
7 import java.util.ArrayList;
8 import java.util.List;
9
10 import be.nikiroo.fanfix.Instance;
11 import be.nikiroo.fanfix.data.MetaData;
12 import be.nikiroo.fanfix.data.Story;
13 import be.nikiroo.utils.Progress;
14 import be.nikiroo.utils.StringUtils;
15 import be.nikiroo.utils.Version;
16 import be.nikiroo.utils.serial.server.ConnectActionClientObject;
17
18 /**
19 * This {@link BasicLibrary} will access a remote server to list the available
20 * stories, and download the ones you try to load to the local directory
21 * specified in the configuration.
22 *
23 * @author niki
24 */
25 public class RemoteLibrary extends BasicLibrary {
26 private String host;
27 private int port;
28 private final String md5;
29
30 /**
31 * Create a {@link RemoteLibrary} linked to the given server.
32 *
33 * @param key
34 * the key that will allow us to exchange information with the
35 * server
36 * @param host
37 * the host to contact or NULL for localhost
38 * @param port
39 * the port to contact it on
40 */
41 public RemoteLibrary(String key, String host, int port) {
42 this.md5 = StringUtils.getMd5Hash(key);
43 this.host = host;
44 this.port = port;
45 }
46
47 @Override
48 public String getLibraryName() {
49 return host + ":" + port;
50 }
51
52 @Override
53 public Status getStatus() {
54 final Status[] result = new Status[1];
55
56 result[0] = Status.INVALID;
57
58 ConnectActionClientObject action = null;
59 try {
60 action = new ConnectActionClientObject(host, port, true) {
61 @Override
62 public void action(Version serverVersion) throws Exception {
63 Object rep = send(new Object[] { md5, "PING" });
64 if ("PONG".equals(rep)) {
65 result[0] = Status.READY;
66 } else {
67 result[0] = Status.UNAUTORIZED;
68 }
69 }
70
71 @Override
72 protected void onError(Exception e) {
73 result[0] = Status.UNAVAILABLE;
74 }
75 };
76
77 } catch (UnknownHostException e) {
78 result[0] = Status.INVALID;
79 } catch (IllegalArgumentException e) {
80 result[0] = Status.INVALID;
81 } catch (Exception e) {
82 result[0] = Status.UNAVAILABLE;
83 }
84
85 if (action != null) {
86 try {
87 action.connect();
88 } catch (Exception e) {
89 result[0] = Status.UNAVAILABLE;
90 }
91 }
92
93 return result[0];
94 }
95
96 @Override
97 public BufferedImage getCover(final String luid) {
98 final BufferedImage[] result = new BufferedImage[1];
99
100 try {
101 new ConnectActionClientObject(host, port, true) {
102 @Override
103 public void action(Version serverVersion) throws Exception {
104 Object rep = send(new Object[] { md5, "GET_COVER", luid });
105 result[0] = (BufferedImage) rep;
106 }
107
108 @Override
109 protected void onError(Exception e) {
110 Instance.getTraceHandler().error(e);
111 }
112 }.connect();
113 } catch (Exception e) {
114 Instance.getTraceHandler().error(e);
115 }
116
117 return result[0];
118 }
119
120 @Override
121 public BufferedImage getSourceCover(final String source) {
122 final BufferedImage[] result = new BufferedImage[1];
123
124 try {
125 new ConnectActionClientObject(host, port, true) {
126 @Override
127 public void action(Version serverVersion) throws Exception {
128 Object rep = send(new Object[] { md5, "GET_SOURCE_COVER",
129 source });
130 result[0] = (BufferedImage) rep;
131 }
132
133 @Override
134 protected void onError(Exception e) {
135 Instance.getTraceHandler().error(e);
136 }
137 }.connect();
138 } catch (Exception e) {
139 Instance.getTraceHandler().error(e);
140 }
141
142 return result[0];
143 }
144
145 @Override
146 public synchronized Story getStory(final String luid, Progress pg) {
147 final Progress pgF = pg;
148 final Story[] result = new Story[1];
149
150 try {
151 new ConnectActionClientObject(host, port, true) {
152 @Override
153 public void action(Version serverVersion) throws Exception {
154 Progress pg = pgF;
155 if (pg == null) {
156 pg = new Progress();
157 }
158
159 Object rep = send(new Object[] { md5, "GET_STORY", luid });
160
161 MetaData meta = null;
162 if (rep instanceof MetaData) {
163 meta = (MetaData) rep;
164 if (meta.getWords() <= Integer.MAX_VALUE) {
165 pg.setMinMax(0, (int) meta.getWords());
166 }
167 }
168
169 List<Object> list = new ArrayList<Object>();
170 for (Object obj = send(null); obj != null; obj = send(null)) {
171 list.add(obj);
172 pg.add(1);
173 }
174
175 result[0] = RemoteLibraryServer.rebuildStory(list);
176 pg.done();
177 }
178
179 @Override
180 protected void onError(Exception e) {
181 Instance.getTraceHandler().error(e);
182 }
183 }.connect();
184 } catch (Exception e) {
185 Instance.getTraceHandler().error(e);
186 }
187
188 return result[0];
189 }
190
191 @Override
192 public synchronized Story save(final Story story, final String luid,
193 Progress pg) throws IOException {
194 final String[] luidSaved = new String[1];
195 Progress pgSave = new Progress();
196 Progress pgRefresh = new Progress();
197 if (pg == null) {
198 pg = new Progress();
199 }
200
201 pg.setMinMax(0, 10);
202 pg.addProgress(pgSave, 9);
203 pg.addProgress(pgRefresh, 1);
204
205 final Progress pgF = pgSave;
206
207 new ConnectActionClientObject(host, port, true) {
208 @Override
209 public void action(Version serverVersion) throws Exception {
210 Progress pg = pgF;
211 if (story.getMeta().getWords() <= Integer.MAX_VALUE) {
212 pg.setMinMax(0, (int) story.getMeta().getWords());
213 }
214
215 send(new Object[] { md5, "SAVE_STORY", luid });
216
217 List<Object> list = RemoteLibraryServer.breakStory(story);
218 for (Object obj : list) {
219 send(obj);
220 pg.add(1);
221 }
222
223 send(null); // done sending the story
224 luidSaved[0] = (String) send(null); // get LUID
225
226 pg.done();
227 }
228
229 @Override
230 protected void onError(Exception e) {
231 Instance.getTraceHandler().error(e);
232 }
233 }.connect();
234
235 // because the meta changed:
236 clearCache();
237 refresh(pgRefresh);
238 story.setMeta(getInfo(luidSaved[0]));
239
240 pg.done();
241
242 return story;
243 }
244
245 @Override
246 public synchronized void delete(final String luid) throws IOException {
247 new ConnectActionClientObject(host, port, true) {
248 @Override
249 public void action(Version serverVersion) throws Exception {
250 send(new Object[] { md5, "DELETE_STORY", luid });
251 }
252
253 @Override
254 protected void onError(Exception e) {
255 Instance.getTraceHandler().error(e);
256 }
257 }.connect();
258 }
259
260 @Override
261 public void setSourceCover(final String source, final String luid) {
262 try {
263 new ConnectActionClientObject(host, port, true) {
264 @Override
265 public void action(Version serverVersion) throws Exception {
266 send(new Object[] { md5, "SET_SOURCE_COVER", source, luid });
267 }
268
269 @Override
270 protected void onError(Exception e) {
271 Instance.getTraceHandler().error(e);
272 }
273 }.connect();
274 } catch (IOException e) {
275 Instance.getTraceHandler().error(e);
276 }
277 }
278
279 @Override
280 public synchronized File getFile(final String luid, Progress pg) {
281 throw new java.lang.InternalError(
282 "Operation not supportorted on remote Libraries");
283 }
284
285 /**
286 * Stop the server.
287 */
288 public void exit() {
289 try {
290 new ConnectActionClientObject(host, port, true) {
291 @Override
292 public void action(Version serverVersion) throws Exception {
293 send(new Object[] { md5, "EXIT" });
294 }
295
296 @Override
297 protected void onError(Exception e) {
298 Instance.getTraceHandler().error(e);
299 }
300 }.connect();
301 } catch (IOException e) {
302 Instance.getTraceHandler().error(e);
303 }
304 }
305
306 @Override
307 protected List<MetaData> getMetas(Progress pg) {
308 final Progress pgF = pg;
309 final List<MetaData> metas = new ArrayList<MetaData>();
310
311 try {
312 new ConnectActionClientObject(host, port, true) {
313 @Override
314 public void action(Version serverVersion) throws Exception {
315 Progress pg = pgF;
316 if (pg == null) {
317 pg = new Progress();
318 }
319
320 Object rep = send(new Object[] { md5, "GET_METADATA", "*" });
321
322 while (true) {
323 if (!RemoteLibraryServer.updateProgress(pg, rep)) {
324 break;
325 }
326
327 rep = send(null);
328 }
329
330 for (MetaData meta : (MetaData[]) rep) {
331 metas.add(meta);
332 }
333 }
334
335 @Override
336 protected void onError(Exception e) {
337 Instance.getTraceHandler().error(e);
338 }
339 }.connect();
340 } catch (Exception e) {
341 Instance.getTraceHandler().error(e);
342 }
343
344 return metas;
345 }
346
347 @Override
348 protected void clearCache() {
349 }
350
351 // The following methods are only used by Save and Delete in BasicLibrary:
352
353 @Override
354 protected int getNextId() {
355 throw new java.lang.InternalError("Should not have been called");
356 }
357
358 @Override
359 protected void doDelete(String luid) throws IOException {
360 throw new java.lang.InternalError("Should not have been called");
361 }
362
363 @Override
364 protected Story doSave(Story story, Progress pg) throws IOException {
365 throw new java.lang.InternalError("Should not have been called");
366 }
367 }