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