New web library (http/https)
[nikiroo-utils.git] / src / be / nikiroo / fanfix / library / WebLibrary.java
CommitLineData
f433d153
NR
1package be.nikiroo.fanfix.library;
2
3import java.io.File;
4import java.io.IOException;
5import java.io.InputStream;
6import java.net.URL;
7import java.util.ArrayList;
8import java.util.HashMap;
9import java.util.List;
10import java.util.Map;
11
12import org.json.JSONArray;
13import org.json.JSONObject;
14
15import be.nikiroo.fanfix.Instance;
16import be.nikiroo.fanfix.data.JsonIO;
17import be.nikiroo.fanfix.data.MetaData;
18import be.nikiroo.fanfix.data.Story;
19import be.nikiroo.utils.IOUtils;
20import be.nikiroo.utils.Image;
21import be.nikiroo.utils.Progress;
22
23/**
24 * This {@link BasicLibrary} will access a remote server to list the available
25 * stories, and download the ones you try to load to the local directory
26 * specified in the configuration.
27 * <p>
28 * This remote library uses http:// or https://.
29 *
30 * @author niki
31 */
32public class WebLibrary extends BasicLibrary {
33 private String host;
34 private int port;
35 private final String key;
36 private final String subkey;
37
38 // informative only (server will make the actual checks)
39 private boolean rw;
40
41 /**
42 * Create a {@link RemoteLibrary} linked to the given server.
43 * <p>
44 * Note that the key is structured:
45 * <tt><b><i>xxx</i></b>(|<b><i>yyy</i></b>|<b>wl</b>)(|<b>rw</b>)</tt>
46 * <p>
47 * Note that anything before the first pipe (<tt>|</tt>) character is
48 * considered to be the encryption key, anything after that character is
49 * called the subkey (including the other pipe characters and flags!).
50 * <p>
51 * This is important because the subkey (including the pipe characters and
52 * flags) must be present as-is in the server configuration file to be
53 * allowed.
54 * <ul>
55 * <li><b><i>xxx</i></b>: the encryption key used to communicate with the
56 * server</li>
57 * <li><b><i>yyy</i></b>: the secondary key</li>
58 * <li><b>rw</b>: flag to allow read and write access if it is not the
59 * default on this server</li>
60 * <li><b>wl</b>: flag to allow access to all the stories (bypassing the
61 * whitelist if it exists)</li>
62 * </ul>
63 * <p>
64 * Some examples:
65 * <ul>
66 * <li><b>my_key</b>: normal connection, will take the default server
67 * options</li>
68 * <li><b>my_key|agzyzz|wl</b>: will ask to bypass the white list (if it
69 * exists)</li>
70 * <li><b>my_key|agzyzz|rw</b>: will ask read-write access (if the default
71 * is read-only)</li>
72 * <li><b>my_key|agzyzz|wl|rw</b>: will ask both read-write access and white
73 * list bypass</li>
74 * </ul>
75 *
76 * @param key
77 * the key that will allow us to exchange information with the
78 * server
79 * @param host
80 * the host to contact or NULL for localhost
81 * @param port
82 * the port to contact it on
83 */
84 public WebLibrary(String key, String host, int port) {
85 int index = -1;
86 if (key != null) {
87 index = key.indexOf('|');
88 }
89
90 if (index >= 0) {
91 this.key = key.substring(0, index);
92 this.subkey = key.substring(index + 1);
93 } else {
94 this.key = key;
95 this.subkey = "";
96 }
97
98 this.rw = subkey.contains("|rw");
99
100 this.host = host;
101 this.port = port;
102
103 // TODO: not supported yet
104 this.rw = false;
105 }
106
107 @Override
108 public Status getStatus() {
109 try {
110 download("/");
111 } catch (IOException e) {
112 try {
113 download("/style.css");
114 return Status.UNAUTHORIZED;
115 } catch (IOException ioe) {
116 return Status.INVALID;
117 }
118 }
119
120 return rw ? Status.READ_WRITE : Status.READ_ONLY;
121 }
122
123 @Override
124 public String getLibraryName() {
125 return (rw ? "[READ-ONLY] " : "") + host + ":" + port;
126 }
127
128 @Override
129 public Image getCover(String luid) throws IOException {
130 InputStream in = download("/story/" + luid + "/cover");
131 if (in != null) {
132 return new Image(in);
133 }
134
135 return null;
136 }
137
138 @Override
139 public void setSourceCover(String source, String luid) throws IOException {
140 // TODO Auto-generated method stub
141 throw new IOException("Not implemented yet");
142 }
143
144 @Override
145 public void setAuthorCover(String author, String luid) throws IOException {
146 // TODO Auto-generated method stub
147 throw new IOException("Not implemented yet");
148 }
149
150 @Override
151 protected List<MetaData> getMetas(Progress pg) throws IOException {
152 List<MetaData> metas = new ArrayList<MetaData>();
153 InputStream in = download("/list/luids");
154 JSONArray jsonArr = new JSONArray(IOUtils.readSmallStream(in));
155 for (int i = 0; i < jsonArr.length(); i++) {
156 JSONObject json = jsonArr.getJSONObject(i);
157 metas.add(JsonIO.toMetaData(json));
158 }
159
160 return metas;
161 }
162
163 @Override
164 // Could work (more slowly) without it
165 public MetaData imprt(final URL url, Progress pg) throws IOException {
166 if (true)
167 throw new IOException("Not implemented yet");
168
169 // Import the file locally if it is actually a file
170
171 if (url == null || url.getProtocol().equalsIgnoreCase("file")) {
172 return super.imprt(url, pg);
173 }
174
175 // Import it remotely if it is an URL
176
177 // TODO
178 return super.imprt(url, pg);
179 }
180
181 @Override
182 // Could work (more slowly) without it
183 protected synchronized void changeSTA(final String luid,
184 final String newSource, final String newTitle,
185 final String newAuthor, Progress pg) throws IOException {
186 // TODO
187 super.changeSTA(luid, newSource, newTitle, newAuthor, pg);
188 }
189
190 @Override
191 protected void updateInfo(MetaData meta) {
192 // Will be taken care of directly server side
193 }
194
195 @Override
196 protected void invalidateInfo(String luid) {
197 // Will be taken care of directly server side
198 }
199
200 // The following methods are only used by Save and Delete in BasicLibrary:
201
202 @Override
203 protected int getNextId() {
204 throw new java.lang.InternalError("Should not have been called");
205 }
206
207 @Override
208 protected void doDelete(String luid) throws IOException {
209 throw new java.lang.InternalError("Should not have been called");
210 }
211
212 @Override
213 protected Story doSave(Story story, Progress pg) throws IOException {
214 throw new java.lang.InternalError("Should not have been called");
215 }
216
217 //
218
219 @Override
220 public File getFile(final String luid, Progress pg) {
221 throw new java.lang.InternalError(
222 "Operation not supportorted on remote Libraries");
223 }
224
225 // starts with "/"
226 private InputStream download(String path) throws IOException {
227 URL url = new URL(host + ":" + port + path);
228
229 Map<String, String> post = new HashMap<String, String>();
230 post.put("login", subkey);
231 post.put("password", key);
232
233 return Instance.getInstance().getCache().openNoCache(url, null, post,
234 null, null);
235 }
236}