Remote: try to send the stories image-per-image
[fanfix.git] / src / be / nikiroo / fanfix / library / RemoteLibraryServer.java
1 package be.nikiroo.fanfix.library;
2
3 import java.io.IOException;
4 import java.security.InvalidParameterException;
5 import java.util.ArrayList;
6 import java.util.List;
7
8 import be.nikiroo.fanfix.Instance;
9 import be.nikiroo.fanfix.data.Chapter;
10 import be.nikiroo.fanfix.data.MetaData;
11 import be.nikiroo.fanfix.data.Paragraph;
12 import be.nikiroo.fanfix.data.Story;
13 import be.nikiroo.utils.Version;
14 import be.nikiroo.utils.serial.server.ConnectActionClientObject;
15 import be.nikiroo.utils.serial.server.ConnectActionServerObject;
16 import be.nikiroo.utils.serial.server.ServerObject;
17
18 /**
19 * Create a new remote server that will listen for order on the given port.
20 * <p>
21 * The available commands are given as arrays of objects (first item is the key,
22 * second is the command, the rest are the arguments).
23 * <p>
24 * The key is always a String, the commands are also Strings; the parameters
25 * vary depending upon the command.
26 * <ul>
27 * <li>[key] GET_METADATA *: will return the metadata of all the stories in the
28 * library</li>
29 * <li>[key] GET_STORY [luid]: will return the given story if it exists (or NULL
30 * if not)</li>
31 * <li>[key] SAVE_STORY [luid]: save the story (that must be sent just after the
32 * command) with the given LUID</li>
33 * <li>[key] DELETE_STORY [luid]: delete the story of LUID luid</li>
34 * <li>[key] GET_COVER [luid]: return the cover of the story</li>
35 * <li>[key] GET_SOURCE_COVER [source]: return the cover for this source</li>
36 * <li>[key] SET_SOURCE_COVER [source], [luid]: set the default cover for the
37 * given source to the cover of the story denoted by luid</li>
38 * <li>[key] EXIT: stop the server</li>
39 * </ul>
40 *
41 * @author niki
42 */
43 public class RemoteLibraryServer extends ServerObject {
44 private final String key;
45
46 /**
47 * Create a new remote server (will not be active until
48 * {@link RemoteLibraryServer#start()} is called).
49 *
50 * @param key
51 * the key that will restrict access to this server
52 * @param port
53 * the port to listen on
54 *
55 * @throws IOException
56 * in case of I/O error
57 */
58 public RemoteLibraryServer(String key, int port) throws IOException {
59 super("Fanfix remote library", port, true);
60 this.key = key;
61 }
62
63 @Override
64 protected Object onRequest(ConnectActionServerObject action,
65 Version clientVersion, Object data) throws Exception {
66 String key = "";
67 String command = "";
68 Object[] args = new Object[0];
69 if (data instanceof Object[]) {
70 Object[] dataArray = (Object[]) data;
71 if (dataArray.length >= 2) {
72 args = new Object[dataArray.length - 2];
73 for (int i = 2; i < dataArray.length; i++) {
74 args[i - 2] = dataArray[i];
75 }
76
77 key = "" + dataArray[0];
78 command = "" + dataArray[1];
79 }
80 }
81
82 System.out.print("[" + command + "] ");
83 for (Object arg : args) {
84 System.out.print(arg + " ");
85 }
86 System.out.println("");
87
88 if (!key.equals(this.key)) {
89 System.out.println("Key rejected.");
90 throw new SecurityException("Invalid key");
91 }
92
93 // TODO: progress (+send name + %age info back to client)
94
95 if ("GET_METADATA".equals(command)) {
96 if (args[0].equals("*")) {
97 List<MetaData> metas = Instance.getLibrary().getMetas(null);
98 return metas.toArray(new MetaData[] {});
99 }
100 throw new InvalidParameterException(
101 "only * is valid here, but you passed: " + args[0]);
102 } else if ("GET_STORY".equals(command)) {
103 Story story = Instance.getLibrary().getStory("" + args[0], null);
104 sendStory(story, action);
105 } else if ("SAVE_STORY".equals(command)) {
106 Story story = recStory(action);
107 Instance.getLibrary().save(story, "" + args[1], null);
108 } else if ("DELETE_STORY".equals(command)) {
109 Instance.getLibrary().delete("" + args[0]);
110 } else if ("GET_COVER".equals(command)) {
111 return Instance.getLibrary().getCover("" + args[0]);
112 } else if ("GET_SOURCE_COVER".equals(command)) {
113 return Instance.getLibrary().getSourceCover("" + args[0]);
114 } else if ("SET_SOURCE_COVER".equals(command)) {
115 Instance.getLibrary().setSourceCover("" + args[0], "" + args[1]);
116 } else if ("EXIT".equals(command)) {
117 stop(0, false);
118 }
119
120 return null;
121 }
122
123 public static void sendStory(Story story, Object sender)
124 throws NoSuchFieldException, NoSuchMethodException,
125 ClassNotFoundException, IOException {
126
127 if (!story.getMeta().isImageDocument()) {
128 sendNextObject(sender, story);
129 return;
130 }
131
132 story = story.clone();
133
134 List<Chapter> chaps = story.getChapters();
135 story.setChapters(new ArrayList<Chapter>());
136 sendNextObject(sender, story);
137
138 for (Chapter chap : chaps) {
139 List<Paragraph> paras = chap.getParagraphs();
140 chap.setParagraphs(new ArrayList<Paragraph>());
141 sendNextObject(sender, chap);
142
143 for (Paragraph para : paras) {
144 sendNextObject(sender, para);
145 }
146 }
147 }
148
149 public static Story recStory(Object source) throws NoSuchFieldException,
150 NoSuchMethodException, ClassNotFoundException, IOException {
151
152 Story story = null;
153
154 Object obj = getNextObject(source);
155 if (obj instanceof Story) {
156 story = (Story) obj;
157
158 Chapter current = null;
159 for (obj = getNextObject(source); obj != null; obj = getNextObject(source)) {
160 if (obj instanceof Chapter) {
161 current = (Chapter) obj;
162 story.getChapters().add(current);
163 } else if (obj instanceof Paragraph) {
164 current.getParagraphs().add((Paragraph) obj);
165 }
166 }
167 }
168
169 return story;
170 }
171
172 private static Object getNextObject(Object clientOrServer)
173 throws NoSuchFieldException, NoSuchMethodException,
174 ClassNotFoundException, IOException {
175 if (clientOrServer instanceof ConnectActionClientObject) {
176 ConnectActionClientObject client = (ConnectActionClientObject) clientOrServer;
177 return client.send(null);
178 } else if (clientOrServer instanceof ConnectActionServerObject) {
179 ConnectActionServerObject server = (ConnectActionServerObject) clientOrServer;
180 Object obj = server.rec();
181 server.send(null);
182 return obj;
183 } else {
184 throw new ClassNotFoundException();
185 }
186 }
187
188 private static void sendNextObject(Object clientOrServer, Object obj)
189 throws NoSuchFieldException, NoSuchMethodException,
190 ClassNotFoundException, IOException {
191 if (clientOrServer instanceof ConnectActionClientObject) {
192 ConnectActionClientObject client = (ConnectActionClientObject) clientOrServer;
193 client.send(obj);
194 } else if (clientOrServer instanceof ConnectActionServerObject) {
195 ConnectActionServerObject server = (ConnectActionServerObject) clientOrServer;
196 server.send(obj);
197 server.rec();
198 } else {
199 throw new ClassNotFoundException();
200 }
201 }
202 }